果壳中的USB(3)USB协议

USB 协议

与 RS-232 这类未定义数据发送格式的串行接口不同,USB 由几层协议共通组成。这听起来有些复杂,不过无需担心,一旦明白了内中种种,你会发现自己只需关注上层协议。实际上,大部分情况下,下层协议由 USB 控制器 IC 处理,对终端设计者(end designer)来说这部分相当于黑盒。

每个 USB 数据包都包含:

  • 令牌包(Token Packet)
  • 可选的数据包(Optional Data Packet,内含数据负载)
  • 状态包(Status Packet),用于提供回应(Acknowledge)或错误检测

正如我们已经知道的,USB 是以主机为中心的总线。主机启动所有事务。主机生成的第一个数据包(也称为令牌),令牌包描述了后续是什么格式的数据、数据是读取还是写入、设备的地址信息、指定的端点信息。下一个数据包通常是负载数据,后续接一个握手数据包(handshaking packet),握手数据包用来报告数据或令牌是否成功接收、端点是否停止、端点是否无法接受数据。

USB 数据包字段(USB Packet Fields)

USB 总线上的数据是 LSBit 优先。USB 数据包包含如下字段:

  • Sync

所有数据包都必须以同步字段开头。对于低速和全速,Sync 字段为 8-bit,对于高速则为 32-bit,用于将接收器的时钟与发送器的时钟同步。Sync 字段的最后两位指示PID字段的起始位置。

  • PID
这里的 PID 代表的是 Packet ID,该字段用于标识正在发送的数据包的类型。下表显示了可能的值②:
Token 0001 OUT Token
1001 IN Token
0101 SOF Token
1101 SETUP Token
Data 0011 DATA0
1011 DATA1
0111 DATA2
1111 MDATA
Handshake 0010 ACK Handshake
1010 NAK Handshake
1110 STALL Handshake
0110 NYET (No Response Yet)
Special 1100 PREamble
1100 ERR
1000 Split
0100 Ping
PID 有 4 位,为了确保正确接收对 4 位进行补充和重复,从而使 PID 总共达到 8 位,结果格式如下所示:
  • ADDR
地址字段指定数据包将发往的设备,长度 7-bit,最大支持 127 个设备。地址 0 无效,因为尚未分配地址的设备都必须响应发送到地址 0 的数据包。
  • ENDP
端点字段由 4-bit 组成,允许最大 16 个可能的端点。但是,低速设备在默认管道的顶部只能有 2 个其他端点(最多4个端点)。
  • CRC
CRC(Cyclic Redundancy Checks)字段用于保护令牌数据(不包括 PID 部分)和负载数据所有令牌数据包均具有 5-bit CRC,而负载数据包具有 16-bit CRC。
  • EOP
包结束字段(End of packet),由持续约 2 bit 时间的 SE0 (Single Ended Zero)、后面接一个 1 bit 时间的 J 产生。
 

USB 数据包类型(USB Packet Types)

USB 有四种不同的数据包类型。令牌包指示要遵循的事务类型,数据包包含数据负载,握手包用于确认数据或报告错误,帧开始包指示新帧的开始。

  • 令牌包
令牌包有三种类型:
(1)In - 主机从 USB 设备读取信息
(2)Out - 主机向 USB 设备发送信息
(3)Setup - 开始控制传输
令牌数据包格式:
Sync PID ADDR ENDP CRC5 EOP

  • 数据包
有两种类型的数据包,每种都可以传输最多 1024 字节的数据。
(1)Data0
(2)Data1
高速模式定义了另外两种数据 PID,DATA2 and MDATA。
扩展阅读:DATA0 和 DATA1 可以用来实现 data toggle 同步。对于批量传输、控制传输和中断传输来说,数据包最开始都是被初始化为 DATA0 的,然后为了传输的正确性,就一次传 DATA0,一次传 DATA1,一旦哪次打破了这种平衡,主机就可以认为传输出错了。对于等时传输来说,data toggle 并不被支持,USB 就是在使用这种简单的哲学来判断对于错。(《Linux那些事儿之我是USB Core》)

数据包格式:
Sync PID Data CRC16 EOP
(1)低速设备最大数据负载 8 字节
(2)全速设备最大数据负载 1023字节
(3)高速设备最大数据负载 1024字节
(4)数据必须以多字节方式发送

  • 握手包
