本文是我整理的一些 USB 的学习心得,希望能对大家有所帮助。
文章目录
- 前言
- 🍍USB 协议层数据格式
- 🍇包格式
- 🍓 PID 域
- 🍓 令牌包
- 🍓 数据包
- 🍓 握手包
- 🍇传输类型
- 🍓 批量传输
- 🍓 中断传输
- 🍓 实时传输
- 🍓 控制传输
- 🍍USB 描述符
- 总结
前言
这篇文章为大家介绍 USB协议层数据格式 以及 USB描述符 。
USB 模块 全面解析(一)
🍍USB 协议层数据格式
在USB设备中,数据传输的基本单位是 “ 包 ”
。数据先传输最低位(LSB)。那 USB “包” 里面具体包含哪些内容(“域”)?
🍇包格式
至于SOP, SYNC, EOP 具体的电平状态,在上篇文章中都已详细介绍了 : USB 模块 全面解析(一)
- SOP : “包” 的开始。
- SYNC : 用来同步时钟。
- Packet Content : PID(包类型) + 地址/帧号/数据 + CRC(校验)。
地址 :确定 包 要发给哪个 USB 设备。 - EOP : “包” 的结束。
下面主要介绍 包格式里 “Packet Content” 部分 的 PID。
🍓 PID 域
在 USB 协议中, PID 是用来标识 USB 数据包类型的关键字段。用于指示 数据包的类型 和 方向。
在 USB 包中,PID域 使用 8 位来表示,格式如下:
- 前 4 位 : 标识数据包的类型。
- 后 4 位:是前 4 位的取反,用于校验 PID 类型的正确性。如果接收方发现 后 4 位不是 前 4 位的取反,就认为发生了错误。
“ 包 ” 可以分为 4 种类型:
① 令牌包(Token):指示数据传输的开始 和 方向。 (最低 2 位是 01 B)
② 数据包(Data):用于实际传输的数据部分。( 11 B)
③ 握手包(Handshake):确认数据包的接收状态。( 10 B)
④ 特殊包(Special):用于特殊用途的包。( 00 B)
下面是根据 4 位的 PID 分为 16 种具体的 “包”类型:
🍓 令牌包
这里需要注意一点,有 4 种令牌包,其中 SOF 用于通知所有的设备,而 OUT, IN, SETUP 用来通知某个设备。下面是对于 OUT, IN, SETUP 令牌包的结构。
由于 令牌包 起通知作用,要通知某个具体的USB 设备,所以要知道 USB设备的地址(7位)
和 USB设备的端点号(4位)
。
所以一个完整的令牌包如下:
首先 发送 SOP 表示包的开始 -> SYNC 进行信号的同步 -> 根据 PID 的类型决定是 读/写数据 -> 11 位的帧号确定USB设备 -> CRC 校验 -> EOP 表示包的结束。
🍓 数据包
Host 使用 OUT、IN、SETUP 来通知设备:我要传输数据了。数据通过"数据包"进行传输。数据包也有 4 种类型:DATA0、DATA1、DATA2、MDATA。我们只需了解 DATA0、DATA1。
为什么要 引入不同类型的数据包?
Host 和设备都会维护自己的数据包切换机制,当数据包成功发送或者接收时,数据包类型切换。当检测到对方使用的数据包类型不对时,USB 系统认为发生了错误。
比如:
① Host 发送 DATA0 给设备,设备返回 ACK 表示成功接收,设备期待下一个数据是 DATA1
② 但是 Host 没有接收到 ACK,Host 认为数据没有发送成功,Host 继续使用 DATA0 发送上一次的数据
③ 设备再次接收到 DATA0 数据包,它就知道:哦,这是重传的数据包
一个完整的数据包如下:
🍓 握手包
握手包有 4 类:ACK、NAK、STALL、NYET。
- ACK : 数据接收方用来回复发送方,表示正确接收到了数据并且有足够的空间保存数据。
- NACK : Host 发送数据给设备时,设备可以回应 NAK 表示"我还没准备好,没办法接收数据";Host 想读取设备的数据时,设备可以回复 NAK 表示"我没有数据给你"。
- STALL : 表示发生了错误,比如设备无法执行这个请求(不支持该断点等待)、断点已经挂起。设备返回 STALL 后,需要主机进行干预才能接触 STALL 状态。
- NYET : 仅适用于高速设备。Host 可以发出 PING 包用来确认设备有数据,设备可以回应NYET 表示"还没呢"。Hub 也可以回应 NYET 表示低速/全速传输还没完结。
一个完整的握手包如下:
🍇传输类型
USB 设备支持 4 种不同的传输类型,每种不同的传输类型使用不同的场景和需求。
在介绍这 4 种传输类型之前,先来了解几个概念:
- 事务:完整的数据传输,需要涉及多个包 令牌包、数据包、握手包。这个完整的数据传输过程,被称为事务(Transaction)。
- 传输:由一个 或者多个事务组成,完成一次完整的通信。
有些事务需要握手包,有些事务不需要握手包,有些事务可以传输很大的数据,有些事务只能传输小量数据。
有四类事务:
① 批量事务:用来传输
大量的数据
,数据的正确性有保证,时效没有保证。
② 中断事务:用来传输周期性的、小量的数据,数据的正确性和时效
都有保证。
③ 实时事务:用来传输实时数据
,数据的正确性没有保证,时效有保证。
④ 建立事务:跟批量事务类似,只不过令牌包是 SETUP
令牌包。
有四类传输(Transfer):
① 批量传输:就是使用
批量事务
实现数据传输,比如 U 盘。
② 中断传输:就是使用中断事务
实现数据传输,比如鼠标。
③ 实时传输:就是使用实时事务
实现数据传输,比如摄像头。
④ 控制传输:由建立事务、批量事务
组成,所有的 USB 设备都必须支持控制传输,用于"识别/枚举"。
-
过程 :
对于 批量,中断,实时传输 都是由一个 事务组成,不再划分为多个阶段。
对于 控制传输 由多个 事务组成,这些事务分别处于 多个过程:建立过程,数据过程,状态过程。 -
阶段 :
事务由 包 组成,这些 包 处于 3 个阶段:令牌阶段,数据阶段,握手阶段。令牌阶段(Token phase):由令牌包实现。 数据阶段(Data phase):由数据包实现。握手阶段(Handshake phase):由握手包实现。
① BIT 组成域(Field)
② 域组成包(Packet)
③ 包组成事务(Transaction)
④ 事务组成传输(Transfer)
🍓 批量传输
-
批量传输用批量事务来实现,用于传输大量的数据,数据的正确性有保证,时效没有保证。
-
批量事务由 3 个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有 SOP、SYNC、PID、EOP。(下图中各个矩形框就对应一个完整的包)
🍓 中断传输
-
中断传输用中断事务来实现,用于传输小量的、周期性的数据。数据的正确性和时效都有保证。
-
中断事务由 3 个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有 SOP、SYNC、PID、EOP。中断事务的优先级比批量事务更高,它要求实时性,而批量事务不要求实时性。
中断传输 要求实时性,由于 USB 协议中没有 中断的功能,所以,它使用"周期性的读、写"来实现及时性。具体过程如下:
① Host 每隔 n 毫秒发出一个 IN 令牌包
② 鼠标有数据的话,发出 DATA0 或 DATA1 数据包给 Host;鼠标没有数据的话,发出 NAK
给Host。从下图中可以看到没有 NYET 延时等待
。
🍓 实时传输
- 实时传输用实时事务来实现,用于传输实时数据,对数据的正确性没有要求。
- 实时事务由 2 个阶段(phase)组成:令牌阶段、数据阶段。每个阶段都是一个完整的包,含有 SOP、SYNC、PID、EOP。
实时事务不需要握手阶段。
实时传输 不要求数据的准确性,没有握手阶段。(适用场景:视频通话等)
🍓 控制传输
控制传输由多个事务组成,这些事务分别处于 3 个过程:建立过程(stage)、数据过程(stage)、状态过程(stage)。
① 建立过程(stage),使用 SETUP 事务:Host 发出 SETUP 令牌包、DATA0 数据包、得到 ACK握手包。
② 数据过程(stage),使用批量事务:
a. 对于输出:Host 发出OUT 令牌包,发出 DATA0、DATA1 数据包、得到 ACK 握手包
b. 对于输入:Host 发出 IN 令牌包,读到 DATA0、DATA1 数据包、发出 ACK 握手包
③ 状态过程(stage),使用批量事务:
a. 对于输出:Host 发出IN 令牌包,读到 DATA1 数据包,发出 ACK 握手包
b. 对于输入:Host 发出 OUT 令牌包,发出 DATA1 数据包,等待 ACK 握手包
上图的 每一个方框,都是一个完整的事务,含有:Token Packet、Data Packet、Handshake Packet。
例如,对于一个 SETUP 事务,下面是它的组成包 :
在"setup 事务"中:
① SETUP 令牌包:用来通知设备,“要开始传输了”
② DATA0 数据包 ( 8 字节数据 ):它含有固定的格式,用来告诉设备"是读还是写"、“读什么”、“写什么”。
🍍USB 描述符
设备/配置/接口/端点 :
- 对于一个 USB设备,它可以有多种配置 (Configuration)。
- 一个配置下 可以有 多个接口 (Interface), 接口等同于 功能。 比如 USB 耳机有 2 个接口(功能):声音收发,按键控制。
- 一个接口 可以有 多个设置(Setting),比如 默认设置下 它使用较低的带宽,也可以选择其他设置去使用更高的带宽。
- 一个接口 由 一个/ 多个 端点(Endpoint)组成。端点0 属于整个设备,是双向的。
怎么描述 设备,配置,端点,接口?
使用描述符(Descriptors)。有设备描述符、配置描述符、接口描述符、端点描述符。所谓描述符,就是一些格式化的数据,用来描述信息。
一个 USB 设备:
① 只有一个设备描述符
:用来表示设备的 ID、它有多少个配置、它的端点 0 一次最大能传
输多少字节数据
② 可能有多个配置描述符
:用来表示它有多少个接口、供电方式、最大电流
③ 一个配置描述符下面,可能有多个接口描述符
:用来表示它是哪类接口、有几个设置
(Setting)、有几个端点
③ 一个接口描述符符下面,可能有多个端点描述符
:用来表示端点号、方向(IN/OUT)、类
型(批量/中断/同步)
还有 一些字符串描述符(String descriptors),它用可读的文字来描述设备,是可选的。
总结
下篇文章为大家介绍 工业控制中经常用到的 Modbus 通信协议。