2. USB协议核心:包结构、传输类型与帧/微帧
USB协议说复杂也复杂,说简单也简单。你想想看,一根线上要传数据、地址、校验信息,还得让设备知道自己该干什么——这全靠包结构来组织。我个人习惯把USB协议拆成三个层次来理解:包(Packet)、事务(Transaction)、传输(Transfer)。这一章我们先啃最底层的包结构,再把四种传输类型和帧概念讲透。
2.1 包结构:USB通信的最小单元
USB总线上的所有通信,本质上就是主机和设备之间来回扔包。每个包由五个字段组成,但不是每个包都包含全部字段。我画了一张结构图,你先有个整体印象:
2.2 逐字段拆解
2.2.1 SOP与EOP:包的边界
SOP其实就是一串特定的同步序列(Sync Pattern),让接收方的时钟与发送方对齐。USB 2.0高速模式下,SOP是32位的同步码。EOP则用SE0(Single-Ended Zero)状态来表示包结束。嗯,这里要注意:EOP之后总线会进入空闲状态(Idle),等待下一个包。
2.2.2 PID:包的身份标签
PID是包类型标识符,一共8位——高4位是类型码,低4位是取反校验。为什么这么设计?说白了就是为了抗干扰。接收方收到PID后,会检查高4位和低4位是否互为取反,不一致就直接丢弃。
PID分为四大类,我列个表方便你对照:
| PID类型 | PID值(二进制) | 名称 | 用途 |
|---|---|---|---|
| 令牌(Token) | 0001 | OUT | 主机→设备,通知设备准备接收数据 |
| 令牌(Token) | 1001 | IN | 主机→设备,请求设备发送数据 |
| 令牌(Token) | 0101 | SOF | 主机→设备,帧起始标记 |
| 令牌(Token) | 1101 | SETUP | 主机→设备,控制传输的起始 |
| 数据(Data) | 0011 | DATA0 | 数据包,偶数据切换位 |
| 数据(Data) | 1011 | DATA1 | 数据包,奇数据切换位 |
| 数据(Data) | 0111 | DATA2 | 高速同步/中断专用 |
| 数据(Data) | 1111 | MDATA | 高速同步/中断专用 |
| 握手(Handshake) | 0010 | ACK | 接收方确认,数据正确接收 |
| 握手(Handshake) | 1010 | NAK | 设备忙,暂时无法接收/发送 |
| 握手(Handshake) | 0110 | STALL | 端点挂起,出现错误 |
| 握手(Handshake) | 1110 | NYET | 高速模式下,设备未准备好 |
| 特殊(Special) | 1100 | PRE | 低速设备前同步 |
| 特殊(Special) | 1100 | ERR | 高速模式错误报告 |
| 特殊(Special) | 1000 | SPLIT | 高速HUB拆分事务 |
| 特殊(Special) | 0100 | PING | 高速模式探测端点状态 |
2.2.3 ADDR与ENDP:谁跟谁说话
ADDR是设备地址,7位宽,范围0~127。地址0是默认地址,设备刚上电时用这个地址跟主机通信,枚举完成后主机才会分配一个新地址。ENDP是端点号,4位宽,每个设备最多16个端点(0~15)。端点0是控制端点,所有USB设备都必须有。
你想想看,主机怎么找到某个设备上的某个端点?其实就是靠ADDR+ENDP的组合。比如ADDR=3, ENDP=1,就表示“3号设备的1号端点”。
2.2.4 CRC:数据完整性保障
CRC分两种:令牌包用5位CRC,数据包用16位CRC。5位CRC的生成多项式是x⁵+x²+1,16位CRC的生成多项式是x¹⁶+x¹⁵+x²+1。接收方计算CRC,如果跟发送方的不一致,就说明传输过程中出了错。
2.3 四种传输类型
USB协议定义了四种传输类型,每种类型对应不同的应用场景。我习惯用一个表格来对比它们:
| 传输类型 | 特点 | 带宽保证 | 错误重试 | 典型应用 |
|---|---|---|---|---|
| 控制传输 | 双向、可靠、有握手 | 10%保留带宽 | 支持 | 设备枚举、配置、命令 |
| 批量传输 | 可靠、无带宽保证 | 无 | 支持 | U盘、打印机、扫描仪 |
| 中断传输 | 可靠、有轮询周期 | 有(按轮询间隔) | 支持 | 鼠标、键盘、游戏手柄 |
| 同步传输 | 实时、无重试 | 有(按分配带宽) | 不支持 | 音频、视频、摄像头 |
2.3.1 控制传输
控制传输是USB的“官方语言”,所有设备都必须支持。它分三个阶段:建立阶段(SETUP事务)、数据阶段(可选,DATA0/DATA1交替)、状态阶段(握手)。控制传输的默认端点号是0,最大包长在低速模式下是8字节,全速是8/16/32/64字节,高速是64字节。
我个人习惯把控制传输看作“命令通道”——主机通过它来配置设备、获取描述符、设置地址。枚举过程就是靠控制传输完成的。
2.3.2 批量传输
批量传输的特点是“尽力而为”——有带宽就用,没带宽就等着。但它保证数据可靠,因为出错会重试。批量传输适合大数据量、对实时性要求不高的场景,比如U盘读写。
批量传输的最大包长:全速是8/16/32/64字节,高速是512字节,超速(USB 3.0)是1024字节。嗯,这里要注意:批量传输没有固定的带宽,如果总线上有其他实时传输(比如同步传输),批量传输就得让路。
2.3.3 中断传输
中断传输的名字容易让人误解——它并不是真的“中断”,而是主机定期轮询设备。轮询间隔由设备在描述符中指定,范围是1~255毫秒(全速/低速)或1~65535微帧(高速)。
中断传输保证在轮询间隔内至少有一次传输机会,出错会重试。鼠标、键盘这类人机交互设备就用中断传输——你想想看,鼠标移动的数据如果丢了,光标就会卡顿,用户肯定受不了。
2.3.4 同步传输
同步传输是唯一不保证可靠性的传输类型——出错不重试。为什么?因为音频、视频这类数据对实时性要求极高,重试会导致延迟和卡顿。宁可丢一帧,也不能等重试。
同步传输的最大包长:全速是1023字节,高速是1024字节。它需要预先分配带宽,主机在每帧/微帧中为同步传输预留固定时间片。
2.4 帧与微帧
USB总线的时间被划分成一个个“帧”(Frame)。全速/低速模式下,每帧1毫秒。高速模式下,每帧又分成8个微帧(Microframe),每个微帧125微秒。
主机每帧开始时发送一个SOF(Start of Frame)包,里面包含帧号(11位,0~2047循环)。设备可以用SOF来同步自己的时钟,或者计算时间间隔。
帧/微帧的概念对固件开发有什么实际意义?我举个例子:你在写一个USB音频设备的固件,音频数据必须每微帧发送一次,否则就会出现爆音。这时候你就得算好每个微帧能传多少数据——高速模式下每微帧125微秒,如果同步传输分配了80%的带宽,那每微帧最多能传1024字节(同步包最大长度)。
2.5 本章小结
这一章我们把USB协议的核心概念过了一遍。包结构是USB通信的基石——SOP、PID、ADDR、ENDP、CRC、EOP,每个字段都有它的作用。四种传输类型各有各的适用场景:控制传输管配置,批量传输管数据,中断传输管交互,同步传输管实时流。帧和微帧则是USB总线的时间骨架,所有传输都在这个骨架里调度。