USB CDC从理论到实践
本文摘自ST官網(wǎng)的“USB CDC類入門培訓(xùn)”。整理的內(nèi)容是我能夠看得懂的,認(rèn)為比較實(shí)用的,記錄下來,以便以后查閱,同時(shí)也把原文檔中的筆誤給更正了一下。若要看更詳細(xì)的可以去ST技術(shù)文檔中查看,鏈接為:
http://bbs.21ic.com/forum.php?mod=viewthread&tid=726814&page=1&extra=#pid4225064
1 USB CDC類基礎(chǔ)理論知識(shí)介紹
1.1 USB CDC類、USB2.0標(biāo)準(zhǔn)與PSTN之間的關(guān)系
CDC(Communication Device Class)類是USB2.0標(biāo)準(zhǔn)下的一個(gè)子類,定義了通信相關(guān)設(shè)備的抽象集合。它與USB2.0標(biāo)準(zhǔn)以及其下的子類的相互關(guān)系如下圖所示:
如上圖,USB2.0標(biāo)準(zhǔn)下定義了很多子類,有音頻類,CDC類,HID,打印,大容量存儲(chǔ)類,HUB,智能卡等等,這些在usb.org官網(wǎng)上有具體的定義,這里主要介紹通信類CDC。
1.2 從一個(gè)具體的CDC類通信數(shù)據(jù)說起
如上圖,USB CDC類的通信部分主要包含三部分:枚舉過程、虛擬串口操作和數(shù)據(jù)通信。其中虛擬串口操作部分并不一定強(qiáng)制需要,因?yàn)槿籼^這些虛擬串口的操作,實(shí)際上USB依然是可以通信的,這也就是為什么上圖中,在操作虛擬串口之前會(huì)有兩條數(shù)據(jù)通信的數(shù)據(jù)。之所以會(huì)有虛擬串口操作,主要是我們通常使用PC作為Host端,在PC端使用一個(gè)串口工具來與其進(jìn)行通信,PC端的對(duì)應(yīng)驅(qū)動(dòng)將其虛擬成一個(gè)普通串口,這樣一來,可以方便PC端軟件通過操作串口的方式來與其進(jìn)行通信,但實(shí)際上,Host端與Device端物理上是通過USB總線來進(jìn)行通信的,與串口沒有關(guān)系,這一虛擬化過程,起決定性作用的是對(duì)應(yīng)驅(qū)動(dòng),包含如何將每一條具體的虛擬串口操作對(duì)應(yīng)到實(shí)際上的USB操作。需要注意的是,Host端與Device端的USB通信速率并不受所謂的串口波特率影響,它就是標(biāo)準(zhǔn)的USB2.0全速(12Mbps)速度,實(shí)際速率取決于總線的實(shí)際使用率、驅(qū)動(dòng)訪問USB外設(shè)有效速率(兩邊)以及外部環(huán)境對(duì)通信本身造成的干擾率等因素組成。
1.3 CDC類設(shè)備枚舉過程
CDC類設(shè)備與其他標(biāo)準(zhǔn)USB設(shè)備枚舉過程的并沒有什么特殊的地方。在設(shè)備描述符內(nèi)可以使用DeviceClass=0x00, SubClass=0x00, Protocol=0x00 表示此類信息在接口描述符內(nèi)給出;或者也可以使用0x02,0x00,0x00;來表明該設(shè)備為CDC類設(shè)備。或者使用0xef, 0x02,0x01表示當(dāng)前為復(fù)合設(shè)備。
CDC類設(shè)備在枚舉過程中最主要的信息存儲(chǔ)在配置描述符內(nèi):
如上圖所示,CDC類的配置描述符一般包含兩個(gè)接口:一個(gè)控制接口(Interface 0),另外一個(gè)是數(shù)據(jù)接口(Interface 1), 除此之外,還有一個(gè)虛線指向的IAD(Interface Association Description),表示這個(gè)是可選的,得根據(jù)實(shí)際情況來確定其是否真實(shí)存在。
在ST給出的CDC例程中,主要是使用SetLineCoding指令來設(shè)置和修改虛擬串口的波特率,使用GetLineCoding來獲取當(dāng)前波特率,使用SetControlLineState來打開或關(guān)閉串口,這種操作是在Host端CDC驅(qū)動(dòng)來具體映射實(shí)現(xiàn)的, Device端收到控制指令可以處理也可以不處理,用CubeMx自動(dòng)生成的CDC類代碼對(duì)接收到的任何控制指令到?jīng)]有做任何處理,如果需要的話,用戶可按應(yīng)用的需要來處理。
2 CDC類軟件框架介紹
2.1 CDC軟件框架簡(jiǎn)介
如上圖所示,黃色USB Device Core部分為USB設(shè)備庫文件,屬于中間件,它為USB協(xié)議棧的核心源文件,一般不需要修改:
USB Device Core中,Log/debug為打印/調(diào)試開關(guān);
core為USB設(shè)備核心;
USB request中定義了枚舉過程中各種標(biāo)準(zhǔn)請(qǐng)求的處理;
I/O request為底層針對(duì)USB通信接口的封裝。
黃色USB Device Class部分為USB類文件,也屬于中間件,USB設(shè)備庫,目前ST DEMO中支持的類有HID, Customer HID, CDC, MSC, DFU, Audio, ST提供了這些類的源碼框架,其他的Class或者是復(fù)合設(shè)備需要自己根據(jù)實(shí)際需求情況進(jìn)行擴(kuò)展或定制。如果用戶需求只是需要一個(gè)標(biāo)準(zhǔn)類,比如CDC通信,那么最好就使用現(xiàn)成的代碼,不需要做任何修改就可以實(shí)現(xiàn)這個(gè)CDC類通信的功能。
藍(lán)色USB Device HAL Driver為HAL庫部分,是對(duì)USB外設(shè)接口的封裝,屬于底層驅(qū)動(dòng),不需要修改,它分為PCD和LL Driver,PCD處于LL Driver之上。
洋紅色USB Device Configuration為USB配置封裝,位于USB底層HAL層驅(qū)動(dòng)與中間件USB協(xié)議棧之間,一方面向上層(USB設(shè)備庫)提供各種操作調(diào)用接口,另一方面,向底層USB驅(qū)動(dòng)提供各種回調(diào)接口。正是由于它的存在,使得USB協(xié)議棧(USB設(shè)備庫)與底層硬件完全分離,從而使USB設(shè)備庫具有更加兼容所有STM32的通用性。USB Device Configuration為開放給用戶的源文件,用戶可以根據(jù)自己的某些特殊需要進(jìn)行修改,也可以使用默認(rèn)的源文件,假如沒有任何特殊要求的話,我們使用默認(rèn)即可。
Application為應(yīng)用層,USB Device Class有可能將自己對(duì)應(yīng)該的操作接口封裝在一個(gè)操作數(shù)據(jù)結(jié)構(gòu)中,由應(yīng)用來具體實(shí)現(xiàn)這些操作,在系統(tǒng)初始化時(shí),由應(yīng)用將已經(jīng)定義好的操作接口注冊(cè)到對(duì)應(yīng)的USB類中,比如usbd_cdc_if, 就這樣,使得應(yīng)用層的應(yīng)用代碼與屬于中間件層的USB協(xié)議棧分離。同時(shí),USB協(xié)議棧會(huì)將一些字符串描述符放到APP中,當(dāng)USB初始化時(shí)將這些已經(jīng)定義好的字符串通過指針初始化到USB協(xié)議棧中,以便后續(xù)需要時(shí)獲取。
2.2 工程源碼文件與軟件框架的對(duì)應(yīng)關(guān)系
2.3 USBD內(nèi)核與USBD_CDC的關(guān)系
2.1節(jié)中,提到過ST官方Cube庫中提供的官方USB協(xié)議棧,主要是包含了USBD內(nèi)核與USB各種類。USBD內(nèi)核一般是固定的,用戶一般不需要修改,但USBD類,如果用戶需要修改或者擴(kuò)展,比如復(fù)合設(shè)備或者用戶自定義設(shè)備,還有就是,ST目前官方提供的USB設(shè)備類的DEMO程序并沒有囊括所有USB類,因此,若用戶需要實(shí)現(xiàn)這些官方提供DEMO之外的USB類時(shí),則用戶需要根據(jù)自己的需要來定制化自己的USB類。
ST提供的USB協(xié)議棧中已經(jīng)有USBD內(nèi)核,且這個(gè)內(nèi)核源文件一般是不需要修改的,我們需要自定義這么一個(gè)USB類,我們首先得知道要自定義的USB類是如何與USBD內(nèi)核打交道的。
USB協(xié)議棧將所有USB類都抽象成一個(gè)數(shù)據(jù)結(jié)構(gòu):USBD_ClassTypeDef,其定義如下所示:
這個(gè)結(jié)構(gòu)體是一個(gè)抽象類,定義了一些虛擬函數(shù),比如初始化,反初始化,類請(qǐng)求指令處理函數(shù),端點(diǎn)0發(fā)送完成,端點(diǎn)0接收處理,數(shù)據(jù)發(fā)送完成,數(shù)據(jù)接收處理,SOF中斷處理,同步傳輸發(fā)送未完成,同步傳輸接收未完成處理等等;用戶在實(shí)現(xiàn)自己具體的USB類的時(shí)候需要將它實(shí)例化,USBD_ClassTypeDef結(jié)構(gòu)體是USBD內(nèi)核提供給外部定義一個(gè)USB設(shè)備類的窗口,而USB類文件(如usbd_cdc.c)實(shí)際就是實(shí)現(xiàn)這個(gè)結(jié)構(gòu)體具體實(shí)例化的過程。最后將這個(gè)具體實(shí)例化的對(duì)象注冊(cè)到USBD內(nèi)核的同時(shí), USBD內(nèi)核與USBD類也進(jìn)行了關(guān)聯(lián)。
可以這么說,USBD內(nèi)核與USBD類之間的紐帶就是USBD_ClassType這個(gè)結(jié)構(gòu)體。
下面我們來看看ST提供的CDC DEMO中具體CDC類:
這個(gè)就是具體一個(gè)CDC類實(shí)例化的對(duì)象,上層應(yīng)用通過USBD_RegisterClass函數(shù),將此對(duì)象注冊(cè)到usbd內(nèi)核 :
它主要在usbd_cdc.c源文件中實(shí)現(xiàn)它的各個(gè)成員函數(shù),當(dāng)然,usbd_cdc.c源文件中,除了這些CDC類成員函數(shù)的具體實(shí)現(xiàn)之外,還包含其他一些對(duì)上層提供的接口,比如發(fā)送USBD_CDC_TransmitPacket, USBD_CDC_RegisterInterface,上層應(yīng)用通過調(diào)用USBD_CDC_TransmitPacket來發(fā)送數(shù)據(jù),通過USBD_CDC_RegisterInterface來注冊(cè)操作接口,這也是我們接下來將要講述的內(nèi)容。
2.4 USBD_CDC與USBD_CDC_If的關(guān)系
講完了USBD內(nèi)核與USBD_CDC的關(guān)系,接下來講USBD_CDC與上層應(yīng)用是如何對(duì)接的。為了將USBD_CDC與上層應(yīng)用層完全分離出來,類似USBD內(nèi)核與USBD_CDC類完全分離一般,USBD_CDC類對(duì)上層同樣提供一個(gè)抽象的數(shù)據(jù)操作接口USBD_CDC_If結(jié)構(gòu)體:
如上所示,如何處理來自Host端發(fā)送過來的控制指令和數(shù)據(jù),完全是由應(yīng)用層來決定,具體實(shí)現(xiàn)是應(yīng)用層將此抽象的操作接口具體實(shí)例化,并注冊(cè)到USBD_CDC類對(duì)象中:
如上圖所示,通過引入U(xiǎn)SBD_CDC_If這么一個(gè)數(shù)據(jù)結(jié)構(gòu),就實(shí)現(xiàn)了USBD_CDC類與應(yīng)用層的完全分離。USBD_CDC_If的具體實(shí)例化對(duì)象如下:
源文件usbd_cdc_if.c就是實(shí)現(xiàn)這些成員函數(shù)的過程,除此之外,還包含發(fā)送接口。最后應(yīng)用層通過調(diào)用USBD_CDC_RegisterInterface函數(shù)將此操作接口注冊(cè)到USBD_CDC類中 :
2.5 應(yīng)用接口
初始化 :
如上圖所示 :
初始化分4步:
1> 初始化USBD內(nèi)核
2> 給USBD內(nèi)核注冊(cè)USBD_CDC類
3> 給USBD_CDC類注冊(cè)USBD_CDC_If接口
4> 正式啟動(dòng)USBD
- 發(fā)送數(shù)據(jù):
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); - 接收回調(diào)處理:
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len); - 接收控制指令處理 :
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length);
3 實(shí)踐動(dòng)手部分
3.1 實(shí)驗(yàn)環(huán)境及STM32F072-Discovery板簡(jiǎn)介
硬件準(zhǔn)備:
- STM32F072 Discovery板一塊
- Mini USB線兩根
- PC一臺(tái)
軟件準(zhǔn)備:
- IAR V6.7.0 或者以上版本
- STM32CubeF0 V1.7.0
- STM32CubeMX V4.19
- SSCOM串口工具
- VCP虛擬串口驅(qū)動(dòng)
3.2 使用STM32CubeMx制作CDC工程
使用內(nèi)部48M的HSI48 RC作為時(shí)鐘源
最終生成的代碼工程與USB CDC類軟件框架的對(duì)應(yīng)關(guān)系:
3.3 添加測(cè)試代碼
為了更好的驗(yàn)證通信,我們需要添加點(diǎn)測(cè)試代碼:
在接收回調(diào)中,我們將接收到的數(shù)據(jù)轉(zhuǎn)給HandleReceiveData函數(shù)處理:
而在HandleReceiveData函數(shù)中我們將收到的數(shù)據(jù)原樣返回給Host端,這樣一來,Host端的串口工具將發(fā)送什么就將收到什么。
另一方面,我們定義了一全局變量StartFlag,它用來標(biāo)志是否循環(huán)從Device端向Host端主動(dòng)發(fā)送數(shù)據(jù),其值由外部按鍵控制。然后在Main函數(shù)內(nèi)的while(1)循環(huán)內(nèi)添加如下測(cè)試代碼:
只要StartFlag標(biāo)志為1,在枚舉結(jié)束后則不斷向Host端發(fā)送數(shù)據(jù)。
3.4 驗(yàn)證結(jié)果
在編譯完并將代碼燒錄進(jìn)MCU后,我們首先驗(yàn)證PC端通過串口工具發(fā)送數(shù)據(jù)的情況:
如上圖所示,串口工具發(fā)送63個(gè)字節(jié)到Device端后,能夠接收到從Device端返回到的一模一樣的數(shù)據(jù),這說明發(fā)送與接收都是正常的。
在按下用戶按鍵后,串口工具能夠無限收到來自Device端的數(shù)據(jù)。
收發(fā)同時(shí)進(jìn)行也是正常的。至此,USB CDC設(shè)備端的收發(fā)驗(yàn)證均正常。
3.5 注意事項(xiàng)
STM32CubeMx默認(rèn)生成的工程在發(fā)送64整數(shù)倍數(shù)據(jù)的時(shí)候PC端收不到,這個(gè)問題可以參考以下兩個(gè)鏈接:
http://blog.csdn.net/flydream0/article/details/53205286
http://bbs.21ic.com/icview-1708972-1-1.htmlCDC device端若無限向PC端發(fā)送數(shù)據(jù),若PC端沒有及時(shí)讀走數(shù)據(jù),導(dǎo)致PC端接收緩存爆滿,此時(shí)PC端回復(fù)NACK,此時(shí)會(huì)導(dǎo)致發(fā)送返回BUSY。
總結(jié)
以上是生活随笔為你收集整理的USB CDC从理论到实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑城最常用的分区工具DM分区图解
- 下一篇: 小学计算机教案模板范文,小学信息技术教案