本文基於MCUXpresso SDK的USB協議棧,討論了多CDC ACM在NXP RT1060平台的實現。文中的工作在MCUXpresso SDK USB協議棧的基礎上做了兩處改進:
-
由於Notification功能在大多數實際的CDC ACM應用中基本不會用到,本文去掉了Notification使用的EP,在EHCI USB控制器支持8個雙向硬體EP的情況下,實現了多達7個CDC ACM通道的理論最大值。
-
屏蔽了複雜的USB協議和代碼的諸多細節,使得CDC ACM 的數量僅僅由一個宏來進行控制,這樣把開發時切換CDC ACM數目的時間,從數小時到數天縮短為秒級,大幅提升了用戶使用體驗。
改進之後的代碼經過在RT1060 EVK上面測試,運行良好。
USB CDC的內容非常廣泛,本文只討論其最常見的一種應用模型——ACM。ACM是英文Abstract Control Model的縮寫。這個模型是隸屬於PSTN設備,PSTN是Public Switched Telephone Network的英文縮寫。PSTN是一種非常古老的電話交換網絡。ACM是為模擬PSTN中傳統的Modem設備而設計的。
我們知道,Modem的控制接口正是UART。全功能支持Modem的UART控制信號線多達9根。但是在嵌入式的世界,更多使用的是精簡版本的UART,即只使用TX、RX、GND這三個信號實現簡單的雙向通信。所以我們可以把CDC ACM看成是一個USB to UART的Bridge。
隨著時代的發展,很多PC,尤其是筆記本電腦,目前已經取消了UART,USB成為了主流的標配。但是,多年來,由於UART簡單易用,並且有深厚的群眾基礎,經年累月的使用習慣,放棄UART會是一件很痛苦的事情。而主流的OS比如Linux、Windows、MacOS對CDC ACM的支持都很好,CDC ACM逐漸的代替了傳統的物理串口,延續了傳統物理串口在新型電腦上的使用。在PC上,UART的肉體滅亡了,但是靈魂依舊永存,依附於USB,UART會一直存在。
從協議的角度講CDC ACM,相信會很枯燥。因為USB浩如煙海的複雜協議會看得每個正常的人心煩意亂。所以小編這裡並不準備把整個CDC ACM的協議內容在這裡完整的講一遍,那實在是太複雜了。但是如果完全不講協議,小編也無法表達多CDC ACM實現技術的重點。下面小編會嘗試用最簡潔的方式來進行表達,會涉及協議,但是會突出重點,省略掉很多不重要的細節。
這裡可以看到,一個CDC ACM實例由Communication接口和Data接口構成。Communication接口包含class專用接口和一個可選的中斷型EP。而Data接口包含一對雙向的BULK EP用於數據通信,他們就是虛擬UART的TX和RX的物理載體。
在我們SDK的默認實現中,Communication接口下的端點默認是使能的。這樣,實現一個CDC ACM通道就需要2個端點,RT1060的USB控制器共有8個雙向端點。除去端點0,只有7個端點可以用於CDC ACM,這樣RT1060上可實現的CDC ACM實例最大數目為3。
而根據USB規範,Communication接口下的端點是可選的,小編嘗試了對此端點進行移除。移除後,每個CDC ACM僅占用一個雙向端點,這樣,最終成功實現了7個CDC ACM實例。
小編在實踐的過程中,心中一直有個疑問,那就是Communication接口的那個Notification用的INT IN EP到底是幹嘛用的。藉助協議分析儀提供的線索,小編終於在Spec中找到了定義:
說白了是全功能UART的設備狀態模擬,用於原始Modem的狀態上報和載波控制。而我們大多數的情況下使用CDC ACM,只是為了做簡單的雙向收發,而並不需要全功能的UART。在移除了Notification EP後,系統會變得更加簡單,CDC ACM模擬的全功能UART退化為只有TX、RX的精簡版本。
小編在實踐過程中的另一個疑問是,對於多CDC的情況,設置波特率之類的命令,是如何區分該命令是給哪個CDC ACM的實例呢?
藉助於USB邏輯分析儀,我們可以很快找到答案,每一組命令都是針對某一個Interface的,我們可以通過Interface的編號來識別當前的命令是傳給哪一個CDC ACM實例的。
下圖更加清晰地展示了實現的諸多細節。需要注意的是,這些命令是從EP0走的,移除Notification EP對此命令並無影響。
說到這裡,小編想小結一下:CDC ACM是用於模擬PSTN環境下的Modem控制接口,即全功能UART,我們可以在此基礎上進行精簡,得到僅具備TX, RX功能的虛擬UART設備。
由於USB協議和代碼的複雜性,為了方便用戶使用,小編實現了通過一個宏定義來控制CDC的通道數。用戶只需要修改一個宏定義的值,就可以控制CDC的通道數量,代碼如下:#define USB_DEVICE_CONFIG_CDC_ACM (6U)
具體的實現,有興趣的讀者可以去參考本文提供的代碼,這裡小編只說一下實現的思路。
為了實現通過一個宏控制CDC的數量,我們需要軟體能夠提供以下功能:
-
自動分配每個CDC ACM的接口編號
-
自動分配每個CDC ACM的端點編號
-
自動生成配置描述符
-
自動初始化SDK USB協議棧的數據結構
-
自動匹配SDK USB協議棧的其他各種要求
為了完成所有這些自動化的操作,經粗略統計,在原始SDK的基礎上,涉及的更改點大約有66處。
本文的原代碼可以從github.com進行下載,無需密碼,下載鏈接為:該代碼編譯後可以直接下載到RT1060 EVK運行。
在本人的實踐過程中,最開始只是實現了nCDC用一個宏定義的自動生成部分,並未能成功實現CDC ACM的Communication接口下的EP移除,在RT1060最大僅能自動實現3個CDC ACM實例。來自NXP LPC/Kinetis SE團隊的ZhangYang同學提供的AN給出了詳細的操作細節(ZhangYang同學成功的在Kinetis MCU上實現了15個CDC ACM實例,其USB控制器支持16個硬體端點)。另外,來自NXP中國區SE團隊的資深USB專家梁平老師提供了寶貴的理論指導意見。在二位同事的熱心幫助下,才使本文設計的實驗能成功實現,並發布本文章。恩智浦MCU加油站
這是由恩智浦官方運營的公眾號,著重為您推薦恩智浦MCU的產品信息、開發技巧、教程文檔、培訓課程等內容。
長按二維碼,關注我們