嵌入式工程师必知:从BC1.2到PD3.1的充电协议演进与实战
2026/9/19 17:48:49 网站建设 项目流程

做嵌入式这些年,我见过太多同行在充电协议上栽跟头。最常见的一幕:自己做的板子插上充电器,屏幕上明明显示“正在充电”,电流却死活上不去;或者干脆充不进去,翻手册、量波形折腾一下午,最后发现是CC引脚上少焊了一个5.1k的电阻。充电协议这个东西,表面上看是手机厂商和充电器厂商之间的博弈,可真到了嵌入式产品开发里,它就是横在硬件、固件和电源设计之间绕不开的一道坎。

这篇帖子我想把嵌入式视角下的充电协议讲透:从最早的BC1.2,到高通的QC2.0、QC3.0,再到今天几乎所有Type-C设备都绕不开的PD3.1,把技术演进脉络、协议协商的核心原理,以及我在实际项目中用到的硬件选型、状态机设计、调试方法和踩坑经验,一次性掰开揉碎放在一起说。不管你是刚入门,想搞明白PD诱骗器是怎么回事,还是已经在做带PD sink功能的量产板,这篇应该都能给你点参考。

1. 为什么嵌入式工程师必须搞懂充电协议

先说说我自己的经历。前几年做一款工业手持设备,整机功耗峰值能做到40W,按道理用一个65W的氮化镓充电器供电绰绰有余。结果设备拿到手,插上充电器只能跑5V/3A,开机没几分钟电池就往下掉。排查了半天,问题不在电源适配器,而在我们自己设备的Type-C口上——它压根没有实现PD协商逻辑,默认只把自己当成一个5V的小负载,65W的充电器也只能按最保守的档位来喂它。这个场景太典型了,嵌入式产品只要带Type-C口,不管是充电、供电还是数据传输,充电协议都躲不掉。

那充电协议到底在解决什么问题?一句话:解决“电源能给多少”和“设备想要多少”之间的匹配。早期USB时代,接口标准划定的供电能力很死板,USB 2.0口默认就是5V/500mA,谁来了都一样。后来电池越做越大,快充需求爆发,电源适配器的能力也越来越强,如果不协商清楚,要么设备只能龟速充电,要么充电器盲目高压输出把设备烧掉。于是就有了各种充电协议,本质上都是一套“握手+协商”的机制,只是实现方式不同。

对嵌入式工程师来说,理解充电协议不仅仅是为了“让电池充快点”。你还得处理这些场景:设备插入之后怎么识别充电器类型?怎么在上电瞬间避免拉载导致电压跌落?怎么在不支持快充的普通口上安全降级?怎么做过压、过流保护?这些全部建立在协议理解的基础上。我经常和团队里新人说一句话:USB供电这块,看得见的是Type-C接口那24个引脚,看不见的是引脚上跑的各种时序和状态机,后者才是真正决定产品体验的东西。

按我的经验,嵌入式产品里和充电协议打交道的常见形态有三种。第一种是纯sink设备,比如电动牙刷、TWS耳机充电仓、手持扫码枪,只管从适配器取电,要做的是把“请求多少伏、多少安”写对。第二种是source设备,比如充电宝、多口桌面充,自己作为供电方,要能正确广播自己的能力并响应设备的请求。第三种是DRP双角色设备,比如笔记本、平板,既可能当source给别人供电,也可能当sink从适配器取电,角色切换逻辑最复杂。绝大多数入门者接触的是第一种,但理解了第一种,后面两种学起来就是顺水推舟的事。

2. 演进路线:从BC1.2到QC再到PD的博弈

充电协议不是一天建成的。回看这十几年的演进,其实就是一条“从无到有、从私有到公开、从粗放到精细”的路,每一步都被当时的物理限制和市场需求推着走。

2.1 BC1.2:USB充电的第一套官方规矩

在BC1.2出现之前,USB充电基本处于“野蛮生长”状态。USB 2.0规范只定义了500mA的标准电流,却没有规定“充电”这件事怎么做。于是各家充电器开始用私有方案,有的在D+和D-之间加电阻,有的直接短路,设备端识别不了充电器到底能供多大电流,所以只能按500mA的保守值来充,一部手机充五六个小时很正常。

