1. USB事务:通信的原子操作单元
USB事务是USB协议栈中最基础的通信单元,相当于数据传输的"原子操作"。想象一下公司晨会的场景:经理(主机)和员工(设备)之间的每次对话都遵循固定流程——经理先点名(令牌包),员工回应工作进展(数据包),最后经理给予反馈(握手包)。这种一问一答的标准化交互就是USB事务的生动体现。
在实际硬件层面,每个事务由特定序列的物理信号组成。以全速USB为例,当主机检测到设备插入时,首先会发送一个SE0信号(D+和D+同时拉低)维持10ms以上触发复位,随后通过差分信号(D+或D-拉高)识别设备速度。这个初始握手过程本身就是通过特殊的事务完成的。
2. 事务的三大基本类型
2.1 SETUP事务:设备控制的指挥棒
SETUP事务是控制传输的专属事务,其特殊性体现在数据阶段固定使用DATA0包(其他事务采用DATA0/DATA1交替)。我曾用逻辑分析仪抓取过枚举过程的SETUP事务:主机发送的8字节数据包含bmRequestType(请求方向)、bRequest(具体请求)和wValue/wIndex等字段。例如获取描述符的请求中,bRequest=0x06表示GET_DESCRIPTOR,wValue高位字节指明描述符类型。
技术细节:SETUP事务后设备必须接受数据,这与OUT事务不同。如果设备返回STALL,主机会尝试复位端点。
2.2 IN事务:设备到主机的数据通道
当主机需要读取设备数据时,典型的IN事务流程如下:
- 主机发送IN令牌包(包含设备地址和端点号)
- 设备根据状态返回:
- DATAx包(含有效数据)
- NAK(临时无数据)
- STALL(端点故障)
- 主机收到有效数据后回复ACK
在调试HID设备时,我发现一个关键点:中断传输的IN事务有严格的轮询间隔。比如鼠标描述符中bInterval=10表示主机每10ms查询一次,这就是为什么USB鼠标的采样率通常为100Hz。
2.3 OUT事务:主机到设备的数据通道
OUT事务的特别之处在于支持PING协议(仅高速模式):当设备缓冲区不足时,可以通过NYET握手包告知主机。我在开发大容量存储设备时,就遇到过主机连续发送OUT事务导致设备丢包的情况,最终通过优化PING协议处理解决了问题。
3. 事务的包组成结构
3.1 令牌包:事务的发起者
令牌包最关键的PID字段定义如下:
OUT: 0xE1IN: 0x69SOF: 0xA5SETUP: 0x2D
地址域采用7位编码(0-127),这意味着一个USB主机最多支持127个设备。实际测试中发现,当设备地址冲突时,主机会自动分配新地址。
3.2 数据包:有效载荷载体
USB采用DATA0/DATA1交替机制(同步传输除外)来防止数据重复或丢失。我曾用示波器捕捉到这样的序列:
SETUP(DATA0) -> IN(DATA1) -> OUT(DATA0) -> IN(DATA1)这种"乒乓缓冲"机制确保了数据传输的可靠性。
3.3 握手包:传输的保险丝
握手包类型包括:
ACK(0xD2):正确接收NAK(0x5A):临时拒绝STALL(0x1E):致命错误
特殊情况下,高速设备可能返回NYET(0x96)表示暂时无法接收更多数据。在分析USB摄像头数据流时,频繁出现的NAK往往表明设备处理能力不足。
4. 不同传输类型中的事务差异
4.1 控制传输的三段式事务
典型的设备枚举过程包含以下事务序列:
- SETUP事务(发送GET_DESCRIPTOR请求)
- IN事务(设备返回描述符)
- OUT事务(状态确认)
抓包示例显示,获取设备描述符时,主机先发送8字节SETUP数据:
80 06 00 01 00 00 40 00设备随后返回18字节描述符,包含厂商ID、产品ID等关键信息。
4.2 同步传输的无握手特性
音频设备采用同步传输时,事务仅包含令牌包和数据包。实测发现,当传输MP3音频流时,即使有少量数据错误也不会重传,这是为了保证实时性而做的设计妥协。
4.3 批量传输的事务重试
在大文件传输过程中,当设备返回NAK时,主机会根据以下算法进行重试:
// 典型的重试间隔算法 retry_delay = min(2^(retry_count) * base_interval, max_delay);这种指数退避策略能有效应对临时性拥塞。
4.4 中断传输的定时轮询
键盘等HID设备的中断事务有严格的时间要求。配置描述符中的bInterval字段决定了轮询频率,例如:
- 125Hz对应
bInterval=4(每8ms一次) - 1000Hz对应
bInterval=1(每1ms一次)
5. 事务层的关键特性解析
5.1 主机主导原则
所有事务都由主机通过定时发送SOF包(全速1ms间隔,高速125μs)来同步。在示波器上可以清晰看到,即使没有数据传输,SOF包也会周期性出现,就像心跳信号维持总线活动。
5.2 错误处理机制
常见的错误场景包括:
- CRC校验失败:接收方直接丢弃包
- 超时无响应:主机等待超过16个位时间后重试
- Babble错误:设备发送超时被主机强制终止
5.3 数据切换同步
DATAx切换的规则如下:
- SETUP事务总是使用DATA0
- 成功传输后切换DATA0/DATA1
- 错误时保持当前状态不变
这个机制在USB协议分析仪上可以直观观察到,正常通信时DATA PID会规律交替。
6. 实战案例分析
6.1 设备枚举过程抓包解析
使用Wireshark捕获的典型枚举流程:
- 总线复位(SE0状态持续10ms+)
- 获取设备描述符(控制传输)
- 设置地址(SET_ADDRESS请求)
- 获取配置描述符
其中每个步骤都包含完整的事务序列,通过分析这些原始数据可以深入理解协议运作。
6.2 高速设备识别过程
高速设备先以全速连接,然后通过Chirp信号协商切换:
- 主机发送Chirp K
- 设备回应Chirp K-J-K
- 主机确认后切换到高速模式
这个握手过程本质上也是一种特殊的事务交互。
7. 开发调试技巧
在调试USB设备驱动时,有几个实用方法:
- 使用USBlyzer等工具监控事务级通信
- 对于NAK过多的情况,检查端点描述符的
wMaxPacketSize - STALL状态通常需要清除端点特性
- 通过USB电气特性测试仪检查信号质量
记得有一次调试自定义HID设备时,发现主机收不到IN事务数据,最终发现是端点描述符中的传输类型设置错误。这种事务层的故障往往需要逐层分析才能定位。