前言:本篇博客为手把手教学的 USB2.0 协议栈类精品博客,该专栏博客侧重针对 USB 2.0 协议进行讲解。第 3 篇重点为 USB2.0 协议中的 设备描述符 Device Descriptors 进行讲解,并结合 CH32V307 与 STM32 代码进行分析。USB 协议栈是嵌入式工程研发过程中很大的坑,USB 协议栈非常冗杂且深奥,但它在工程项目中却至关重要,希望这篇博文能给读者朋友的工程项目给予些许帮助,Respect!
Universal Serial Bus 版本:
USB Descriptor:
推荐网址
USB官网:Front Page | USB-IF
USB中文网:USB中文网 (usbzh.com)
沁恒WCH官网:首页 - 南京沁恒微电子股份有限公司 (wch.cn)
一、设备描述符
USB 描述符其实就是 C 语言里面的结构体 Structure 和数组 Array,数组包含的信息说明当前的设备具有哪些特征。USB 描述符有设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符,HID 设备有 HID 描述符、报告描述符和物理描述符。我们先学会每个描述符的细节,作者会进行非常详细的讲解,后期在回顾 USB 枚举的时候会通过抓包和波形来学习每一个描述符在总线上的作用,并且会介绍每一个描述符是在什么时候以哪种方式在总线上进行传输的,本篇博客是重点学习 USB 设备描述符的组成。
设备描述符是 USB 主机枚举 USB 设备申请的第 1 个描述符,每个设备有且仅有一个设备描述符,也就是大家以后看到的任何的 USB 设备都只有一个设备描述符数组,设备描述符的长度是 18 字节,下面我们来学习设备描述符数据结构,看看 USB 设备具有哪些特征,它的结构如下表所示:
二、MCU设备描述符代码
2.1 STM32代码
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 // 设备描述符类别
#define USB_OTG_MAX_EP0_SIZE 64 // 端点0支持的最大包长
#define USBD_VID 0x0483 // 厂商ID
#define USBD_PID 0xDF11 // 产品ID
#define USBD_IDX_MFC_STR 0x01 // 厂商字符串的索引
#define USBD_IDX_PRODUCT_STR 0x02 // 产品字符串的索引
#define USBD_IDX_SERIAL_STR 0x03 // 产品序列号字符串的索引
#define USBD_CFG_MAX_NUM 1 // 设备的配置数
/* USB Standard Device Descriptor */
uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] =
{
0x12, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor low*/
HIBYTE(USBD_VID), /*idVendor high*/
LOBYTE(USBD_PID), /*idVendor low*/
HIBYTE(USBD_PID), /*idVendor high*/
0x00, /*bcdDevice rel. 2.00*/
0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
USBD_IDX_PRODUCT_STR, /*Index of product string*/
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
USBD_CFG_MAX_NUM /*bNumConfigurations*/
} ; /* USB_DeviceDescriptor */
0x12
: 描述符的长度(18字节),这是整个设备描述符的大小。
USB_DEVICE_DESCRIPTOR_TYPE
: 描述符类型,对于设备描述符,这个值通常是0x01
。
0x00, 0x02
: USB的规范版本号,这里是0x0200
,表示USB 2.0。
0x00
: 设备类代码,0x00
表示设备属于由接口描述符定义的类(复合设备常用)。
0x00
: 设备子类代码,0x00
表示没有指定子类。
0x00
: 设备协议代码,0x00
表示没有指定协议。
USB_OTG_MAX_EP0_SIZE
: 端点0的最大包大小,通常为0x40
(64字节)。
LOBYTE(USBD_VID), HIBYTE(USBD_VID)
: 供应商ID(Vendor ID),通常是分配给生产该设备公司的唯一16位数字。LOBYTE
和HIBYTE
分别代表这个ID的低位字节和高位字节。
LOBYTE(USBD_PID), HIBYTE(USBD_PID)
: 产品ID(Product ID),由制造商分配给特定设备的唯一16位数字,用于区分同一供应商的不同产品。同样地,LOBYTE
和HIBYTE
分别代表这个ID的低位字节和高位字节。
0x00, 0x02
: 设备的USB版本号,这里是0x0200
,表示设备的发布版本号。
USBD_IDX_MFC_STR
: 制造商字符串的索引,指向一个字符串描述符,描述了设备的制造商。
USBD_IDX_PRODUCT_STR
: 产品字符串的索引,指向一个字符串描述符,描述了设备的名称。
USBD_IDX_SERIAL_STR
: 序列号字符串的索引,指向一个字符串描述符,描述了设备的序列号。
USBD_CFG_MAX_NUM
: 配置数量,表示设备支持的配置数量。
2.2 沁恒CH32V307代码
const uint8_t MyDevDescr[ ] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0xFF, // bDeviceClass
0xFF, // bDeviceSubClass
0xFF, // bDeviceProtocol
DEF_USBD_UEP0_SIZE, // bMaxPacketSize0 64
(uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8), // idVendor 0x1A86
(uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8), // idProduct 0x5537
DEF_IC_PRG_VER, 0x00, // bcdDevice 0.01
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x03, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
0x12
: 描述符的长度(18字节),这是整个设备描述符的大小。
0x01
: 描述符类型,对于设备描述符,这个值通常是0x01
,表示这是一个设备描述符。
0x00, 0x02
: USB的规范版本号,这里是0x0200
,表示USB 2.0。
0xFF
: 设备类代码,0xFF
是一个通配符值,表示设备类由接口描述符定义。
0xFF
: 设备子类代码,0xFF
同样是一个通配符值,表示没有指定子类。
0xFF
: 设备协议代码,0xFF
也是一个通配符值,表示没有指定协议。
DEF_USBD_UEP0_SIZE
: 端点0的最大包大小,通常为0x40
(64字节),表示这是设备控制传输的最大数据包大小。
(uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8)
: 供应商ID(Vendor ID),这是一个16位的值,通常由USB组织分配给生产该设备的公司。DEF_USB_VID
假设是一个16位的宏或定义,它的低字节和高字节分别通过(uint8_t)DEF_USB_VID
和(uint8_t)(DEF_USB_VID >> 8)
来获取。
(uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8)
: 产品ID(Product ID),这也是一个16位的值,由制造商分配给特定设备的唯一值,用于区分同一供应商的不同产品。同样地,通过右移操作符>>
和类型转换来获取低字节和高字节。
DEF_IC_PRG_VER, 0x00
: 设备的版本号,这里是0x0001
,表示设备的版本是0.01。
0x01
: 制造商字符串的索引,指向一个字符串描述符,描述了设备的制造商。
0x02
: 产品字符串的索引,指向一个字符串描述符,描述了设备的名称。
0x03
: 序列号字符串的索引,指向一个字符串描述符,描述了设备的序列号。
0x01
: 配置数量,表示设备支持的配置数量为1。
三、设备描述符组成详解
介绍设备描述符每一个内容的详细含义(所有的描述符都是小端格式,先低后高)
3.1 bLength
描述符长度(一般 18 字节,十六进制为 0x12),就是标志描述符数据结构的长度
3.2 bDescriptorType
bDescriptorType 代表了本描述符的类型,设备描述符为 0x01。所有的描述符类型表示如下图,大家以后也可以速查:
3.3 bcdUSB
以 BCD 码表示的 USB 规范发布版本编号。这个字段确定了设备及其描述符所遵循的 USB 规范发布版本。
该字段的值采用 BCD (用二进制编码的十进制数)格式。bcdUSB 字段的值为 0xJJMN (JJ–主版本号(major version number),M– 次版本号(minor version number),N– 子次版本号(sub-minor version number)),例如,版本 2.1.3 用值 0213H 表示,版本 3.0 用值 0300H 表示。 如果要将这个数值转化为十进制数的话,前面的 1 字节(8位)代表整数部分,接下来的4位代表十分位,最后 4 位代表百分位。
USB 1.1: 0x0110
USB 2.0: 0x0200
USB 2.1: 0x0210
USB 2.5: 0x0250
USB 3.0: 0x0300
USB 3.1: 0x0310
USB 3.2: 0x0320
支持 BOS descriptor 的设备的 bcdUSB 值必须是 0201H 或更大的值。
符合 Wireless USB specification 的设备的 bcdUSB 值必须是 0250H。
3.4 bDeviceClass、bDeviceSubClass、bDeviceProtocol
bDeviceClass、bDeviceSubClass、bDeviceProtocol 代表设备类型,子类型,设备使用的协议, USB-IF 区分设备类分了 3 个等级(类-子类-协议码)其中,类包含人机交互类、图像类、无线类、音频类等等,子类比如音频类的音频控制、音频流等等,协议比如人机接口类中的鼠标、键盘、触摸屏等,为何会有这么多 USB 的 Class 分类,子分类,设备协议。我们要知道,USB 协议设计的目的,就是为实现通用,用单一的 USB 接口取代之前种类繁多的各种其他接口。而为了取代其他各种接口,那意味着就要实现各种设备所对应的各种功能。如下图显示 USB 设备的各种类别,USB 设备类信息更详细内容可进入Defined Class Codes | USB-IF。
3.5 bMaxPackeSize0
就是 Endpoint 端点一次最大传多少个字节。USB 协议里有规定,Endpoint 端点 0 最低 8 字节,端点的最大传输大小和 USB 速度等级以及传输类型有关,控制传输一般使用端点 0,低速最大 8 字节,全速和高速最大传输 64 字节,如下图:
针对 USB2.0/USB1.x,最大包大小等于此字段的值。
针对低速(Low Speed)必须是8。
针对全速(Full Speed)只能是8、16、32或64。
针对高速(High Speed)只能是64。
3.6 idVender
idVender ID,这个字段的值由 USB-IF 分配给其成员和其他缴纳了管理费的用户。主机可能会含有 INF 文件,其中就含有此值,且如果有,Windows 操作系统可使用此值来为设备选择驱动程序。除了内部使用(由用户负责防止冲突)的设备外,每个设备描述符必须在这个字段上拥有一个有效的厂商 ID。
3.7 idProduct
idProduct ID。这个字段是表明厂商设备的产品 ID。厂商 ID 的拥有者指定了产品 ID。设备描述符和主机上设备的 NF 文件都可能含有此值,如果有,Windows 操作系统可能会使用这个值来帮助为设备选择驱动程序。对于厂商 ID 来说,每个产品ID都是唯一的,因此多个制造商可使用同一产品 ID 却不会引起冲突。
3.8 bcdDevice
BCD 格式表示的设备版本号。厂商指定这个值。主机可能会使用这个值来为设备选择驱动程序。
3.9 iManufacturer
iManufacturer 指向描述制造商的字符串描述符的索引。如果没有制造商描述符,此值即为 0。
3.10 iProduct
iProduct 指向一个描述产品的字符串描述符的索引。如果没有字符串描述符,此值为 0。
3.11 iSerialNumber
iSeriaINumber 指向含有设备序列号的字符串描述符的索引。如果没有序列号,此值为 0。若用户在总线上拥有多个相同的设备,且即使在重启之后主机仍需要将它们区分开,这种情况下序列号十分有用。序列号还可使主机能够确定设备是与之前所使用的相同,还是一个新安装的有相同制造商 ID 和产品 ID 的设备。带有同样制造商 ID、产品 ID 和设备版本号的设备,就不能再共享序列号了。使用批量专属协议的大容量存储设备必须含有序列号。
3.12 bNumConfigurations
bNumConfigurations 是当前运行速度下设备所支持的配置数目。其他运行速度下的配置数目不包含在其中。
四、粉丝交流群
嵌入式交流群 1 群:958820627(可能已满);嵌入式交流群 2 群:876919359(可能已满);嵌入式交流群 3 群:957431539(推荐加入)。欢迎加群,有问题可以群内分享技术交流,秋招和春招会有诸多大厂内推码或者内推名额推荐。希望大家友好讨论技术知识!!!