BC1.2全称Battery Charging Specification 1.2,是USB-IF在2010年前后推出的第一套专门针对充电的标准。它核心做了一件事:用D+和D-两根数据线上的电气状态来区分端口类型,让设备能判断自己插到了什么上面。

我整理了个表,这个到现在还有参考意义:

端口类型D+/D-状态最大供电能力典型场景
SDP(标准下行端口)正常USB数据差分信号500mA电脑USB口
CDP(充电下行端口)数据通信正常,D+/D-可被设备短接触发识别1500mA支持BC1.2的电脑口
DCP(专用充电端口)D+与D-直接短接1500mA以上各类充电器、充电宝

BC1.2的识别机制很朴素:设备检测到D+和D-短接,就认为自己是插在了DCP上,可以拉比较大电流;如果D+和D-有差分信号,就判定为SDP。这套逻辑虽然简陋,但直到今天,很多嵌入式项目的充电器类型识别模块还在沿用同样的思想,只不过把检测方式换成了现代一点的ADC采样和比较器。

BC1.2的局限很明显,1.5A封顶,功率上限7.5W左右,对后来动辄四五千毫安时的电池来说,杯水车薪。所以它只能算是个序幕,真正的快充大战是私有协议开启的。

2.2 QC 2.0:D+/D-高低电平换来的固定档位

高通在2013年前后推出Quick Charge 2.0,算是把快充这个概念彻底点燃了。它的思路非常巧妙:不用额外加引脚,还是复用USB数据线D+和D-,只不过传输的不再是数据,而是几个电压档位的组合编码。

QC 2.0分Class A和Class B两种规格。Class A支持5V/9V/12V,Class B在此基础上追加了20V。设备端通过D+/D-上施加不同的直流电平组合,告诉充电器“我要哪个档位”。具体常见的对应关系是这样的:

请求电压D+电平D-电平
5V0.6V0.6V
9V3.3V0.6V
12V0.6V3.3V
20V3.3V3.3V

这组电平组合在很多快充协议识别芯片的datasheet里都能看到,也是我最早在嵌入式里手写协议识别时参考过的表。实现方法很简单:用GPIO配合DAC,或者干脆用PWM滤波产生直流电平,再加两路ADC去读取充电器端D+/D-上的反馈。握手时序是:设备先把D+拉低到0.6V左右,充电器检测到后会把D+/D-短接,随后设备再根据自己需要的电压给D+和D-施加对应电平,充电器据此调整VBUS。

QC 2.0的缺点也明显,它是跳变式的。请求9V,VBUS就直接从5V跳到9V,中间没有过渡。对电源路径上的电容和负载来说,这就是一次不小的冲击,搞不好就会导致后级保护。对于嵌入式设备来说,如果要做QC 2.0兼容,硬件上必须考虑耐压和浪涌,软件上也得在切换瞬间做好负载断开,否则很容易翻车。

2.3 QC 3.0:连续可调才是快充的正确姿势

QC 2.0固定档位虽然粗暴有效,但实际充电场景中,电池电压是逐渐升高的,如果只能在12V和9V之间二选一,那效率就不是最优。于是高通在QC 3.0里引入了INOV算法,全称Intelligent Negotiation for Optimal Voltage,核心变化就是把电压从固定档位变成了以200mV为步进的连续调整。

QC 3.0的物理层仍然复用D+/D-,但信息传递方式从“电平组合”换成了“脉冲序列”。设备端在D+上发出连续的脉冲信号,每个脉冲代表一次电压调整请求,通过脉冲周期和数量的变化告诉充电器升压还是降压,目标电压从3.6V到20V之间以200mV粒度连续可调。这个设计对嵌入手写实现来说比QC 2.0稍微麻烦一点,因为要靠GPIO中断或者定时器输入捕获去精确测量脉冲宽度,好在大部分场景下我们不需要自己解这个协议——直接用现成的识别芯片更省事。

INOV的价值在于,充电器可以贴着电池的当前电压输出,把转换损耗压到最低。这也是为什么QC 3.0在很长一段时间里都是安卓中高端手机的标配。不过说到底,QC系列再成功也是高通的私有协议,它要照顾的只是高通芯片平台的手机。对整个行业来说,接口和协议碎片化的矛盾并没有解决,Type-C时代需要一个新的、公开的、智能的协议站出来,这个位置后来被USB PD占据。

2.4 从QC 4+到USB PD:私有协议最终被收编

