3. USB协议基础:数据包结构与传输类型

USB协议,说白了就是一套设备之间通信的“行话”。你想想看,主机和设备要交换数据,总得有个约定好的格式吧?这个格式,就是数据包结构。而不同的应用场景,又催生了四种传输类型。这一章,我们就来把这些基础打牢。

3.1 数据包结构:USB通信的最小单元

USB总线上的所有通信,都是以“包”为单位的。一个完整的USB数据包,就像一封信,有固定的格式。我个人习惯把它拆成五个部分来看:SOP、PID、数据、CRC、EOP。

字段 全称 长度 说明
SOP Start of Packet 同步序列 告诉接收方,准备好,数据要来了
PID Packet Identifier 8 bits 包的类型标识,比如是令牌包还是数据包
数据 Data Field 0~1023 bytes 实际要传输的内容
CRC Cyclic Redundancy Check 5或16 bits 校验数据有没有传错
EOP End of Packet 结束序列 告诉接收方,包结束了

3.1.1 SOP与EOP:包的“起跑线”和“终点线”

SOP是一个特定的同步序列,它让接收端的时钟与发送端对齐。EOP则是一个信号结束的标志。没有它们,接收方就不知道什么时候开始读、什么时候结束读。

我的经验: 调试USB信号时,示波器上最先找的就是SOP和EOP。如果这两个信号不干净,后面的数据基本不用看了。我曾经在一个项目中,因为线缆过长导致EOP信号畸变,折腾了两天才定位到问题。

3.1.2 PID:包的“身份证”

PID是包类型的核心。它只有8位,但其中4位是类型码,另外4位是校验码(取反)。接收方通过校验码就能快速判断这个PID有没有被干扰。

常见的PID类型有:

  • 令牌包(Token):OUT、IN、SETUP、SOF
  • 数据包(Data):DATA0、DATA1、DATA2、MDATA
  • 握手包(Handshake):ACK、NAK、STALL、NYET
  • 特殊包(Special):PRE、ERR、SPLIT、PING
重点: PID的校验机制很巧妙。比如,一个正确的OUT包的PID是0x87(二进制1000 0111),其中高4位1000是校验,低4位0111是类型。如果接收方发现校验不对,会直接丢弃这个包。

3.1.3 数据字段与CRC:内容与“防伪码”

数据字段是实际要传输的信息,长度可变。CRC则是对数据字段的校验。对于令牌包,CRC是5位;对于数据包,CRC是16位。

为什么CRC这么重要?USB是差分信号,抗干扰能力不错,但长距离传输或高噪声环境下,还是可能出错。CRC就是最后一道防线。

避坑指南: 我曾经遇到一个设备,偶尔会返回错误数据。抓包分析发现,CRC校验总是失败。最后查出是晶振频率偏差太大,导致数据采样点偏移。所以,硬件设计时,晶振精度一定要选对。

3.2 四种传输类型:各司其职

USB协议定义了四种传输类型,分别对应不同的应用场景。你想想看,鼠标和硬盘的通信需求能一样吗?鼠标要求实时性,硬盘要求吞吐量。所以,协议设计了不同的传输方式。

USB四种传输类型对比 控制传输 用于设备枚举、配置 双向、可靠、有保证带宽 每个端点只能有一个 典型应用:USB设备识别 批量传输 用于大量数据传输 非实时、保证可靠 利用空闲带宽传输 典型应用:U盘、打印机 中断传输 用于小数据、周期性传输 保证最大延迟 轮询方式实现 典型应用:鼠标、键盘 同步传输 用于实时数据流 保证带宽、不保证可靠 无重传机制 典型应用:音频、视频 选择哪种传输类型,取决于你的应用对实时性、可靠性和吞吐量的要求

3.2.1 控制传输:USB的“管理通道”

控制传输是USB协议中最复杂的传输类型,也是每个USB设备必须支持的。它主要用于设备枚举、配置和命令控制。

