USB 协议基础:USB 2.0 / 3.0 协议简介与传输类型

做 OTG 调优,绕不开协议本身。今天咱把 USB 2.0 和 3.0 的核心概念捋一遍,顺便聊聊控制、批量、中断、同步四种传输类型,以及最底层的数据包结构。这些东西不是死记硬背的,你在调试波形、分析抓包时,每个字段都会对应到实际现象。

从 USB 2.0 到 3.0:变与不变

先说个总印象。USB 2.0 是半双工,一根差分对(D+ / D-)负责所有传输。USB 3.0 加了一套独立的高速差分对(SSTX / SSRX),变成了全双工。我最早接触 USB 3.0 时有个误区——以为所有的 2.0 特性都升级了。其实不是,控制、批量、中断、同步这些逻辑类型在两代协议里基本一致,只是物理层和链路层天差地别。

关键对比点: USB 2.0 用 帧/微帧 来调度传输,USB 3.0 改用 DPP(Device Packet Protocol) 加流控机制。但这不影响应用层看到的传输类型。

四种传输类型——你的外设该选哪个?

USB 规范定义了四种传输类型:控制、批量、中断、同步。每种都有固定的端点属性和调度要求。我习惯把它们比作快递服务:控制是挂号信,批量是卡车运输,中断是加急件,同步是实时直播流。

1. 控制传输(Control Transfer)

用于设备枚举、标准请求,比如获取描述符、设置配置。每个设备必须有一个默认控制端点(端点 0)。控制传输分三个阶段:Setup / Data(可选)/ Status。数据阶段可以双向,但最常用的还是主机发起的控制请求。

  • 典型场景: 插拔识别、配置接口、HID 报告描述符获取。
  • 带宽占用: 10% 常驻预留,不能做大流量。
  • 我踩过的坑: 曾经用控制传输批量输出日志,结果枚举时反复超时,因为控制端点一次只能处理一个请求,排队多了就丢。

2. 批量传输(Bulk Transfer)

最常用,也是最需要调优的类型。批量传输没有带宽保证,但出错后自动重试,适合打印机、U 盘、数据采集这类非实时的大量数据。

调优提示: USB 2.0 批量传输最大包大小是 512 字节,USB 3.0 升到 1024 字节,而且可以开启单次突发(Burst)传输,一个微帧里连续发多个包。我在做硬盘加密卡时,把包大小从 512 改成 1024,配合队列深度优化,吞吐量直接翻了一倍。

3. 中断传输(Interrupt Transfer)

名义上叫“中断”,其实和硬件中断不是一回事。它是主机轮询端点,定时获取数据。USB 2.0 轮询间隔最小 1 微帧(125 μs),USB 3.0 间隔可以更小,但实际受总线调度影响。

  • 适用场景: 鼠标、键盘、游戏手柄。
  • 注意: 中断传输有最大延迟保证,但不保证带宽。

你应该遇到过鼠标偶尔跳帧,往往不是鼠标坏了,是轮询间隔太大了。我习惯把快速鼠标的轮询间隔设成 1 ms(USB 2.0 下就是 8 个微帧),再低的话主机可能拒绝。

4. 同步传输(Isochronous Transfer)

专门对付实时流,比如音频、视频、工业相机。同步传输不保证成功送达——它没有重试机制。你想想看,USB 麦克风如果因为丢了一个包就重传,录音直接卡顿,反而不如丢掉那一个采样。

特性 控制 批量 中断 同步
保证传输 是 是(重试) 是(重试) 否(无重试)
带宽保证 10% 预留 无 有最高延迟 有固定带宽
最大包大小(2.0) 64 B 512 B 64 B(低速)/ 1023 B(全速) 1023 B
最大包大小(3.0) 64 B 1024 B 1024 B 1024 B(可突发)

数据包结构——从 到 Handshake

USB 2.0 的包格式简单:每个事务由 包 + Data 包(可选)+ Handshake 包构成。 包指明设备地址和端点。Data 包包含实际数据。Handshake 包给 ACK、NAK、STALL。我记得刚学 USB 时,抓了个枚举过程,看到 ACK 一直以为是好信号,结果发现设备一直 NAK,主机只能轮询等待,浪费了很多时间。

// USB 2.0 令牌包格式(以 IN 事务为例)
字节0: PID (0x96 = IN)
字节1-2: 设备地址 (7bit) + 端点号 (4bit)
         + CRC5 (5bit)
字节3: 包结束 EOP

USB 3.0 的包结构复杂得多。它取消了传统 包,用链路层包(Header Packet) + 数据包(Data Packet)区分,并且每个包都有 LCRC 和链路层确认。你看 3.0 的抓包,会发现多了很多 LTSSM(链路训练)状态,比如 Polling、Recovery。这不是故障,是正常的链路管理。

避坑: 你做 OTG 调试时,如果看到 USB 3.0 链路反复退出 U0 进入 U1/U2/U3 低功耗状态,千万不要直接关掉电源策略。有时只是线缆太长导致信号不稳定,触发链路训练。我曾经贴了铝箔屏蔽线解决过一例。

一张图看懂本章知识脉络

USB 2.0 / 3.0 协议核心要素 物理层 / 链路层 2.0: 半双工, 帧调度 物理层 / 链路层 3.0: 全双工, DPP + 流控 控制传输 批量传输 中断传输 同步传输 数据包结构 2.0: + Data + Handshake 3.0: Header Packet + Data Packet + 链路确认 调优重点:根据传输类型选择端点和包大小,避免 NAK 风暴和链路降速

上图展示了两代协议共用四种传输类型,但数据包结构完全不同。做调优时,你得时刻记住当前工作在哪个协议版本下——写固件时经常要查 usb_ctrlrequest 结构体里的 bMaxPacketSize,写错了枚举就会卡住。

避坑指南:传输类型选错会怎样?

  • 把中断当批量用: 主机规定轮询间隔,你的数据量一大,就被截碎成小包,吞吐上不去。
  • 把批量当同步用: 批量传输的实时性没法保证,直播流一旦被前面的大包堵塞,画面直接卡成幻灯片。
  • 忽略端点描述符的 bInterval: 我接手过一个 USB 音频项目,播放时莫名爆音,查了两天发现中断端点的 bInterval 写成了 0,规范不允许,主机根本不认。

我的个人习惯: 设计 OTG 设备时,先把四个传输类型的典型用途列在纸上,然后给每个数据流画一条“端点到端点”的带宽预算线。这样既不会错选类型,也能提前发现瓶颈。