有意思的是,高通自己最后也“投诚”了。QC 4和QC 4+开始全面兼容USB PD协议,核心快充逻辑走PD,D+/D-上只保留一部分兼容性识别。原因很简单:Type-C口成为统一接口之后,USB PD有USB-IF在做标准制定,有完整的认证体系和文档,如果高通继续在D+/D-上搞私有协议,反而会成为生态的阻碍。

对嵌入式开发者来说,PD协议的公开是一大利好。QC协议虽然也能从各种逆向资料里查到,但毕竟是非公开的,很多细节摸不准。PD的协议文档、状态机、消息定义全部公开,USB-IF官网上就能下到,这意味着我们可以正大光明地在自己的MCU上实现一套PD通信逻辑,而不是只能依赖专用芯片。后面我会详细拆PD3.1,这是现在所有Type-C设备都必须具备的基础能力。

3. PD 3.1核心机制深度拆解

到了PD这一代,充电协议终于从“模拟信号猜哑谜”进化成了“数字通信对话”。PD运行在Type-C物理层之上,有一套完整的消息机制、状态机和电源协商流程。PD 3.0时代定义了100W的供电上限,PD 3.1则把上限推到了240W,同时引入了更灵活的电压调度方式。

3.1 CC线:一根线扛起连接检测和通信

Type-C接口里CC(Configuration Channel)引脚是个神奇的存在。它只需要一根物理线,却干了三件事:检测连接是否建立、判断设备角色和方向、承载PD通信数据。这也是很多新手最懵的地方——怎么一根线又能检测又能通信?

先讲物理层的静态偏置。source设备(供电方)会在CC1和CC2上通过上拉电阻Rp供电,sink设备(受电方)则会在CC1和CC2上接下拉电阻Rd。当Type-C公头插入母座时,source端通过检测CC1和CC2上不同的电压状态,就能判断插没插、正着插还是反着插。Rd的典型值是5.1kΩ,Rp的值则暗示了source的电流能力:56kΩ对应默认USB电流,22kΩ左右对应1.5A能力,10kΩ左右对应3A能力。这个细节在做产品时很关键,别人用充电器5V/3A充你的设备,你能不能拉3A,取决于你有没有正确设置Rp或者跟source协商,而不是随便接个电容电阻就完事。

PD数据通信也是在CC线上跑的,和静态电平共存的方式是交流叠加:PD PHY在CC线上叠加BMC编码的高频信号,接收端用电容耦合把交流分量取出来。BMC编码叫Bi-Phase Mark Code,和曼彻斯特编码是近亲,基本思路是每个bit单元开始时电平必翻转,bit位为1时在中间再翻转一次,bit为0时中间不翻转。PD 3.0里的BMC数据速率是300kbps左右,虽然不高,但对充电协商这种小数据量场景完全够用。

另外还有一个细节:带E-mark芯片的线缆会在CC引脚上挂一个特殊的Ra电阻,source检测到Ra而不是Rd,就知道插入的是一根有电子标记的线缆,后续可以通过SOP'通信去读取线缆的能力信息,比如是否支持5A电流、是否支持EPR电压。这个在线缆合格的产品上通常不会出问题,但如果你遇到“明明充电器支持100W,插了线却跑不满”的怪问题,有很大概率就是卡在E-mark线缆识别这一步。

3.2 PDO、消息与协商流程:一次完整的心跳

PD通信的消息分为两大类型:控制消息(Control Message)和数据消息(Data Message)。控制消息没有数据载荷,只负责拍板,比如GoodCRC、Accept、Reject、Wait、PS_RDY、Get_Source_Cap等。数据消息则带一段payload,最常见的是Source_Capabilities和Request。

把一次完整的PD协商流程走一遍,大概是这样的:

  1. Source设备上电后,周期性在CC线上广播Source_Capabilities消息,里面是一串PDO(Power Data Object,功率数据对象)。一个PDO就代表一组电源能力,比如“5V/3A”“9V/3A”“15V/3A”“20V/5A”等,每个PDO是一个32位的数据结构,里面用固定字段表示电压值、电流值和类型。
  2. Sink设备收到后,先回一条GoodCRC表示确认收到,然后从PDO列表里挑一个最符合自己需求的档位,发送Request消息,里面指定目标PDO的编号和请求电流。
  3. Source收到Request,根据自身状态决定接受还是拒绝,接受就回Accept,拒绝就回Reject或者Wait。
  4. Source在确认接受后,实际去调整VBUS电压,等电压稳定后发送PS_RDY消息。
  5. Sink设备收到PS_RDY,才真正开启大电流拉载。

