×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-08-21 发布时间:
|
    接下来介绍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 plain copy
 
  1. /******************************************************************************* 
  2. * Function Name  : Setup0_Process 
  3. * Description    : Get the device request data and dispatch to individual process. 
  4. * Input          : None. 
  5. * Output         : None. 
  6. * Return         : Post0_Process. 
  7. *******************************************************************************/  
  8. uint8_t Setup0_Process(void)  
  9. {  
  10.   
  11.   union  
  12.   {  
  13.     uint8_t* b;  
  14.     uint16_t* w;  
  15.   } pBuf;  
  16.   
  17. #ifdef STM32F10X_CL  
  18.   USB_OTG_EP *ep;  
  19.   uint16_t offset = 0;  
  20.    
  21.   ep = PCD_GetOutEP(ENDP0);  
  22.   pBuf.b = ep->xfer_buff;  
  23. #else    
  24.   uint16_t offset = 1;  
  25.     
  26.   pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */  
  27. #endif /* STM32F10X_CL */  
  28.   
  29. #ifdef  USB_DEBUG0  
  30.   printf("\r\nSETUP0中断-->控制传输.建立过程\r\n");  
  31. #endif /* #if USB_DEBUG0 */  
  32.   
  33.   if (pInformation->ControlState != PAUSE)  
  34.   {  
  35. #ifdef USB_DEBUG0  
  36.     printf("设备可以接收新的数据\r\n");  
  37. #endif /* USB_DEBUG0 */  
  38.     pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */  
  39.     pInformation->USBbRequest = *pBuf.b++; /* bRequest */  
  40.     pBuf.w += offset;  /* word not accessed because of 32 bits addressing */  
  41.     pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */  
  42.     pBuf.w += offset;  /* word not accessed because of 32 bits addressing */  
  43.     pInformation->USBwIndex  = ByteSwap(*pBuf.w++); /* wIndex */  
  44.     pBuf.w += offset;  /* word not accessed because of 32 bits addressing */  
  45.     pInformation->USBwLength = *pBuf.w; /* wLength */  
  46.   
  47. #ifdef USB_DEBUG0  
  48.     printf("设备接收数据如下:\r\n");  
  49.     printf("0x%x ",pInformation->USBbmRequestType);//用于指定请求的 数据传输反向 请求类型 请求的接收者  
  50.     printf("0x%x ",pInformation->USBbRequest);//标准请求及代码  
  51.   
  52.     printf("0x%x ",pInformation->USBwValue0);  
  53.     printf("0x%x ",pInformation->USBwValue1);//具体见圈圈书P77页  
  54.   
  55.     printf("0x%x ",pInformation->USBwIndex0);  
  56.     printf("0x%x ",pInformation->USBwIndex1);    
  57.   
  58.     printf("0x%x ",pInformation->USBwLength1);  
  59.     printf("0x%x ",pInformation->USBwLength0);  
  60.   
  61.     printf("\r\n");  
  62. #endif /* USB_DEBUG0 */  
  63.   }  
  64. return Post0_Process();  
  65. pInformation->ControlState = SETTING_UP;  
  66.   if (pInformation->USBwLength == 0)  
  67.   {  
  68.     /* Setup with no data stage */  
  69.     NoData_Setup0();  
  70.   }  
  71.   else  
  72.   {  
  73.     /* Setup with data stage */  
  74.     Data_Setup0();  
  75.   }  
  76.   return Post0_Process();  
  77. }  

在打印信息之后直接就让函数返回,使主机得不到ACK应答,下面根据打印信息看下测试情况。

 

 

 

 

 

 

 

 

 

 

 

 

 

根据打印信息,由于从机没有ACK应答给PC机的请求,在PC机尝试发了3次请求后,就放弃了。可以在PC机的设备管理器看到,在请求打印3次以后出现了unknown device。

关于8个字节的请求代码的具体含义请参照USB协议,或者在《圈圈教你玩USB》里面对照。

    以上就是枚举过程获取设备描述符的第一步控制传输的建立过程,主机发送获取描述符的请求,下一篇我们将代码中ACK返回,使主机接收到建立过程的应答,从而进入到数据过程,即设备响应主机的请求,将设备描述符发送给主机。

关键字:STM32  USB  枚举过程

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
MSP430F5529 上手小例程2