Lazy loaded image
USB专题03 - USB协议层数据格式
Words 5024Read Time 13 min
2025-4-26
参考资料:
  • 《圈圈教你玩USB》
  • 官网:https://www.usb.org/documents
    • notion image
  • 《usb_20.pdf》的《Chapter 8 Protocol Layer》
  • USB的NRZI信号格式:https://zhuanlan.zhihu.com/p/460018993
  • USB2.0包Packet的组成:https://www.usbzh.com/article/detail-459.html

1. 硬件拓扑结构

notion image
  • compound device :多个设备组合起来,通过HUB跟Host相连
  • composite device :一个物理设备有多个逻辑设备(multiple interfaces)
在软件开发过程中,我们可以忽略Hub的存在,硬件拓扑图简化如下:
notion image
一个物理设备里面可能有多个逻辑设备,Hos可以外接多个逻辑设备,硬件拓扑图如下:
notion image

2. 协议层

要理解协议层、理解数据如何传输,带着这几个问题去看文档、看视频:
  • 如何寻址设备?
  • 如何表示数据方向(读、还是写)
  • 如何确认结果?
提前罗列出来:
  • USB系统是一个Host对应多个设备,要传输数据首先要通知设备:
    • 发出IN令牌包:表示想读数据,里面含有设备地址
    • 发出OUT令牌包:表示想写数据,里面含有设备地址
  • 数据阶段:
    • Host想读数据:前面发出IN令牌包后,现在读取数据包
    • Host想发出数据:前面发出OUT令牌包后,现在发出数据包
  • 结果如何?有握手包
    • Host想读数据,设备可能未就绪,就会回应NAK包
    • Host想写数据,它发出数据后,设备正确接收了,就回复ACK包
 
先传输最低位(LSB)。在后续文档中,描述数据时按照传输顺序从左到右列出来。
 

2.1 包格式

notion image
USB总线上传输的数据以包为单位。USB包里含有哪些内容(“域”)?
  • SOP:用来表示包的起始
  • SYNC:8位(低速/全速)或32位(高速),用于同步接收方和发送方的时钟
  • PID:表示包的类型
  • 地址:在USB硬件体系中,一个Host对应多个Logical Device,那么Host发出的包,如何确定发给谁?
    • 发给所有设备:包里不含有设备地址
    • 发给某个设备:包里含有设备地址、端点号
  • 帧号、数据等跟PID相关的内容
  • CRC校验码:循环冗余校验码,用于检测地址和端点字段的传输错误
发起一次完整的传输,可能涉及多个包。那么,第1个包里含有设备地址、端点号,后续的包就没必要包含设备地址、端点号。

2.2 SYNC 域

Host发出SOP信号后,就会发出SYNC信号:它是一系列的、最大传输频率的脉冲,接收方使用它来同步数据。对于低速/全速设备,SYNC信号是8位数据(从做到右是00000001);对于高速设备,SYNC信号是32位数据(从左到右是00000000000000000000000000000001)。使用NRZI编码时,前面每个”0”都对应一个跳变。
在很多文档里,把SOP和SYNC统一称为”SYNC”,它的意思是”SYNC”中含有”SOP”。

2.3 PID 域

注意:所有的USB文档提到的”输入”、“输出”,都是基于Host的角度,“输出”表示从Host输出到设备,“输入”表示Host从设备得到数据。
PID域是USB包格式中的一个关键组成部分,它紧跟在同步域(Sync Field)之后。PID域的结构如下:
  • PID域长度为8位(8 bits)
  • 高4位表示包类型
  • 低4位是高4位的按位取反,用于错误检测
notion image
根据包数据里的PID的bit1, bit0可以分为4个大类:
  • 令牌包(Token):01B
  • 数据包(Data):11B
  • 握手包(Handshake):10B
  • 特殊包(Special):00B