我之所以强调“收到PS_RDY之后才能拉载”,是因为这个坑太常见了。很多开发者以为发送了Request、收到了Accept,就可以把负载打开了,结果VBUS电压还没稳定,瞬间大电流直接把前级电源拉崩,甚至导致适配器保护重启。PD协议里这个时序设计是有讲究的:Accept只是逻辑上同意,PS_RDY才是物理上就绪的信号。

PDO的类型也值得展开说说。基础的有固定PDO(Fixed PDO)、可变PDO(Variable PDO)、电池PDO(Battery PDO),后来PD 3.0又加入了APDO(Augmented PDO),也就是PPS(Programmable Power Supply)模式。PPS允许sink在3.3V到21V之间以20mV为步进连续请求电压,电流步进50mA,也就是说电压可以“微调”到非常精确的值。这对需要恒压恒流充电的锂电池应用来说是大利好,很多现代快充方案都靠PPS实现精细化充电曲线。

3.3 SPR与EPR:从100W到240W要过哪些坎

PD 3.0定义了SPR(Standard Power Range),电压最高20V,电流最高5A,所以理论上限是100W。这个数字对手机、平板、轻薄本都够用,但到了大功率电动工具、高端游戏本、显示器甚至便携电动车充电场景,100W就显得不够了。PD 3.1在2021年随USB Type-C 2.1规范和USB PD 3.1规范推出,把供电范围扩展到了EPR(Extended Power Range)。

EPR在SPR的基础上增加了三个固定电压档:28V、36V、48V,同样以5A为电流上限,所以功率上限来到了240W。另外EPR还支持AVS(Adjustable Voltage Supply)模式,电压不是固定档位,而是在一个范围内连续可调,比如某个PDO可以声明“20V到48V可调,步进100mV”,sink可以在该范围内自由选择任意电压,灵活性比固定档位高很多。这种模式特别适合那些希望在很宽的输入电压范围内保持高效工作的设备,比如车载逆变器、大型无人机电池充电站。

但是,EPR不是说你充电器支持48V,设备就能直接用。它要求整条链路都支持EPR规格:source端的PD协议控制器要把EPR模式打开,线缆必须是经过EPR认证的E-mark线缆,sink端也要在协议层面声明支持EPR,并且物理层要承受48V的耐压。有一句忠告我每次讲PD都会说:在产品设计阶段,如果打算支持EPR,PCB的爬电距离、电容耐压、MOS管耐压、TVS选型全部得按60V以上设计,千万别只看协议层的电压数字。我见过有人为了省成本只在协议上支持28V,结果一次插拔浪涌就把充电管理芯片打穿的案例,那真是用真金白银买教训。

4. 嵌入式实战:从原理图到协议栈落地

聊完原理,落地才是重头戏。我在实际项目里做PD设备,通常先定角色,再选硬件方案,最后才是写状态机。这节按硬件选型、电路要点、软件逻辑、现成方案四条线来写。

4.1 硬件设计:CC检测、VBUS路径与PHY选型

如果你做的产品是sink端,比如一块电池管理板、一个手持设备底座,硬件上最少需要这几块:

第一,CC引脚下拉电阻。CC1和CC2各接一个5.1kΩ电阻到GND,这是让source识别你为sink的最小必要条件。缺了这两个电阻,source根本不知道有设备连接,VBUS都不会上电。

第二,PD通信PHY。方案分三种:专用PD控制器芯片、带Type-C/PD外设的MCU、用普通MCU加外部模拟电路。我比较常用的是前两种。专用控制器里,NXP的FUSB302是很经典的,I2C接口,内部集成了BMC收发和物理层检测,MCU只负责解析消息和跑状态机;ST的STUSB4500更省事,它直接把sink协商逻辑做在芯片里,上电自己读EEPROM里的配置,自动和source协商出你要的电压,连MCU都省了。带PD外设的MCU,典型代表是STM32G0系列的UCPD外设,直接在MCU内部搞定BMC编解码,省一颗专用芯片,硬件BOM上很漂亮,但软件复杂度会高一些。

第三,VBUS路径上的功率级。既然是sink,VBUS从接口进来后一般经过一个负载开关或者MOS管再进后级DC-DC,由MCU控制VBUS_EN信号。电流采样电阻和运放可以用来做输入电流监测,实现电池充电管理里的CC/CV逻辑。VBUS入口处建议放一个TVS管,压敏电阻也行,防止热插拔浪涌。

source端(比如充电宝、桌面充)的硬件则反过来:CC上不再是下拉,而是上拉电阻Rp,阻值按你要广播的电流能力选,56k/22k/10k对应默认/1.5A/3A。VBUS路径上要加可控的电源开关,且必须具备过流保护。source端的PD PHY选型可以考虑TI的TPS65987等,这类芯片功能全,支持source、sink、DRP三种模式,还能配置复杂的策略,缺点是对新手来说寄存器多,上手曲线陡峭。

4.2 软件状态机:sink端协商流程的实现思路

PD的软件部分,本质上是一个状态机。我在不同项目里写的状态机大同小异,核心骨架如下:

typedef enum { PD_STATE_IDLE, /* 空闲,等待CC连接 */ PD_STATE_WAIT_CAPS, /* 已连接,等待Source_Capabilities */ PD_STATE_REQUEST_SENT, /* 已发送Request,等待Accept/PS_RDY */ PD_STATE_POWER_READY, /* 协商完成,输出使能 */ PD_STATE_ERROR /* 异常状态 */ } pd_state_t;

状态机跑在主循环里,每次迭代先收一次PD消息,再根据当前状态做响应。要注意的是,PD消息层依赖底层的GoodCRC机制保证可靠性:收到任何消息后,必须立刻回复GoodCRC,否则对端会超时重发。如果MCU主循环太忙,回GoodCRC不够及时,就会出现“协商老失败”的问题。比较稳妥的做法是把GoodCRC响应放在中断里,或者用带硬件自动回复功能的PD PHY,FUSB302就支持硬件自动回GoodCRC,能省掉不少实时性烦恼。

选档策略是sink状态机里的核心决策逻辑。我的做法是:先解析所有PDO,过滤掉电压超过后级电路承受范围的档位,再按功率从高到低排序,选第一个满足最大电流限制的PDO。如果应用需要恒压恒流控制,比如做锂电池充电,那就优先选择PPS模式的APDO,因为它能精确微调电压。一个常见误区是按“最大功率”来选择,却不考虑线缆和板端压降。USB-C线缆看着差不多,实际内阻差异很大,粗线可能只有几十毫欧,细线能到几百毫欧,20V/5A下压降可能达到好几伏。所以我一般在选档时还会估算线缆压降,把请求电压往上提一点,或者限制请求电流,保证设备端最终得到的电压在合理范围内。

4.3 代码骨架:简化版PD sink请求逻辑

下面这段是我在项目里写过的简化逻辑,去掉了完整的PD消息解析和时序细节,只保留协商主流程,方便你理解整体思路:

/* 简化版:基于FUSB302+MCU的PD sink协商主流程 */ volatile pd_state_t g_pd_state = PD_STATE_IDLE; void pd_task(void) { pd_message_t msg; if (pd_phy_poll_message(&msg)) { /* 每收到一条完整消息,先进这里 */ if (msg.type == MSG_SOURCE_CAPABILITIES) { int pdo_count = pd_parse_source_caps(&msg, g_pdo_list); int best_index = pd_select_pdo(g_pdo_list, pdo_count, &g_request); if (best_index >= 0) { pd_send_request(best_index, g_request); g_pd_state = PD_STATE_REQUEST_SENT; } } else if (msg.type == MSG_ACCEPT) { /* Accept只是逻辑同意,等PS_RDY才能拉载 */ g_pd_state = PD_STATE_WAIT_PS_RDY; } else if (msg.type == MSG_PS_RDY) { vbus_load_enable(1); /* 真正开启负载 */ g_pd_state = PD_STATE_POWER_READY; } } /* 超时保护:长时间没收到PS_RDY就复位协商 */ if (g_pd_state == PD_STATE_WAIT_PS_RDY && pd_timeout_ms() > 500) { pd_send_request(g_request); /* 重发Request */ } }

