Source 和 Sink 角色:OTG 中的角色定义与切换

角色到底是什么?

在 USB OTG 里,Source 和 Sink 是电源角色的两个端点。说白了,Source 就是负责供电的那一方,Sink 则是用电的那一方。传统 USB 里,主机永远是 Source,设备永远是 Sink,这个关系是死的。但 OTG 打破了这种固定搭配——一台手机既可以当充电宝给外设供电,也可以反过来被充电。

我刚开始接触 OTG 时,以为角色切换就是简单的硬线切换。结果在项目里踩了个大坑:电源角色和 Data 角色是两个独立的概念,不能混为一谈。后来才明白,电源角色决定谁提供 VBUS,Data 角色决定谁当主机。这两个角色可以同步切换,也可以独立管理。

Source 的职责

  • 提供 VBUS 电压(通常 5V,PD 时可协商更高)
  • 检测 Sink 的连接状态
  • 管理电源能力协商(比如通过 PD 协商电流)
  • 在空闲时关闭 VBUS 以省电

Sink 的职责

  • 从 VBUS 取电
  • 向 Source 请求需要的电流或电压
  • 在不需要电源时通知 Source 关闭 VBUS
举个实际例子:一部手机通过 OTG 线连接 U 盘。手机作为 Source 提供电源,U 盘作为 Sink 取电。但手机同时作为 Data 角色(主机)管理 U 盘的文件系统。如果把 OTG 线换成反向的,手机就成了 Sink(被充电),而另一端的设备(比如充电宝)成为 Source。

角色切换的时机

OTG 规范定义了两种切换方式:HNP(主机交换协议)和 SRP(会话请求协议)。HNP 用于交换 Data 角色,SRP 用于唤醒休眠中的总线。但在实际产品中,我更推荐直接使用 USB PD 的 DR_Swap 消息,它更灵活,且兼容性更好。

我以前参与过一个双角色快充方案,最初用的 HNP,结果发现某些老旧设备不支持 HNP 握手。后来改用 PD 的电源角色交换,问题就解决了。嗯,这里要注意:HNP 依赖硬件 ID 引脚,而 PD 是通过 CC 线协商的,后者更干净。

电源角色与 Data 角色的关系

很多人以为 Source 必须同时是主机,Sink 必须同时是设备。其实不是。下表列出四种可能组合:

电源角色Data 角色实际场景
SourceHost手机通过 OTG 接鼠标
SourcePeripheral手机连接 PC,但手机给 PC 供电(罕见,需硬件支持)
SinkHost平板接键盘,同时从键盘取电(键盘内置电池时)
SinkPeripheral手机连接电脑传文件、同时充电

注意: 表格最后一种即最常见的“充电 + 数据通信”模式。这个时候电源角色是 Sink,Data 角色是 Peripheral,并不冲突。

角色切换流程

下面这张图展示了 OTG 双角色设备之间的一次典型角色交换过程。初始时设备 A 是 Source + Host,设备 B 是 Sink + Peripheral;经过 HNP + SRP 或 PD 协商后,双方交换角色。

OTG 双角色切换状态图 设备 A Source + Host 设备 B Sink + Peripheral VBUS + 数据 HNP / SRP 或 PD DR_Swap 触发 角色交换请求 设备 A Sink + Peripheral 设备 B Source + Host 电源角色与 Data 角色可独立切换,但实际产品中大多同步进行 交换后 VBUS 方向反转,主机身份也随之交换

如何检测当前角色?

在嵌入式开发中,我们通常通过读取硬件状态寄存器或者系统接口来获知角色。以 Linux 为例,可以读取 /sys/class/power_supply/usb/ 下的文件,或者使用 USB gadget 的配置接口。下面是一个简化的检测示例:

# 检查 VBUS 是否存在(Sink 角色)
cat /sys/class/power_supply/usb/online
# 输出 1 表示有 VBUS,即本设备作为 Sink

# 检查当前 gadget 角色
cat /sys/kernel/config/usb_gadget/g1/UDC
# 如果非空,表示本设备作为 Peripheral(Data 角色)

但更可靠的方法是直接读取 USB 控制器的角色寄存器。我习惯在初始化时打印这些值,方便调试。

避坑指南:我曾经在项目里只检测了 VBUS,以为有电就是 Sink,结果设备作为 Source 时 VBUS 是自己提供的,同样检测到有线高。正确的做法是区分“本设备输出的 VBUS”和“对方提供的 VBUS”。建议在硬件上加一个方向检测引脚(如 ID 线)或使用 PD 的 CC 线状态来判断。

角色切换的工程陷阱

  • VBUS 浪涌:角色切换时 VBUS 会经历“断开-重新建立”,可能产生浪涌电流。我通常会在 VBUS 路径上加 soft-start 电路。
  • 协议优先级:如果同时支持 HNP 和 PD,应该优先使用 PD 协商。因为 HNP 需要 ID 引脚,而有些 Type-C 线缆已经不再包含 ID 线。
  • 角色锁死:某些设备的固件在角色协商失败后会死锁。建议增加超时回退机制,比如 3 秒内协商失败就恢复到默认角色。
我的经验:调试角色切换时,最好准备一个带电流和电压显示的 USB 测试仪,可以直观看到 VBUS 的方向和电压变化。有一次我发现某个设备在切换后一直无法充电,用测试仪一看,原来是 VBUS 只有 3.3V——根本原因是 Source 端的升压电路没使能。这种问题光看软件日志是看不出来的。

小结

Source 和 Sink 是 OTG 的电源角色,它们决定了谁供电谁用电。配合 Data 角色,总共可以组合出四种模式。角色切换的核心在于正确检测当前状态、触发协商协议、以及安全地翻转 VBUS。在实际项目中,多花点时间在硬件保护上,比在软件里堆各种状态机要划算得多。