做电源和嵌入式这些年,USB PD协议算是我调试过最需要耐心、也最容易出惊喜的协议之一。很多人一听到“USB PD”,第一反应就是“快充”,然后就把Type-C接口和PD协议当成一回事,结果调板子的时候对着一堆报文发懵。实际上USB PD(USB Power Delivery)是一套完整的供电协商协议,它跑在Type-C的CC线上,决定的是“谁供电、供几伏、供几安、什么时候切、异常了怎么复位”。这篇文章我会把协议的核心机制、协商流程、工程实现和常见坑一次性讲透,适合刚接触Type-C供电的硬件工程师、嵌入式开发者,以及想自己搞PD诱骗取电的电子爱好者。
1. USB PD协议到底在解决什么问题
1.1 从5V到48V:功率红线怎么一步步抬高的
先聊个背景。在Type-C出现之前,USB接口的供电能力非常固定:USB 2.0时代是5V/0.5A,也就是2.5W;USB 3.0把电流提到0.9A,也就4.5W。这个功率给个U盘、键鼠绰绰有余,但想给笔记本充电,连门槛都摸不到。后来各家厂商开始用私有协议硬拔电流,比如通过D+/D-上的电压组合告诉充电器“我要高压”,这才有了早期一堆互不兼容的快充方案。
USB PD的思路完全不同:它不靠D+/D-上的模拟电平“约暗号”,而是直接在Type-C接口的CC引脚上建立一套数字通信协议,让供电方Source和受电方Sink互相报出能力、协商出最合适的电压电流组合。PD 2.0把上限做到20V/5A,也就是100W;PD 3.1又增加了28V、36V、48V三档扩展功率范围,最高能到240W。你可以把传统USB比作“只有一档的公交车”,而PD是“可变速的出租车”——你要到哪个电压,广播一下自己的需求,合适的车就过来载你。
所以USB PD解决的核心问题不是“快”,而是“功率动态协商”。同一个USB-C口,可以为耳机输出5V/1A,为手机输出9V/2A,为显示器输出20V/5A,甚至给48V的电动工具供电,全看双方怎么谈。这套机制把充电从“一插定音”变成了“按需供给”。
1.2 Type-C物理基础:CC线上的“握手礼仪”与上下拉电阻
要理解PD协议,必须先搞清楚CC线。Type-C接口里有一对非常重要的引脚叫CC1和CC2,全称是Configuration Channel。别小看这两根线,它们承担了三件事:连接检测、方向识别、PD通信。
初始连接时,Source端(比如充电器)会在CC1和CC2上各放一个上拉电阻Rp,Sink端(比如手机)会在CC1和CC2上各放一个5.1kΩ的下拉电阻Rd。当充电器和手机用C-C线连起来后,Source侧一开始不知道线材另一头插的是哪个方向,它会在两个CC脚上分别测电压:你想想,一个上拉电阻和一个5.1kΩ的下拉电阻串联分压,Source的CC引脚会被拉到一个较低的电压。Source根据“哪一路CC被拉低了”就能判断出接口方向,同时知道“有个Sink接上来了”。
这里有个新手很容易搞反的点:Rp的方向和阻值不是随便定的。Rp取56kΩ表示默认USB电流能力,22kΩ表示1.5A,10kΩ表示3A,这个电流能力是Type-C基础充电协议里的,跟PD协商没直接关系,但会影响连接的初始判定。而Sink端的Rd几乎总是5.1kΩ,别去动它。我自己调试时见过有人把Sink的CC下拉电阻焊成了10kΩ,结果Source怎么都识别不到设备,折腾半天查出来就是一颗电阻的问题。
当设备接入后,PD的BMC信号就在这根CC线上传输,直流电平负责“证明我还在这”,叠加的跳变沿负责“我要跟你说话”。顺便说一句,线缆里的E-Marker芯片也是通过CC线通信的,它会用内部Ra电阻来标记自己是3A线还是5A线,所以“随便找根线就能跑满100W”这事在PD生态里是不成立的,后面我再细说。
2. PD协议的消息机制与协商流程
2.1 消息怎么在空中跑:BMC编码、SOP和CRC
PD物理层采用的是BMC(双相标记编码,Bi-Phase Mark Coding)编码。你不用记太深,只要把它理解成一种“自带时钟”的传输方式:每一个bit周期的中间必然有一次电平翻转,这个翻转用来给接收端恢复时钟;如果这个bit本身是1,那比特周期开始时还会多翻转一次;是0则没有额外翻转。接收端靠中间跳变就能把数据解出来,不需要单独的时钟线。这好比是摩斯电码里的“点”和“划”都用固定节奏,区别只在细节上。
编码之后,消息还要打包。一条完整的PD数据包由SOP起始标志、消息头、数据体和CRC32校验组成。SOP也有讲究:SOP用于Source和Sink之间的端到端通信;SOP'和SOP''则是专门和线缆里的E-Marker芯片通信用的。封装上有个细节很关键,每次发消息都带消息ID,接收方收到消息之后必须回一个GoodCRC报文,发送方确认收到GoodCRC后这个事务才算完成。如果你没收到GoodCRC,就要用相同的消息ID重新发送。这一套机制保证了在CC线这样一条单线半双工的信道上,报文不会丢,也不会因为插拔瞬间的毛刺导致两端认知错位。
实际工程中,很多人觉得BMC解码是协议栈里最麻烦的部分,因为CC线上的直流偏置会被上下拉电阻设定在一个电平,而BMC信号是叠加上去的毫伏级跳变。如果你直接用示波器的普通探头去抓,看到的可能是一坨噪声。正确做法是使用PD控制器芯片(比如FUSB302这类物理层芯片)把BMC的收发解调都交给硬件,MCU只负责解析已经解好的数据包。别试图用单片机GPIO去裸采BMC信号,除非你只是想验证一下波形原理,否则调试周期会让你怀疑人生。
2.2 一次完整的“点单”:从Source_Capabilities到PS_RDY
PD协商的核心流程可以类比成去餐厅点菜。插上设备后,Source端先输出一个安全的5V(规范里叫vSafe5V),然后它会主动发送一条Source_Capabilities消息,相当于把菜单递给你:“我能提供这些电压电流组合,你挑一个。”这条消息里包含一个或多个PDO(Power Data Object),每个PDO描述一个供电档位。
Sink收到这个菜单之后,会从里面挑一个符合自己需求的PDO,然后回一条Request消息,相当于“我要这个套餐”。这条Request消息里带有一个很重要的字段叫Object Position,它指明你选了菜单上的第几项;同时还会带上你实际需要的电流、请求的电压、是否需要不支持就回退等信息。
Source收到Request后,会回Accept、Reject或Wait。如果Accept,Source会开始调整VBUS电压,等电压稳定到目标值后,再给Sink发一条PS_RDY(Power Supply Ready)消息。注意:真正的“换挡”时间点是在PS_RDY之后。Sink在收到PS_RDY前,不能马上按新档位拉大电流,否则很容易把Source的输出打成过流。PS_RDY之后,Sink才可以把背光、充电、电机这些重载逐步打开。
这套流程里有个特别容易被忽略的细节:Source发Source_Capabilities并不是只发一次。在空闲状态下,它会反复广播自己的菜单,尤其是在Sink没有响应的时候。所以做Sink端固件时,不要写“接收一次菜单就死等”,要处理菜单重复到达的情况。我见过有人写Sink逻辑,收到第一份菜单后设置了一个“已初始化”标志,之后就忽略后续菜单,结果在某些充电头上因为时序问题死活稳定不到高压,后来去掉这个标志就好了。
2.3 PDO与RDO的解剖:设备究竟在“选”什么
PDO和RDO这两个缩写,几乎是所有PD调试问题的根源。PDO是Source端的供电能力表述,RDO是Sink端的供电请求表述。PDO分为固定档位、可变档位、电池档位和PPS档位(编程电源档位),每种档位的32位数据格式里,电压和电流的刻度都不一样。比如固定PDO里电压一般是以50mV为单位编码的,电流以10mA为单位编码;而PPS档位里电压最小单位是20mV,电流是50mA。你写程序解析PDO时,一定要先看类型再算数值,别拿一套换算关系套所有档位。
最实用的几个经验:如果你做的是PD诱骗器,就是在没有协议栈的情况下从充电头取电,你主要干的事就是“解析菜单→组RDO→等PS_RDY”。RDO里除了Object Position,还有很多控制位,比如Capability Mismatch标志、GiveBack标志、No Suspend标志等。其中No Suspend标志通常建议置1,表示“我这个Sink不希望你在系统挂起时切断我的电源”,对很多需要持续供电的外设很关键。
另外,别迷信菜单上的最大电流。很多Sink在写Request时会直接把PDO的最大电流作为请求电流,但你要考虑到VBUS走线、接插件、线缆压降。系统里损耗压降一旦超过几百毫伏,实际到设备端的电压就低于PDO标称值,有些敏感的电源管理芯片会触发欠压保护。稳妥的做法是留10%~20%的电流余量,尤其是做便携设备时,别把PD协议协商出来的功率当成“线缆无损的额定额定值”。
3. PPS与PD3.1:协议进阶玩法与场景适配
3.1 PPS可编程电源怎么用,适合什么设备
PPS(Programmable Power Supply)是我个人非常喜欢的一个特性。它和普通PDO最大的区别是:普通PDO是Source先定好一组离散的档位让你选,而PPS允许Sink在一个连续电压区间内任意请求电压。比如某个PPS档位标称3.3V~21V、5A,那么Sink可以精确地请求5.3V、9.6V,甚至每20mV步进往上调。
PPS的价值在于动态调整电压而不需要重新做一次完整的PD协商。很多直接充电方案(比如手机里的电荷泵充电)需要实时根据电池电压调整充电输入电压,让系统效率一直保持在最高点。如果只能用固定档位,电压只能一跳一跳地切,效率和发热都不理想;有了PPS,充电芯片可以像“呼吸”一样平滑调压。
实现上,PPS的Request消息有个特殊字段叫Output Voltage,用于写想要的电压值,同时还可以设置Operating Current。Source收到后如果Accept,就会把VBUS调到这个电压。注意PPS并没有改变整套消息流程,它改变的只是RDO里参数组织方式。调试PPS设备时,记得用逻辑分析仪或协议分析器(支持PD解码的那种)抓一下完整的握手过程,重点看Request里带的电压值是不是符合你的期望。很多时候你以为写对了电压,结果单位弄错了,把20mV当成了50mV的步进,出来的电压差了近一倍。
3.2 PD3.1新增的EPR:28V/36V/48V的生态
PD 3.1把协议的功率上限从100W推到了240W,增加了一个叫EPR(Extended Power Range)的概念。标准功率范围SPR维持在0~100W,EPR则引入了28V、36V、48V三档固定扩展电压,以及一个叫AVS的可调电压档。尤其是48V/5A这个组合,直接把USB-C从“电脑充电口”变成了“万能供电口”,理论上可以为显示器、电动工具、电动自行车电池、小型伺服电机供电。
但EPR不是插上就能用的。它要求充电器、设备、线缆三方面都支持EPR。普通Type-C线如果没有E-Marker,或者E-Marker只支持到SPR,那VBUS最高只敢跑到20V,超过可能烧线。Source在发送扩展消息时,会通过消息里的EPR能力字段询问Sink是否支持EPR,Sink确认支持后,Source才会把电压提到28V以上。整个过程有两个阶段协商,比普通PD复杂一些。
工程上有个建议:现阶段除非你确实需要100W以上的功率,否则别急着上EPR。EPR带来的是高压大电流下的绝缘、散热、线缆认证、EMC等一系列问题,PCB layout时VBUS和CC之间的防护间距、ESD器件耐压这些都要重新评估。我见过有人把20V的电源管理芯片放在48V EPR链路上,一充电就炸管,原因就是没想到充电头会把电压抬到48V。要做EPR产品,先看USB-IF的EPR认证清单,别自己拍脑袋。
4. 实操:选型、调试与一个最小PD Sink的握手过程
4.1 PD控制芯片选型对比与避坑指南
做PD相关的产品,第一个绕不开的问题是:用现成PD芯片还是自己搭协议栈。市面上主流的PD控制芯片大致分三类,选型逻辑完全不同:
自带协议栈的独立PD芯片 ,典型代表是STUSB4500、CYPD3175。这类芯片内部已经把PD的Source/Sink状态机都跑完了,你通过I2C或者引脚配置一下期望的PDO,它自己就能完成协议握手,然后给你输出一个使能信号。STUSB4500是我很推荐给“只是想取电、不想写协议”的人用的,你给它配置好“我想要12V/3A”,它遇到支持12V的充电头就会自己协商,完事之后拉高电源使能引脚。缺点是灵活性差,想现场改电压档位比较麻烦。
物理层芯片+MCU协议栈 ,典型代表是FUSB302。FUSB302只做BMC收发和CRC校验这类物理层工作,协议逻辑要你自己在MCU里跑。好处是灵活,Source、Sink、DRP都能做,还能自己定义行为;坏处是坑多,SM状态机、超时、重发逻辑都得自己维护。如果你要做一个支持PD的HUB或者想深入理解协议,这条路最值得走。
国产协议识别/诱骗芯片 ,比如CH224K、IP2721。这类芯片非常适合DIY取电场景,CH224K价格便宜,通过电阻配置就能选择目标PDO,插上充电头后自动完成请求,输出稳定电压。做移动电源、桌面小供电模块、Type-C转DC口这种项目,用它比用STUSB4500还省事。需要注意某些芯片型号对PDO的响应逻辑比较“死板”,在遇到输出能力很弱的充电头时可能会反复请求失败,选型前最好看下具体型号的兼容性测试报告。
选型块避坑:不要只看“支持PD3.0”这个宣传语。PD3.0和PD3.1、PPS支持与否、是否支持EPR、是否内置VBUS放电、是否支持双角色切换,这些都会影响最终方案。先定应用场景,再选芯片,别反过来。
4.2 用示波器和诱骗芯片验证协议握手
很多新手第一次验证PD协议时,拿个USB转串口模块怼在CC线上,想直接抓包,结果什么都没有。这是因为PD信号是BMC编码、半双工、快速变化的,普通串口根本解不出来。正确的验证路径分两步。
先测物理层。把示波器探头接在CC1或CC2上(挑实际连接的那一路),探头对地,触发模式设置在CC线电压突变。你会看到一串几十毫秒内的快速翻转脉冲,这就是BMC信号。用Score或Read解码,能大致看出SOP、Payload这样的结构。建议探头带宽至少100MHz,否则脉冲边沿被滤平,看起来像噪声。如果CC线上什么都抓不到,先检查上下拉:Source有没有Rp上拉?Sink有没有Rd下拉?线缆是不是有CC通路?
然后测协议层,一个很实用的办法是拿诱骗芯片(比如CH224K)加一个可调直流电子负载。先把CH224K用电阻配置成你要的电压(比如12V),插到充电头上,电子负载慢慢拉电流,同时用万用表盯着VBUS。芯片正常工作时,VBUS会从5V跳到12V,电子负载上电流也能稳定输出。如果它跳不起来,就用示波器看CC线上的BMC波形,确认Source有没有发Source_Capabilities。这个方法比直接抓完整报文快多了,特别适合验证“充电头是不是真的支持这个档位”。
4.3 最小Sink握手流程的伪流程参考
我自己实现过基于FUSB302的最简Sink握手,剥离所有状态机细节后,核心步骤大概是这样的顺序,供你自己搭建时参考:
- 初始化I2C,配置FUSB302进入Sink模式,让芯片把CC脚配置成Rd下拉,同时开启CC检测中断。
- 等待CC检测中断,读取芯片CC状态寄存器,确认是CC1还是CC2连着。
- 接收Source_Capabilities包:芯片会把解调好的报文放进FIFO,MCU读FIFO,先校验SOP类型和CRC,再解析出PDO列表。
- 从头到尾遍历PDO,挑一个满足自己电压、电流需求的档位,记录Object Position。
- 组Request消息(也就是RDO),填入Object Position、请求电流、No Suspend标志等字段,写进FIFO,触发发送。
- 等待接收端回GoodCRC,事务完成;接着准备接收Accept或Reject。如果收到Reject,则换一个PDO再发Request。
- 收到Accept后,不要立刻拉大负载;继续等待PS_RDY消息,等PS_RDY到来后,再把负载逐渐加大。
这条路径最麻烦的是超时处理,每个状态都要有超时退出机制。PD规范里大量时间参数是毫秒级的,比如Sink等待菜单超时、等待Accept超时、等待PS_RDY超时。如果固件里少写一个超时,设备在遇到不支持的充电头时就会卡死成“假死”。我建议无论用不用官方协议栈,都先画一张简单的状态转移表,把所有超时的出口标出来,然后逐个实现,这样调试时能少掉不少头发。
5. 常见问题与排查技巧实录
5.1 插上只有5V不握手:先别怪芯片
“插上充电头,设备只有5V,没有触发快充”是最常见的反馈。遇到这种情况,90%的人第一反应是“协议芯片坏了”或者“充电头不兼容”,但根据我的经验,最先该查的是线缆、CC上下拉、板子供电这三件事。
线缆排查最简单:换一根质量过关的C-to-C线试试。很多C-to-A线或者所谓“快充线”根本没有CC引脚,或者CC引脚被短接到地,这种情况下Source永远检测不到Sink,再好的PD协议栈也白搭。如果你做的是纯Sink设备,把CC1和CC2都接上Rd下拉,不要只接一路——虽然只接一路在某些单方向Type-C插头上也能工作,但会严重影响兼容性,正反插只有一边能用。
其次是上下拉电阻:Source的Rp和Sink的Rd要严格按Type-C规范选,别贪便宜用可调电阻去“凑电压”。我见过有人把Source端的Rp做成了10kΩ想提高初始电流能力,结果分压后CC电压超出了Sink的判定阈值,设备误以为自己没被识别。最后是板子供电:很多开发板(比如STM32的核心板)的USB-C口是直接连到板上5V LDO的,你以为插的是PD充电头,其实CC脚悬空,根本没有协商发生。这种板子想测PD,必须先断开自带的5V通路,把外部供电改到VBUS上。
5.2 热插拔、Hard Reset和VBUS安全要注意的坑
PD协议有一个安全网叫Hard Reset。当通信持续异常、出现过压、或者某一端觉得“没法聊了”的时候,发送方会在CC线上给出一个特殊的Hard Reset信号,通知对方“我要把VBUS降到安全电压重新开始”。收到Hard Reset的设备,必须立刻把VBUS放电到安全阈值以下,然后重新进入初始状态。这是保护机制,但也会给调试带来困扰。
我踩过的一个具体坑:某个Sink设备在20V/5A下工作,Source端因为某种原因触发Hard Reset,把VBUS切断,但Sink的VBUS输入端有大容量电容,还来不及放电,芯片继续以20V状态运行,结果Source重新输出5V时,两者压差瞬间过大,把Sink板上的MOSFET击穿了。解决办法是在Sink的VBUS入口处加一个可控的放电通路(一个MOSFET加泄放电阻),或者在收到Hard Reset时先把负载断开到零,让VBUS尽快放到5V安全范围。这个细节在很多参考设计里都有,但做的产品验证时往往被忽略。
关于热插拔,还有一点:Sink在拔掉时不能把VBUS上的大电容能量全部瞬间灌到CC线上的信号回路里。布局上,VBUS和CC之间的环路要小,ESD防护要靠近连接器放置。我在量产项目中吃过亏,拔插几百次之后,CC线上ESD管被反复打坏,表现为“用一段时间后只能5V不能快充”,换掉ESD管就好了。原因就是VCONN和VBUS之间的回路上寄生了比较高的工作尖峰。
5.3 从PD到QC、UFCS:兼容性该怎么看
做产品时常常被问“你们支持QC吗支持UFCS吗”。我的理解是,PD协议不是唯一一款快充协议,但它已经成为Type-C生态的“普通话”。高通的QC4、QC4+实际上就是把PD协议里的PPS能力拿过去作为握手基础,所以支持QC4+的充电头通常会兼容PD。UFCS是另一套国内主导的融合快充标准,它的物理层、协议层跟PD完全不同,芯片选型时要注意同时支持两种协议的方案。
在硬件层面,如果设计里只需要取电,强烈建议优先选“PD为主、其他协议顺带支持”的芯片路线,比如某些国产协议芯片同时内置PD、QC、华为SCP、VOOC等识别逻辑。但要注意:协议兼容和线缆兼容是两回事。PD协议协商成功只代表芯片说了话,之后VBUS上能不能稳定输出还取决于电源设计、线缆压降、负载响应。别把“支持PD”当成“一定能跑满功率”。我做移动电源时就碰到过,充电头能出20V/5A,但线缆是3A的E-Marker线,恳求到5A之后线材发热吓人,后来加了电流侦测逻辑把上限限制在3A才算稳。
6. 除了设备充电,USB PD还能这么玩
前面讲的都是把PD当成“充电协议”来看,但它的应用场景其实比我刚开始做时想象得宽得多。比如用PD做可调电源:拿一个PD诱骗器接上充电头,通过配置PPS档位,你能得到一路最大电流巨大、可动态调压的输入源。很多人拿它来做桌面电子负载的前端、电池化成设备的前端、或者给模型车充电,比传统线性电源体积小很多,效率也高。
另一个很有意思的方向是用PD做“单线供电+通信”:Type-C除了VBUS和GND,还有CC线可以做协议通道,D+/D-还能做USB 2.0数据。这意味着一个C口可以同时给传感器供电、读取传感器数据、还能远程控制电源通断。很多工业传感器、便携仪表、物联网网关已经开始用这种方案,省掉独立的DC电源座和RS232/RS485线缆,整机防水和防呆性都好很多。
最后再分享一个小技巧:如果你不确定手里的充电头支持哪些PDO,与其上网查参数,不如自己做一个带PD诱骗能力的探头——把CH224K配好一个可调电压,直接插上充电头,在CC线上串一个很小的采样电阻,用示波器对比VBUS电压和CC波形,基本能把这个充电头的菜单摸个七七八八。这个工具我已经用了几年,比某些商业协议分析仪还顺手。PD协议本身并不难,难的是把规范里的状态机、超时、安全机制都理解到位,再通过实打实的波形去验证。你只要把上面这几条链路走通一次,以后再遇到Type-C相关的供电问题,基本就能一眼看穿症结所在。
425



被折叠的 条评论
为什么被折叠?



