OTG协议基础:主机与设备角色切换原理

传统USB的世界里,角色是固定的。电脑永远是主机,U盘、鼠标永远是设备。但OTG打破了这种硬绑定。你想想看,两台手机能不能直接传文件?打印机能不能没电脑就自己打照片?OTG说:可以。核心就是让设备能动态切换主从角色。嗯,这里有个关键——靠物理层加协议层配合完成。

从ID引脚到会话

OTG里,每个设备都有一个ID引脚。这个引脚接地还是悬空,直接决定了初始角色。

  • ID接地:该设备初始作为A设备(主机角色),负责提供VBus电源。
  • ID悬空:该设备初始作为B设备(外设角色),等待主机供电。

我在项目中遇到过一根OTG线内部ID引脚虚焊,结果设备插上后一直认成B设备,主机端死活枚举不到。查了三天,最后用万用表量ID对地电阻才找到问题。说白了,物理层不牢,协议层再对也没用。

另外还有一个概念叫“会话”(Session)。会话是指A设备提供VBus电源、B设备可以正常通信的那段时间。会话的开启、维持和结束,由SRP和HNP共同管理。

HNP:角色切换的握手协议

HNP的全称是Host Negotiation Protocol。它让B设备能申请成为主机,A设备可以主动让出主机角色。整个过程分三步:

  1. 初始分配:上电后,根据ID引脚确定A、B角色。A设备拉起VBus,开始会话。
  2. 请求切换:B设备觉得自己更适合当主机(比如它想读A设备里的数据),就在总线空闲时拉低D+线超过2ms,向A设备发出切换请求。
  3. 角色互换:A设备检测到B设备的HNP请求后,释放总线控制权(停止驱动VBus并断开DP/DM的上拉电阻),B设备随后拉高D+并开始驱动VBus——身份互换完成。
避坑指南: 我曾经在调试HNP时发现B设备请求后,A设备就是不响应。查了芯片手册才发现,A设备的USB控制器必须在配置里使能“HNP支持位”。默认这个位是0。很多人漏了这一步,结果整条链路卡在第二步。

注意一点:HNP不是所有OTG设备都实现的可选功能。很多简单的OTG设备(比如读卡器)只做B设备,根本不支持HNP。你如果想让手机当主机去控制另一个设备,那个设备必须支持HNP才行。

SRP:唤醒沉睡主机的秘密

SRP(Session Request Protocol)解决的是另一类场景:如果A设备认为会话超时、为了省电关掉了VBus,B设备该怎么把它叫醒?

SRP分两个阶段:

  • 数据线脉冲:B设备先在D+(或D-)上输出一个脉冲(~20ms),告诉A设备“我想开始通信”。
  • VBus脉冲:如果A设备在线,它会回应一个VBus脉冲(维持电流>8mA),表示“我准备好给你供电了”。

我记得有一次客户反馈,手机接上U盘后插拔一次就再也识别不到了。追下去发现是U盘(B设备)发完SRP数据脉冲后,手机(A设备)没检测到VBus脉冲——因为手机端USB PHY在低功耗模式下把VBus检测功能关了。嗯,这里要注意,SRP的接收端必须始终保持VBus检测能力。

HNP与SRP对比一览

特性 HNP SRP
目的 交换主机/外设角色 请求A设备重新供电
触发者 B设备(请求成为主机) B设备(请求恢复VBus)
前提 会话已建立 会话已结束或未开始
物理信号 D+线拉低≥2ms D+脉冲 + VBus脉冲
典型应用 手机互传文件 U盘插入无供电手机

完整的OTG角色切换流程

实际产品中,HNP和SRP常常交替使用。比如:B设备首次插入时可能依靠SRP唤醒A设备,建立会话后再用HNP反转角色。我画了一张流程图帮你理清关系。

OTG角色切换完整流程 A设备上电 B设备上电 ID接地→主机 ID悬空→外设 提供VBus 建立会话 B设备请求SRP? B设备请求HNP? A设备回应VBus脉冲 角色互换完成 注意 ID引脚状态在硬件 连接时由OTG线缆 决定,不支持软件修改 常见问题 HNP失败:检查双方 是否都使能了HNP SRP超时:检查VBus检测

角色切换的硬件保障

协议靠软件,但硬件是地基。我建议你在原理图阶段就确认以下三点:

  • ID引脚必须能干净地连到地或悬空,不能有上拉/下拉干扰。
  • VBus的开关(通常是一个P-MOSFET)必须能承受至少1A电流,且开通时间要小于SRP的超时窗口。
  • D+/D-线上的上拉电阻(1.5kΩ)和下拉电阻(15kΩ)必须严格按照OTG规范安装,不要在BOM里随便替换成其他阻值。
警告: 千万不要在OTG端口上使用普通USB线缆!普通线缆的ID引脚是内部短路的,会导致设备始终检测为A设备。必须使用专用OTG线:一头是micro-A插头(ID接地),另一头是标准A插座。

调试心得

我记得刚做OTG产品那会儿,经常遇到设备插上后主机角色切换不成功。拿示波器抓ID引脚电平,发现A设备的ID在0V和3.3V之间波动——原来是机械接触不良。后来在ID引脚上并联一个100nF电容,波形才稳定下来。这种小坑,不是靠看协议就能知道的。

另外,你如果看到B设备反复发送SRP请求但A设备没反应,先别急着怀疑程序。把VBus波形抓出来,看看A设备在B设备发出数据线脉冲后,有没有在1秒内拉到有效电压。很多低功耗芯片在唤醒后需要几十ms才能准备好GPIO,这个时间差经常被忽略。