这个逻辑看着简单,但真正的坑都在细节里。比如请求电流的值,不能直接填PDO里的最大值。PD规范里,sink在Request中指定的是“我想要的最大电流”,source有权根据自身能力和线缆能力降低它,但不会升高。如果你希望拉满5A,那Request里就得填5000mA,而source回复的Accept里会带有它最终允许的电流值,你的代码必须去解析这个值,用它来限制后面的负载设定。我见过有人忽略了这个反馈电流,直接在PS_RDY后按PDO标称电流去控制充电电流,遇上source能力缩水就出问题。

另一个容易踩的是VBUS检测。协商成功后,VBUS电压会从5V升到目标电压,这个过程有时间窗口。可靠的做法是在PS_RDY到达且VBUS电压稳定后,再打开后级。如果VBUS检测做得太粗糙,开负载太早,还是会触发低压保护。所以我在设计里一般加一级VBUS比较器或者用ADC连续采样,电压稳定后才enable负载。

4.4 不想写协议栈?现成方案了解一下

有些项目根本不需要在软件层面处理PD消息,用现成的诱骗芯片能省大量时间。国产的CH224、LDR6328就是这类典型:芯片内部固化了sink协商逻辑,外部用电阻配置请求的电压档位,插上充电器后自动协商,输出稳定的目标电压。这类方案适合产品形态固定、不需要动态切换电压、也不需要监控协商状态的场景,比如做一个固定输入19V的工业控制板、给一个小家电做PD快充输入。

STUSB4500则定位再高一点,它支持通过I2C甚至NVM配置多个PDO,断电后配置不丢失,上电后自动按照优先级去协商,完全不需要外部MCU。但它只是sink,如果你想做DRP或者source,还是要换别的芯片。选择哪条路,本质是在BOM成本、软件工作量、灵活度之间做取舍。我的建议是:原型验证阶段直接用诱骗芯片,先把功率路径和整机功能跑通;一旦要往量产走,再评估是不是需要上FUSB302+MCU的“全自主”方案,因为纯诱骗芯片对动态PPS、线缆补偿、热管理这些高级策略支持不够。

5. 常见问题与排查技巧实录

做充电协议调试这几年,我总结了一个规律:协议文档读得再多,也不如实际拿示波器量一次CC波形学得快。下面这些问题是项目里反复出现的,整理成速查表,希望能帮你少走弯路。

5.1 协商失败的六类典型原因

现象可能原因排查方法
插上充电器,VBUS无5VCC1/CC2下拉电阻没焊或焊错用万用表测CC到GND的电阻,确认是5.1k左右
有5V但协商无响应上拉电阻选错或CC线被ESD电容短路示波器看CC静态电平,断开负载排查
收到Source_Capabilities但Request发不出去固件没及时回GoodCRC抓包或逻辑分析仪看BMC波形,确认回包时序
收到Accept后一直等不到PS_RDY固件状态机卡死或VBUS调压超时打印状态机日志,检查source的VBUS是否真的在变
协商成功但大电流拉载就掉电线缆内阻大、适配器限流、接触不良换线测试,用电子负载分级拉载
换了适配器就协商失败适配器只兼容某协议或E-mark线缆异常确认适配器PDO列表,换认证线缆

这六类问题里,我遇到次数最多的是第一类和第五类。下拉电阻焊错基本是PCB封装画错或者BOM用错,上电前用万用表量一下就能避免;线缆问题则隐蔽得多,一条看起来挺粗的Type-C线,里面可能没有E-mark芯片,或者线芯特别细,导致20V下根本跑不了5A,这种只能靠换线交叉验证。

5.2 示波器和逻辑分析仪怎么用

调试PD协议,示波器是基本配置。CC线上的PD信号是叠加在静态直流电平上的BMC波形,你需要用交流耦合来看。正常情况下,你会观察到300kbps左右的方波翻转包络,包络内部是正常的BMC编码。如果波形畸形、幅值太小、或者有大量毛刺,大概率是CC路径上的电容太大、PCB走线过长、或者PHY芯片驱动配置不对。

逻辑分析仪比示波器更适合人眼看协议内容。很多逻辑分析仪软件带PD解码插件,可以直接把BMC波形解成Source_Capabilities、Request这类消息,一眼就能看出协商进行到哪一步。没有PD解码插件的话,也可以用普通SPI/UART解码的边沿触发方式辅助看时序,但效率低很多。如果项目预算允许,我强烈建议添一台USB PD协议分析仪,市面上几百到两千价位的都有,它相当于一个透明的sink串在充电器和设备之间,能完整抓取lines上的协议包,对定位高难度协商问题帮助极大。