握手包有三种类型,仅由 PID 构成。
(1)ACK - 通知对方数据成功接收
(2)NAK - 通知对方设备暂时无法发送/接收数据,也用于(中断传输下)告知主机目前设备没有数据需要发生
(3)STALL - 设备处于需要主机干预的状态。
握手包格式:
Sync PID EOP

  • SOF(Start of Frame)包
SOF 包内有一个 11-bit 的帧数字(frame number),由主机周期性发送,全速总线发送间隔 1ms ± 500ns,高速总线发送间隔125 µs ± 0.0625 µs
SOF 包格式:
Sync PID Frame Number CRC5 EOP

USB 功能(USB Functions)

当我们想到 USB 设备时,我们想到的是 USB 外围设备。但是 USB 设备(USB device)可能是主机或外设上使用的 USB 收发器,也可能是一个 USB 集线器或主机控制器 IC,还可能是一个 USB 外设设备(USB peripheral device)。所以标准定义了一个“USB 功能”的术语,用于描述具有的某一项能力(capability)或功能(function)的 USB 设备,比如打印机,Zip驱动器,扫描仪,调制解调器或其他外围设备。

USB 功能图示:

大多数功能都有一系列缓冲区,缓冲区长度通常为 8 个字节。每个缓冲区隶属于一个端点——EP0 IN,EP0 OUT等等。举例来说,主机发送一个设备描述符请求。功能硬件(function hardware)将读取设置数据包(setup packet),解析后判断该数据包是否是发给自己的,如果是,则将后续数据包的有效负载复制到合适的端点缓冲区中——端点由设置令牌(setup token)的端点字段标明。然后功能硬件回复一个握手数据包,以确认该字节的接收,并在微控制器内为合适的端点产生一个中断,通知端点设备已经收到数据包。通常,这都是在硬件中完成的。

至此,软件获得中断事件,然后应读取端点缓冲区的内容并解析设备描述符请求。

端点(Endpoints)

端点可以描述为数据的发送端(sources)或接收端(sinks)。由于总线是以主机为中心的,因此端点出现在 USB 功能的通信通道末端。例如,在软件层,您的设备驱动程序可以将数据包发送到设备 EP1。随着数据从主机流出,它将最终进入 EP1 OUT 缓冲区。然后,您的固件将在空闲的时候读取此数据。如果要返回数据,功能(function)不能直接把数据写入总线,因为总线是由主机控制的。它只能将数据写入位于缓冲区的 EP1 IN,由主机发起 IN 数据包以请求数据。端点也可以视为功能设备的硬件与功能设备上运行的固件之间的接口。

所有设备必须支持 “0” 端点“0” 端点用于接收枚举期间、设备在总线上运行时的整个时间内的所有设备的控制和状态请求。

总结:端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点 0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。

管道(Pipes)

设备在一系列的端点上完成数据的发送和接收,客户端软件则通过管道传输数据。管道是主机和端点之间的逻辑连接。管道自身也关联了一组参数,例如分配给管道的带宽,使用的传输类型(控制,批量,同步或中断),数据流的方向,最大的数据包/缓冲区大小。默认管道是双向管道,由具有控制传输类型的“0”输入端点和“0”输出端点组成.

USB定义了两种类型的管道:

  • 流管道(Stream Pipes ),它没有定义 USB 数据格式,也就是说,您可以用它发送任何类型的数据,并且可以从另一端解析数据。数据按顺序发送,并具有预先定义的方向,要么流入,要么流出。流管道将支持批量、同步、中断传输类型。流管道可以由主机或设备控制。
  • 消息管道(Message Pipes)具有定义的 USB 数据格式。这类管道由主机控制,通过主机发送请求进行初始化。数据按照指定的方向传输,传输方向定义在主机发送的请求中。因此,消息管道允许数据双向传输,但仅支持控制传输。

附录

②注:更多信息见 USB 2.0 Specification,8.3.1〈Table 8-1. PID Types〉
③注:这部分内容参阅 USB 2.0 Specification,Chapter 8 Protocol Layer
原文地址:https://www.cnblogs.com/rockyching2009/p/13905350.html