文章目录
目录
一、USB简介
二、USB(HID)协议及描述符
1.USB描述符简介
2.USB描述符
USB根据速度可分为:
具体应用以及特性如下:
一般USB接口有4根线,分别是VCC DM DP GND。DM,DP是数据线。
USB的检测:
每一个主机USB的DM, DP都有内部15K下拉到GND,没有外设插入情况下是低电平。在USB从设备中,如果设备是高速USB则在DP上加有1.5K上拉到VCC,如果是低速设备则在DM上加1.5K上拉到VCC。当DP或者DM被拉高就可以检测USB插入,并且可以区分是高速还是低速USB。
USB的硬件端口是统一的,但是USB设备却是多种多样的,USB主机根据USB设备的描述符来区分不同的USB设备。每一个USB设备都有自己的描述符,当插入USB设备之后,主机会向从机发送命令,从机收到命令之后,会返回特定的描述符信息。主机通过解析收到的描述符,来识别从机设备的相关信息,这个过程,就是设备枚举(enumeration)过程。
USB有5种标准设备描述符,分别是:设备描述符、配置描述符、字符串描述符、接口描述符、端点描述符。
另外还有:HID描述符、报告描述符等各个类特有的描述符。见下表:
要注意的是,设备描述符有且只有一个。其包含关系如下图所示。
设备描述符有且仅有一个!
描述符使用到的宏定义如下:
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define HID_DESCRIPTOR_TYPE 0x21
设备描述符类型定义固定为0x01
USB HID设备的设备描述符代码例子(STM32 USB HID)如下:
/* USB Standard Device Descriptor */
const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
{
0x12, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
0x40, /*bMaxPacketSize40*/
0x83, /*idVendor (0x0483)*/
0x04,
0x50, /*idProduct = 0x5750*/
0x57,
0x00, /*bcdDevice rel. 2.00*/
0x02,
1, /*Index of string descriptor describing
manufacturer */
2, /*Index of string descriptor describing
product*/
3, /*Index of string descriptor describing the
device serial number */
0x01 /*bNumConfigurations*/
}; /* CustomHID_DeviceDescriptor */
其结构成员意义如下:
(1)bLength
描述符长度(18字节,十六进制为0x12),就是标志描述符数据结构的长度。
(2)bDescriptorType
bDescriptorType代表了本描述符的类型,设备描述符为0x01 (设备描述符固定为0x01)
(3)bcdUSB
USB协议版本,表示形式0xJJMN版本JJ.M.N(JJ - 主要版本号,M - 次要版本号,N - 次要版本)
例子:如果是USB2.0,写成:0200H;如果是USB1.1,写成:0110H 如果是USB3.11,写成:0311H
(4)bDeviceClass、bDeviceSubClass、bDeviceProtocol
bDeviceClass、bDeviceSubClass、bDeviceProtocol分别代表设备类型,子类型,设备使用的协议,USB-IF区分设备类分了三个等级(类-子类-协议码)其中,类包含人机交互类、图像类、无线类、音频类等等,子类比如音频类的音频控制、音频流等等,协议比如人机接口类中的鼠标、键盘、触摸屏等,为何会有这么多USB的Class分类,子分类,设备协议。我们要知道,USB协议设计的目的,就是为实现通用,用单一的USB接口取代之前种类繁多的各种其他接口。而为了取代其他各种接口,那意味着就要实现各种设备所对应的各种功能。如下图显示USB设备的各种类别,USB设备类信息更详细内容可进入https://www.usb.org/defined-class-codes查看。
(5)bMaxPackeSize0
就是端点一次最大传多少个字节。USB协议里有规定,端点0最低8字节,端点的最大传输大小和USB速度等级以及传输类型有关,控制传输一般使用端点0,低速最大8字节,全速和高速最大传输64字节,如下图:
(6)idVender
厂商ID,就是个2字节的编号,由USB协议分配,厂商申请时需要交费。自己随便写的话,仅限于学习、测试的情况下,不能用做产品。
(7)idProduct
产品ID,厂家自己随便定义。
(8)bcdDevice
产品版本号,厂家自己随便定义。
(9)iManufacturer
描述厂商的字符串的索引,为0则表示没有。
(10)iProduct
描述产品的字符串的索引,为0则表示没有。
(11)iSerialNumber
产品序列号字符串的索引,为0则表示没有。
(12)bNumConfigurations
指示设备由多少个配置,前面提到过,一个USB可能有多个配置,一般USB产品都是1个配置。
配置描述符至少有一个,可以有多个,一般一个设备只设置一个配置描述符。
配置描述符类型定义固定为0x02
USB HID设备的配置描述符代码例子(STM32 USB HID)如下:(注意其中除了配置描述符还包括其他如接口描述符和端点描述符)
/* USB Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] =
{
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
CUSTOMHID_SIZ_CONFIG_DESC,/* wTotalLength: Bytes returned */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing
the configuration*/
0xC0, /* bmAttributes: Self powered */
0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
/************** Descriptor of Custom HID interface ****************/
/* 09 */
0x09, /* bLength: Interface Descriptor size */
USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
0, /* iInterface: Index of string descriptor */
/******************** Descriptor of Custom HID HID ********************/
/* 18 */
0x09, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x10, /* bcdHID: HID Class Spec release number */
0x01,
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
0x22, /* bDescriptorType */
CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: Total length of Report descriptor */
0x00,
/******************** Descriptor of Custom HID endpoints ******************/
/* 27 */
0x07, /* bLength: Endpoint Descriptor size */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
0x81, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
0x02, /* wMaxPacketSize: 2 Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (32 ms) */
/* 34 */
0x07, /* bLength: Endpoint Descriptor size */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
/* Endpoint descriptor type */
0x01, /* bEndpointAddress: */
/* Endpoint Address (OUT) */
0x03, /* bmAttributes: Interrupt endpoint */
0x02, /* wMaxPacketSize: 2 Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (20 ms) */
/* 41 */
}; /* CustomHID_ConfigDescriptor */
其中配置描述符代码段:
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
CUSTOMHID_SIZ_CONFIG_DESC,/* wTotalLength: Bytes returned */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing
the configuration*/
0xC0, /* bmAttributes: Self powered */
0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
配置描述符的各个域的意义如下:
bLength:大小为1字节,表示该描述符的长度。标准的USB配置描述符的长度为9字节。
bDescriptorType:配置描述符的类型。
wTotalLength:表示整个配置描述符集合的总长度,包括配置描述符、接口描述符、端点描述符和类特殊描述符(HID类)。注意低字节在前。
bNumInterfaces:该配置描述符所支持的接口数量(接口编号数量而不是接口描述符数量,不同的接口描述符可能使用同一个编号接口)。功能单一设备只有一个,而复合设备则具有多个接口。
bConfigurationValue:表示该配置的值。通常一个USB设备可以支持多个配置,bConfigurationValue就是每个配置的标识。
iConfiguration:描述该配置的字符串的索引值。如果该值为0,则表示没有字符串。
bmAttributes:用来描设备的一些特性。其中,D7是保留的,必须要设置为1。D6表示供电方式,D6=1时,表示设备自供电;D6=0时,表示设备时总线供电。D5表示是否支持远程唤醒,D5=1时,支持远程唤醒。D4~D0保留,设置为0
bMaxPower:表示设备需要从总线获取的最大电流量,单位为2mA。如需要200mA的最大电流,则该字节的值为100
如上面代码中
/************** Descriptor of Custom HID interface ****************/
/* 09 */
0x09, /* bLength: Interface Descriptor size */
USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
0, /* iInterface: Index of string descriptor */
该段代码定义的是HID的接口描述符。
USB_INTERFACE_DESCRIPTOR_TYPE为固定值表示该配置是接口描述符。
bNumEndpoints,该接口使用的端点个数。注意一点,这个端点个数不包括0端点。
bInterfaceClass的定义如下表:
bInterfaceSubClass 除带有由接口定义的类的设备外,此字段于设备描述符中的bDeviceSubClass 相同。若 bInterfaceClass 等于00h,bInterfaceSubClass 也必须等于 00h。若 bInterfaceClass 取从 01h到FEh的值,bInterfaceSubClass则等于00h或等于一个为接口的类定义的值。FFh表明为厂商定义的子类。
bInterfaceProtocol 除了带有接口定义的类的设备外,此字段于设备描述符中的bDeviceProtocol相同。此字段可为所选bInterfaceClass和bInterfaceSubClass 所规定的协议。若bInterfaceClass取从01h到FEh的值,bInterfaceProtocol必须等于00h,或等于为接口的类定义的值。FFh表明为厂商定义的协议。
iInterface 是指向描述接口的字符串的索引。若没有字符串描述符,该值为0.
上面在接口描述符中定义了设备类型为0x03的HID设备,那么需要定义HID描述符,上面代码中HID描述符代码如下:
/* 18 */
0x09, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x10, /* bcdHID: HID Class Spec release number */
0x01,
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
0x22, /* bDescriptorType */
CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: Total length of Report descriptor */
0x00,
bcdHID为0x0110,表面该HID协议为1.1版本
bCountryCode: 设备所适用的国家。如果使用的键盘是美式键盘,代码为33,即0x21
bNumDescriptors:下级描述符的数量。这个值至少为1,也就是HID类设备至少要有一个报告描述符。下级描述符可以是报告描述符或者物理描述符。
wItemLength: 报告描述符的总长度。
上面HID的端点描述符代码:
/******************** Descriptor of Custom HID endpoints ******************/
/* 27 */
0x07, /* bLength: Endpoint Descriptor size */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
0x81, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
0x02, /* wMaxPacketSize: 2 Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (32 ms) */
bEndpointAddress: bit7 :方向 1/0 :in/out,对于控制端点可以忽略;bit4~bit6 保留,bit3~bit0:端点号
bmAttributes,属性。如下
bit1~bit0:
00 = Control-控制传输
01 = Isochronous-等时传输
10 = Bulk-批量传输
11 = Interrupt-中断传输
如果不是一个等时传输端点,第5~2位是保留的,必须设置为0。如果它是等时的,则定义如下:
Bits 3..2: Synchronization Type-同步类型
00 = No Synchronization-无同步
01 = Asynchronous-异步
10 = Adaptive-适配
11 = Synchronous-同步
/*Bits 5..4: Usage Type-用途*/
00 = Data endpoint-数据端点
01 = Feedback endpoint-反馈端点
10 = Implicit feedback Data endpoint-暗含反馈的数据端点
11 = Reserved-保留
wMaxPackeSize,端点支持的最大包长。对于等时端点,此值用于在调度中保留总线时间,这是每(微)帧数据有效负载所需的时间。在进行中,管道实际使用的带宽可能比保留的带宽少。如果有必要,设备会报告通过其正常的、非usb定义的机制所使用的实际带宽。
对于所有的端点,bit10~bit0指定最大数据包大小(以字节为单位)。
/*5.对于高速同步和中断端点:bit12~bit11指定每个微帧的额外通信次数:
00 = None (1 transaction per microframe)
01 = 1 additional (2 per microframe)
10 = 2 additional (3 per microframe)
11 = Reserved
bInterval,查询时间,说白了就是主机多久和设备通讯一次。根据设备运行速度以帧或微帧表示。
对于全/高速等时端点,此值必须在1到16之间。bInterval值用作2的指数;例如,bInterval为4,表示周期为8, 2(4 – 1)。
对于全速/低速中断端点,该字段的值可以是1到255。
对于高速中断端点,使用bInterval值作为2的指数;例如,bInterval为4表示周期为8 ,2(4-1)。这个值必须在1到16之间。
对于高速批量/控制输出端点,bInterval必须指定端点的最大NAK速率。值0表示端点永不NAK。其它值表示每个微帧的bInterval数最多1个NAK。这个值的范围必须在0到255之间。
报告描述符包含多个报告,不同的报告通过报告ID来识别,报告的第一个字节就是报告ID。当报告描述符中没有定义报告ID时,开始就是数据。
报告描述符由条目(item)来组成,一个条目占据一行。HID协议规定了两种条目:短条目和长条目,常用的是短条目。
短条目的构成:一字节的前缀 + 可选的数据字节。可选的数据字节可以是0、1、2、4字节。实际中所使用的条目,大部分是1字节的可选数据
一个条目前缀如下
bSize:bit1~bit0后面紧跟的字节数