USB Device:公头悬空为何误报 Suspend
环境:USB 2.0 Device(DWC 类控制器 / 同类 UDC)· 对照 Linux
dwc2+usb-role-switch的会话门控思路
关联:USB 2.0 枚举流程 · DWC2 gadget 接口
状态:机理已理清;正确修法是插入门控,而非改 PHY 门限或给 D− 常驻下拉
目录
- 1. 现象
- 2. 结论先行
- 3. 规范里的空闲与 Suspend
- 4. 为何「悬空公头」会踩中
- 5. 软件侧常见误用
- 6. 实验:探头与下拉在改变被测对象
- 7. 和「有插入检测」平台的差异
- 8. 不该怎么修
- 9. 建议修法
- 附录 A 线态速记
- 附录 B 要点速记
1. 现象
在 USB Device 固件已启动、数据线 soft-connect(D+ 经约 1.5 kΩ 上拉)之后,用 USB 公对公线 一端接设备、另一端悬空(或未接到真正的 Host):
- 控制器频繁上报 Suspend(如
USBSUSP/DSTS.SUSPSTS) - 日志或状态机上像「反复挂起 / 异常断连」
- 同一套软件,真正插到 PC Host 后枚举往往正常
- 逻辑分析仪夹到 D− 后,误报明显减少甚至消失
- 实测:在 D− 对地串约 5 kΩ 下拉 后,悬空公头场景下 误报不再复现(仅作机理验证,见 §6、§8)
预期:未接到 Host 时不应表现为「已连接且空闲 3 ms 后进入 Suspend」的产品语义。
实际:软件已把端口当成在线 Device,总线在电气上却接近「半截天线」。
2. 结论先行
| 问题 | 答案 |
|---|---|
| 根因是什么 | 未插入却 soft-connect +(常见)软件强制 B-session 有效;悬空 D+/D− 噪声/线态抖动,叠加规范上的「空闲约 3 ms → Suspend」 |
| 是不是 PHY squelch 设太灵 | 基本不是;FS 阶段 Suspend 看的是线态空闲计时,不是 HS squelch 电压档 |
| 为何夹探头 / 加下拉就好转 | 探头电容或 D− 下拉 改变了总线,压住悬空噪声、稳住接近 FS J;不是协议自己好了 |
| D− 加 5 kΩ 下拉 | 悬空复现条件下降误报 不再出现;证明缺的是「对端把 D− 拉住」,但仍 不宜作产品常驻方案 |
| 产品上怎么修 | 无 VBUS / 无插入证据前不要 connect;对齐「先检测会话,再 pullup」;不要给 D− 常驻下拉凑合 |
3. 规范里的空闲与 Suspend
3.1 Full-Speed 线态(Device 上拉在 D+)
| 线态 | D+ | D− | 常见含义 |
|---|---|---|---|
| J | 高 | 低 | FS 空闲 |
| K | 低 | 高 | 与 J 相反(如 Resume 相关) |
| SE0 | 低 | 低 | 复位等 |
| SE1 | 高 | 高 | 非法/异常单端态;悬空时 D− 被抬高且 D+ 仍被上拉时可见 |
UTMI 线态编码(DWC 手册,utmi_linestate[1:0])与上表对应关系如下。编码表里的 01=J / 10=K 是 组合后的线态名,不要和后文 DSTS.DevLnSts 的「原始高低比特」混读。

soft-connect 后,D+ 经约 1.5 kΩ 上拉,电平相对钉在高;对端若没有 Host 约 15 kΩ 下拉,D− 近乎高阻,最容易被噪声抬高。
此时更常见的是:D− 在「低 / 中间 / 高」之间晃 → 线态在 J(D− 仍偏低)与 SE1(D+、D− 同高)之间变化;只有噪声强到把 D+ 也拉低 时,才容易见到 K 或 SE0。
即便不怎么「乱跳」、长时间停在 J,已 soft-connect 的控制器仍可按规范在约 3 ms 空闲后报 Suspend。
3.2 Suspend 条件(概念)
对已处于 连接/在线 的 Device:总线保持 空闲 约 3 ms,控制器置挂起状态并上报 Suspend 中断。
DWC 上与此直接相关的状态/中断位(手册摘录):


