4、电源角色与策略:Source 端的功率广播机制、Sink 端的功率请求流程、角色切换与数据角色交换

好,咱们进入第四讲。这一讲的内容,说白了就是搞清楚 PD 协议里「谁给谁供电」以及「怎么切换供电关系」这两个核心问题。

我刚开始接触 PD 协议时,总觉得 Source 和 Sink 就是固定的——充电器永远是 Source,手机永远是 Sink。后来踩了坑才发现,事情远没那么简单。你想想看,一个支持 OTG 的手机,插上 U 盘时它自己就变成 Source 了。这就是角色切换的魅力所在。

4.1 Source 端的功率广播机制

Source 端,也就是供电方,它的核心任务就是告诉 Sink:「我能给你多少电」。这个广播过程,我习惯叫它「亮家底」。

4.1.1 能力源消息(Source_Capabilities)

Source 上电后,会主动发送一条 Source_Capabilities 消息。这条消息里包含了一组 PDO(Power Data Object),每个 PDO 描述一个可用的电压/电流组合。

PDO 的典型结构(以固定电源 PDO 为例):

  • Bit[31:30]:PDO 类型(00=固定电源,01=电池,10=可调电源,11=保留)
  • Bit[29:20]:电压值(50mV 为单位,比如 5000mV = 100 个单位)
  • Bit[19:10]:电流值(10mA 为单位,比如 3000mA = 300 个单位)
  • Bit[9:0]:保留或特殊标志位

举个例子,一个典型的 65W 充电器,它的 Source_Capabilities 可能长这样:

// 伪代码示例:Source_Capabilities 消息内容
PDO #1: 5V @ 3A   (固定电源,15W)
PDO #2: 9V @ 3A   (固定电源,27W)
PDO #3: 15V @ 3A  (固定电源,45W)
PDO #4: 20V @ 3.25A (固定电源,65W)

这里有个细节要注意:PDO 的顺序是有讲究的。按照规范,Source 应该按电压从低到高排列。但我在项目中遇到过某家芯片厂商的固件,它把 20V 的 PDO 放在了最前面。结果呢?某些 Sink 端直接选了第一个 PDO,导致设备烧了。嗯,这就是不按规范来的后果。

4.1.2 功率广播的时序要求

Source 不能一直发 Source_Capabilities,它有严格的时序控制:

  • 上电后 250ms 内必须发出第一条 Source_Capabilities
  • 每次发送后,等待 Sink 回复 GoodCRC
  • 如果 Sink 回复了 Request 消息,Source 要在 15ms 内回复 Accept
  • 如果 Sink 没回复,Source 可以重发,但重发次数有限制

我曾经踩过的坑:有一次调试,Source 端发送 Source_Capabilities 后,Sink 端一直没反应。我查了半天,发现是 Source 端的 CC 线路上有个 10kΩ 下拉电阻焊错了。PD 协议对 CC 线路的阻抗匹配要求极高,稍微偏差一点就会导致通信失败。

4.2 Sink 端的功率请求流程

Sink 端收到 Source_Capabilities 后,就要开始「讨价还价」了。它需要从 Source 提供的 PDO 列表里选一个,然后发送 Request 消息。

4.2.1 请求消息(Request)的结构

Request 消息里包含一个 RDO(Request Data Object),它告诉 Source:

  • 我选哪个 PDO(通过 Object Position 字段指定)
  • 我要多少电流(可以小于 PDO 里标称的最大电流)
  • 我要不要支持能力不匹配(Capability Mismatch)
  • 我要不要开启 USB 通信(USB Communications Capable)
// 伪代码示例:Sink 发送的 Request 消息
RDO:
  Object Position: 3 (选择第3个 PDO,即 15V @ 3A)
  Operating Current: 2000mA (实际只需要 2A)
  Max Current: 3000mA (最大支持 3A)
  Capability Mismatch: 0 (能力匹配)
  USB Communications Capable: 1 (支持 USB 通信)

我个人习惯把 Sink 的请求策略分为三种:

策略类型 描述 适用场景
最大功率策略 直接选电压最高、电流最大的 PDO 快充场景,比如手机充电
固定电压策略 只选某个特定电压的 PDO 设备有电压要求,比如 12V 风扇
协商策略 根据当前负载动态选择 复杂系统,比如笔记本同时充电和运行

4.2.2 功率协商的完整流程

