目录
链接快速定位
前沿
1 概述
1.1 特点及应用范围
1.2 拓扑结构
1.3 电气特性
1.4 线缆
2 设备的识别
2.1 插入检测和速度检测
2.2 枚举过程
3 各类描述符解析
3.1 设备描述符
3.2 配置描述符
3.3 接口描述符
3.4 端点描述符
3.5 字符串描述符
3.6 其它描述符
4 Packet
4.1 Packet的组成
4.2 Packet的内容
4.2.1 Packet包的内容--PID域
4.2.2 Packet包的内容--地址域
4.2.3 Packet包的内容--帧号域
4.2.4 Packet包的内容--数据域
4.2.5 Packet包的内容--CRC域
4.3 Packet的类型
4.3.1 Packet包的类型--令牌包
4.3.2 Packet包的类型--SOF包
4.3.3 Packet包的类型--数据包
4.3.4 Packet包的类型--握手包
5 传输类型
5.1 控制传输
5.2 中断传输
5.3 批量传输
5.4 同步传输
6 复位挂起和唤醒机制
USB官网
USB2.0资料下载
本小节主要围绕USB2.0的概述、设备的识别、描述符、传输类型、复位及唤醒机制讲解。
USB2.0分为低速、全速和高速系列,不同速度的应用场景有所不同,具体见下图。
USB总线基于分层的星状拓扑结构,拓扑结构有以下特点:
下图是USB的拓扑结构实例。
USB使用差分传输模式,标准的USB连接线使用4芯电缆:5V电源线(VBUS)、差分数据线负(DM)、差分数据线正(DP)和地线(GND)。在USB OTG中,使用5芯线缆,比标准的USB多了一条身份识别线(ID)。
USB线缆分为很多种,这里展示常见的5种线缆,分别是Mini-USB、USB-TypeA、USB-TypeB、USB-TypeC、Micro-USB接口。
下图展示了全速和低速设备的检测机制,主机端的DM、DP信号线下拉15K的电阻,当有设备接入的时候,DM和DP信号线会呈现不同的电平。
当DP上拉1.5K电阻接入主机的时候,DP为1,DM为0,此时设备被识别为全速设备;当DM上拉1.5K电阻接入主机的时候,DM为1,DP为0,此时设备被识别为低速设备。
高速设备首先被检测为全速设备,然后通过成为“chirp sequence”的总线握手机制检测高速的能力。
USB主机在检测到USB设备插入后,就要对设备进行枚举了。为什么要枚举呢?枚举就是从设备读取各种描述符信息,这样主机就可以根据这些信息来加载合适的驱动程序,从而知道设备是什么类型的设备,如何进行通讯等。调试USB设备,很重要的一点就是USB的枚举过程,只要枚举成功了,剩下的工作就不多了。
枚举的过程可以用下图来简单的概括。
以下是一个简单的枚举过程,帮助大家理解软件层面的协议。
Host [ 80 06 00 01 00 00 40 00 ] 主机:你是什么设备? |
Device [ 12 01 00 02 0A 00 00 40 70 34 08 00 00 02 01 02 03 01 ] 设备:我是CDC设备 |
Host [ 00 05 21 00 00 00 00 00 ] 主机设置唯一设备地址(地址只能从0-127),以后使用此地址和设备通讯 |
Host [ 80 06 00 01 00 00 12 00 ] 主机:你是什么设备? |
Device [ 12 01 00 02 02 02 02 40 70 34 08 00 00 02 01 02 03 01 ] 设备:我是CDC设备 |
Host [ 80 06 00 02 00 00 FF 00 ] 主机:你有几个接口?每个接口使用了哪几个端点? |
Device [ 09 02 43 00 02 01 00 C0 32 09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 00 01 04 24 02 02 05 24 06 00 01 07 05 82 03 08 00 FF 09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 81 02 ] |
Device [ 40 00 00 ] 设备:我有2个接口,一个接口使用了输入端点2,一个接口使用了输入端点1和输出端点3 |
Host [ 80 06 00 03 00 00 FF 00 ] 主机:你的字符串使用的是什么编码格式? |
Device [ 04 03 09 04 ] 设备:我使用的美国的编码格式 |
Host [ 80 06 02 03 09 04 FF 00 ] 主机:你的产品名称是什么? |
Device [ 32 03 53 00 54 00 4D 00 33 00 32 00 20 00 56 00 69 00 72 00 74 00 75 00 61 00 6C 00 20 00 43 00 4F 00 4D 00 20 00 50 00 6F 00 72 00 74 00 20 00 20 00 ] 设备:我的产品名称是… |
Host [ 80 06 03 03 09 04 FF 00 ] 主机:你的设备UID是什么? |
Device [ 1A 03 35 00 43 00 44 00 45 00 35 00 38 00 34 00 30 00 33 00 32 00 33 00 30 00 ] 设备:我的 UID是.... |
以下是USB2.0协议的截图,USB2.0资料下载,主要讲解了枚举过程的SETUP指令的含义,这里举个请求设备描述符(80 06 00 01 00 00 40 00)的例子:
命令格式 | bmRequestType | bRequest | wValue | wIndex | wLength |
命令数据 | 80 | 06 | 0100 | 0000 | 0040 |
含义 | Data transfer direction: Device-to-host Type: Standard Recipient: Device |
GET_DESCRIPTOR | Descriptor Descriptor |
0 | Descriptor |
这里主要讲解设备端回复的描述符,主机端请求的类型需要参考USB2.0手册根据具体请求回复具体的命令。
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
数字 |
该描述子包含的字节数目 |
一般都是18 |
1 |
bDescripotorType |
1 |
常数 |
设备描述符的类型常数 |
1 |
2 |
bcdUSB |
2 |
BCD |
该设备符合遵循的USB协议版本号 |
|
4 |
bDeviceClass |
1 |
Class |
由USB-IF分配的,能在 Defined Class Codes | USB-IF查询 |
|
5 |
bDeviceSubClass |
1 |
SubClass |
||
6 |
bDeviceProtocol |
1 |
Protocol |
||
7 |
bMaxPacketSize0 |
1 |
数字 |
EPO的最大包长 |
HS必须是64 |
8 |
idVendor |
2 |
ID |
USB-IF分配的 |
0x3470 |
10 |
iProduct |
2 |
ID |
厂家分配的 |
0x0008 |
12 |
bcdDevice |
2 |
BCD |
该设备自身的版本号 |
|
14 |
iManufacturer |
1 |
Index |
各自在众多字符串描述符中的序号 |
|
15 |
iProduct |
1 |
Index |
||
16 |
iSerialNumber |
1 |
index |
||
17 |
bNumConfigurations |
1 |
数字 |
该设备在当前速度下支持多少种configuration |
Virtual_Com_Port_DeviceDescriptor[ ] =
{
0x12, /* 整个Descriptor的长度:18字节 */
0x01, /* Descriptor的类别:Device Descriptor(0x01) */
0x00, 0x02, /* 设备所遵循的USB协议的版本号:2.00 */
0x0A, /* 设备所实现的类:CDC Class*/
0x00, /* 设备所实现的子类:*/
0x00, /* 设备所遵循的协议类别:*/
0x40, /* 端点0的最大数据包长度:64字节*/
0x70, 0x34, /* IDVendor: 0x3470 */
0x08, 0x00, /* IDProduct: 0x0008 */
0x00, 0x02, /* bcdDevice: 2.00*/
1, /* 用于描述生产厂商的字符描述符的索引号 */
2, /* 用于描述产品的字符描述符的索引号*/
3, /* 用于描述产品系列号的字符描述符的索引号*/
0x01 /* 设备所支持的配置数目:1*/
}
bDeviceClass、bDeviceSubClass和bDeviceProtocol可在USB官网进行查询,idVendor是向USB机构申请的,需要支付一笔费用,如果针对开发者,可以选择芯片厂商的idVendor进行开发。
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
数字 |
该描述子包含的字节数目 |
一般都是9 |
1 |
bDescripotorType |
1 |
常数 |
配置描述符的类型常数 |
2 |
2 |
wTotalLength |
2 |
数字 |
包含了所有描述子的长度(配置、接口、端点、类相关、厂商相关) |
当主机要求配置描述符时,所有相关的接口、端点描述符都要返回 |
4 |
bNumInterfaces |
1 |
数字 |
该配置包含几个接口 |
|
5 |
bConfigurationValue |
1 |
数字 |
选择该配置时,传递给SetConfiguration0的参数 |
|
6 |
iConfiguration |
1 |
index |
在众多字符串描述符中的序号 |
|
7 |
bmAttributes |
1 |
位图 |
D7:保留为1是否由总线供电 D6:是否支持远程唤醒 D5:D4~D0:保留为0 |
|
8 |
bMaxPower |
1 |
mA |
该设备在该configuration下全速工作时需要从总线获取的电流(以2mA为单位) |
Virtual_Com_Port_ConfigDescriptor[ ] =
{
0x09, /* 描述符的长度:9字节 */
0x02, /* 描述符的类型: 0x02 配置描述符 */
VIRTUAL_COM_PORT_SIZ_CONFIG_DESC, 0x00, /* 完整的描述 符包括接口描述符、 端点描述符和类描述符的长度 */
0x02, /* 配置所支持的接口数目:2*/
0x01, /* 用SetConfiguration选择此配置时所指定的配置号*/
0x00, /* 用于描述此配置的字符描述符的索引号:0 */
0xC0, /* 供电配置:B7(1 保留), B6(自供电), B5(远程唤醒), B4- B0(0 保留) */
0x32, /* 最大功耗,以2mA为单位计算:0x32表示 100mA */
}
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
数字 |
该描述子包含的字节数目 |
一般都是9 |
1 |
bDescripotorType |
1 |
常数 |
接口描述符的类型常数 |
4 |
2 |
bInterfaceNumber |
1 |
数字 |
该接口的序号:在该配置所支持的众多接口中的序号 |
从0开始 |
3 |
bAlternateSetting |
1 |
数字 |
用来选择该接口的某个setting |
|
4 |
bNumEndpoints |
1 |
数字 |
该接口支持多少个非0的EP |
如果此项为0则该接口使用默认的控制通道 |
5 |
blnterfaceClass |
1 |
Class |
由USB-IF分配 |
|
6 |
bInterfaceSubClass |
1 |
SubClass |
||
7 |
blnterfaceProtocol |
1 |
Protocol |
||
8 |
ilnterface |
1 |
index |
在众多字符串描述符中的序号 |
Virtual_Com_Port_InterfaceDescriptor[ ] =
{
0x09, /* 描述符的长度:9字节 */
4, /* 描述符的类型:0x04接口描述符(Interface) */
0x00, /* 选择此接口的索引号,从0开始计算:0 */
0x00, /* 用于选择此设置的索引号:0 */
0x02, /* 实现此接口需要使用的端点数目:2 */
0x0A, /* 此接口所遵循的类:CDC Class */
0x00, /* 此接口所遵循的子类:*/
0x00, /* 此接口所支持的协议:*/
0, /* 用于描述此接口的字符描述符的索引号 */
}
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
数字 |
该描述子包含的字节数目 |
一般都是7 |
1 |
bDescripotorType |
1 |
常数 |
端点描述符的类型常数 |
5 |
2 |
bEndpointAddress |
1 |
端点 |
Bit7: 方向 (0-OUT; 1-IN) Bit6~4:保留为0 Bit3~0:端点号 |
|
3 |
bmAttributes |
1 |
位图 |
传输类型 |
|
4 |
wMaxPacketSize |
2 |
数字 |
该端点的最大包长 |
|
6 |
bInterval |
1 |
数字 |
主机查询EP的间隔,以帧或微帧为单位 FS/HS的ISO EP:取值1~16,间隔是2(bInterval-1)6bInterval数字 FS/LS的INTR EP: 取值1~255 HS的INTR EP:取值在1~16,间隔是2(bInterval1) HS的BULK/CTRL OUT EP:设定了设备的最大NAK率(即每个微帧最多回几个NAK) ; 取值0~255 |
Virtual_Com_Port_InterfaceDescriptor[ ] =
{
0x07, /* 描述符长度:7字节 */
5, /* 描述符类型:端点描述符*/
0x81, /* 端点的特性:B3-B0(端点号), B6-B4(0), B7(1=IN, 0=OUT)
0x81:Endpoint1/ IN */
0x02, /* 端点的类型:B1-B0(00=控制 01=同步 10=大容量 11=中断) 0x02:大容量端点 */
0x40, 0x00 /* 此端点的最大有效数据长度:64 字节 */
0x00, /* 主机查询此端点数据的间隔时间:大容量端点,忽略此值*/
}
字符串描述符包括以下:
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
常数 |
该描述子包含的字节数目 |
一般为4 |
1 |
bDescripotorType |
1 |
常数 |
字符串描述符的类型常数 |
3 |
2 |
LangID |
2 |
数字 |
语言ID码 |
Offset |
Field |
Size |
Value |
描述 |
备注 |
0 |
bLength |
1 |
N+2 |
该描述子包含的字节数目 |
|
1 |
bDescripotorType |
1 |
常数 |
字符串描述符的类型常数 |
3 |
2 |
WLANGID[O] |
2 |
数字 |
语言编号编码0 |
|
… |
… |
… |
… |
… |
… |
n |
WLANGID[x] |
2 |
数字 |
语言编号编码n |
Packet主要由下面四部分组成:
接下来重点讲解一下Packet Connent域里面的内容。
状态 |
速度 |
差分值 |
J状态 |
LS |
差分0 |
FS |
差分1 |
|
K状态 |
LS |
差分1 |
FS |
差分0 |
PID:Packet Identifier,包标识,LSB在前,前4个字节为PID码,后四个字节是前四个字节的取反。
PID0(LSB) |
PID1 |
PID2 |
PID3 |
PID0 |
PID1 |
PID2 |
PID3 (MSB) |
以下是PID的类型码。
PID类型 |
PID名 |
PID[3:0] |
说明 |
令牌类 |
OUT |
0001B |
通知设备将要输出数据 |
IN |
1001B |
通知设备将要输入数据 |
|
SOF |
0101B |
通知设备这是一个帧起始包 |
|
SETUP |
1101B |
通知设备将要开始一个控制传输 |
|
数据类 |
DATA0 |
0011B |
不同类型的数据包 |
DATA1 |
1011B |
||
DATA2 |
0111B |
||
MDATA |
1111B |
||
握手类 |
ACK |
0010B |
确认 |
NAK |
1010B |
不确认 |
|
STALL |
1110B |
挂起 |
|
NYET |
0110B |
未准备好 |
|
特殊类 |
PRE |
1100B |
前导(这是一个令牌包) |
ERR |
1100B |
错误(这是一个握手包) |
|
SPLIT |
1000B |
分裂事物(这是一个令牌包) |
|
PING |
0100B |
PING测试(这是一个令牌包) |
|
…… |
0000B |
保留,未使用 |
地址由7位的设备地址和4位的端点地址组成。
addr0 (LSB) |
addr1 |
addr2 |
addr3 |
addr4 |
addr5 |
addr6 |
addr0 (LSB) |
addr1 |
addr2 |
addr3 |
根据传输类型的不同,数据域的数据长度从0-1024字节不等。
传输类型 |
控制传输 |
批量传输 |
中断传输 |
同步传输 |
||||||||
设备速度 |
HS |
FS |
LS |
HS |
FS |
LS |
HS |
FS |
LS |
HS |
FS |
LS |
数据包长度 |
64 |
64 |
8 |
512 |
64 |
N.A |
1024 |
64 |
8 |
1024 |
1023 |
N.A |
令牌包的组成为:PID+地址+CRC
SOF包的组成为:PID+帧号+CRC
数据包的组成为:PID+数据+CRC
握手包的组成为:PID
注意:
1. 当收到SETUP包的时候,设备只能回复ACK;
2. 当同步传输的时候,没有握手包。
USB的传输类型分为控制传输、中断传输、批量传输和同步传输,每种传输类型用在特定的场合。
非周期性传输,用于命令和状态的传输。每个USB设备都必须有控制端点,支持控制传输来进行命令和状态的传输。USB主机驱动将通过控制传输与USB设备的控制端点通讯,完成USB设备的枚举和配置。
控制传输是双向的传输,必须有IN和OUT两个方向上的特定端点号的控制端点来完成两个方向上的控住传输。
周期性,低频率传输,允许有限延迟的通信,中断传输用于那些频率不高,但对周期有一定要求的数据传输。具有保证的带宽,并能在下个周期对先前错误的传输进行重传;对于全速端点,中断传输的时间间隔在1ms到255ms之间,对于低速端点,时间间隔限制在10ms到255ms之间,对于高速端点, 时间间隔为2bInterval-1*125us,bInterval的值在1到16之间。
中断传输总算单向的,可以用单向的中断端点来实现某个方向上的中断传输。
非周期性,大容量数据的通信,数据可以占用任意带宽。大容量数据传输适用于那些需要大数据量传输,但是对实时性,对延迟性和带宽没有严格要求的应用。大容量传输可以占用任意可用的数据带宽。
大容量传输是单向的,可以用单向的大容量传输端点来实现某个方向的大容量传输。
周期性,持续的传输,用于传输与时效相关的信息,并且在数据中保存时间戳的信息。同步传输用于传输那些需要保证带宽,并且不能忍受延迟的信息。整个带宽都将用于保证同步传输的数据完整,并且不支持出错重传。
同步传输总是单向的,可以使用单向的同步端点来实现某个方向上的同步传输。
USB使用的差分传输模式,两个数据线D+和D-(VOH:2.8V VOL:0.3V)
状态 |
速度 |
差分值 |
J状态 |
LS |
差分0 |
FS |
差分1 |
|
K状态 |
LS |
差分1 |
FS |
差分0 |
接下来讲解USB的各类应用及代码,敬请期待。。。