在USB上电枚举的过程中,有几个描述符是经常要用到的,它们分别是:设备描述符、配置描述符、接口描述符、端点描述符、HID描述符、字符串描述符以及语言ID描述符,最后是报告描述符。
其中设备描述符是USB主机申请的第1个描述符,然后配置描述符,接口描述符端点描述符hId描述符,以配置集合的形式返回给USB主机。字符串描述符是可选的,它和语言ID描述符一起发送给主机,告诉主机当前设备的名称是什么。
最麻烦的是报告描述符,它的结构和功能相比前面的几个描述符都发生了很大的变化,理解起来相对困难一些。
在稍后的文章中,我会尽量以通俗的语言来解释这几个描述符。这一节,咱们主要研究下设备描述符。
所谓描述符其实就是C语言里面的数组,数组里包含的信息说明当前的设备具有哪些特征。每个设备有且仅有一个设备描述符,设备描述符的长度是18字节,它的结构我们可以通过下面的表格来描了解。
偏移量 | 名称 | 大小 | 说明 |
0 | bLength | 1 | 描述符长度(18字节) |
1 | bDescriptorType | 1 | 描述符类型(设备描述符为0x01) |
2 | bcdUSB | 2 | 设备使用的USB协议版本 |
4 | bDeviceClass | 1 | 类代码 |
5 | bDeviceSubClass | 1 | 子类代码 |
6 | bDeviceProtocol | 1 | 设备使用的协议 |
7 | bMaxPackeSize0 | 1 | 端点0最大包长 |
8 | idVender | 2 | 厂商ID |
10 | idProduct | 2 | 产品ID |
12 | bcdDevice | 2 | 设备版本号 |
14 | iManufacturer | 1 | 描述厂商的字符串的索引 |
15 | iProduct | 1 | 描述产品的字符串的索引 |
16 | iSerialNumber | 1 | 产品序列号字符串的索引 |
17 | bNumConfigurations | 1 | 可能的配置数 |
注意:USB协议中,数据格式使用“小端”模式,所以多个字节排列时,低位在前。
18个字节,包含14项内容,通过表格中的说明,我们可以获取很多信息。
bLength,不用说了,0x12=18
bDescriptorType,描述符类型。总共有哪些描述符?我们通过下面代码可以看出:
#define USB_DESC_TYPE_DEVICE 0x01U
#define USB_DESC_TYPE_CONFIGURATION 0x02U
#define USB_DESC_TYPE_STRING 0x03U
#define USB_DESC_TYPE_INTERFACE 0x04U
#define USB_DESC_TYPE_ENDPOINT 0x05U
#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07U
#define USB_DESC_TYPE_BOS 0x0FU
bcdUSB,USB协议版本。如果是USB2.0,写成:
0x00,0x02
如果是USB1.1,写成
0x10,0x01
bDeviceClass和bDeviceSubClass,也就是类代码和子类代码,大部分情况下,这两个值都是0.
bDeviceProtocol,当bDeviceClass和bDeviceSubClass为0时,它也是0.
bMaxPackeSize0,USB协议中有一个端点的定义,你可以理解为通道。我们以高速公路为例:
向前有4个行车道(1,2,3,4),向后有4个行车道(1,2,3,4),这就是4个双向端点。假设它们都属于一条津某高速路(一个USB接口),有的向前有的向后(有的输入有的输出),有向前的1号行车道(有输出的1号端点)
至于最大包长,说白了就是一次最多传多少个字节。USB协议里有规定,端点0最低8字节,不能再少了。
厂商ID,就是个2字节的编号,由USB协议分配,厂商申请时需要交费。自己随便写的话,仅限于学习、测试的情况下,不能用做产品。
产品ID,厂家自己随便定义。
bcdDevice,设备版本,厂家根据自己产品的版本来定义。
后面三个:描述厂商的字符串的索引、描述产品的字符串的索引、产品序列号字符串的索引,如果是0,表示程序里没有这三项内容。如果想添加,这里按顺序设置索引号为1、2、3。为什么是这三个数字,后面讲到字符串描述符的时候会说明。
bNumConfigurations,可能的配置数,一般USB产品,这里都是1。
这里放一个STM32程序中自带的设备描述符来看一下:
/** USB standard device descriptor. */
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
0x12, /*bLength */
USB_DESC_TYPE_DEVICE, /*bDescriptorType 0x01*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize 64*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID_FS), /*idProduct*/
HIBYTE(USBD_PID_FS), /*idProduct*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string 1*/
USBD_IDX_PRODUCT_STR, /*Index of product string 2*/
USBD_IDX_SERIAL_STR, /*Index of serial number string 3*/
USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations 1*/
};
对照看一下,你会发现很好理解。
好了,打完收工!
终于明白了,谢谢你!
客气了