要点:
- 判的是 「已在线 + 空闲够久」(看 linestate /
phy_line_state长时间无活动),不是「差分包幅度够不够」 ErlySusp对应约 3 ms Idle;USBSusp/SuspSts为挂起检测与状态- HS squelch 调节(PHY 上常见的差分门限/偏置)管的是 高速包有无活动,对 FS 空闲挂起 通常对不上
因此:把「接收灵敏度」拧到极限,也解决不了这类误报。
4. 为何「悬空公头」会踩中
USB 规范假定的拓扑是:
Host(VBUS + D± 下拉 + 驱动) ←合格线→ Device(需要时才 D+ 上拉)公对公 + 一端悬空 不在合法产品用法里:
- 没有 Host 的 15 kΩ 下拉 → D− 近乎高阻,易受耦合(天线效应)
- Device 若已 soft-connect → 控制器认为自己在线
- 线态在噪声下抖动或长时间「像空闲 J」→ Suspend 语义被合法触发或反复骚扰
规范用 VBUS / 会话有效 约束「何时算插上」;不是要求 Device 在 D− 上常驻下拉来防悬空线。
5. 软件侧常见误用
很多无片内 VBUS 检测、又未外接 Type-C/端口控制器的板子,会走捷径:
启动
→ 软件强制 B-session valid(覆盖 GOTGCTL 一类 override)
→ 清除 soft-disconnect,拉起 D+ pullup
→ 此后一直当「已连接 Device」对照更干净的做法(Linux dwc2 在启用 usb-role-switch 时的思路,公开源码):
启动
→ 打开 session override,但先把 valid 清成无效
→ 仅当端口层判定为 Device(例如 Sink + VBUS 有效)时
→ 置 B-session valid + soft-connect
→ 拔出 / 角色 NONE
→ 清 session + soft-disconnect差异不在「DWC 会不会 Suspend」,而在 有没有在无 Host 时假装已连接。
6. 实验:探头与下拉在改变被测对象
下列现象容易误导排查方向:
| 操作 | 常见结果 | 解释 |
|---|---|---|
| 逻辑分析仪夹 D− | 误报减少 | 探头电容 + 弱对地阻抗,稳住 D− |
| D− 对地约 5 kΩ 下拉 | 悬空场景下误报 不再复现 | 模拟「对端把 D− 拉低」、接近 FS J;比 Host 标称约 15 kΩ 更强 |
| 示波器探头测毛刺 | 幅度可能只剩 mV 级,或一夹现象就变 | 测量加载;未探头时噪声往往更大 |
| 调节 HS squelch 寄存器 | 假 Suspend 仍在 | 改错子系统 |
结论:这类实验适合 验证「悬空线态 / 噪声、缺 Host 侧下拉」假设;不能当成产品方案,也不能据此认为「总线上永远只有几毫伏毛刺」。
5 kΩ 能复现「一拉就好」,恰好说明根因在 D− 未被合法端接时的线态,而不是要在量产 Device 上永久并联比 Host 更强的下拉。
示波器抓偶发尖峰时,注意探头 10× 与通道倍率一致;时基可先从约 10 µs/div 扫起,并接受「一探头就改变电路」的现实。
软件侧也可轮询 DSTS.DevLnSts 观察 D+/D− 原始电平。手册字段说明如下(注意:手册把 D+/D− 标反了,见附录 A):

7. 和「有插入检测」平台的差异
带 外置 Type-C 端口控制器 或 VBUS GPIO 的平台,典型路径是:
- 硬件/ TCPC 确认 VBUS / 角色(Sink)
- 再
usb_role_switch(或等价回调)通知 UDC - UDC 才强制 B-session 并 soft-connect
参考一类 Type-C OTG 接法:座子上的 CC 进端口控制器,D+/D− 经串阻到 SoC USB,VBUS 另作检测/供电网络;端口控制器通过 I2C + 中断上报插拔与角色,再驱动 UDC 会话——而不是一上电就 soft-connect。

因此:板子已上电、OTG 未接到 Host 时,B-session 不应被置为有效;自然也少见「悬空公头刷 Suspend」。
这不是「那边的 DWC 更聪明」,而是 会话有效性有外部真值。
8. 不该怎么修
| 做法 | 问题 |
|---|---|
| 在 Device 上给 D− 常驻下拉(含实测有效的约 5 kΩ) | 悬空时可消误报,但与 Host 侧约 15 kΩ 并联后等效更强,影响线态、HS 协商与合规;真插入后埋雷 |
| 靠 PHY HS squelch / 端接 / PLL 调参 | 不对症;还可能伤长线/HS 眼图 |
| 「永远夹着探头」或板载模拟探头电容 | 改变 SI,非正式方案 |
| 忽略 Suspend 中断却仍保持错误 connect | 治标,未插入时总线语义仍错 |
9. 建议修法
按优先级:
门控 soft-connect
无插入证据(VBUS 比较器、GPIO 分压、Type-C/TCPC、或明确的用户态「开始枚举」)前,保持 soft-disconnect。门控 B-session override
仅在进入 Device 会话时置 valid;退出时清除(对齐 Linuxusb-role-switch语义)。硬件补检测(可选)
插座 VBUS → GPIO;不必上完整 Type-C 芯片也能做「插上再 connect」。软件兜底(可选)
未完成枚举 / 未配置成功前降权处理 Suspend;不能替代 1、2。
调试用公对公线时:另一端悬空且固件已 connect,出现 Suspend 在错误模型下是预期现象;应用合格线接到真 Host,或先 disconnect 再测。
附录 A 线态速记
Full-Speed(上拉在 D+):
- J = D+ 高、D− 低(空闲)
- K = D+ 低、D− 高
- SE0 = 双低;SE1 = 双高(异常)
- Host 负责 D± 约 15 kΩ 下拉;Device 连接时上拉 D+,默认不应再给 D− 加产品级下拉
- 悬空时优先不稳的是 D−;D+ 有上拉,一般不会像 D− 那样飘
- 读
DSTS.DevLnSts([23:22])时注意:DWC 手册写[1]=D+、[0]=D−,与实测对调(手册把 D+/D− 标反了);勿与 UTMIlinestate的01=J编码表直接混用
附录 B 要点速记
- 误报 Suspend ≈ 已 connect 的空闲语义 + 无 Host 端接的悬空线
- USB 用 VBUS/会话 处理「没插上」,不是 Device 侧给 D− 下拉防天线
- 探头 / D− 约 5 kΩ 下拉 好转 = 负载改变电路(机理验证);要对照未加载时的日志,勿当量产方案
- 修法:先检测,再 pullup / 置 B-session;对照公开树里
dwc2的usb-role-switch路径即可,无需依赖私有代码