之前使用ST官方的庫以及網絡的資料,完成了使用USB HID類進行STM32和PC機的通訊。由于其他原因并沒有深入的分析,雖然實現了功能,但是關于USB設備的枚舉,以及具體的通訊方式都沒有清晰的概念,所以現在回頭重新學習USB相關知識。主要參考資料是《圈圈教你玩USB》、USB枚舉過程圖解,ST官方的USB HID例程。
一,USB數據包
1. USB數據包分類
USB總線上的數據傳輸以包為基本的單位。USB協議規定了四種包:令牌包、數據包、握手包、特殊包。不同的包通過包中的8位PID域區分。
令牌包
令牌包用于啟動 一次USB傳輸,USB的數據傳輸必須由主機發起。令牌包有四種:
輸出令牌包(OUT):用來通知設備將要輸出一個數據包。 數據方向 主機-->設備
輸入令牌包(IN):用來通知設備將要返回一個數據包。 數據方向 設備-->主機
建立令牌包(SETUP):通知設備將要輸出一個數據包,類似OUT包。不過SETUP包只能往端點0發包,只用在控制傳輸中。
幀起始包(SOF):用于幀計數,USB全速設備每毫秒產生一幀,USB高速設備每125μS產生一幀。
OUT , IN, SETUP包的結構:同步域+8位PID+7位地址+4位端點號+5位CRC校驗+包結束符EOP
數據包
數據包用來傳輸數據,分成DATA0. DATA1 。數據格式如下
同步域+8位PID+N個字節的數據+CRC16校驗+包結束符EOP
握手包
握手包用來表示一個傳輸是否被對方確認,有ACK,NAK,STALL,NYET。
ACK:表示正確的接收數據并且有足夠的空間容納數據。主機和設備都可以使用ACK來確認,NAK,STALL,NYET只能夠用于設備返回,主機不能使用。
NAK:表示沒有數據需要返回,或者數據正確接收但是沒有空間容納。當主機收到NAK后,知道設備還未準備好,主機會在合適的時候重新進行數據傳輸。
STALL:表示設備無法執行該請求,或者端點已經被掛起。
NYET:USB高速設備中用。
握手包的格式:同步域+8位PID+包結束符EOP
2. 數據包的處理
在傳輸過程中,具體的處理細節由USB接口的芯片處理完成。
當USB接口芯片正確接收到數據時,如果有空間保存,則它將數據保存并返回ACK,同時,設置一個標志表示已經正確接收到數據;如果沒有空間保存數據,則自動返回NAK。
收到輸入請求時,如果有數據需要發送,則發送數據,并等待接收ACK。只有到數據成功發送出去(即接收到ACK標志后),它才設置標志,表示數據已成功發送;如果無數據需要發送,則它自動返回NAK。
通常只需根據芯片提供的一些標志,準備要發送的數據到端點,或者從端點讀取接收到的數據即可。
二 ,USB事務
雖然USB定義了數據在總線上傳輸的基本單位是包,為了傳輸數據,必須按照一定的關系把這些不同的包組織成事務才能傳輸數據。事務通常由兩個或者三個包組成:令牌包、數據包和握手包。
令牌包用來啟動一個事務,總是由主機發送;數據包用來傳送數據,可以從主機到設備,也可以由設備到主機,方向由令牌包來指定;握手包用來指定數據傳輸結果。
三,USB傳輸類型
USB規定了4種傳輸類型:批量傳輸、等時傳輸、中斷傳輸、控制傳輸。其中前三個傳輸一次數據都是一個事務;控制傳輸包括三個過程,建立過程和狀態過程分別是一個事務,數據過程則可能包含多個事務。
接下來介紹USB設備的枚舉,枚舉就是從設備讀取各種描述符信息,這樣主機就可以根據這些信息來加載合適的驅動,從而知道是什么樣的設備,如何進行通信。 枚舉過程使用的是控制傳輸。控制傳輸可以保證數據的正確性。控制傳輸分三個過程:建立過程,可選數據過程及狀態過程。
下面介紹枚舉的詳細過程。
USB主機檢測到USB設備插入后,就會先對設備復位,并通過一個帶數據過程的控制傳輸完成設備描述符的獲取。
第一步,USB主機會往地址0的端點0發送獲取設備描述符的標準請求,發送請求屬于控制傳輸的建立過程。建立過程是一個事務。首先是令牌包,即主機發送一個SETUP令牌,令牌的格式如上一篇描述的那樣,有令牌的PID,地址和端點號等;其次是數據包,SETUP使用DATA0數據包,數據包中包括標準請求的ID;最后是握手包,設備只能使用ACK來應答,除非出錯不應答。下面根據網上找的USB協議分析捕捉的圖分析該建立過程。
下面通過STM32官方的USB的例子,自己添加打印信息,查看該控制傳輸的建立工程中USB主機發送的請求。如上一篇介紹,我們只需根據硬件置的標志位來判斷USB傳輸的狀態即可。在usb_istr.c的USB_Istr()函數中,根據中斷標志,添加打印信息。在正確傳輸中斷的處理函數CTR_LP()中Setup0_Process()函數表示端點0的建立過程,即上面USB主機復位獲取設備描述符將執行的函數。增加打印信息的函數如下:
/*******************************************************************************
* Function Name : Setup0_Process
* Description : Get the device request data and dispatch to individual process.
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t Setup0_Process(void)
{
union
{
uint8_t* b;
uint16_t* w;
} pBuf;
#ifdef STM32F10X_CL
USB_OTG_EP *ep;
uint16_t offset = 0;
ep = PCD_GetOutEP(ENDP0);
pBuf.b = ep->xfer_buff;
#else
uint16_t offset = 1;
pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */
#endif /* STM32F10X_CL */
#ifdef USB_DEBUG0
printf("rnSETUP0中斷-->控制傳輸.建立過程rn");
#endif /* #if USB_DEBUG0 */
if (pInformation->ControlState != PAUSE)
{
#ifdef USB_DEBUG0
printf("設備可以接收新的數據rn");
#endif /* USB_DEBUG0 */
pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
pInformation->USBbRequest = *pBuf.b++; /* bRequest */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwLength = *pBuf.w; /* wLength */
#ifdef USB_DEBUG0
printf("設備接收數據如下:rn");
printf("0x%x ",pInformation->USBbmRequestType);//用于指定請求的 數據傳輸反向 請求類型 請求的接收者
printf("0x%x ",pInformation->USBbRequest);//標準請求及代碼
printf("0x%x ",pInformation->USBwValue0);
printf("0x%x ",pInformation->USBwValue1);//具體見圈圈書P77頁
printf("0x%x ",pInformation->USBwIndex0);
printf("0x%x ",pInformation->USBwIndex1);
printf("0x%x ",pInformation->USBwLength1);
printf("0x%x ",pInformation->USBwLength0);
printf("rn");
#endif /* USB_DEBUG0 */
}
return Post0_Process();
pInformation->ControlState = SETTING_UP;
if (pInformation->USBwLength == 0)
{
/* Setup with no data stage */
NoData_Setup0();
}
else
{
/* Setup with data stage */
Data_Setup0();
}
return Post0_Process();
}
在打印信息之后直接就讓函數返回,使主機得不到ACK應答,下面根據打印信息看下測試情況。
根據打印信息,由于從機沒有ACK應答給PC機的請求,在PC機嘗試發了3次請求后,就放棄了。可以在PC機的設備管理器看到,在請求打印3次以后出現了unknown device。
關于8個字節的請求代碼的具體含義請參照USB協議,或者在《圈圈教你玩USB》里面對照。
以上就是枚舉過程獲取設備描述符的第一步控制傳輸的建立過程,主機發送獲取描述符的請求,下一篇我們將代碼中ACK返回,使主機接收到建立過程的應答,從而進入到數據過程,即設備響應主機的請求,將設備描述符發送給主機。
上一篇介紹到了主機上電復位USB設備,在控制傳輸的建立過程,發送了8個字節的數據給設備,這8個字節為0x80 0x06 0x00 0x01 0x00 0x00 0x40 0x00,該請求為USB標準設備請求中的GET_DESCRIPTOR請求。0x80表示標準設備請求,數據方向是設備到主機。0x60表示請求類型GET_DESCRIPTOR。0x01表示描述符類型是設備描述符。0x40表示描述符長度。
設備在收到該請求以后,首先進行解析,根據請求中的0x40表示該控制傳輸有數據過程,因此進入到Data_Setup0()函數。該函數根據請求的不同描述符,執行不同的回調函數
CopyRoutine(),并在DataStageIn()函數中把要發送給主機的描述符填入USB緩沖區,等待USB主機發送IN令牌包。
主機在建立過程最后收到ACK以后,發送IN令牌包,從而進入到數據過程。在CTR_LP()函數中判斷是IN0中斷后,進入In0_Process()函數。在數據過程將之前填在USB緩沖器的設備描述符發給主機,并等待主機的應答。
主機在確認接收到的設備描述符沒有出錯后,就會返回一個0數據長度的確認包,即控制傳輸的狀態過程。在CTR_LP()函數中判斷是OUT0中斷,進入Out0_Process()函數,由于在狀態過程,所以調用回調函數Process_Status_OUT()。
下面和上篇一樣,對照著USB分析儀捕捉的數據分析獲取設備描述符這次控制傳輸的數據過程和狀態過程。
下面通過串口打印信息查看獲取設備描述符控制傳輸過程中的數據包的數據。打印信息如下
至此,USB主機成功獲取到設備描述符。打印信息最后可以看到,主機再次復位USB,將進入到設置地址的階段。
前幾篇介紹中,USB主機完成了獲取設備的描述符,現在進入第二步,設置設備的地址階段。
該階段是一個無數據過程的控制傳輸。首先,在建立過程中USB主機往設備的端點0發出一個設置地址的請求,新地址在建立過程的數據包中。該事務的結構包括:SETUP0令牌包+SET_ADDRESS數據包+握手包。在建立過程之后直接進入到的狀態過程,因為設置地址階段是一個無數據過程的控制傳輸。在狀態過程,設備等待主機請求狀態返回(即等待主機發送一個IN令牌包),收到IN令牌包后,設備就返回一個0長度的數據包,如果主機確認該數據包已經正確收到,就會發送應答包ACK給設備,設備收到ACK之后,就要啟動新的設備地址,這樣設備就分配到了一個唯一的設備地址。
接下來將這段設置地址的過程通過USB分析儀捕捉分析如下
接著分析STM32 USB_HID例子中的枚舉過程的設置地址階段。同樣在接收到主機的setup0令牌后,STM32 USB進入中斷處理函數Setup0_Process(),由于是沒有數據過程的控制傳輸,接著進入NoData_Setup0()函數,函數最后通過USB_StatusIn()等待主機的IN令牌,即狀態階段。主機發IN令牌進入到狀態階段,USB中斷函數中執行In0_Process()函數,該函數把在建立過程函數Setup0_Process()中保存在pInformation的地址信息,通過SetDeviceAddress()函數,配置新的設備地址。串口的調試信息如下
至此,設備新的地址設置成功,這里設置成0x6,之后的過程將使用這個新地址。
接下來,主機將使用新的設備地址和設備進行通信。 主機需要再次獲取設備描述符,配置描述符,字符串描述符,另外HID設備還要獲取報告描述符等。根據《圈圈教你玩USB》里面介紹,我們可以使用BUS Hound工具,對主機發送給設備的數據進行抓包,分析數據包,根據USB協議完成相應的主機的請求。
在STM32 USB_HID的例子中,和以上獲取描述符相關的主要文件有Usb_desc.c(定義了各種描述符),Usb_prop.c (其中的CustomHID_GetStringDescriptor函數完成了對主機獲取字符串描述符種類的細分)。具體的內容可以自己根據調試信息按照之前幾篇文章中介紹的分析方法分析。
上一篇:基于STM32的USB程序開發筆記(四)——USB設備的枚舉(上)
下一篇:USB通訊的執行過程 - STM32 USB設計
推薦閱讀
史海拾趣
設計資源 培訓 開發板 精華推薦
- 激光雷達第一個國標來了!禾賽、華為、速騰聚創參與起草
- 國產工控機品牌推薦:英康仕——以自主可控技術賦能智能制造
- 從五顆芯片到一顆芯片:看Qorvo的PMIC如何重塑企業級SSD
- Qorvo如何讓UWB和Matter重塑智能世界?
- 下一代Wi-Fi 8該怎么做?Qorvo超前分享相關技術路徑
- 干貨丨Profinet轉Canopen網關,讓不同協議設備互聯互通
- 消息稱臺積電 FOPLP 先進封裝技術 CoPoS 目標 2028 年底至 2029 年量產
- 高通宣布在越南成立人工智能研發中心
- 貿澤新一期EIT系列探索可持續技術與工程創新的交匯點
- 地瓜機器人發布 RDK S100 算控一體化機器人開發套件,50+客戶同步開展測評