调试顺序上,我的习惯是“先静态、再动态、最后看消息内容”。先量CC静态电平确认检测正常,再量BMC波形确认物理层通信正常,最后才用协议分析仪看消息对不对。很多人一上来就抱着协议分析仪看包,结果物理层根本没通,看半天也找不到头绪。

5.3 一个真实项目的踩坑复盘

之前做过一块电池管理板的PD诱骗功能,主控是STM32G0系列,直接用芯片内置的UCPD外设,目标是从65W适配器协商出20V/2.25A给后端充电。PCB回来之后,第一次上电就出问题:协商过程反复失败,偶尔能成功一次,但概率很低。

我先用协议分析仪抓包,发现source正常广播Source_Capabilities,设备端也正常回复了GoodCRC,但随后source每隔几百毫秒就重发一次,说明设备端的GoodCRC没有真正送到source。进一步查,发现STM32G0的UCPD外设默认没有开启硬件自动GoodCRC功能,而我在中断里回GoodCRC的代码又因为优先级问题和主循环里的I2C操作产生了冲突,导致回包延迟超时。修复方式是开启UCPD的硬件自动GoodCRC,并把PD消息处理从定时器中断挪到主循环。改完再测,协商稳定多了。

第二个坑出现在20V输出阶段。PS_RDY收到后,我直接使能了后级负载,结果VBUS电压从5V切换到20V的过程中产生了一次明显的过冲,后端电源芯片触发过压保护。后来看了示波器波形才发现,source在PS_RDY前其实已经开始抬升VBUS,但我使能负载时电压还在爬升中间值,瞬间电流把电压又拉下来了。解决方法是加了一个简单的“VBUS稳定检测”,用ADC连续采样VBUS,当电压连续50ms稳定在目标值的±5%范围内,才打开负载开关。

这两个坑其实都是“协议时序”和“硬件行为”之间的配合问题。协议状态机写对了只完成一半,另一半要对硬件时序有足够的敬畏心。这也是我一直强调团队里做嵌入式的人要既能懂协议又能看波形的原因。

6. 一些值得参考的产品思路

如果看完前面的内容,你准备在自己的项目里落地PD能力,我最后分享几个具体的小建议。

关于选型,我个人的经验是:如果产品是纯sink、且电压需求固定,优先考虑CH224这类诱骗芯片,硬件成本低,不需要写协议栈,开发周期能缩短一半以上。如果产品要做自适应电压、PPS微调、或者需要根据温升动态调整功率,那就要上MCU+PD PHY的架构,推荐FUSB302起步,资料多、例程全、社区活跃。如果产品形态是充电器或者充电宝,要考虑DRP或者source模式,TI的方案和NXP的高端型号都值得看看,重点是看芯片支持的PDO数量、是否支持EPR、以及是否能承受你设计的功率等级。

关于测试,至少要在三到五个不同品牌、不同功率等级的充电器上跑一轮兼容性测试。充电协议最大的特点就是“总量不多,变体多”,同一个PD协议,不同厂商实现细节会不同,有的适配器对超时时间特别敏感,有的对End of PDO处理比较激进。你产品里拿到实验室里测没问题,不代表换到用户手里就没事。所以早点建立一套自己的兼容性测试矩阵,把所有测试结果记录下来,对后续迭代帮助非常大。

最后关于安全,还是要重复一遍:充电协议涉及高压、大电流,PCB布局、器件选型、保护电路都不能省。PD协商只是一种“约定”,它不能替代硬件保护。即使协议协商成功了,过流保护、过压保护、反向电流保护这些硬件兜底机制也必须配置齐全。我见过太多人把注意力放在协议实现上,却忽略硬件保护,最后在兼容性测试中烧了开发板,教训相当惨痛。

做充电协议这几年,我最大的体会是:协议本身并不复杂,复杂的是它和硬件、时序、线缆、兼容性纠缠在一起的无数细节。但反过来说,正因为细节多,这个领域的经验才值钱。一个能快速定位“明明是PD充电器却只能跑5V”问题的工程师,和一个只会照着demo改参数的人,在项目里发挥的价值完全不在一个量级。希望这篇帖子能把你在充电协议这条路上的一些坑提前填平,也欢迎在评论区聊聊你踩过的PD坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询