文章目录
- 一、USB 系统硬件框架和软件框架
- 1.1 实验现象
- 1.2 硬件框架
- 1.3 软件框架
- 二、USB 电气信号
- 2.1 USB 设备状态切换图
- 2.2 硬件线路
- 2.3 电子信号
- 2.4 低速/全速信号电平
- 2.5 高速信号电平
- 2.6 设备连接与断开
- 2.6.1 连接
- 2.6.2 断开
- 2.7 复位
- 2.8 设备速率识别
- 2.8.1 低速/全速
- 2.8.2 高速
- 2.9 数据信号
- 2.9.1 低速/全速的 SOP 和 EOP
- 2.9.2 高速的 SOP
- 2.9.3 SYNC 同步域
- 2.9.4 NRZI 与位填充
- 三、USB 协议层数据格式
- 3.1 硬件拓扑结构
- 3.2 协议层
- 3.3 字节/位传输顺序
- 3.4 SYNC 域
- 3.5包格式
- 3.5.1 PID 域
- 3.5.2 令牌包(Token)
- 3.5.3 数据包
- 3.5.4 握手包
- 3.6 传输细节
- 3.6.1 传输(Transfer)和事务(Transaction)
- 3.6.2 过程(stage)和阶段(phase)
- 3.6.3 批量传输
- 3.6.4 中断传输
- 3.6.5 实时传输
- 3.6.6 控制传输
- 3.7 使用工具体验数据格式
一、USB 系统硬件框架和软件框架
1.1 实验现象
现象: 把 USB 设备比如 Android 手机接到 PC
-
右下角弹出"发现 android phone"
-
跳出一个对话框, 提示你安装驱动程序
-
问 1:USB 设备插到电脑上去, 接触到的对方设备是什么?
答 1:是 USB 控制器,是 USB 控制器内嵌的 root hub -
问 2. 既然还没有"驱动程序",为何能知道是"android phone"?
答 2. windows 里已经有了 USB 的总线驱动程序, 接入 USB 设备后, 是"总线驱动程序" 知道你是"android phone"、提示你安装的是"设备驱动程序"。USB 总线驱动程序负责:识 别 USB 设备, 给 USB 设备找到对应的驱动程序。
-
问 3. 为什么一接入 USB 设备, PC 机就能发现它?
答 3. PC 的 USB 口内部,D-和 D+接有 15K 的下拉电阻, 未接 USB 设备时为低电平。USB 设备的 USB 口内部, D-或 D+接有 1.5K 的上拉电阻;它一接入 PC,就会把 PC USB 口的 D-或 D+拉高,从硬件的角度通知 PC 有新设备接入。
-
问 4. USB 设备种类非常多,为什么一接入电脑, 就能识别出来它的种类?
答 4. PC 和 USB 设备都得遵守一些规范。比如: USB 设备接入电脑后, PC 机会发出"你 是什么"?USB 设备就必须回答"我是 xxx", 并且回答的格式是固定的。USB 总线驱动程序会 发出某些命令想获取设备信息(描述符),USB 设备必须返回"描述符"给 PC。
-
问 5. PC 机上接有非常多的 USB 设备, 怎么分辨它们?
答 5. 每一个 USB 设备接入 PC 时, USB 总线驱动程序都会给它分配一个编号。 PC 机想 访问某个 USB 设备时,发出的命令都含有对应的编号(地址)。
-
问 6. USB 设备刚接入 PC 时, 还没有编号; 那么 PC 怎么把"分配的编号"告诉它?
答 6. 新接入的 USB 设备的默认编号是 0,在未分配新编号前, PC 使用 0 编号和它通 信。
-
1.2 硬件框架
在 USB 系统中, 有 2 个硬件概念:
-
USB Host:它跟处理器相连,处理器通过 USB Host 跟各类 USB 设备通信。 USB Host 中 集成有一个 root hub
-
USB Device:这分为两类设备
- Hub:用来扩展 USB 接口
- Function:就是普通的 USB 设备,比如 U 盘、声卡等
1.3 软件框架
APP 可以通过 USB 设备驱动程序访问 USB 设备,也可以绕过 USB 设备驱动,直接通过 USB 控制器驱动访问 USB 设备。
二、USB 电气信号
参考资料:
-
《圈圈教你玩 USB》
-
简书 jianshu_kevin@126.com 的文章
- https://www.jianshu.com/p/3afc1eb5bd32
- https://www.jianshu.com/p/cf8e7df5ff09
- USB 协议(三):https://www.jianshu.com/p/2a6e22194cd3
-
官网:https://www.usb.org/documents
-
《usb_20.pdf》的《chapter5 7 Electrical》
-
USB 的 NRZI 信号格式: https://zhuanlan.zhihu.com/p/460018993
-
USB2.0 包 Packet 的组成: https://www.usbzh.com/article/detail-459.html
2.1 USB 设备状态切换图
USB 2.0 协议支持 3 种速率: 低速(Low Speed,1.5Mbps)、全速(Full Speed, 12Mbps)、 高速(High Speed, 480Mbps)。
USB Hub、USB 设备, 也分为低速、全速、高速三种类型。 一个 USB 设备, 可能兼容低速、全速, 可能兼容全速、高速, 但是不会同时兼容低速、高速。
2.2 硬件线路
下图是兼容高速模式的 USB 收发器电路图:
USB 连接涉及 Hub Port 和 USB 设备,硬件连接如下:
2.3 电子信号
USB 连接线有 4 条: 5V、D+、D-、GND。数据线 D+、D-,只能表示 4 种状态。 USB 协议 中,很巧妙地使用这两条线路实现了空闲(Idle)、开始(SOP)、传输数据(Data)、结束(EOP) 等功能。
2.4 低速/全速信号电平
2.5 高速信号电平
2.6 设备连接与断开
2.6.1 连接
Hub 端口的 D+、D-都有 15K 的下拉电阻,平时为低电平。全速设备内部的 D+有 1.5K 的 上拉电阻, 低速设备内部的 D-有 1.5K 的上拉电阻,连接到 Hub 后会导致 Hub 的 D+或 D-电 平变化,Hub 根据变化的引脚分辨接进来的是全速设备还是低速设备。
高速设备一开始也是作为全速设备被识别的。
全速设备、高速设备连接时, D+引脚的电平由低变高:
低速设备连接时,D-引脚的电平由低变高:
2.6.2 断开
对于低速、全速设备,接到 Hub 时导致 D-或 D+引脚变为高电平, 断开设备后, D-或 D+ 引脚变为低电平:
对于高速设备,它先作为全速设备被识别出来,然后再被识别为高速设备。工作于高速模式时, D+的上拉电阻是断开的,所以对于工作于高速模式的 USB 设备, 无法通过 D+的 引脚电平变化监测到它已经断开。
工作于高速模式的设备, D+、D-两边有 45 欧姆的下拉电阻,用来消除反射信号:
当断开高速设备后, Hub 发出信号,得到的反射信号无法衰减, Hub 监测到这些信号后就知道高速设备已经断开,内部电路图如下:
2.7 复位
从状态切换图上看,一个 USB 设备连接后,它将会被供电, 然后被复位。当软件出错时,我们也可以发出复位信号重新驱动设备。
那么, USB Hub 端口或 USB 控制器端口如何发出复位信号? 发出 SE0 信号,并维持至少 10ms。
USB 设备看到 Reset 信号后,需要准备接收"SetAddress()“请求; 如果它不能回应这个请求, 就是"不能识别的设备”。
2.8 设备速率识别
2.8.1 低速/全速
Hub 端口的 D+、D-都有 15K 的下拉电阻,平时为低电平。全速设备内部的 D+有 1.5K 的上拉电阻, 低速设备内部的 D-有 1.5K 的上拉电阻,连接到 Hub 后会导致 Hub 的 D+或 D-电
平变化,Hub 根据变化的引脚分辨接进来的是全速设备还是低速设备。
2.8.2 高速
高速设备必定兼容全速模式, 所以高速设备内部 D+也有 1.5K 的上拉电阻, 只不过这个电阻是可以断开的: 工作于高速模式时要断开它
。
高速设备首先作为全速设备被识别出来,然后 Hub 如何确定它是否支持高速模式? Hub 端口如何监测一个新插入的 USB 设备能否工作于高速模式? 流程如下:
- 对于低速设备,Hub 端口不会监测它能否工作于高速模式。低速设备不能兼容高速模式。
- Hub 端口发出 SE0 信号,这就是复位信号
- USB 设备监测到 SE0 信号后,会发出"a high-speed detection handshake"信号表示自己能支持高速模式, 这可以细分为一下 3 种情景:
- 如果 USB 设备原来处于"suspend"状态,它检测到 SE0 信号后, 就发出"a high- speed detection handshake"信号。
- 如果 USB 设备原来处于"non-suspend"状态,并且处于全速模式, 它检测到 SE0 信号后, 就发出"a high-speed detection handshake"信号。这个情景,就是一个设备刚插 到 Hub 端口时的情况,它一开始工作于全速模式。
- 如果 USB 设备原来处于"non-suspend"状态, 并且处于高速模式,它会切换回到全速模式(重新连接 D+的上拉电阻),然后发出"a high-speed detection handshake"信号。
“a high-speed detection handshake"信号,就是"高速设备监测握手信号”,既然是握手信号, 自然是有来有回:
- USB 设备维持 D+的上拉电阻,发出"Chirp K "信号, 表示自己能支持高速模式
- 如果 Hub 没监测到"Chirp K "信号, 它就知道这个设备不支持高速模式
- 如果 Hub 监测到"Chirp K “信号后, 如果 Hub 能支持高速模式, 就发出一系列的"Chirp K”、"Chirp J"信号,这是用来通知 USB 设备: Hub 也能支持高速模式。发出一系列的 “Chirp K”、"Chirp J"信号后,Hub 继续维持 SE0 信号直到 10ms。
- USB 设备发出"Chirp K “信号后,就等待 Hub 回应一系列的"Chirp K”、"Chirp J"信号
- 收到一系列的"Chirp K"、"Chirp J"信号: USB 设备端口 D+的上拉电阻,使能高速模式
- 没有收到一系列的"Chirp K"、"Chirp J"信号: USB 设备转入全速模式
2.9 数据信号
2.9.1 低速/全速的 SOP 和 EOP
SOP:Start Of Packet,Hub 驱动 D+、D-这两条线路从 Idle 状态变为 K 状态。 SOP 中的 K 状态就是 SYNC 信号的第 1 位数据, SYNC 格式为 3 对 KJ 外加 2 个 K。
EOP:End Of Packet,由数据的发送方发出EOP,数据发送方驱动D+、D-这两条线路, 先设为 SE0 状态并维持 2 位时间, 再设置为 J 状态并维持 1 位时间, 最后 D+、D-变为高阻状态, 这时由线路的上下拉电阻使得总线进入 Idle 状态。
2.9.2 高速的 SOP
高速的 EOP 比较复杂,作为软件开发人员无需掌握。
高速模式中,Ide 状态为:D+、D-接地。SOP 格式为: 从 Idle 状态切换为 K 状态。 SOP 中的 K 状态就是 SYNC 信号的第 1 位数据。
高速模式中的 SYNC 格式为:KJKJKJKJ KJKJKJKJ KJKJKJKJ KJKJKJKK,即 15 对 KJ,外 加 2 个 K。
2.9.3 SYNC 同步域
同步域(SYNC),这个域固定为 0000 0001,这个域通过 NRZI 编码之后,就是一串方波(NRZI 遇 0 翻转遇 1 不变),接受者可以用这个 SYNC 域来同步之后的数据信号。
因为在 USB 的 NRZI 编码下,逻辑 0 会造成电平翻转,所以接受者在接受数据的同时,根据接收到的翻转信号不断调整同步频率,保证数据传输正确。但是,这样还是会有一个问题,就是虽然接受者可以主动和发送者的频率匹配,但是两者之间总会有误差。假如数据信号是 1000 个逻辑 1,经过 USB的 NRZI 编码之后,就是很长一段没有变化的电平,在这种情况下,即使接受者的频率和发送者相差千分之一,就会造成把数据采样成 1001 个或者 999 个1 了。USB 对这个问题的解决办法,就是强制插 0,也就是传说中的 bit-stuffing,如果要传输的数据中有 7 个连续的 1,发送前就会在第 6 个 1 后面强制插入一个 0,让发送的信号强制出现翻转,从而强制接受者进行频率调整。接受者只要删除 6 个连续 1 之后的 0,就可以恢复原始的数据了。
低速或全速的同步域为00000001
高速的同步域为31个0,后面为一个1
2.9.4 NRZI 与位填充
参考文章:USB 的 NRZI 信号格式, https://zhuanlan.zhihu.com/p/460018993
使用UART和I2C/SPI通信简单说明:
NRZI:Non Return Zero Inverted Code,反向不归零编码。 NRZI 的编码方位为:对于数据 0,波形翻转;对于数据 1,波形不变
。
使用 NRZI,发送端可以很巧妙地把"时钟频率"告诉接收端: 只要传输连续的数据 0 即可。在下图中, 低速/全速协议中"Sync Pattern"的原始数据是"00000001",接收端从前面的 7 个 0 波形就可以算出"时钟频率"。
使用 NRZI 时, 如果传输的数据总是"1",会导致波形维持不变。如果电平长时间维持不变, 比如传输 100 位 1 时, 如果接收方稍有偏差,就可能认为接收到了 99 位 1、101 位 1。而 USB 中采用了 Bit-Stuffing 位填充处理,即在连续发送 6 个 1 后面会插入 1 个 0
,强制翻转发送信号,从而让接收方调整频率,同步接收。而接收方在接收时只要接收到连续 的 6 个 1 后,直接将后面的 0 删除即可恢复数据的原貌。
NRZI 数据格式如上图所示。
三、USB 协议层数据格式
3.1 硬件拓扑结构
由下图可见,Host跟各个Device是一主多从的关系。为什么Host能发送数据到指定的Device,这时我们就需要对其发送的数据包进行解析。每个Device有各自的地址,所以这个数据包必定包含了Device的地址和端点,并且还含有目的和方向(读、写数据),在3.5中有包的格式图。
compound device :多个设备组合起来,通过 HUB 跟 Host 相连
composite device :一个物理设备有多个逻辑设备(multiple interfaces)
在软件开发过程中, 我们可以忽略 Hub 的存在,硬件拓扑图简化如下:
一个物理设备里面可能有多个逻辑设备, Hos 可以外接多个逻辑设备, 硬件拓扑图如 下:
Host发送数据到Device:
Host从Device上读取数据:
3.2 协议层
要理解协议层、理解数据如何传输,带着这几个问题去看文档、看视频:
- 如何寻址设备?
- 如何表示数据方向(读、还是写)
- 如何确认结果?
提前罗列出答案:
- USB 系统是一个 Host 对应多个设备, 要传输数据首先要通知设备:
- 发出 IN 令牌包: 表示想读数据,里面含有设备地址
- 发出 OUT 令牌包:表示想写数据, 里面含有设备地址
- 数据阶段:
- Host 想读数据: 前面发出 IN 令牌包后, 现在读取数据包
- Host 想发出数据:前面发出 OUT 令牌包后, 现在发出数据包
- 结果如何?有握手包
- Host 想读数据, 设备可能未就绪, 就会回应 NAK 包
- Host 想写数据, 它发出数据后,设备正确接收了, 就回复 ACK 包
3.3 字节/位传输顺序
先传输最低位(LSB)。在后续文档中,描述数据时按照传输顺序从左到右列出来
3.4 SYNC 域
Host 发出 SOP 信号后, 就会发出 SYNC 信号:它是一系列的、最大传输频率的脉冲,接 收方使用它来同步数据。对于低速/全速设备, SYNC信号是8位数据(从做到右是00000001); 对于高速设备, SYNC信号是32位数据(从左到右是00000000000000000000000000000001)。 使用 NRZI 编码时,前面每个"0"都对应一个跳变。
在很多文档里, 把 SOP 和 SYNC 统一称为"SYNC",它的意思是"SYNC"中含有"SOP"。
3.5包格式
USB 总线上传输的数据以包为单位。 USB 包里含有哪些内容(“域”)?
- SOP:用来表示包的起始
- SYNC:用来同步时钟
- PID:表示包的类型
- 地址:在 USB 硬件体系中, 一个 Host 对应多个 Logical Device,那么 Host 发出的包, 如何确定发给谁?
- 发给所有设备:包里不含有设备地址
- 发给某个设备:包里含有设备地址、端点号
- 帧号、数据等跟 PID 相关的内容
- CRC 校验码
发起一次完整的传输, 可能涉及多个包。那么,第 1 个包里含有设备地址、端点号, 后续的包就没必要包含设备地址、端点号。
3.5.1 PID 域
注意: 所有的 USB 文档提到的"输入"、“输出”,都是基于 Host 的角度, "输出"表示从 Host 输出到设备,"输入"表示 Host 从设备得到数据。
有哪些 USB 包? 根据包数据里的 PID 的 bit1, bit0 可以分为 4 类:
- 令牌包(Token):01B
- 数据包(Data):11B
- 握手包(Handshake):10B
- 特殊包(Special):00B
PID 有 4 位,使用 bit1,bit0 确定分类, 使用 bit3,bit2 进一步细分。如下表(来自 《圈圈教你玩 USB》)所示:
在 USB 包中,PID 域使用 8 位来表示,格式如下:
前 4 位表示 PID,后 4 位是对应位的取反。接收方发现后 4 位不是前 4 位的取反的话, 就认为发生了错误。
3.5.2 令牌包(Token)
令牌类 的 PID ,起 "通知作用 " ,通知谁 ?SOF 令牌包被用来通 知所有设 备, OUT/IN/SETUP 令牌包被用来通知某个设备。
对于 OUT、IN、SETUP 令牌包, 它们都是要通知到具体的设备, 格式如下:
USB 设备的地址有 7 位,格式如下:
USB 设备的端点号有 4 位, 格式如下:
对于 SOF 包,英文名为"Start-of-Frame marker and frame number"。对于 USB 全速 设备, Host 每 1ms 产生一个帧; 对于高速设备, 每 125us 产生一个微帧, 1 帧里有 8 个微帧。 Host 会对当前帧号进行累加计数, 在每帧或每微帧开始时, 通过 SOF 令牌包发送帧号。 对于高速设备, 每 1 毫秒里有 8 个微帧,这 8 个微帧的帧号是一样的, 每 125us 发送一个 SOF 令牌包。
SOF 令牌包格式如下:
3.5.3 数据包
Host 使用 OUT、IN、SETUP 来通知设备:我要传输数据了。数据通过"数据包"进行传 输。
数据包也有 4 种类型:DATA0、DATA1、DATA2、MDATA。其中 DATA2、MDATA 在高速设备 中使用。对软件开发人员来说,我们暂时仅需了解 DATA0、DATA1。
为什么要引入 DATA0、DATA1 这些不同类型的数据包? 为了纠错。
Host 和设备都会维护自己的数据包切换机制,当数据包成功发送或者接收时,数据包 类型切换。当检测到对方使用的数据包类型不对时,USB 系统认为发生了错误。
比如:
- Host 发送 DATA0 给设备,设备返回 ACK 表示成功接收, 设备期待下一个数据是 DATA1
- 但是 Host 没有接收到 ACK,Host 认为数据没有发送成功,Host 继续使用 DATA0 发送上 一次的数据
- 设备再次接收到 DATA0 数据包, 它就知道:哦,这是重传的数据包
数据包格式如下:
对于全速设备, 数据包中的数据做大是 1023 字节;对于全速设备, 数据包中的数据做 大是 1024 字节。
3.5.4 握手包
握手包有 4 类: ACK、NAK、STALL、NYET
- ACK:数据接收方用来回复发送方,表示正确接收到了数据并且有足够的空间保存数据。
- NAK:Host 发送数据给设备时, 设备可以回应 NAK 表示"我还没准备好,没办法接收数据"; Host 想读取设备的数据时, 设备可以回复 NAK 表示"我没有数据给你"。
- STALL:表示发生了错误,比如设备无法执行这个请求(不支持该断点等待)、断点已经挂起。设备返回 STALL 后,需要主机进行干预才能接触 STALL 状态。
- NYET:仅适用于高速设备。 Host 可以发出 PING 包用来确认设备有数据,设备可以回应 NYET 表示"还没呢"。Hub 也可以回应 NYET 表示低速/全速传输还没完结。
3.6 传输细节
3.6.1 传输(Transfer)和事务(Transaction)
USB 传输的基本单位是包(Packet),包的类型由PID 表示。 一个单纯的包,是无法传输完整的数据。
为什么?比如想输出数据,可以发出 OUT 令牌包, OUT 令牌包可以指定目的地。但是数据如何传输呢? 还需要发出 DATA0 或 DATA1 数据包。设备收到数据后, 还要回复一个 ACK 握手包。
所以,完整的数据传输, 需要涉及多个包:令牌包、数据包、握手包。这个完整的数据传输过程,被称为事务(Transaction)。
有些事务需要握手包,有些事务不需要握手包,有些事务可以传输很大的数据,有些 事务只能传输小量数据。
-
有四类事务:
- 批量事务:用来传输大量的数据,数据的正确性有保证,时效没有保证。
- 中断事务:用来传输周期性的、小量的数据, 数据的正确性和时效都有保证。
- 实时事务:用来传输实时数据, 数据的正确性没有保证,时效有保证。
- 建立事务:跟批量事务类似,只不过令牌包是 SETUP 令牌包。
-
有四类传输(Transfer):
- 批量传输:就是使用批量事务实现数据传输, 比如 U 盘。
- 中断传输:就是使用中断事务实现数据传输, 比如鼠标。
- 实时传输:就是使用实时事务实现数据传输, 比如摄像头。
- 控制传输:由建立事务、批量事务组成,所有的 USB 设备都必须支持控制传输, 用于" 识别/枚举"。(一个批量传输由多个事务实现)
-
暂时记住这个关系:
- BIT 组成域(Field)
- 域组成包(Packet)
- 包组成事务(Transaction)
- 事务组成传输(Transfer)
3.6.2 过程(stage)和阶段(phase)
事务由多个包组成, 比如 Host 要发送数据给设备,这就会涉及很多个包:
- Host 发出 OUT 令牌包, 表示要发数据给哪个设备
- Host 发出 DATA0 数据包
- 设备收到数据后, 回应 ACK 包
这个完整的事务涉及 3 个包(Packet),分为 3 个阶段(Phase):
- 令牌阶段(Token phase):由令牌包实现
- 数据阶段(Data phase):由数据包实现
- 握手阶段(Handshake phase):由握手包实现
事务由包组成, 这些包分别处于 3 个阶段(phase):令牌阶段,数据阶段, 握手阶段。
对于批量传输、中断传输、实时传输,它们分别由一个事务组成,不再细分为若干个 过程。
但是控制传输由多个事务组成,这些事务分别处于 3 个过程: 建立过程(stage)、数据 过程(stage)、状态过程(stage)。
总结起来就是:
- 控制传输由多个过程(stage)组成, 每个过程由一个事务来实现
- 每个事务由多个阶段(phase)组成, 每个阶段有一个包来实现
3.6.3 批量传输
批量传输用批量事务来实现,用于传输大量的数据, 数据的正确性有保证, 时效没有保证。
批量事务由 3 个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有 SOP、SYNC、PID、EOP。
下图中各个矩形框就对应一个完整的包。
批量传输就是批量事务的一次或多次重复。批量传输还有特殊包:Ping包。Host可以发出Ping包来询问Device有没有数据,要是Device有数据会回复ACK,没有数据回复NAK,出错回复SATLL。
《圈圈教你玩 USB》中有详细的示例:
3.6.4 中断传输
中断传输用中断事务来实现,用于传输小量的、周期性的数据,数据的正确性和时效都有保证。
中断事务由 3 个阶段(phase)组成: 令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有 SOP、SYNC、PID、EOP。
下图中各个矩形框就对应一个完整的包。
所有的中断传输都是由Host主动发起,主动去操作设备的,即Host->Device,中断传输相比于批量传输在于:比如中断传输在1s里面每隔一定时间会去通过中断事务访问Device。
中断事务跟批量事务非常类似,Host 使用它来周期性地读数据、写数据。
以鼠标为例,我们需要及时获得鼠标的数据, 不及时的话你会感觉鼠标很迟钝。但是 USB 协议中并没有中断功能,它使用"周期性的读、写"来实现及时性。具体过程如下:
-
Host 每隔 n 毫秒发出一个 IN 令牌包
-
鼠标有数据的话,发出 DATA0 或 DATA1 数据包给 Host;鼠标没有数据的话,发出 NAK 给 Host。
中断事务的优先级比批量事务更高,它要求实时性,而批量事务不要求实时性。
3.6.5 实时传输
实时传输用实时事务来实现, 用于传输实时数据, 对数据的正确性没有要求。
实时事务由 2 个阶段(phase)组成: 令牌阶段、数据阶段。每个阶段都是一个完整的包, 含有 SOP、SYNC、PID、EOP。
实时事务不需要握手阶段,一个示例的场景是:为了传输摄像头的实时数据,偶尔的数据错误是可以忍受的,大不了出现短暂的花屏。如果为了解决花屏而重传数据, 那就会导致后续画面被推迟,实时性无法得到保证。
下图中各个矩形框就对应一个完整的包。
实时事务跟中断事务非常类似,Host 也会周期性的发起实时事务,主要区别在于:
-
实时事务不要求准确性,没有握手阶段
-
实时事务传输的数据量比较大, 中断事务传输的数据量比较小
3.6.6 控制传输
在使用批量传输时, 使用 IN 令牌包或 OUT 令牌包表示数据传输方向。
控制传输的令牌包永远是 SETUP,怎么分辨是读数据, 还是写数据? 发出 SETUP 令牌包后,还要发出 DATA0 数据包,根据数据的内容来确定后续是读数据,还是写数据。这个过程称为"建立事务"(SETUP Transaction)
但是控制传输由多个事务组成,这些事务分别处于 3 个过程: 建立过程(stage)、数据过程(stage)、状态过程(stage)。
-
建立过程(stage),使用 SETUP 事务:Host 发出 SETUP 令牌包(通知Device要开启一个控制传输 是无方向的)、DATA0 数据包(Host和Device会约定好DATA0数据包的固定格式来决定 Host是要写入或者读取什么数据)、得到 ACK 握手包
-
数据过程(stage),使用批量事务:
- 对于输出:Host 发出 OUT 令牌包,发出 DATA0、DATA1 数据包、得到 ACK 握手包
- 对于输入:Host 发出 IN 令牌包,读到 DATA0、DATA1 数据包、发出 ACK 握手包 ③ 状态过程(stage),使用批量事务:
- 对于输出:Host 发出 IN 令牌包,读到 DATA1 数据包,发出 ACK 握手包 b. 对于输入:Host 发出 OUT 令牌包,发出 DATA1 数据包,等待 ACK 握手包
上图中的每一个方框,都是一个完整的事务, 含有: Token Packet、Data Packet、 Handshake Packet。
Set up过程发送Set up事务,这个事务分为三个阶段,一个是令牌阶段,一个是数据阶段,还有一个是握手阶段,在令牌阶段发送的是令牌包(Host->Device),数据阶段发送的是数据包(Host->Device),握手阶段接收到的是设备返回的握手包(Device->Host)。
发送过程:当我们发起一个控制传输,发送很多数据给Device后,Device会返回一个状态,回应过程如下:
需要注意的是令牌包是IN,当发送完令牌包后,Device会发送数据包给Host,但此时里面是没有数据的,发送的只是与前面的DATA1对应(前面是DATA1 这里也是DATA1)的数据号,这里只是要表示一个前面发送成功的状态,当其返回的data数据长度为0时,说明发送成功,最后Host返回一个握手包给Device,表示接收成功。如果此时Device正在忙,则会发送NAK给Host,流程比起上面会少掉中间的第二行数据包发送,第三行的PID包则为NAK。
读取过程:由Device告诉Host,即Device->Host。在读取数据时,不断的发送令牌包且PID包为IN,Host不断发给Device,最后需要Device发送包给Host来告诉Host数据是否完全读取完毕,但由上面发送过程的图可知,读取数据的最后一位是Host向Device发送的OUT,最后的输出过程是Host发送给Device,并不是发送给Device告诉其数据是否读取完毕,这里详细过程如下:
Host向指定Device发送令牌包后,并不会向其中写入任何数据(发送的是OUT所以应该写入数据),发送完毕后Device接收到则会向Host发送握手包,其中握手包的PID包会向Host表明此时状态,真正意义上是Host的读取状态。
3.7 使用工具体验数据格式
LeCroy(力科)成立于 1964 年, 是一家专业生产示波器厂家。旗下生产有数字示波器、SDA 系列数字示波器、混合信号示波器、模块化仪器、任意波形发生器。
官网是:https://teledynelecroy.com/,似乎无法注册新用户,无法下载软件。 可以在搜索引擎里搜"usbprotocolsuite"。
安装"usbprotocolsuite"后, 可以在文档目录里找打很多示程序(后缀名为 usb):
使用"usbprotocolsuite"打开这些文件,即可体验 USB 数据传输: