第2章:协商流程拆解——Source/Sink角色、VDM消息、电力协商时序

PD协商,说白了就是供电方和用电方之间的一场“谈判”。

我刚开始接触PD时,觉得USB Type-C只是正反插方便,没想到背后还有这么一套复杂的握手流程。如果你在项目中遇到了协商超时,那八成是对这个流程的某个环节理解不到位。今天我就带你把整个流程拆开,看看每个节点都在做什么。

2.1 Source与Sink:谁说了算?

在PD协议里,角色很清晰。

  • Source:供电方。通常是充电器、扩展坞、或者支持PD输出的笔记本。
  • Sink:用电方。手机、平板、或者是需要充电的笔记本。

你想想看,一个协议里总得有个主控方吧?PD里,Source就是那个主控方。它负责发出协商邀约,决定要不要给电、给多少电。

我建议你在定位问题时,先确认一下双方的角色。如果Source没检测到Sink,或者Sink没正确回应,那后面所有的协商都是白搭。

关键点:Source通过CC引脚检测Sink的存在,并检测Ra电阻(通常为1kΩ)来确认Sink有PD通信能力。

2.2 VDM消息:协商的“语言”

协商不是瞎聊,得有共同语言。PD协议里,双方通过VDM(Vendor Defined Message)和标准数据消息来沟通。

这里面有一种消息特别重要——Source Capabilities。Source会通过这个消息告诉Sink:“我能提供的电压和电流有这几档,你选吧。”

  • Source Capabilities:Source定期广播。包含PDO(Power Data Object),比如5V/3A、9V/3A、15V/3A等。
  • Request:Sink回复Source,表明自己选择哪一档。
  • Accept:Source同意切换。
  • PS_RDY:Source完成电压切换,告诉Sink“可以正常用电了”。

避坑指南:我曾经遇到过一个项目,Sink端总是超时。最后发现,Source发Capabilities时,Sink的协议栈在处理某个自定义VDM时卡住了,没及时回复Request。所以,如果你看到协商卡在某个点上,先检查一下Sink的协议栈是不是在忙于处理其他消息。

2.3 电力协商时序:时间就是生命

PD协议对时序要求非常严格。Source发完Capabilities后,如果Sink没有在规定时间内回复,Source就会认为协商失败,或者重复发送。

时序节点 描述 超时时间
tSrcSink Source等待Sink响应Request消息 24ms + 240μs
tSinkTx Sink等待Source回复Accept/Reject 4.1ms – 5ms
tPSTransition Source切换电压并发出PS_RDY 12ms – 145ms
tSenderResponse 收到Request后,Source必须在规定时间内回复 2ms – 26.8ms

嗯,这里要注意:很多超时问题都出在tSinkTx这个时间窗口。Sink端如果有大中断处理,或者MCU主频较低,很容易错过这个时间窗口。

// 伪代码示例:Sink端接收Source Capabilities后,发送Request
function handleSourceCapabilities(pdoList):
    // 选择最高电压档
    selectedPdo = selectBestPdo(pdoList)
    if selectedPdo is not None:
        sendRequest(selectedPdo)
        startTimer(tSinkTx) // 4.1ms ~ 5ms
    else:
        sendHardReset()
    // 等待PS_RDY

警告:不要在这个时序窗口里做功耗计算或者长循环操作。我曾经见过一个团队,在接收到Capabilities后,先计算了电池电量再去发起Request,结果直接超时。正确的做法是:收到Capabilities后立刻复用预设的策略,后续再用异步方式处理电量计算。

2.4 完整协商时序图

我把整个流程画出来了。你看一下,应该能直观理解Source和Sink是怎么一步步握手成功的。

PD协商时序图 PD协商时序图(Source → Sink) Source (供电方) Sink (用电方) Source Capabilities (PDO列表) 解析PDO并决策 Request (选择档位) Accept / Reject 电压切换 (tPSTransition) PS_RDY (电源就绪) 正常供电 tSrcSink (≤24ms) tSinkTx (4.1ms~5ms) tSenderResponse (2ms~26.8ms) tPSTransition (12ms~145ms) 时序关键提醒 每一个步骤都有严格超时限制。Sink处理Request阶段最容易被忽略, 建议在协议栈中设置中断优先级,确保Request能及时发出。

2.5 实际项目中的常见超时点

我复盘过好几个PD超时项目,总结下来,最常见的坑就这几个:

  1. Sink端没响应Source Capabilities:CC引脚检测失败,或者Sink协议栈没初始化好。
  2. Request发送太慢:Sink在解析PDO时耗时太多,超过了tSinkTx。
  3. Source没收到Accept/Reject的超时:常见于线缆质量不好,或者Source端的接收中断被更高优先级任务抢占。
  4. 电压切换超时:Source端电源芯片响应慢,或者负载电流导致的电压调节滞后。

个人经验:定位问题的时候,我习惯先在Source端抓CC线上的BMC编码信号。用逻辑分析仪看波形,一眼就能看出是哪个消息没回应。比单纯看代码日志快多了。

理解清楚Source/Sink的角色和时序窗口,是定位协商超时问题的基本功。你想想看,如果连谁先说话、什么时候回话都不知道,那排查起来岂不是大海捞针?