2. OTG 角色切换机制:HNP 协议、SRP 协议、角色切换时序
做 USB OTG 调试,最头疼的就是角色切着切着就断了。我记得刚接触 OTG 那年,遇到一个平板连键盘投屏的案子,设备死活不切换 Host 模式,最后查出来是 HNP 协商超时。说白了,角色切换不是一个简单的电平跳变,它是有一套完整握手协议的。
2.1 SRP 协议:谁先发起对话?
SRP(Session Request Protocol)是设备想主动干活的敲门砖。你想想看,一条 USB 线平时是静默的,VBUS 甚至可能都没电。这时候某个设备想发起会话,就得通过 SRP 让总线活起来。
SRP 分为两步:
- 数据线脉冲(Data Line Pulsing):发起方在 D+ 或 D- 上拉一个 5~10ms 的脉冲。B 设备想当 Host 时,拉 D+;A 设备想结束会话时,拉 D-。
- VBUS 脉冲(VBus Pulsing):如果数据线脉冲没反应,发起方再拉一下 VBUS(大概 2.1V 以上、20ms 左右),告诉对面“我要用电了”。
我遇到过的一个坑:某款 Type-C 转 micro-B 线缆,VBUS 上的下拉电阻选型不对,导致 VBUS 脉冲幅度一直被拉低到 1.8V,另一端死活检测不到。嗯,这里要注意:SRP 的 VBUS 脉冲阈值是 2.0V,小于这个值就不会触发。
SRP 关键参数速查表(这些是我在实际抓波形时记下来的)
| 参数 | 最小值 | 典型值 | 最大值 | 说明 |
|---|---|---|---|---|
| 数据线脉冲宽度 | 5 ms | 10 ms | 20 ms | 超过 20ms 视为超时 |
| VBUS 脉冲电压 | 2.0 V | 2.1 V | 3.6 V | 高于 3.6V 可能误触发过压保护 |
| VBUS 脉冲持续时间 | 10 ms | 20 ms | 40 ms | 太短容易漏检 |
| SRP 后的等待时间 | 100 ms | — | 1 s | 超时后发起方应重试或放弃 |
2.2 HNP 协议:角色互换的握手流程
HNP(Host Negotiation Protocol)才是真正的“换座位”。只有支持 OTG 的设备才能玩这个。你能想象吗?一根线插上,两个设备商量谁来当 Host。有一次我在调试一块开发板,连接 U 盘后想切到 Device 模式,结果 HNP 一直失败,抓着逻辑分析仪一看——对方根本没发 HNP 请求。
HNP 的标准流程:
- 初始状态:A 设备(默认 Host)提供 VBUS,B 设备(默认 Peripheral)挂起。
- B 设备申请切换:B 设备把 D+ 拉低(至少 2ms),然后释放。这表示“我想当 Host”。
- A 设备响应:A 设备检测到 D+ 上的脉冲后,停止驱动 D+/D-,并释放总线。A 设备进入 Peripheral 模式。
- B 设备接管:B 设备在检测到总线空闲超过 3ms 后,驱动 D+ 上拉,成为新 Host。
- 总线重新枚举:新 Host 开始复位和枚举,原来的 A 设备作为 Peripheral 响应。
注意,HNP 要求双方都必须支持 OTG(即有 ID 引脚或 Type-C CC 逻辑)。我个人习惯在协议分析仪上同时抓 D+/D- 和 VBUS,这样才能看到完整的脉冲时序。
曾经让我通宵的一个 Bug:某颗 MCU 的 OTG 控制器在 HNP 握手期间,被 USB 中断强行打断了 D+ 脉冲的检测窗口。结果导致 A 设备认为 B 设备没发请求,双方僵持在那里。解法是把 USB 中断优先级降低,或者用 DMA 处理数据,让脉冲检测不受影响。
2.3 角色切换时序:谁先动、谁后动?
时序是 OTG 切换的命门。SRP 和 HNP 都依赖严格的时间窗。我见过产品送检时因为时序差几毫秒被 USB-IF 打回的案例。下面这张图基本覆盖了完整的“A 设备 vs B 设备”切换过程。
2.4 切换失败时的常见根因分析
我整理了一个对照表,大家调试时可以直接对号入座:
| 现象 | 可能原因 | 我的排查建议 |
|---|---|---|
| 永远切不过去 | ID 引脚或 CC 逻辑未正确实现 | 检查 OTG ID 引脚是否悬空,Type-C 的 CC1/CC2 是否正确上拉/下拉 |
| 切过去后无法枚举 | HNP 时序中总线空闲时间不足 3ms | 用示波器测量 D+ 释放到对方上拉的时间差 |
| 偶尔切成功,大部分失败 | SRP 脉冲宽度不够稳定 | 看固件里定时器是否被中断抢占,我建议在 HNP 请求期间关中断 |
| 切完角色很快又自动切回来 | 对方设备在枚举期间又发了一次 HNP 请求 | 检查新 Host 是否在枚举完成前误判了总线状态 |
我的一个小窍门:调试 HNP 时别光看逻辑分析仪的 D+/D- 电平,把 VBUS 也拉上。有一次我发现 VBUS 在切换瞬间跌落到了 4.2V 以下,导致新 Host 启动时电压不足,枚举失败。加一个足够大的 VBUS 电容就能解决。
2.5 关于 SRP 和 HNP 的一点补充
你可能会问:为什么需要两个协议?我简单解释一下:SRP 是“我要用电,开启会话”,HNP 是“我要当管理,交换角色”。在 USB-IF 的规范里,SRP 可以独立于 HNP 使用——比如一个鼠标想从挂起状态唤醒总线,只需要 SRP 就够了,不需要切换角色。但如果你要做的是手机通过 OTG 线连 U 盘又想反过来插电脑,那你就得先后经过 SRP + HNP 完整走一遍。
嗯,还有一点容易忽略:有些设备只实现了 SRP 却没有实现 HNP,所以它只能唤醒总线,不能切换主机。这在调试时容易误判——你看到它发出脉冲了,以为它在做 HNP,结果它只是 SRP。我曾经在客户现场被这个问题坑过两个多小时。