USB 2.0 协议专栏之 USB 设备描述符(三)

前言:本篇博客为手把手教学的 USB2.0 协议栈类精品博客,该专栏博客侧重针对 USB 2.0 协议进行讲解。第 3 篇重点为 USB2.0 协议中的 设备描述符 Device Descriptors 进行讲解,并结合 CH32V307STM32 代码进行分析。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位数字。LOBYTEHIBYTE分别代表这个ID的低位字节和高位字节。

  • LOBYTE(USBD_PID), HIBYTE(USBD_PID): 产品ID(Product ID),由制造商分配给特定设备的唯一16位数字,用于区分同一供应商的不同产品。同样地,LOBYTEHIBYTE分别代表这个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(推荐加入)。欢迎加群,有问题可以群内分享技术交流,秋招和春招会有诸多大厂内推码或者内推名额推荐。希望大家友好讨论技术知识!!!

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

混分巨兽龙某某

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值