Skip to content

USB Device:公头悬空为何误报 Suspend ​

环境:USB 2.0 Device(DWC 类控制器 / 同类 UDC)· 对照 Linux dwc2 + usb-role-switch 的会话门控思路
关联:USB 2.0 枚举流程 · DWC2 gadget 接口
状态:机理已理清;正确修法是插入门控,而非改 PHY 门限或给 D− 常驻下拉


目录 ​


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 的「原始高低比特」混读。

DWC UTMI linestate:SE0/J/K/SE1 编码

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 上与此直接相关的状态/中断位(手册摘录):

GINTSTS:USBSusp 与 ErlySusp(约 3 ms Idle)

GSTS.SuspSts:Suspend 状态,依赖 phy_line_state 有无活动

要点:

  • 判的是 「已在线 + 空闲够久」(看 linestate / phy_line_state 长时间无活动),不是「差分包幅度够不够」
  • ErlySusp 对应约 3 ms Idle;USBSusp / SuspSts 为挂起检测与状态
  • HS squelch 调节(PHY 上常见的差分门限/偏置)管的是 高速包有无活动,对 FS 空闲挂起 通常对不上

因此:把「接收灵敏度」拧到极限,也解决不了这类误报。


4. 为何「悬空公头」会踩中 ​

USB 规范假定的拓扑是:

text
Host(VBUS + D± 下拉 + 驱动)  ←合格线→  Device(需要时才 D+ 上拉)

公对公 + 一端悬空 不在合法产品用法里:

  1. 没有 Host 的 15 kΩ 下拉 → D− 近乎高阻,易受耦合(天线效应)
  2. Device 若已 soft-connect → 控制器认为自己在线
  3. 线态在噪声下抖动或长时间「像空闲 J」→ Suspend 语义被合法触发或反复骚扰

规范用 VBUS / 会话有效 约束「何时算插上」;不是要求 Device 在 D− 上常驻下拉来防悬空线。


5. 软件侧常见误用 ​

很多无片内 VBUS 检测、又未外接 Type-C/端口控制器的板子,会走捷径:

text
启动
  → 软件强制 B-session valid(覆盖 GOTGCTL 一类 override)
  → 清除 soft-disconnect,拉起 D+ pullup
  → 此后一直当「已连接 Device」

对照更干净的做法(Linux dwc2 在启用 usb-role-switch 时的思路,公开源码):

text
启动
  → 打开 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):

DSTS.DevLnSts:Device 线电平(手册标注与实测对调)


7. 和「有插入检测」平台的差异 ​

带 外置 Type-C 端口控制器 或 VBUS GPIO 的平台,典型路径是:

  1. 硬件/ TCPC 确认 VBUS / 角色(Sink)
  2. 再 usb_role_switch(或等价回调)通知 UDC
  3. UDC 才强制 B-session 并 soft-connect

参考一类 Type-C OTG 接法:座子上的 CC 进端口控制器,D+/D− 经串阻到 SoC USB,VBUS 另作检测/供电网络;端口控制器通过 I2C + 中断上报插拔与角色,再驱动 UDC 会话——而不是一上电就 soft-connect。

Type-C OTG 参考:CC 检测与 D+/D− 分路

因此:板子已上电、OTG 未接到 Host 时,B-session 不应被置为有效;自然也少见「悬空公头刷 Suspend」。

这不是「那边的 DWC 更聪明」,而是 会话有效性有外部真值。


8. 不该怎么修 ​

做法问题
在 Device 上给 D− 常驻下拉(含实测有效的约 5 kΩ)悬空时可消误报,但与 Host 侧约 15 kΩ 并联后等效更强,影响线态、HS 协商与合规;真插入后埋雷
靠 PHY HS squelch / 端接 / PLL 调参不对症;还可能伤长线/HS 眼图
「永远夹着探头」或板载模拟探头电容改变 SI,非正式方案
忽略 Suspend 中断却仍保持错误 connect治标,未插入时总线语义仍错

9. 建议修法 ​

按优先级:

  1. 门控 soft-connect
    无插入证据(VBUS 比较器、GPIO 分压、Type-C/TCPC、或明确的用户态「开始枚举」)前,保持 soft-disconnect。

  2. 门控 B-session override
    仅在进入 Device 会话时置 valid;退出时清除(对齐 Linux usb-role-switch 语义)。

  3. 硬件补检测(可选)
    插座 VBUS → GPIO;不必上完整 Type-C 芯片也能做「插上再 connect」。

  4. 软件兜底(可选)
    未完成枚举 / 未配置成功前降权处理 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− 标反了);勿与 UTMI linestate 的 01=J 编码表直接混用

附录 B 要点速记 ​

  1. 误报 Suspend ≈ 已 connect 的空闲语义 + 无 Host 端接的悬空线
  2. USB 用 VBUS/会话 处理「没插上」,不是 Device 侧给 D− 下拉防天线
  3. 探头 / D− 约 5 kΩ 下拉 好转 = 负载改变电路(机理验证);要对照未加载时的日志,勿当量产方案
  4. 修法:先检测,再 pullup / 置 B-session;对照公开树里 dwc2 的 usb-role-switch 路径即可,无需依赖私有代码

基于 VitePress 构建