控制传输分为三个阶段:

  1. 建立阶段(Setup Stage):主机发送一个SETUP令牌包,后面跟着一个DATA0包,包含8字节的请求信息。
  2. 数据阶段(Data Stage):可选。根据请求,可能传输数据。
  3. 状态阶段(Status Stage):报告传输结果,成功或失败。
关键点: 控制传输有保证的带宽,但吞吐量不大。USB 2.0中,控制传输的最大包长是64字节。我调试设备枚举时,最喜欢看的就是控制传输的Setup包,里面包含了请求类型、请求码、值、索引和长度,信息量很大。

3.2.2 批量传输:大块数据的“搬运工”

批量传输,顾名思义,就是用来搬大块数据的。它不保证实时性,但保证可靠性。USB协议会通过错误检测和重试机制,确保数据准确无误。

批量传输的特点:

  • 非周期性:什么时候有空带宽,什么时候传。
  • 可靠:硬件自动重传,直到成功或放弃。
  • 大包长:USB 2.0中,批量传输的最大包长是512字节;USB 3.0中更是达到了1024字节。
我的习惯: 设计U盘或硬盘类产品时,我会优先考虑批量传输。但要注意,如果总线上有其他实时性要求高的设备(比如摄像头),批量传输可能会被挤到后面。我曾经在一个项目中,因为摄像头占用了太多带宽,导致U盘写入速度暴跌。后来通过调整端点描述符的带宽分配才解决。

3.2.3 中断传输:小数据的“快递员”

中断传输这个名字有点误导人。它并不是真的“中断”,而是主机定期轮询设备,看看有没有数据要传。它保证最大延迟,适合鼠标、键盘这类设备。

中断传输的关键参数:

参数 说明 典型值
轮询间隔 主机多久查询一次设备 1ms ~ 255ms
最大包长 每次传输的最大数据量 USB 2.0: 64字节
延迟保证 从设备有数据到主机收到的最长时间 轮询间隔 × 2
避坑指南: 我曾经设计一个游戏手柄,轮询间隔设成了1ms。结果发现,主机根本忙不过来,反而导致丢包。后来改成4ms,手感反而更好了。所以,轮询间隔不是越小越好,要综合考虑主机的处理能力。

3.2.4 同步传输:实时数据的“高速公路”

同步传输是为音频、视频这类实时数据流设计的。它保证带宽,但不保证可靠性。换句话说,数据丢了就丢了,不会重传。因为对于音视频来说,偶尔丢一帧,比卡顿等待要好得多。

同步传输的特点:

  • 周期性:每个帧或微帧内,主机都会分配固定的带宽。
  • 无重传:出错的数据直接丢弃。
  • 无握手:没有ACK/NAK等握手包。
  • 最大包长:USB 2.0中,同步传输的最大包长是1023字节。
深入理解: 同步传输的带宽是预先分配的。比如,一个USB麦克风,可能要求每个微帧(125μs)传输48字节的音频数据。主机在调度时,会预留这部分带宽。如果总线上还有其他同步设备,带宽不够了,主机就会拒绝新的同步请求。

3.3 传输类型的选择策略

在实际项目中,怎么选?我一般按这个思路来:

  1. 是不是控制命令? 是 → 控制传输。
  2. 是不是大量数据,且要求可靠? 是 → 批量传输。
  3. 是不是小数据,且要求低延迟? 是 → 中断传输。
  4. 是不是实时数据流,可以容忍偶尔丢包? 是 → 同步传输。

嗯,这里要注意,一个设备可以同时使用多种传输类型。比如,一个USB摄像头,控制传输用来调节参数,同步传输用来传视频流,中断传输用来传按钮状态。这就是USB协议的灵活性所在。

我的经验: 设计复合设备时,端点描述符的配置要特别小心。我曾经在一个项目中,把同步端点和中断端点的轮询间隔搞混了,结果视频流卡顿,按钮响应也慢。后来重新梳理了端点描述符,问题才解决。

好了,这一章的内容就到这里。数据包结构和传输类型是USB协议的基石,理解了它们,后面的协议栈分析就会轻松很多。