一个完整的功率协商流程是这样的:

  1. Source 发送 Source_Capabilities:亮出家底
  2. Sink 回复 GoodCRC:确认收到
  3. Sink 发送 Request:提出需求
  4. Source 回复 Accept:同意请求
  5. Source 切换电源:调整电压/电流到新值
  6. Source 发送 PS_RDY:告诉 Sink 电源已就绪
  7. Sink 回复 GoodCRC:确认收到

这里有个容易忽略的点:Source 切换电源是需要时间的。比如从 5V 切换到 20V,电源芯片需要时间升压。规范要求 Source 在收到 Accept 后的 15ms 内完成切换并发送 PS_RDY。如果超时,Sink 会认为协商失败,重新开始流程。

我的经验:在调试 Sink 端时,我建议你在 Request 消息里把 Capability Mismatch 标志位设成 1,然后观察 Source 的反应。有些 Source 会直接拒绝,有些会尝试协商。这个测试能帮你判断 Source 端的兼容性。

4.3 角色切换与数据角色交换

角色切换,说白了就是 Source 和 Sink 互换身份。这在 USB-C 的生态里非常常见。

4.3.1 电源角色交换(Power Role Swap)

电源角色交换是指 Source 变成 Sink,Sink 变成 Source。这个过程的触发方式有两种:

  • DR_Swap 消息:由当前 Source 发起,询问 Sink 是否愿意交换角色
  • PR_Swap 消息:由当前 Sink 发起,请求成为 Source

交换流程大致如下:

// 电源角色交换流程示例
1. Source 发送 PR_Swap 消息
2. Sink 回复 Accept
3. Source 关闭 VBUS(电压降到 0V)
4. Sink 开启 VBUS(电压升到目标值)
5. Sink 发送 PS_RDY
6. 角色交换完成

你想想看,这个过程中最危险的是什么?是 VBUS 切换的瞬间。如果 Source 还没完全关闭 VBUS,Sink 就开始输出,两个电源就会「打架」。我在项目中就遇到过这种情况,结果 VBUS 上出现了 30V 的尖峰,直接把保护芯片打坏了。

避坑指南:我曾经在调试一个双角色设备时,发现角色交换后 Sink 端无法正常充电。查了三天,最后发现是 Sink 端的 VBUS 放电电阻没接。角色交换后,Sink 变成了 Source,但它的 VBUS 上还挂着之前的负载,导致电压拉不上去。记住:角色交换后,新的 Source 必须先断开自己的负载,再开启 VBUS。

4.3.2 数据角色交换(Data Role Swap)

数据角色交换和电源角色交换是独立的。数据角色指的是 DFP(下行端口,类似 Host)和 UFP(上行端口,类似 Device)。

举个例子:你用一个支持 OTG 的手机连接一个 U 盘。手机是 UFP(Device),U 盘是 DFP(Host)。但手机想读取 U 盘里的数据,怎么办?它需要发起数据角色交换,让自己变成 DFP,U 盘变成 UFP。

数据角色交换的流程:

  1. 当前 UFP 发送 DR_Swap 消息
  2. 当前 DFP 回复 Accept
  3. 双方交换数据角色
  4. 重新枚举 USB 总线

这里要注意:数据角色交换不会影响电源角色。也就是说,手机可以同时是 Source(供电方)和 UFP(数据设备),也可以同时是 Sink(受电方)和 DFP(数据主机)。这两个角色是正交的。

4.3.3 角色交换的时序要求

角色交换对时序要求非常严格:

阶段 最大时间 说明
发送 PR_Swap 到收到 Accept 15ms 超时则重试或放弃
关闭 VBUS 20ms 电压降到 0.8V 以下
开启 VBUS 20ms 电压升到目标值
发送 PS_RDY 15ms 从开启 VBUS 完成开始计时

嗯,这里要特别提醒:关闭 VBUS 的时间要求比开启更严格。因为如果关闭太慢,新的 Source 开启 VBUS 时就会产生冲突。我见过一个设计,它的 VBUS 放电回路用了 100kΩ 的电阻,结果放电时间长达 50ms,远远超过了规范要求。后来改成了 10kΩ,问题才解决。

小结

这一讲的内容,说白了就是三件事:

  • Source 端:通过 Source_Capabilities 广播自己的供电能力,PDO 的顺序和内容都有讲究
  • Sink 端:通过 Request 消息提出自己的需求,策略选择直接影响充电效率
  • 角色切换:电源角色和数据角色可以独立交换,但时序要求严格,稍有不慎就会出问题

下一讲,我们会深入 PD 协议的状态机,看看这些消息是如何在硬件层面流转的。到时候我会分享一个我调试过的实际案例,保证让你印象深刻。