STM32 USB 枚举分析

4 篇文章 0 订阅

STM32 USB枚举分析

芯片:STM32F407VE

编译器:KEIL5

作者:SY

日期:2017-7-19 08:14:14

STM32 USB枚举

用到比较重要的寄存器:OTG_HS 主机端口控制和状态寄存器 (OTG_HS_HPRT)

  • 系统复位

    • 等待USB连接,延时100ms
    • 主机对USB设备复位,主机检测到端口使能位置位,与设备建立连接
    • 主机再次对USB设备复位,复位结束,开始枚举过程。
    • 主机拥有8个通道,其中IN占用0通道,OUT占用1通道。打开INOUT管道
  • 获取设备描述符,只获取8个字节,为了得到通道0的最大包长度。将状态机调整到HOST_CTRL_XFER。同时备份当前全局状态,便于跳转到HOST_CTRL_XFER恢复状态。

    USBH_Get_DevDesc(pdev , phost, 8); -->
    USBH_GetDescriptor(); -->
            phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; //发送的请求
          phost->Control.setup.b.wLength.w = length; //数据长度。如果为0,则在[控制传输]中忽略数据阶段
            USBH_CtlReq(); -->
                    USBH_SubmitSetupRequest(); -->
                        USBH_HandleControl(); --> 
                            CTRL_SETUP -> CTRL_SETUP_WAIT -> 
                            if (phost->Control.setup.b.wLength.w);
                          then
                                [CTRL_DATA_IN/CTRL_DATA_OUT]
                          else
                                [CTRL_STATUS_IN/CTRL_STATUS_OUT]
                          fi                    
    • 发送SETUP令牌包,等待回复
    • 发送DATA1数据包,等待回复
    • 发送状态,回复从机

    流程走完后,获取到当前通道的最大包长度64,因此修改当前通道的最大包长度为64

  • 获取全部设备描述符,长度18字节

    typedef struct _DeviceDescriptor
    {
    uint8_t   bLength;
    uint8_t   bDescriptorType;
    uint16_t  bcdUSB;        /* USB Specification Number which device complies too */
    uint8_t   bDeviceClass;
    uint8_t   bDeviceSubClass; 
    uint8_t   bDeviceProtocol;
    /* If equal to Zero, each interface specifies its own class
    code if equal to 0xFF, the class code is vendor specified.
    Otherwise field is valid Class Code.*/
    uint8_t   bMaxPacketSize;
    uint16_t  idVendor;      /* Vendor ID (Assigned by USB Org) */
    uint16_t  idProduct;     /* Product ID (Assigned by Manufacturer) */
    uint16_t  bcdDevice;     /* Device Release Number */
    uint8_t   iManufacturer;  /* Index of Manufacturer String Descriptor */
    uint8_t   iProduct;       /* Index of Product String Descriptor */
    uint8_t   iSerialNumber;  /* Index of Serial Number String Descriptor */
    uint8_t   bNumConfigurations; /* Number of Possible Configurations */
    }
    USBH_DevDesc_TypeDef;
    • 可以看到第8个字节,正好是bMaxPacketSize最大包大小
    • 而且已经获取到设备的VIDPID
  • 设置地址

    
    #define USBH_DEVICE_ADDRESS                             1
    
    USBH_SetAddress(pdev, phost, USBH_DEVICE_ADDRESS) -->
    phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
    USBH_CtlReq(pdev, phost, 0 , 0 ); -->
        USBH_HandleControl(); -->
    typedef union _USB_Setup
    {
    uint8_t d8[8];
    
    struct _SetupPkt_Struc
    {
      uint8_t           bmRequestType;
      uint8_t           bRequest;
      uint16_t_uint8_t  wValue;
      uint16_t_uint8_t  wIndex;
      uint16_t_uint8_t  wLength;
    } b;
    } USB_Setup_TypeDef;
    • SETUP包一共包含8个字节
    + 将设备的地址设置为`1``SETUP`包包含设备地址字段
    + 发送`SETUP`令牌包,等待回复
    + 发送状态,回复从机
  • 获取配置描述符

    
    #define USB_CONFIGURATION_DESC_SIZE                        9
    
    USBH_Get_CfgDesc(pdev, phost, USB_CONFIGURATION_DESC_SIZE); -->
    USBH_GetDescriptor(); -->
            USBH_ParseCfgDesc();
    typedef struct _ConfigurationDescriptor
    {
    uint8_t   bLength;
    uint8_t   bDescriptorType;
    uint16_t  wTotalLength;        /* Total Length of Data Returned */
    uint8_t   bNumInterfaces;       /* Number of Interfaces */
    uint8_t   bConfigurationValue;  /* Value to use as an argument to select this configuration*/
    uint8_t   iConfiguration;       /*Index of String Descriptor Describing this configuration */
    uint8_t   bmAttributes;         /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/
    uint8_t   bMaxPower;            /*Maximum Power Consumption */
    }
    USBH_CfgDesc_TypeDef;
    • 这9个字节为第一次获取配置描述符时,从机返回的数据。主要获取wTotalLength的值。实测wTotalLength=32
  • 获取配置描述符集合

    /* get FULL config descriptor (config, interface, endpoints) */
    USBH_Get_CfgDesc(pdev, phost, phost->device_prop.Cfg_Desc.wTotalLength); -->
    USBH_GetDescriptor(); -->
            USBH_ParseCfgDesc();
    • 获取到的数据存储在数组中,数据结构如下:

      typedef  struct  _DescHeader 
      {
       uint8_t  bLength;       
       uint8_t  bDescriptorType;
      } 
      USBH_DescHeader_t;
    • 描述符类型bDescriptorType列表:

      /* Table 9-5. Descriptor Types of USB Specifications */
      
      #define  USB_DESC_TYPE_DEVICE                              1
      
      
      #define  USB_DESC_TYPE_CONFIGURATION                       2
      
      
      #define  USB_DESC_TYPE_STRING                              3
      
      
      #define  USB_DESC_TYPE_INTERFACE                           4
      
      
      #define  USB_DESC_TYPE_ENDPOINT                            5
      
      
      #define  USB_DESC_TYPE_DEVICE_QUALIFIER                    6
      
      
      #define  USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION           7
      
      
      #define  USB_DESC_TYPE_INTERFACE_POWER                     8
      
      
      #define  USB_DESC_TYPE_HID                                 0x21
      
      
      #define  USB_DESC_TYPE_HID_REPORT                          0x22
      
    • 解析数据:

      • 解析接口描述符
      typedef struct _InterfaceDescriptor
      {
       uint8_t bLength;
       uint8_t bDescriptorType;
       uint8_t bInterfaceNumber;
       uint8_t bAlternateSetting;    /* Value used to select alternative setting */
       uint8_t bNumEndpoints;        /* Number of Endpoints used for this interface */
       uint8_t bInterfaceClass;      /* Class Code (Assigned by USB Org) */
       uint8_t bInterfaceSubClass;   /* Subclass Code (Assigned by USB Org) */
       uint8_t bInterfaceProtocol;   /* Protocol Code */
       uint8_t iInterface;           /* Index of String Descriptor Describing this interface */
      
      }
      USBH_InterfaceDesc_TypeDef;

      获取到bNumEndpoints端点个数为2

      • 然后解析端点描述符
      typedef struct _EndpointDescriptor
      {
       uint8_t   bLength;
       uint8_t   bDescriptorType;
       uint8_t   bEndpointAddress;   /* indicates what endpoint this descriptor is describing */
       uint8_t   bmAttributes;       /* specifies the transfer type. */
       uint16_t  wMaxPacketSize;    /* Maximum Packet Size this endpoint is capable of sending or receiving */  
       uint8_t   bInterval;          /* is used to specify the polling interval of certain transfers. */
      }
      USBH_EpDesc_TypeDef;
    • 通知用户,此时通过接口描述符可以知道设备是哪一种类:

    
    #define MSC_CLASS                             0x08 /* MSC */
    
    
    #define HID_CLASS                             0x03 /* HID */
    
    
    
    #define USB_AUDIO                             0x01 /* Audio */
    
    
    #define USB_CDCC                              0x02  /* Communications and CDC Control */
    
    
    #define USB_HID                               0x03  /* HID (Human Interface Device) */
    
    
    #define USB_PRINTER                           0x07  /* Printer */
    
    
    #define USB_MSC                               0x08  /* Mass Storage */
    
    
    #define USB_HUB                               0x09  /* Hub */
    
    
    #define USB_CDCD                              0x0A  /* CDC-Data */
    
    
    #define USB_SMARTCARD                         0x0B  /* Smart Card */
    
    
    #define USB_VIDEO                             0x0E  /* Video */
    
    
    #define USB_AVD                               0x10  /* Audio/Video Devices */
    
  • 获取生产厂家字符串描述符

    USBH_Get_StringDesc -->
        USBH_GetDescriptor -->
        USBH_ParseStringDesc -->
    • 值为3SYSTEM
  • 获取产品字符串描述符

    USBH_Get_StringDesc -->
    USBH_GetDescriptor -->
            USBH_ParseStringDesc -->
    • 值为USB Flash Disk
  • 获取产品序列号

    USBH_Get_StringDesc -->
    USBH_GetDescriptor -->
            USBH_ParseStringDesc -->
    • 值为000000000000FD70AC4E2030
  • 设置配置

    USBH_SetCfg -->
    USBH_CtlReq -->
    • 设置默认配置
  • 枚举完成!

总结

  • 枚举大致流程:
    • 设备复位
    • 获取设备描述符
    • 第一次获取8字节,一部分设备描述符
    • 第二次获取18字节,全部的设备描述符
    • 设置设备地址
    • 获取配置描述符
    • 获取配置描述符集合
    • 获取厂家字符串描述符
    • 获取产品字符串描述符
    • 获取产品序列号
    • 设置配置
    • 枚举完成
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值