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通道。打开IN
和OUT
管道
- 等待
获取设备描述符
,只获取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
最大包大小 - 而且已经获取到设备的
VID
、PID
- 可以看到第8个字节,正好是
设置地址
#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
- 这9个字节为第一次获取配置描述符时,从机返回的数据。主要获取
获取
配置描述符集合
/* 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字节,全部的设备描述符
- 设置设备地址
- 获取配置描述符
- 获取配置描述符集合
- 获取厂家字符串描述符
- 获取产品字符串描述符
- 获取产品序列号
- 设置配置
- 枚举完成