USB Interrupt 端点 bInterval 调试:轮询速率、HID 延迟、Full-Speed 与 High-Speed 差异
USB Interrupt 端点 bInterval 排查:轮询速率、HID 延迟、丢输入报告、Full-Speed 与 High-Speed 间隔规则、端点描述符错误。
USB Interrupt 端点用在键盘、鼠标、游戏手柄、传感器、触摸屏、条码枪、UPS 和很多自定义 HID 工具上。输入明显卡顿、或者报告到达的频率不对的时候,用户搜 "USB bInterval"、"HID 轮询速率"、"USB Interrupt 端点延迟"、"丢输入报告"、"USB 设备 125Hz 250Hz 1000Hz"、"bInterval full speed high speed"。
Bus Scope 在这个场景下有用,因为轮询行为由端点描述符和实际的总线时序一起决定。操作系统 UI 那边可能只显示"设备已连接",但抓包能告诉你主机实际用的间隔到底是多少。
bInterval 是什么意思
Interrupt 端点描述符带一个 bInterval。这个值描述轮询间隔,但具体怎么解读要看速度和端点类型。
重要的区分:
- Low-Speed 和 Full-Speed 的 Interrupt 端点用基于毫秒的 frame 间隔
- High-Speed 的 Interrupt 端点用基于 microframe 的另一套编码
- 主控制器调度和 Hub 拓扑会影响实际观测到的时序
- 应用读节奏 ≠ USB 总线轮询节奏
工程师如果只看应用回调,可能会错过真实的端点调度。
常见症状
轮询间隔问题表现成:
- 鼠标或手柄感觉卡
- HID Input 报告每 8 ms 才来一次而不是 1 ms
- 设备宣传 1000 Hz 实际像 125 Hz
- 传感器数据一阵一阵
- 条码枪扫得快时丢
- 触摸屏 resume 之后明显延迟
- 固件发报告比主机 poll 快
- 切换到 High-Speed 之后报告时序出乎意料
这些症状看起来像延迟或响应度问题,但根因的证据藏在 USB 描述符和包时序里。
Full-Speed 和 High-Speed 解读不一样
同一个数值 bInterval 在不同速度下代表的有效时序不同。Full-Speed HID 端点 bInterval=8 和 High-Speed 端点同样 bInterval=8 不是同一个调度模型。
调试时抓这些:
- 实际协商出的速度
- 端点描述符
- 端点地址
- 传输类型
bInterval- 观测到的 IN token / 传输节奏
- Report payload 时序
Bus Scope 应该把描述符值和实际观测到的时序放在同一个视图里。
固件过产
有些固件生成 Input 报告的速度比主机 poll 快。这些报告可能被覆盖、合并,或者在主机看到之前就被丢了。
症状:
- 设备内部日志能看到事件
- 主机收到的报告却更少
- 快速按键被吞
- 运动看起来平滑了或延迟
- 一阵突发之后,报告里只剩最新状态
这不是 USB 的丢包问题,是固件缓冲和轮询契约的问题。
主机轮询 ≠ 应用读速率
应用可能每 1 ms 读一次,但 USB 主机可能每 8 ms 才 poll 一次。或者主机按时 poll 了,但应用事件循环处理得慢。
抓包把以下分开:
- 总线轮询间隔
- 设备响应时序
- 主机驱动缓冲
- 应用回调延迟
这个区分对 HID 延迟支持工单至关重要。
bInterval 描述符错误
常见的描述符 bug:
- 不小心写成了
bInterval=10而不是1 - Full-Speed 的间隔被错误地复制进 High-Speed 描述符
- HID 描述符里说一个间隔,端点描述符里写另一个
- 固件注释写着 1000 Hz,描述符里却更慢
- Alternate Setting 改了间隔,但固件没处理
描述符里的字节就是主机调度的依据。
排查清单
按这个流程:
- 抓枚举
- 识别 Interrupt 端点描述符
- 记录实际设备速度
- 解码
bInterval - 测量观测到的 Interrupt IN 节奏
- 和预期的轮询速率对比
- 触发快速的输入事件
- 看报告是被丢了还是被合并了
- 对比直连端口 vs 走 Hub
- 描述符和时序证据一起留存
最终诊断
USB Interrupt 延迟不只是应用性能问题。它取决于端点 bInterval、速度模式、主机调度、报告生成和固件缓冲。
Bus Scope 能证明一台 HID 或 Interrupt 设备是否真的按预期速率被 poll,也能告诉你丢输入到底是描述符、固件缓冲、还是主机 / 应用时序的锅。