USB基础 -- USB2.0设备插入的过程
“USB2.0 设备插入后,主机侧从硬件信号到令牌(Token)层的完整过程”按时间线拆开讲清楚。为了便于实现/调试,把每一步的电气线状态(D+/D-)、主机/Hub 的动作、以及紧接着发生的令牌级事务都写在一起,并给出典型时序与数据包结构。
一、物理层:插入→检测→复位→速度判定
1) 线缆插入与上电(Attach/Powered)
-
VBUS:主机/Hub 端口向下游供电(约 5V),设备上电。
-
下拉/上拉电阻:
-
主机/Hub 端口:D+、D- 各有 15 kΩ 下拉到 GND。
-
设备:
- 全速(FS, 12 Mb/s)/高速(HS, 480 Mb/s)设备初始表现为 FS:在 D+ 上拉 1.5 kΩ 到 3.3V。
- 低速(LS, 1.5 Mb/s)设备:在 D- 上拉 1.5 kΩ 到 3.3V。
-
-
连接去抖(Debounce):Hub 监测到某条线持续为“J 状态”达到去抖时间后,判断有设备接入。
- FS/HS 设备接入 → D+ 为高、D- 为低(J 状态(FS 视角))。
- LS 设备接入 → D- 为高、D+ 为低(J 状态(LS 视角))。
线状态速查
J/K 状态:差分逻辑电平,FS/LS 的定义相反:
- FS 视角:J= D+高/D-低;K= D+低/D-高
- LS 视角:J= D-高/D+低;K= D-低/D+高
SE0:D+、D- 同时为低
SE1:D+、D- 同时为高(非法)
2) 端口复位(Reset → Default)
- Hub 报告“连接”后,主机对该端口发起复位:把总线驱到 SE0(D+、D- 都低)持续 ≥10 ms(常见实现 10–20 ms)。
- 设备看到 SE0 复位,进入 Default 状态,地址=0,**端点0(EP0)**处于就绪(控制传输)。
3) 高速协商(HS Chirp,若设备支持 HS)
只有 HS 设备才会进行。不支持 HS 的设备保持 FS/LS。
- 复位末尾,主机仍保持 SE0;HS 设备开始向主机发送“Chirp K”(在 FS 视角下的 K:D-高、D+低)。
- 主机检测到设备 Chirp K 后,回送交替的 K/J 脉冲序列(至少 3 对 KJ)。
- 设备检测到足够的 KJ 对,切换到 HS 终端与驱动(差分 45 Ω 终端、电流模驱动),链路进入 High-Speed(480 Mb/s)。
- 若主机未回 Chirp KJ,设备保持 FS。
结果:
- HS 成功 → 之后主机以 125 μs 微帧调度(SOF/微帧 SOF)。
- FS/LS → 之后主机以 1 ms 帧调度(SOF)。
4) 空闲(Idle)/SOF 启动
-
复位结束后,主机开始发 SOF(Start Of Frame)记时:
- FS:每 1 ms 一个 SOF Token(帧号递增)。
- HS:每 125 μs 一个微帧 SOF Token(微帧号 0–7)。
二、枚举起点:从“地址 0、端点 0”的控制传输开始
控制传输(EP0)三阶段:SETUP → DATA(可选,读/写方向)→ STATUS(0 字节、反向)。
在令牌层(Token/Data/Handshake)上,每个**事务(Transaction)**都由“Token 包 +(可选)Data 包 +(可选)Handshake 包”组成。
包结构速查
- SYNC(位同步,NRZI 编码+位填充)
- PID(8 bit,低 4 位为类型,高 4 位为其反码)
- Token 包(IN/OUT/SETUP/SOF):
PID(8) + ADDR(7) + ENDP(4) + CRC5(5)
(SOF 用 FrameNum(11)+CRC5)- Data 包(DATA0/DATA1/DATA2/MDATA):
PID(8) + Payload(0..N) + CRC16(16)
- Handshake 包(ACK/NAK/STALL/NYET):
PID(8)
- EOP(包结束,SE0 ~2 bit time + J)
数据切换位(Data Toggle):控制读写的 DATA0/DATA1 翻转规则在枚举时尤为重要(见下文示例)。
三、主机侧令牌层:典型的两笔枚举起始事务
以下按令牌级展开两个最关键的控制读事务(以 FS 为例;HS 相同只是速率/微帧不同):
事务 A:读取前 8 字节设备描述符(Get Descriptor, first 8B)
目的:探测 bMaxPacketSize0(EP0 的最大包长),决定后续控制传输的分段。
- SETUP 阶段(Host → Dev)
- Token:
SETUP
,ADDR=0, ENDP=0 - Data:
DATA0
,8 字节 Setup 请求体:
bmRequestType=80h (IN, Standard, Device)
bRequest=GET_DESCRIPTOR (0x06)
wValue=(DEVICE<<8) | 0
wIndex=0
wLength=64
(主机想读最多 64 字节,但先读 8 字节以确定 MPS0) - Handshake:设备 ACK
- DATA 阶段(Dev → Host,控制读)
- Token:
IN
,ADDR=0, EP0 - Data:设备回
DATA1
,仅 8 字节(前 8 Byte 的 Device Descriptor,含bMaxPacketSize0
) - Handshake:主机 ACK
- STATUS 阶段(Host → Dev,反向 0B)
- Token:
OUT
,ADDR=0, EP0 - Data:
DATA1
,零长度包(ZLP) - Handshake:设备 ACK
要点
- 控制读里,数据阶段方向为 IN,状态阶段为 OUT ZLP。
- SETUP 数据包固定使用 DATA0,随后的数据阶段从 DATA1 起始。
- 此时主机已经知道 EP0 的 bMaxPacketSize0(常见 8/16/32/64)。
事务 B:设置地址(SET_ADDRESS)
目的:把设备从默认地址 0 切到 新地址 N(1…127)。
- SETUP 阶段(Host → Dev)
- Token:
SETUP
,ADDR=0, EP0 - Data:
DATA0
,8 字节 Setup:
bmRequestType=00h (OUT, Standard, Device)
bRequest=SET_ADDRESS (0x05)
wValue=N
wIndex=0
wLength=0
- Handshake:设备 ACK
- STATUS 阶段(Dev → Host,反向 0B)
- Token:
IN
,ADDR=0, EP0 - Data:设备发 ZLP(DATA1)
- Handshake:主机 ACK
要点
- 地址切换在状态阶段的 ACK 后生效。之后主机对该设备一律用 ADDR=N 访问。
- 随后主机会用新地址继续 Get_Descriptor(Device)(本次可按 MPS0 分段读取完整 18 字节),再 Get_Descriptor(Configuration) 等,直至 Set_Configuration。
四、更多主机侧“令牌级”细节(你实现/抓包时会用到)
- SOF/SOF 微帧
- FS:每 1 ms 发一次 SOF Token(
PID=SOF + FrameNumber(11) + CRC5
),用于全总线时间基准与带宽预算。 - HS:每 125 μs 发一次 微帧 SOF(帧号与微帧索引)。等时/中断端点在主机调度里按(微)帧精确分配时隙。
- 控制传输的数据切换位
- SETUP 数据包总用 DATA0;
- 随后的 数据阶段:第一个数据包用 DATA1,之后在同一个控制传输内按规则交替;
- 状态阶段:始终用 对端方向的 0 字节包(常见实现中对端一般用 DATA1 作为状态 ZLP)。
- 握手(Handshake)
- ACK:正确接收且 CRC 正确;
- NAK:暂时无数据或未就绪(主机可重试,常见在中断/批量端点);
- STALL:功能不支持或需要清错(主机可能发 ClearFeature(Halt) 恢复);
- NYET/PING:高速优化用语义(大多与 Bulk OUT 的缓冲/分组交互相关)。
- 编码与位填充
- NRZI:数据“0”触发电平翻转,“1”保持;
- 位填充:连续 6 个“1” 后插入一个“0”避免丢失时钟;
- EOP:包末尾强制 SE0 ~2 bit time 再回到 J(空闲)。
- 端口复位与清空数据切换
- 每次 总线复位 会把控制端点的 Data Toggle 复位(EP0 回到初始),这点在你实现栈重连或错误恢复时要注意。
- 速度对应的帧与带宽感知
- LS:受 Hub 事务转换(Split/TT)限制,主机通过上游 Hub 进行低速分时通道调度;
- FS/HS:主机直接调度;HS 里等时传输可在每微帧获得更高吞吐与更低抖动。
五、把“抓包视角”与“实现视角”对齐
-
抓包/分析(Wireshark + USBPcap / Beagle):你会看到上面的 Token→Data→Handshake 三段式序列,PID/ADDR/ENDP/CRC 明确可见。
-
主机栈实现(比如 xHCI/EHCI/OHCI + 类驱动):
- 复位/速度枚举由 Host Controller 驱动(HCD)与 Hub 驱动协作完成(端口电源、复位、启用、速度寄存器读取);
- 令牌级调度由 HCD 的传输描述符(TD/TRB)队列下发,遵循 SOF/微帧时隙;
- 类驱动(HID/CDC/UVC/MSC… 在 EP0 完成 SetAddress/获取描述符/SetConfig 后,按配置的端点类型提交 URB(中断/批量/等时)即可。
六、总结(实现检查清单)
-
电气检测:D+/D- 上拉判速(FS/LS)→ 端口去抖。
-
端口复位:SE0 ≥10 ms → 设备进入 Default。
-
HS 协商(可选):设备 Chirp K → 主机 KJ 对 → 切到 HS 或保持 FS。
-
SOF/微帧启动:提供调度基准。
-
控制传输(EP0):
- Get_Descriptor(前 8B) → 确定 bMaxPacketSize0
- Set_Address(状态阶段后生效)
- 完整 Get_Descriptor(Device/Config/String…) + Set_Configuration
-
后续端点:根据配置进行中断/批量/等时端点的 Token/Data/Handshake 调度;留意 NAK/STALL/NYET 与 数据切换位。