PID有4位,使用bit1,bit0确定分类,使用bit3,bit2进一步细分。如下表所示:
PID类型
二进制值
十六进制值
描述
Token包
OUT
0001
0x1
主机向设备发送数据
IN
1001
0x9
主机从设备接收数据
SOF
0101
0x5
帧起始标记
SETUP
1101
0xD
控制传输设置阶段
Data包
DATA0
0011
0x3
数据包0
DATA1
1011
0xB
数据包1
DATA2
0111
0x7
数据包2(高速传输)
MDATA
1111
0xF
数据包(分割事务)
Handshake包
ACK
0010
0x2
确认接收成功
NAK
1010
0xA
设备暂时无法接收/发送数据
STALL
1110
0xE
设备请求被拒绝(挂起)
NYET
0110
0x6
尚未准备好(高速传输)
Special包
PRE
1100
0xC
前导包(全速设备)
ERR
1100
0xC
错误(高速传输)
SPLIT
1000
0x8
分裂事务
PING
0100
0x4
PING 测试
EXT
1100
0xC
扩展包
PID域在USB通信中扮演角色:
  1. 包类型识别:PID域允许接收方快速识别接收到的包类型,从而知道如何解析后续的数据。
  1. 错误检测:通过低4位与高4位的取反关系,可以检测PID传输错误。
  1. 通信流程控制:不同类型的PID用于控制USB通信的不同阶段,如设置阶段、数据传输阶段和握手阶段。
  1. 流控制:某些PID类型(如NAK、STALL)用于实现USB通信中的流控制机制。

2.4 包类型

2.4.1 令牌包(Token)

令牌类的PID,起”通知作用”,通知谁?SOF令牌包被用来通知所有设备,OUT/IN/SETUP令牌包被用来通知某个设备。
令牌包由主机发出,用于指定后续数据包的传输方向(IN或OUT)以及目标设备地址和端点号
对于OUT、IN、SETUP令牌包,它们都是要通知到具体的设备,格式如下:
令牌包包含以下字段:
notion image
  1. PID域(Packet Identifier):8位,其中高4位标识包类型,低4位是高4位的取反
      • 令牌包的PID类型包括:OUT、IN、SOF和SETUP
  1. 地址域(Address Field):7位,指定目标设备的地址
    1. notion image
      • 地址0保留用于未分配地址的设备
      • 最多支持127个设备
  1. 端点域(Endpoint Field):4位,指定目标端点号
    1. notion image
      端点类型
      描述
      传输方向
      传输模式
      二进制表示
      控制端点
      用于控制传输,主要用于设备配置和命令。每个设备至少有一个控制端点。
      双向(主机 ↔ 设备)
      控制传输
      0000
      批量端点
      用于批量数据传输,适合大数据量的传输,支持流量控制。
      单向(主机 → 设备 或 设备 → 主机)
      批量传输
      0001
      中断端点
      用于短时间的数据传输,适合对延迟敏感的应用,如鼠标和键盘。
      单向(主机 → 设备 或 设备 → 主机)
      中断传输
      0010
      同步端点
      用于实时数据传输,适合音频和视频流等应用。
      单向(主机 → 设备 或 设备 → 主机)
      同步传输
      0011
      • 最多支持16个端点(上面4个端点以外数值为其他可用的批量端点)
对于SOF包,英文名为”Start-of-Frame marker and frame number”。对于USB全速设备,Host每1ms产生一个帧;对于高速设备,每125us产生一个微帧,1帧里有8个微帧。Host会对当前帧号进行累加计数,在每帧或每微帧开始时,通过SOF令牌包发送帧号。对于高速设备,每1毫秒里有8个微帧,这8个微帧的帧号是一样的,每125us发送一个SOF令牌包。
SOF令牌包格式如下:
notion image

2.4.2 数据包

Host使用OUT、IN、SETUP来通知设备:我要传输数据了。数据通过”数据包”进行传输。
数据包与令牌包的关系
  1. OUT事务:主机发送OUT令牌包,然后发送数据包,设备回复握手包
  1. IN事务:主机发送IN令牌包,设备发送数据包,主机回复握手包
  1. SETUP事务:主机发送SETUP令牌包,然后发送数据包(控制请求),设备回复握手包
数据包格式如下:
notion image
  1. PID域(Packet Identifier):有4种PID类型包括:DATA0、DATA1、DATA2和MDATA,其中DATA2、MDATA在高速设备中使用。
  1. 数据域(Data Field):0-1023字节的数据负载[3]
      • 控制传输:最大64字节(全速)
      • 批量传输:最大512字节(高速)
      • 中断传输:最大1024字节(高速)
      • 同步传输:最大1024字节(高速)
为什么要引入DATA0、DATA1这些不同类型的数据包?为了纠错。
USB使用DATA0和DATA1交替传输的机制来确保数据包的顺序和完整性:
  1. 发送方在每次成功传输后切换数据包类型(DATA0 → DATA1 → DATA0...)
  1. 接收方通过检查接收到的数据包类型,可以检测到丢包或重复包
  1. 如果检测到错误,接收方可以请求重传
