基于STM32的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主机复位获取设备描述符将执行的函数。增加打印信息的函数如下:
[cpp]view plaincopy
- /*******************************************************************************
- *FunctionName:Setup0_Process
- *Description:Getthedevicerequestdataanddispatchtoindividualprocess.
- *Input:None.
- *Output:None.
- *Return:Post0_Process.
- *******************************************************************************/
- uint8_tSetup0_Process(void)
- {
- union
- {
- uint8_t*b;
- uint16_t*w;
- }pBuf;
- #ifdefSTM32F10X_CL
- USB_OTG_EP*ep;
- uint16_toffset=0;
- ep=PCD_GetOutEP(ENDP0);
- pBuf.b=ep->xfer_buff;
- #else
- uint16_toffset=1;
- pBuf.b=PMAAddr+(uint8_t*)(_GetEPRxAddr(ENDP0)*2);/**2for32bitsaddr*/
- #endif/*STM32F10X_CL*/
- #ifdefUSB_DEBUG0
- printf("\r\nSETUP0中断-->控制传输.建立过程\r\n");
- #endif/*#ifUSB_DEBUG0*/
- if(pInformation->ControlState!=PAUSE)
- {
- #ifdefUSB_DEBUG0
- printf("设备可以接收新的数据\r\n");
- #endif/*USB_DEBUG0*/
- pInformation->USBbmRequestType=*pBuf.b++;/*bmRequestType*/
- pInformation->USBbRequest=*pBuf.b++;/*bRequest*/
- pBuf.w+=offset;/*wordnotaccessedbecauseof32bitsaddressing*/
- pInformation->USBwValue=ByteSwap(*pBuf.w++);/*wValue*/
- pBuf.w+=offset;/*wordnotaccessedbecauseof32bitsaddressing*/
- pInformation->USBwIndex=ByteSwap(*pBuf.w++);/*wIndex*/
- pBuf.w+=offset;/*wordnotaccessedbecauseof32bitsaddressing*/
- pInformation->USBwLength=*pBuf.w;/*wLength*/
- #ifdefUSB_DEBUG0
- printf("设备接收数据如下:\r\n");
- 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("\r\n");
- #endif/*USB_DEBUG0*/
- }
- returnPost0_Process();
- pInformation->ControlState=SETTING_UP;
- if(pInformation->USBwLength==0)
- {
- /*Setupwithnodatastage*/
- NoData_Setup0();
- }
- else
- {
- /*Setupwithdatastage*/
- Data_Setup0();
- }
- returnPost0_Process();
- }
在打印信息之后直接就让函数返回,使主机得不到ACK应答,下面根据打印信息看下测试情况。
根据打印信息,由于从机没有ACK应答给PC机的请求,在PC机尝试发了3次请求后,就放弃了。可以在PC机的设备管理器看到,在请求打印3次以后出现了unknown device。
关于8个字节的请求代码的具体含义请参照USB协议,或者在《圈圈教你玩USB》里面对照。
以上就是枚举过程获取设备描述符的第一步控制传输的建立过程,主机发送获取描述符的请求,下一篇我们将代码中ACK返回,使主机接收到建立过程的应答,从而进入到数据过程,即设备响应主机的请求,将设备描述符发送给主机。
STM32USB枚举过 相关文章:
- stm32 usb枚举过程(11-28)
- 基于STM32的USB枚举过程学习笔记(一)(11-19)
- 基于STM32的USB枚举过程学习笔记(四)(11-19)
- 基于STM32的USB枚举过程学习笔记(三)(11-19)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)