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

STM32 USB学习笔记8

发布时间:2020-06-16 发布时间:
|

主机环境:Windows 7 SP1


开发环境:MDK5.14


目标板:STM32F103C8T6


开发库:STM32F1Cube库和STM32_USB_Device_Library


现在分析USB器件库核心文件的最后一个文件usbd_ctlreq,该文件提供了标准请求的处理,跟USB2.0协议的第九章节紧密关联。在Setup阶段根据bmRequest字段的内容分为:设备请求、接口请求、端点请求。并根据不同的请求调用不同的函数体,USB2.0协议中定义的标清请求有以下几种



通过第一个竖栏可以看出同一个请求代码可以对应多个接收者,例如CLEAR_FEATURE请求可以是设备请求也可以是接口请求,同样也可以是端点请求。对应的各个请求代码,如下



在usbd_def.h文件中可以找到与之对应的定义,如下:



#define  USB_REQ_GET_STATUS                             0x00

#define  USB_REQ_CLEAR_FEATURE                          0x01

#define  USB_REQ_SET_FEATURE                            0x03

#define  USB_REQ_SET_ADDRESS                            0x05

#define  USB_REQ_GET_DESCRIPTOR                         0x06

#define  USB_REQ_SET_DESCRIPTOR                         0x07

#define  USB_REQ_GET_CONFIGURATION                      0x08

#define  USB_REQ_SET_CONFIGURATION                      0x09

#define  USB_REQ_GET_INTERFACE                          0x0A

#define  USB_REQ_SET_INTERFACE                          0x0B

#define  USB_REQ_SYNCH_FRAME                            0x0C

首先看一下标准设备请求的处理,

/**

* @brief  USBD_StdDevReq

*         Handle standard usb device requests

* @param  pdev: device instance

* @param  req: usb request

* @retval status

*/

USBD_StatusTypeDef  USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef  *req)

{

  USBD_StatusTypeDef ret = USBD_OK;  

  

  switch (req->bRequest) 

  {

  case USB_REQ_GET_DESCRIPTOR: 

    

    USBD_GetDescriptor (pdev, req) ;

    break;

    

  case USB_REQ_SET_ADDRESS:                      

    USBD_SetAddress(pdev, req);

    break;

    

  case USB_REQ_SET_CONFIGURATION:                    

    USBD_SetConfig (pdev , req);

    break;

    

  case USB_REQ_GET_CONFIGURATION:                 

    USBD_GetConfig (pdev , req);

    break;

    

  case USB_REQ_GET_STATUS:                                  

    USBD_GetStatus (pdev , req);

    break;

    

    

  case USB_REQ_SET_FEATURE:   

    USBD_SetFeature (pdev , req);    

    break;

    

  case USB_REQ_CLEAR_FEATURE:                                   

    USBD_ClrFeature (pdev , req);

    break;

    

  default:  

    USBD_CtlError(pdev , req);

    break;

  }

  

  return ret;

}

符合标准的设备请求通过Table 9-3可以看出一共有8种,这里只处理了7种,SET_DESCRIPTOR是没有处理的,当请求不是这7种请求的任何一种时通过USBD_CtlError()函数回应给USB主机一个STALL表明请求错误发生。首先看第一个请求获取描述符请求的处理,如下:


/**

* @brief  USBD_GetDescriptor

*         Handle Get Descriptor requests

* @param  pdev: device instance

* @param  req: usb request

* @retval status

*/

static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , 

                               USBD_SetupReqTypedef *req)

{

  uint16_t len;

  uint8_t *pbuf;

  

    

  switch (req->wValue >> 8)

  { 

#if (USBD_LPM_ENABLED == 1)

  case USB_DESC_TYPE_BOS:

    pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len);

    break;

#endif    

  case USB_DESC_TYPE_DEVICE:

    pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len);

    break;

    

  case USB_DESC_TYPE_CONFIGURATION:     

    if(pdev->dev_speed == USBD_SPEED_HIGH )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_CONFIGURATION;

    }

    else

    {

      pbuf   = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_CONFIGURATION;

    }

    break;

    

  case USB_DESC_TYPE_STRING:

    switch ((uint8_t)(req->wValue))

    {

    case USBD_IDX_LANGID_STR:

     pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len);        

      break;

      

    case USBD_IDX_MFC_STR:

      pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_PRODUCT_STR:

      pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_SERIAL_STR:

      pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_CONFIG_STR:

      pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_INTERFACE_STR:

      pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len);

      break;

      

    default:

#if (USBD_SUPPORT_USER_STRING == 1)

      pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len);

      break;

#else      

       USBD_CtlError(pdev , req);

      return;

#endif   

    }

    break;

  case USB_DESC_TYPE_DEVICE_QUALIFIER:                   

 

    if(pdev->dev_speed == USBD_SPEED_HIGH  )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len);

      break;

    }

    else

    {

      USBD_CtlError(pdev , req);

      return;

    } 

 

  case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:

    if(pdev->dev_speed == USBD_SPEED_HIGH  )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;

      break; 

    }

    else

    {

      USBD_CtlError(pdev , req);

      return;

    }

 

  default: 

     USBD_CtlError(pdev , req);

    return;

  }

  

  if((len != 0)&& (req->wLength != 0))

  {

    

    len = MIN(len , req->wLength);

    

    USBD_CtlSendData (pdev, 

                      pbuf,

                      len);

  }

  

}

也是一大串switch-case语句,这样的代码虽然多但容易分析,在GET_DESCRIPTOR请求中,根据Table 9-3可知wValue字段的含义是描述符类型和描述符索引,在USB2.0协议的9.4.3章节中可以看到wValue的高字节标记了描述符的类型,wValue的低字节标记了描述符的索引。在USBD_GetDescriptor()函数中首先是检测描述符类型,第一个分支是设备描述符,通过pdev句柄的pDesc指针下的GetDeviceDescriptor指针调用所需要的函数即我们之前分析过的usbd_desc.c文件中的对应函数。第二个分支是获取配置描述符,这个是通过设备类指针获取的,放在后面分析,且这里分出了高速和全速模式。接着一个大分支是获取字符串描述符,这里就需要用到wValue的低字节描述符索引来细分各个字符串描述符,获取字符串描述符的处理跟获


关键字:STM32  USB  学习笔记 

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

热门文章 更多