2、批量传输协议基础:USB批量传输的端点特性、事务格式(令牌、数据、握手包)
批量传输(Bulk Transfer)是 USB 协议中用于传输大量数据、且对传输延迟不敏感的主要传输类型。它利用 USB 总线上的空闲带宽进行传输,当总线繁忙时,批量传输会被挂起,直到有可用带宽。本章将深入剖析批量传输的端点特性、事务格式以及构成事务的三个基本阶段:令牌包、数据包和握手包。
2.1 批量传输端点特性
批量端点(Bulk Endpoint)是 USB 设备中实现批量传输的硬件逻辑单元。与中断端点或等时端点不同,批量端点具有以下核心特性:
| 特性 | 描述 | 关键参数 |
|---|---|---|
| 传输方向 | 分为 IN(设备到主机)和 OUT(主机到设备)两种。一个批量端点只能支持单一方向。 | 端点描述符中的 bEndpointAddress 的 bit7 指示方向。 |
| 数据负载 | 全速(Full Speed)模式下最大包大小为 8、16、32 或 64 字节;高速(High Speed)模式下固定为 512 字节。 | 端点描述符中的 wMaxPacketSize 字段。 |
| 错误重试 | 支持硬件级别的错误检测与重传。若数据包或握手包出错,事务会被重试。 | 通过 CRC 校验和 PID 验证实现。 |
| 带宽保证 | 无固定带宽保证。批量传输仅在总线空闲时进行,优先级低于中断和等时传输。 | 由主机控制器(EHCI)的调度策略决定。 |
| 数据流控制 | 通过握手包中的 NYET(高速模式)或 NAK 实现流控。设备未准备好时返回 NAK,主机将重试。 | NYET 仅在高速批量 OUT 事务中使用。 |
| PING 协议 | 高速批量 OUT 端点使用 PING 协议探测设备接收能力,避免无效数据发送。 | 通过 PING 令牌包和 NYET/ACK 握手包实现。 |
开发提示: 在 EHCI 驱动中配置批量端点时,必须正确设置
wMaxPacketSize 为 512(高速),否则会导致数据包分割错误。同时,批量端点的 bEndpointAddress 中的方向位不可更改,IN 和 OUT 必须使用不同的端点号。
2.2 批量事务格式
一个完整的批量事务由三个连续的阶段组成:令牌阶段、数据阶段和握手阶段。每个阶段都通过一个独立的 USB 包(Packet)实现。下图展示了批量 IN 事务和批量 OUT 事务的标准流程。
2.3 事务阶段详解
2.3.1 令牌阶段(Token Stage)
令牌阶段由主机发送一个令牌包(Token Packet)开始。令牌包定义了后续事务的类型和方向。批量传输使用以下三种令牌:
- OUT 令牌(PID = 0x01): 通知设备主机将要发送数据。令牌包中包含设备地址和端点号。
- IN 令牌(PID = 0x09): 通知设备向主机发送数据。令牌包中包含设备地址和端点号。
- PING 令牌(PID = 0x04): 高速批量 OUT 专用。主机在发送数据前先探测设备是否准备好接收。设备以 NYET 或 ACK 响应。
令牌包结构: 同步域(SYNC, 8位)+ 包标识符(PID, 8位)+ 地址域(ADDR, 7位)+ 端点域(ENDP, 4位)+ CRC5(5位)+ 包结束(EOP)。PID 的低 4 位为类型,高 4 位为校验位。
2.3.2 数据阶段(Data Stage)
数据阶段承载实际的有效载荷。批量传输使用 DATA0 和 DATA1 两种数据包 PID 进行交替翻转(Toggle),以实现数据同步和错误恢复。
- DATA0 包(PID = 0xC3): 用于事务序列中的第一个数据包。
- DATA1 包(PID = 0x4B): 用于事务序列中的第二个数据包,之后交替使用。
数据包的最大有效载荷由端点的 wMaxPacketSize 决定。高速批量端点每次最多传输 512 字节。如果传输的数据量超过此值,主机控制器会将其分割为多个连续的事务,每个事务携带一个数据包,并正确维护数据切换序列。
数据切换同步: 主机和设备的批量端点各自维护一个数据切换序列位(Data Toggle Bit)。主机发送 DATA0 后,期望设备返回 ACK,然后切换为 DATA1。如果设备返回 NAK,主机必须重发相同的 DATA0 包,不得切换序列。EHCI 控制器通过
qTD 描述符中的 Toggle 位自动管理此过程。
2.3.3 握手阶段(Handshake Stage)
握手阶段由接收方返回一个握手包,报告事务的接收状态。批量传输中使用的握手包包括:
| 握手包 | PID | 含义 | 使用场景 |
|---|---|---|---|
| ACK | 0xD2 | 数据正确接收,无错误。 | IN 事务中主机发送;OUT 事务中设备发送。 |
| NAK | 0x5A | 设备暂时无法发送或接收数据(忙状态)。 | IN 事务中设备无数据;OUT 事务中设备缓冲区满。 |
| NYET | 0x96 | 高速批量 OUT 事务中,设备尚未准备好接收下一个数据包。 | 仅高速模式,设备在 PING 响应或 OUT 事务握手阶段使用。 |
| STALL | 0x1E | 端点发生不可恢复的错误,或端点被主机强制设置为 Halt 状态。 | 设备返回 STALL 后,主机需通过控制传输清除端点停止状态。 |
2.4 批量传输数据流与错误恢复
批量传输的可靠性建立在错误检测与重试机制之上。下图展示了批量 OUT 事务中可能出现的错误场景及恢复流程。
2.5 批量传输与 EHCI 调度
在 EHCI 主机控制器中,批量传输的调度遵循以下原则:
- 异步调度列表: 批量传输被组织在异步调度列表(Async List)中。EHCI 在每个微帧(Microframe)中轮询此列表,处理批量请求。
- 带宽回收: 批量传输利用每个微帧中未被中断或等时传输占用的剩余带宽。EHCI 通过
PeriodicListBase和AsyncListAddr寄存器管理两种调度列表。 - 事务重试: 当批量事务因 NAK 失败时,EHCI 不会立即重试,而是将 qTD 保留在异步列表中,等待下一次调度轮询。这避免了总线被 NAK 风暴淹没。
- PING 协议优化: 对于高速批量 OUT 端点,EHCI 可以启用 PING 协议。在发送数据前先发送 PING 令牌,若设备返回 NYET,则主机推迟数据发送,避免无效的 OUT 事务。
EHCI 配置要点: 在 EHCI 驱动中,批量传输的
qTD 描述符必须设置 Active 位为 1,并正确初始化 Alternate Next 指针。对于高速批量端点,Mult 字段(在 qTD 的 dwToken 中)应设置为 0,表示每个微帧只处理一个事务。
2.6 批量传输应用场景
批量传输广泛应用于以下设备类型:
- 大容量存储设备(Mass Storage): U 盘、移动硬盘、SD 卡读卡器。批量传输用于传输文件数据块。
- 打印机(Printer): 传输打印作业数据。
- 网络适配器(Ethernet Adapter): 传输网络数据包。
- 数据采集设备: 如 USB 示波器、逻辑分析仪,用于传输采样数据。