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

    接下来介绍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返回,使主机接收到建立过程的应答,从而进入到数据过程,即设备响应主机的请求,将设备描述符发送给主机。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值