比如:
  • Host发送DATA0给设备,设备返回ACK表示成功接收,设备期待下一个数据是DATA1
  • 但是Host没有接收到ACK,Host认为数据没有发送成功,Host继续使用DATA0发送上一次的数据
  • 设备再次接收到DATA0数据包,它就知道:哦,这是重传的数据包

2.4.3 握手包

握手包有4类:ACKNAKSTALLNYET
  • ACK:数据接收方用来回复发送方,表示正确接收到了数据并且有足够的空间保存数据。
  • NAKHost发送数据给设备时,设备可以回应NAK表示”我还没准备好,没办法接收数据”;Host想读取设备的数据时,设备可以回复NAK表示”我没有数据给你”。
  • STALL:表示发生了错误,比如设备无法执行这个请求(不支持该断点等待)、断点已经挂起。设备返回STALL后,需要主机进行干预才能接触STALL状态。
  • NYET:仅适用于高速设备。Host可以发出PING包用来确认设备有数据,设备可以回应NYET表示”还没呢”。Hub也可以回应NYET表示低速/全速传输还没完结。
握手包在USB通信中的作用
  1. 确认数据接收:握手包用于确认数据包是否成功接收,确保数据传输的可靠性。
  1. 流量控制:通过NAK和STALL握手包,USB协议实现了流量控制机制,防止数据丢失和设备过载。
  1. 错误处理:STALL握手包可以用于指示错误状态,帮助主机进行适当的错误处理和恢复操作。
握手包的传输流程
  1. 主机发送数据包到设备。
  1. 设备根据接收到的数据包状态,选择发送ACK、NAK或STALL握手包。
  1. 主机根据接收到的握手包类型决定下一步操作:
      • 如果收到ACK,继续发送下一个数据包。
      • 如果收到NAK,稍后重试发送数据包。
      • 如果收到STALL,停止当前操作并处理错误。

2.5 传输细节

2.5.1 传输(Transfer)和事务(Transaction)

USB传输的基本单位是包(Packet),包的类型由PID表示。一个单纯的包,是无法传输完整的数据
为什么?比如想输出数据,可以发出OUT令牌包,OUT令牌包可以指定目的地。但是数据如何传输呢?还需要发出DATA0或DATA1数据包。设备收到数据后,还要回复一个ACK握手包。
所以,完整的数据传输,需要涉及多个包:令牌包、数据包、握手包。这个完整的数据传输过程,被称为事务(Transaction)
有些事务需要握手包,有些事务不需要握手包,有些事务可以传输很大的数据,有些事务只能传输小量数据。
有四类事务:
  • 批量事务:用来传输大量的数据,数据的正确性有保证,时效没有保证。
  • 中断事务:用来传输周期性的、小量的数据,数据的正确性和时效都有保证。
  • 实时事务:用来传输实时数据,数据的正确性没有保证,时效有保证。
  • 建立事务:跟批量事务类似,只不过令牌包是SETUP令牌包。
有四类传输(Transfer):
  • 批量传输:就是使用批量事务实现数据传输,比如U盘。
  • 中断传输:就是使用中断事务实现数据传输,比如鼠标。
  • 实时传输:就是使用实时事务实现数据传输,比如摄像头。
  • 控制传输:由建立事务、批量事务组成,所有的USB设备都必须支持控制传输,用于”识别/枚举”
暂时记住这个关系:
  • BIT组成域(Field)
  • 域组成包(Packet)
  • 包组成事务(Transaction)
  • 事务组成传输(Transfer)

2.5.2 过程(stage)和阶段(phase)

事务由多个包组成,比如Host要发送数据给设备,这就会涉及很多个包:
  • Host发出OUT令牌包,表示要发数据给哪个设备
  • Host发出DATA0数据包
  • 设备收到数据后,回应ACK包
这个完整的事务涉及3个包(Packet),分为3个阶段(Phase):
  • 令牌阶段(Token phase):由令牌包实现
  • 数据阶段(Data phase):由数据包实现
  • 握手阶段(Handshake phase):由握手包实现
事务由包组成,这些包分别处于3个阶段(phase):令牌阶段,数据阶段,握手阶段。
对于批量传输、中断传输、实时传输,它们分别由一个事务组成,不再细分为若干个过程。
但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(setup stage)、数据过程(data stage)、状态过程(status stage)。
总结起来就是:
  • 控制传输由多个过程(stage)组成,每个过程由一个事务来实现
  • 每个事务由多个阶段(phase)组成,每个阶段有一个包来实现

2.5.3 批量传输

