最近有小伙伴反應USB中的 usb_examples/usb_device_cdc_vcom 例程(USB虛擬串口VCOM)中的一些使用問題,今天集中來說說使用example的必知要點~
實驗平臺和軟件版本說明
本篇文章的實驗平臺為:SDK_2_5_0_LPC54605J512oardslpcxpresso54608usb_examplesusb_device_cdc_vcom但實際上本篇文章適用于NXP大部分的硬件平臺,因為usb_device_cdc_vcom(以下簡稱vcom)這部分例程代碼和硬件關系并不大,屬于USB Stack之上的應用部分,另外這部分代碼在SDK的各個版本上變化也不是很大,所以如果您使用的新版本的SDK,本篇文章也同樣適用。
目標讀者
關于vcom的一些基礎環境搭建/編譯下載等基礎問題這篇文章不再贅述,具體可以參考example文件夾下的readme.pdf. 這里假設讀者:
有一定的USB基礎知識
已經成功跑過這個vcom例程,大概瀏覽過源代碼,并且準備使用vcom的代碼作為參考開發自己的項目產品
重要概念解釋
首先一個最基本的概念:USB所有傳輸都是主機發起的,從機只是被動的響應主機發來的請求
USB OUT 傳輸: 即 USB Host(如PC)向USB Device(如MCU)下發數據, 對應vcom 例程中事件kUSB_DeviceCdcEventRecvResponse. 這個很好理解:對于vcom例子,就是虛擬串口上有數據發到了MCU(比如PC端有一個上位機軟件,打開了虛擬串口,并且向虛擬串口寫入數據)。每當MCU收到數據,都會進入kUSB_DeviceCdcEventRecvResponse.在kUSB_DeviceCdcEventRecvResponse事件中,需要MCU這邊盡快的調用USB_DeviceCdcAcmRecv API將USB中的數據讀取出來,然后USB Stack會和USB硬件一起準備好下次USB OUT事件接收工作。(類似串口的DMA接收機制)
從下圖的CallStack可以看出,kUSB_DeviceCdcEventRecvResponse本質就是BulkOut中斷回調上來的:
USB IN傳輸:即USB Host(PC) 向USB Device(如MCU)索要數據, 比OUT傳輸稍微難理解一些:在vcom這個例程中,由于vcom屬于buck傳輸。每當從機響應上一個IN token之后,就會進入kUSB_DeviceCdcEventSendResponse 事件,從下圖的CallStack也可以看到, kUSB_DeviceCdcEventSendResponse事件本質就是 USB Buck In 中斷回調上來的:
所以每當進入到kUSB_DeviceCdcEventSendResponse的時候,都說明USB IN傳輸已經完成(或取消)。那么從機如何向主機發送數據呢?調用USB_DeviceCdcAcmSend 這個API。但是調用這個API你需要注意,每次調用這個API,你都需要等待發送完成事件(kUSB_DeviceCdcEventSendResponse) 或超時(第一次除外)。在任何時候,你都不能在代碼里連續調用USB_DeviceCdcAcmSend 多次。這個機制類似于串口DMA發送,即:每次調用串口DMA發送的時候,你都要確保上一次串口DMA發送已經完成。 總結如下:
實際上,vcom例程實現的東西很簡單,就是自發自收(echo),把虛擬串口接到的數據再原封不動的發回而已。所涉及的數據傳輸過程中的事件也只有:kUSB_DeviceCdcEventSendResponse 和kUSB_DeviceCdcEventRecvResponse. 其他的USB Class回調事件實際上多半是有關一些配置,控制 (波特率,打開,關閉虛擬串口)等,這部分內容暫不展開,需自學。
usb_device_cdc_vcom的問題 這個例程不太方便的地方就是代碼里把發送和接收是耦合在一起的,對于新手且對USB不熟悉的用戶,都不知道怎么解耦。實際應用中,串口的發送和接收應該是獨立的,沒有太大關系的,但是很可惜,這個example設計的時候硬生生的把發送和接收”粘”在一起,讓新手不太容易剝離開。
這里給出一個簡單的改造方案,把VCOM的發送和接收拆開:
1. 首先對于USB_IN: 注釋掉之前的 USB_DeviceCDCAcmRecv部分,USB IN 傳輸和USB OUT之間沒有必然關系。另外在kUSB_DeviceCdcEventSendResponse中,定義一個標志is_cdc_in_compelte (類比于串口的發送完成中斷,或者DMA發送完成中斷):
2. 對于USB OUT: 將之前的代碼替換為下圖,在收到Host下發的數據后,第一時間調用USB_DeviceCDCAcmRecv,把數據接下來,然后通過一個消息隊列(你可以用你自己實現的一個消息隊列) 發送給應用層。不要在DeviceCdcEventSendResponse中做過多的應用層處理:
3. 其他的有關原demo中的一些變量,比如s_recvSize, s_sendSize 之類的,刪掉處理。在while(1)主循環中,處理USB中斷回調發出來的消息隊列:
通過解耦VCOM的Tx(發送)與Rx(接收),代碼不僅變得清晰簡潔,還提升了模塊間的獨立性和可維護性。這種設計促進了代碼的復用性和可擴展性,為未來的功能升級或定制開發奠定了堅實基礎。無論是對于初次接觸的開發者還是資深工程師,都能從中受益,享受更流暢的編程體驗。希望本期分享對大家有所幫助!
恩智浦致力于打造安全的連接和基礎設施解決方案,為智慧生活保駕護航。
-
NXP
+關注
關注
61文章
1328瀏覽量
187358 -
usb
+關注
關注
60文章
8136瀏覽量
270688 -
虛擬串口
+關注
關注
3文章
63瀏覽量
14138 -
VCOM
+關注
關注
0文章
15瀏覽量
15770 -
指南針
+關注
關注
2文章
17瀏覽量
10990
原文標題:關鍵指南針-NXP USB CDC_VCOM虛擬串口例程
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
評論