分享

基于STM32的USB枚举过程学习笔记(二)

 goodwangLib 2017-10-25

    接下来介绍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('\r\nSETUP0中断-->控制传输.建立过程\r\n'); #endif /* #if USB_DEBUG0 */ if (pInformation->ControlState != PAUSE) { #ifdef USB_DEBUG0 printf('设备可以接收新的数据\r\n'); #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('设备接收数据如下:\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 */ } 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返回,使主机接收到建立过程的应答,从而进入到数据过程,即设备响应主机的请求,将设备描述符发送给主机。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多