批量传输用批量事务来实现(一次货多次重复),用于传输大量的数据,数据的正确性有保证,时效没有保证。
批量事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP
下图中各个矩形框就对应一个完整的包。
notion image
《圈圈教你玩USB》中有详细的示例:
notion image

2.5.4 中断传输

中断传输用中断事务来实现,用于传输小量的、周期性的数据,数据的正确性和时效都有保证。
中断事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP
下图中各个矩形框就对应一个完整的包。
notion image
中断事务跟批量事务非常类似,Host使用它来周期性地读数据、写数据
以鼠标为例,我们需要及时获得鼠标的数据,不及时的话你会感觉鼠标很迟钝。但是USB协议中并没有中断功能,它使用”周期性的读、写”来实现及时性。具体过程如下:
  • Host 每隔 n毫秒发出一个 IN令牌包
  • 鼠标有数据的话,发出DATA0DATA1数据包给Host;鼠标没有数据的话,发出NAKHost
中断事务的优先级比批量事务更高,它要求实时性,而批量事务不要求实时性。

2.5.5 实时传输

实时传输用实时事务来实现,用于传输实时数据,对数据的正确性没有要求。
实时事务由2个阶段(phase)组成:令牌阶段、数据阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。
实时事务不需要握手阶段,一个示例的场景是:为了传输摄像头的实时数据,偶尔的数据错误是可以忍受的,大不了出现短暂的花屏。如果为了解决花屏而重传数据,那就会导致后续画面被推迟,实时性无法得到保证。
下图中各个矩形框就对应一个完整的包。
notion image
实时事务跟中断事务非常类似,Host也会周期性的发起实时事务,主要区别在于:
  • 实时事务不要求准确性,没有握手阶段
  • 实时事务传输的数据量比较大,中断事务传输的数据量比较小

2.5.6 控制传输

在使用批量传输时,使用IN令牌包或OUT令牌包表示数据传输方向。
控制传输的令牌包永远是SETUP,怎么分辨是读数据,还是写数据?发出SETUP令牌包后,还要发出DATA0数据包,根据数据的内容来确定后续是读数据,还是写数据。这个过程称为”建立事务”(SETUP Transaction)
但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(setup stage)、数据过程(data stage)、状态过程(status stage)。
notion image
  • 建立过程,使用SETUP事务:Host发出SETUP令牌包、DATA0数据包、得到ACK握手包
  • 数据过程,使用一个/多个批量事务:
    • 对于输出:Host发出OUT令牌包,发出DATA0、DATA1数据包、得到ACK握手包
    • 对于输入:Host发出IN令牌包,读到DATA0、DATA1数据包、发出ACK握手包
  • 状态过程,使用一个批量事务:
    • 对于输出:Host发出IN令牌包(相对于数据过程,方向反转一下),读到DATA1数据包,发出ACK握手包
    • 对于输入:Host发出OUT令牌包,发出DATA1数据包,等待ACK握手包
    • notion image
上图中的每一个方框,都是一个完整的事务,含有:Token Packet、Data Packet、Handshake Packet

3. 使用工具体验数据格式

LeCroy(力科)成立于1964年,是一家专业生产示波器厂家。旗下生产有数字示波器、SDA系列数字示波器、混合信号示波器、模块化仪器、任意波形发生器。 官网是:https://teledynelecroy.com/,可以在搜索引擎里搜”usbprotocolsuite”。
安装”usbprotocolsuite”后,可以在文档目录里找打很多示程序(后缀名为usb):
notion image
 
使用”usbprotocolsuite”打开这些文件,即可体验USB数据传输:
notion image
软件简介
Teledyne LeCroy的usbprotocolsuite是一款业界领先的USB协议分析软件,专为工程师设计,以支持USB接口设备的开发、测试和故障排除。版本v5.10带来了更加强大和稳定的性能,确保开发者能够高效地理解和优化他们的USB通信。
特点亮点
  • 全面的USB协议支持:覆盖USB 2.0、3.0及其以上版本,满足不同层次的开发需求。
  • 深度数据解析:提供细致入微的数据包分析,包括错误检测和协议层细节。
  • 用户友好的界面:直观的操作界面,方便快速上手,提高工作效率。
  • 高效的触发与过滤:高级触发机制和定制化的数据过滤,便于捕捉关键事件或特定流量。
  • 日志与报告生成:帮助生成详细的分析报告,便于项目文档化和交流。
上一篇
模板设计模式:让你的代码结构更清晰
下一篇
Guide to Linux System

Comments
Loading...