4. USB中断传输原理
4.1 中断传输的定义与特性
USB中断传输(Interrupt Transfer)是一种保证轮询延迟的传输类型,适用于小数据量、周期性、低延迟的通信场景。在电池供电设备中,中断传输是传感器数据上报、按键状态变化、HID设备报告等交互的核心承载方式。
| 特性 | 描述 |
|---|---|
| 传输方向 | 单向(IN 或 OUT),由端点描述符固定 |
| 数据载荷 | 全速 ≤ 64 字节,高速 ≤ 1024 字节,超高速 ≤ 1024 字节 |
| 延迟保证 | 主机保证在 bInterval 指定的时间间隔内至少轮询一次 |
| 错误重试 | 数据错误时自动重试,直到成功或超时 |
| 带宽预留 | 全速/高速下,中断传输可预留最多 90% 的帧/微帧带宽 |
| 典型应用 | 鼠标、键盘、游戏手柄、传感器数据流、中断事件通知 |
低功耗设计要点: 中断传输的轮询间隔
bInterval 直接影响设备唤醒频率。在电池供电设备中,应尽量将 bInterval 设置为满足功能需求的最大值(如 8ms 或 16ms),以减少主机轮询次数,降低设备平均功耗。
4.2 中断端点类型与描述符
中断端点使用 端点描述符(Endpoint Descriptor) 中的 bmAttributes 字段标识传输类型为中断传输。主机在枚举阶段读取端点描述符,获取轮询间隔、最大包长等信息。
// USB 端点描述符结构(中断端点示例)
typedef struct {
uint8_t bLength; // 描述符长度:7
uint8_t bDescriptorType; // 描述符类型:0x05(端点)
uint8_t bEndpointAddress; // 端点地址:0x81(IN端点1)
uint8_t bmAttributes; // 属性:0x03(中断传输)
uint16_t wMaxPacketSize; // 最大包长:0x0040(64字节)
uint8_t bInterval; // 轮询间隔:0x0A(10ms)
} __attribute__((packed)) usb_endpoint_descriptor_t;
| 字段 | 值示例 | 说明 |
|---|---|---|
bEndpointAddress |
0x81 | Bit7=1(IN方向),Bit3-0=1(端点1) |
bmAttributes |
0x03 | Bit1-0=11(中断传输) |
wMaxPacketSize |
0x0040 | 全速下最大64字节 |
bInterval |
0x0A | 轮询间隔10ms(全速单位:ms) |
端点类型对比: 中断端点与批量端点最大的区别在于延迟保证。批量端点没有固定轮询周期,而中断端点由主机在每帧/微帧中按
bInterval 调度,保证最坏情况延迟。
4.3 中断传输的事务格式
每个中断传输事务由三个阶段组成:令牌包(Token Packet) → 数据包(Data Packet) → 握手包(Handshake Packet)。对于 IN 方向中断传输,事务流程如下:
- 主机发送 IN 令牌包:包含端点地址和设备地址,通知设备准备发送数据。
- 设备返回数据包:设备在收到 IN 令牌后,在指定时间内返回 DATA0/DATA1 数据包。
- 主机发送握手包:主机正确接收数据后,返回 ACK 握手包;如果数据错误,返回 NAK 或 STALL。
4.4 令牌包详解
令牌包由主机发送,标识事务的类型和方向。中断传输使用 IN 令牌(主机读取设备数据)或 OUT 令牌(主机发送数据给设备)。令牌包格式固定为 4 字节:
| 字段 | 长度 | 说明 |
|---|---|---|
| PID | 1 字节 | 包标识符:IN=0x69, OUT=0xE1, SETUP=0x2D |
| ADDR | 7 位 | 设备地址(0~127) |
| ENDP | 4 位 | 端点号(0~15) |
| CRC5 | 5 位 | 对 ADDR+ENDP 的校验 |
常见错误: 在电池供电设备中,如果设备在收到 IN 令牌后没有数据可发送,应返回 NAK 握手包,而不是 STALL。STALL 表示端点发生不可恢复错误,会导致主机停止轮询该端点,影响后续通信。
4.5 数据包详解
数据包携带实际传输的数据负载。中断传输使用 DATA0 和 DATA1 两种数据包 PID 进行交替切换,实现数据同步和错误检测。
- DATA0 PID:0xC3,事务开始时使用
- DATA1 PID:0x4B,与 DATA0 交替使用
- 数据字段:0~1024 字节(取决于速度)
- CRC16:对数据字段进行 16 位循环冗余校验
数据包切换规则:每个成功完成的事务(收到 ACK)后,数据包 PID 翻转。如果事务失败(收到 NAK 或超时),PID 不翻转,主机重试时使用相同 PID。
4.6 握手包详解
握手包是事务的最后一个阶段,用于报告传输状态。握手包仅包含 1 字节 PID,无数据字段和 CRC。
| 握手包类型 | PID 值 | 含义 | 发送方 |
|---|---|---|---|
| ACK | 0xD2 | 数据正确接收,事务成功完成 | 主机(IN)或设备(OUT) |
| NAK | 0x5A | 设备暂时无法发送/接收数据,请重试 | 设备 |
| STALL | 0x1E | 端点发生错误,无法继续通信 | 设备 |
| NYET | 0x96 | 设备尚未准备好(高速/超高速专用) | 设备 |
低功耗优化策略: 在电池供电设备中,频繁返回 NAK 会增加总线活动和功耗。建议在设备没有数据时,让 USB 控制器进入 挂起状态 或 选择性挂起,而不是持续返回 NAK。当有数据需要上报时,通过远程唤醒信号通知主机恢复通信。
4.7 中断传输在电池供电设备中的调度
主机在每帧(全速 1ms)或每微帧(高速 125μs)中,按照端点描述符中的 bInterval 值调度中断传输。调度算法遵循以下规则:
- 全速设备:
bInterval取值范围 1~255,单位 ms。主机每bIntervalms 轮询一次。 - 高速设备:
bInterval取值范围 1~16,实际轮询间隔为2^(bInterval-1) × 125μs。 - 超高速设备:
bInterval取值范围 1~16,实际轮询间隔为2^(bInterval-1) × 125μs,支持服务间隔的微调。
4.8 中断传输与低功耗设计的结合
在电池供电设备中,中断传输的优化需要从以下三个层面入手:
| 优化层面 | 具体措施 | 功耗收益 |
|---|---|---|
| 轮询间隔 | 增大 bInterval 到满足延迟要求的最大值 |
减少主机轮询次数,降低设备唤醒频率 |
| 数据聚合 | 将多次采样数据合并为一次中断传输上报 | 减少事务次数,降低总线活动功耗 |
| 选择性挂起 | 无数据时进入 USB 挂起状态,通过远程唤醒恢复 | 挂起电流可降至微安级 |
| NAK 管理 | 避免频繁返回 NAK,使用挂起代替 | 减少总线握手开销 |
实践建议: 对于电池供电的传感器节点,推荐将
bInterval 设置为 8ms~16ms,并在设备固件中实现 事件驱动上报 机制:仅在数据变化或达到阈值时唤醒并响应轮询,否则保持挂起状态。这样可以在不丢失数据的前提下,将平均功耗降低 60%~80%。