3、USB协议基础:包结构、传输类型与帧/微帧

USB协议采用主从架构,所有通信均由主机(Host)发起。协议栈的核心要素包括:包(Packet)作为最小数据单元,传输(Transfer)作为逻辑事务单元,以及帧(Frame)/微帧(Microframe)作为时间同步基准。理解这三层是掌握USB驱动开发的前提。

3.1 包结构:令牌包、数据包与握手包

USB总线上的每一次事务(Transaction)都由若干包组成。包是物理层之上的最小数据单元,分为三大类:

包类型 PID(包标识符) 功能 典型长度
令牌包(Token) OUT / IN / SETUP / SOF 标识事务方向、目标端点及设备地址 4字节(SYNC + PID + ADDR+ENDP + CRC5)
数据包(Data) DATA0 / DATA1 / DATA2 / MDATA 携带实际有效载荷,支持数据切换同步 2~1024字节(含CRC16)
握手包(Handshake) ACK / NAK / STALL / NYET 报告接收状态:成功、忙、错误或未准备好 1字节(仅PID)
驱动开发要点: 数据包中的 DATA0/DATA1 切换机制是USB协议保证数据完整性的关键。驱动中必须正确维护数据切换序列(Data Toggle),否则设备会持续返回 NAK 或 STALL。

下图展示了一次典型的 IN 事务 包序列:

USB IN 事务包序列 USB IN 事务包序列 令牌包 (IN) 数据包 (DATA0/1) 握手包 (ACK) 包序列说明 ① 主机发送 IN 令牌包,指定设备地址和端点号 ② 设备返回数据包(DATA0 或 DATA1),携带有效载荷 ③ 主机发送 ACK 握手包,确认数据接收成功

3.2 传输类型:控制、批量、中断与等时

USB 定义了四种传输类型,每种类型对应不同的带宽保证、错误重试机制和延迟要求。驱动开发中,选择正确的传输类型直接影响设备性能和稳定性。

传输类型 典型用途 带宽保证 错误重试 最大包长(FS) 最大包长(HS)
控制传输 设备枚举、配置、命令 10% 保留 自动重试(硬件) 64 字节 64 字节
批量传输 存储、打印、大块数据 无保证 自动重试(硬件) 64 字节 512 字节
中断传输 HID 设备(键盘、鼠标) ≤90% 轮询保证 自动重试(硬件) 64 字节 1024 字节
等时传输 音频、视频、实时流 固定带宽 无重试 1023 字节 1024 字节
常见陷阱: 等时传输不提供硬件重试机制,数据丢失时不会自动重发。驱动中必须实现软件层面的丢包补偿或冗余设计,否则音视频流会出现卡顿或断裂。

四种传输类型在 USB 帧中的调度关系如下图所示:

USB 传输类型调度示意 USB 帧内传输类型调度示意 1 帧 (1 ms) / 微帧 (125 µs) 控制传输 中断传输 等时传输 批量传输(填充剩余带宽) 空闲 调度优先级(从高到低) ① 等时传输(固定带宽,不可延迟)→ ② 中断传输(轮询间隔保证)→ ③ 控制传输(保留10%)→ ④ 批量传输(仅用剩余带宽) 批量传输没有带宽保证,当总线繁忙时会被无限期推迟。

3.3 帧与微帧:时间同步基础

USB 总线以帧(Frame)为时间基准进行同步。主机控制器在每个帧起始时发送 SOF(Start of Frame) 令牌包,所有设备据此校准时钟。

总线速度 帧周期 微帧周期 每帧微帧数 SOF 间隔
低速 (LS) / 全速 (FS) 1 ms 不适用 1 1 ms ± 0.05%
高速 (HS) 1 ms 125 µs 8 125 µs ± 0.05%
驱动开发关键: 中断传输的轮询间隔(bInterval)在高速模式下以微帧为单位,在全速模式下以帧为单位。例如,HID 鼠标通常设置 bInterval = 1(高速 = 125 µs 轮询一次,全速 = 1 ms 轮询一次)。驱动中解析端点描述符时,必须根据设备速度正确换算轮询周期。

高速模式下,一个帧被拆分为 8 个微帧,每个微帧可以独立调度事务,从而显著提高总线利用率:

高速模式微帧结构 高速模式:1 帧 = 8 微帧 1 帧 (1 ms) 微帧0 微帧1 微帧2 微帧3 微帧4 微帧5 微帧6 微帧7 每个微帧 125 µs,可独立调度 IN/OUT 事务

3.4 驱动开发中的协议映射

在 Linux USB 驱动中,上述协议概念直接映射为内核 API 和数据结构:

  • URB(USB Request Block):对应一次传输事务,包含包序列的组装与状态管理。
  • usb_control_msg():封装控制传输,用于设备枚举和标准请求。
  • usb_bulk_msg():封装批量传输,适用于大块数据读写。
  • usb_fill_int_urb():配置中断传输,需指定轮询间隔(bInterval)。
  • usb_fill_isoc_urb():配置等时传输,需预先分配帧描述符数组。
调试技巧: 使用 usbmon 工具可以捕获 USB 总线上的原始包序列,包括令牌包、数据包和握手包。这是验证驱动是否正确处理 DATA0/DATA1 切换和错误重试的最直接手段。

掌握包结构、传输类型和帧/微帧机制,是后续理解 USB 设备枚举、HID 报告描述符解析以及驱动中断处理的基础。下一节将深入分析 USB 设备枚举的完整状态机。