2. 控制传输协议详解
控制传输(Control Transfer)是 USB 协议中最基础、最复杂的传输类型,也是 FPGA 验证中故障率最高的环节。它由 Setup 阶段、Data 阶段(可选) 和 Status 阶段 三个逻辑阶段组成,每个阶段都包含严格的令牌包、数据包和握手包交互。本章从 FPGA 验证视角,逐阶段拆解协议细节与常见故障点。
2.1 控制传输整体流程
控制传输总是从主机发起的 Setup 事务开始,随后根据请求方向决定 Data 阶段的方向(IN 或 OUT),最后以 Status 阶段结束。下图展示了标准控制传输的完整状态机:
2.2 Setup 阶段
Setup 阶段是控制传输的起始阶段,由主机向设备发送 8 字节的 Setup 数据包。该阶段包含三个事务:令牌包、数据包和握手包。
2.2.1 令牌包格式
Setup 阶段的令牌包使用 SETUP(PID = 0xB4) 令牌,格式如下:
| 字段 | 宽度(bit) | 描述 |
|---|---|---|
| SYNC | 8 | 同步序列(00000001) |
| PID | 8 | 包标识符(SETUP = 0xB4) |
| ADDR | 7 | 设备地址(0~127) |
| ENDP | 4 | 端点号(控制端点必须为 0) |
| CRC5 | 5 | 令牌包 CRC 校验 |
| EOP | — | 包结束(SE0 状态) |
2.2.2 数据包格式
Setup 阶段的数据包固定为 8 字节,使用 DATA0 PID(0xC3)。数据包结构如下:
| 偏移 | 字段 | 宽度(byte) | 描述 |
|---|---|---|---|
| 0 | bmRequestType | 1 | 请求类型(方向、类型、接收者) |
| 1 | bRequest | 1 | 请求码(如 GET_DESCRIPTOR = 0x06) |
| 2~3 | wValue | 2 | 请求参数(小端序) |
| 4~5 | wIndex | 2 | 索引(如接口号或端点号) |
| 6~7 | wLength | 2 | Data 阶段期望传输的数据长度 |
2.2.3 握手包
设备在正确接收 Setup 数据包后,必须返回 ACK(PID = 0xD2) 握手包。如果设备检测到 CRC 错误或数据包损坏,应保持静默(不返回任何握手包),主机将超时重发。
2.3 Data 阶段(IN/OUT)
Data 阶段根据 Setup 包中 bmRequestType 的 bit[7](方向位)决定:0 = OUT(主机到设备),1 = IN(设备到主机)。Data 阶段可能包含多个数据事务,每个事务使用 DATA1/DATA0 交替翻转(Data Toggle)机制。
2.3.1 IN 事务
主机通过 IN 令牌(PID = 0x96)请求设备发送数据。设备收到 IN 令牌后,返回 DATA 包(DATA1 或 DATA0),主机收到后回复 ACK。
| 事务元素 | 发送方 | PID | 说明 |
|---|---|---|---|
| 令牌包 | 主机 | IN (0x96) | 请求设备发送数据 |
| 数据包 | 设备 | DATA1/DATA0 | 数据负载,最大 64 字节(全速) |
| 握手包 | 主机 | ACK (0xD2) | 确认接收成功 |
2.3.2 OUT 事务
主机通过 OUT 令牌(PID = 0x87)通知设备准备接收数据,随后主机发送 DATA 包,设备回复 ACK。
| 事务元素 | 发送方 | PID | 说明 |
|---|---|---|---|
| 令牌包 | 主机 | OUT (0x87) | 通知设备准备接收 |
| 数据包 | 主机 | DATA1/DATA0 | 数据负载 |
| 握手包 | 设备 | ACK (0xD2) | 确认接收成功 |
2.4 Status 阶段
Status 阶段是控制传输的最后一个阶段,用于确认整个控制传输是否成功完成。Status 阶段的方向与 Data 阶段相反:
- 如果 Data 阶段是 IN(设备→主机),则 Status 阶段为 OUT(主机→设备),主机发送一个零长度数据包,设备回复 ACK。
- 如果 Data 阶段是 OUT(主机→设备),则 Status 阶段为 IN(设备→主机),设备发送一个零长度数据包,主机回复 ACK。
- 如果无 Data 阶段(wLength = 0),则 Status 阶段为 IN,设备发送零长度数据包。
2.5 各阶段数据包格式汇总
下表汇总了控制传输三个阶段中所有可能出现的包格式及其 PID 值:
| 阶段 | 包类型 | PID(二进制) | PID(十六进制) | 数据负载 |
|---|---|---|---|---|
| Setup | 令牌包 | 1011 0100 | 0xB4 | ADDR+ENDP+CRC5 |
| 数据包 | 1100 0011 | 0xC3 | 8 字节 Setup 数据 | |
| 握手包 | 1101 0010 | 0xD2 | 无 | |
| Data (IN) | 令牌包 | 1001 0110 | 0x96 | ADDR+ENDP+CRC5 |
| 数据包 | 1100 0011 / 0100 1011 | 0xC3 / 0x4B | 0~64 字节 | |
| 握手包 | 1101 0010 | 0xD2 | 无 | |
| Data (OUT) | 令牌包 | 1000 0111 | 0x87 | ADDR+ENDP+CRC5 |
| 数据包 | 1100 0011 / 0100 1011 | 0xC3 / 0x4B | 0~64 字节 | |
| 握手包 | 1101 0010 | 0xD2 | 无 | |
| Status | 令牌包 | 1001 0110 / 1000 0111 | 0x96 / 0x87 | ADDR+ENDP+CRC5 |
| 数据包 | 0100 1011 | 0x4B | 零长度(仅 PID+EOP) | |
| 握手包 | 1101 0010 | 0xD2 | 无 |
2.6 FPGA 验证中的常见故障模式
基于实际项目经验,控制传输在 FPGA 验证中高频出现的故障可归纳为以下六类:
- Setup 包 CRC5 错误:FPGA 的令牌包 CRC5 生成器实现错误,导致设备丢弃 Setup 令牌。验证时应使用 USB 分析仪对比 CRC5 计算值。
- Data Toggle 不同步:主机与设备的 DATA PID 翻转状态不一致,设备返回 NYET 或 STALL。FPGA 状态机必须为每个端点维护独立的 toggle 位。
- Status 阶段方向错误:FPGA 状态机未正确解析 bmRequestType[7],导致 Status 阶段使用错误的方向令牌,设备无响应。
- 超时处理不当:设备无响应时,主机未在 5 μs 内超时重试,导致总线挂起。FPGA 验证中需在状态机中插入超时跳转逻辑。
- wLength 与实际数据长度不匹配:Setup 包中的 wLength 字段与 Data 阶段实际传输的数据长度不一致,设备返回 STALL 握手。
- EOP 时序违规:FPGA 的包结束信号(SE0)宽度不符合 USB 规范(全速 2 bit time),导致接收端无法正确识别包边界。