ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32G071实战:USB PD EPR请求处理与调试经验

STM32G071实战:USB PD EPR请求处理与调试经验 最近在调一块基于STM32G071的Type-C受电板客户提了一个需求要支持EPR。EPR是Extended Power Range的缩写USB PD 3.1规范里新增的扩展功率范围。以前PD最高只到20V/100WEPR把上限拉到了48V/240W。单看这个缩写很多人以为它只是加个电压档位实际做起来会发现EPR在协议交互、硬件保护和调试方法上都和传统PD完全不同。这篇文章我会以一个EPR request的实际处理过程为主线讲清楚G071上怎么配置UCPD外设、怎么在协议栈里响应EPR_Request以及我踩过的那些坑。适合做Type-C快充、电源适配器、受电设备的朋友参考。1. 先把EPR到底在请求什么这件事捋清楚1.1 从SPR到EPR等于给PD协议加了一条新车道普通USB PD的SPRStandard Power Range叫标准功率范围电压档是5V、9V、15V、20V最大电流5A功率100W。EPR扩展功率范围在SPR基础上新增了28V、36V、48V三档还是最高5A功率最大240W。这里有一个容易记错的地方EPR并不是把电流从5A提到6A或10A而是把电压往上升电流上限并没有突破USB-C连接器5A的限制所以功率上限是48V乘以5A等于240W。做一个生活化的类比SPR就像一条限速120km/h的高速路EPR相当于给这条路开了更高限速的专用车道但车道数量没变。很多第一次做EPR的人会想着把电流加上去方向完全错了。USB-C连接器的载流能力就摆在那里电流超过5A必须用更高规格的连接器和线缆成本一下子就上去了所以USB PD 3.1选择在电压上做文章。对笔记本、显示器、电动工具这类设备来说20V/100W确实不够用48V/240W才是它们想要的。1.2 EPR request有两层含义别搞混在协议层面EPR request这个说法其实包含两种请求。第一是EPR_Request消息这是Sink发给Source的“请求进入EPR模式”的专用消息。只有Source在Source_Capabilities里明确声明了EPR能力之后Sink才能发这条消息否则Source会直接忽略甚至回NACK。第二是在已经进入EPR模式之后Sink继续通过普通Request消息去请求28V、36V、48V中的某个具体PDO。这里的Request和SPR模式下的Request在格式上没有本质差别但电压数据处理、链路保护逻辑都得按EPR的规则来。很多工程问题就出在这两层没有分清。我之前看到有人在SPR状态下直接发“我要48V”的普通Request被Source拒绝后一头雾水。实际上必须先完成EPR模式切换才能谈目的电压。EPR模式切换的典型流程是Source先广播带EPR能力标志的Source_CapabilitiesSink解析到该标志后发送EPR_RequestSource回复EPR_Accept双方进入EPR模式随后Source重新广播扩展格式的Source_CapabilitiesSink再从中选择合适的PDO并发普通RequestSource调整VBUS并发送PS_RDY电源才真正建立。2. 为什么用STM32G071做EPR处理2.1 G071的UCPD外设能省掉一半事情STM32G071内部有一个UCPD外设全称是USB Type-C和Power Delivery它做的是物理层和数据链路层的脏活。BMC编解码、SOP/SOP/SOP识别、CRC校验、GoodCRC自动回复、字节级FIFO这些都不用主控操心。MCU要做的只是从FIFO里读出报文或者把要发的报文填进FIFO再跑一个PD状态机。这在以前是很奢侈的配置。很多板子用一颗独立的PD控制芯片比如STUSB4500再加一颗普通MCU成本高一截灵活性也差。G071把Type-C检测、PD通信、系统控制做进一颗片子里一颗芯片能同时负责电源环路、按键、显示、通信。做低成本EPR电源是很好用的选择。不过要注意UCPD外设并不是把整个USB PD协议栈都做完了协议栈还得自己跑。G071的Flash有128KB、RAM有36KB跑一个完整PD协议栈加应用逻辑是够用的但如果还要跑复杂触摸屏界面或大型算法就得仔细算一算余量。协议栈本身占资源不多真正吃Flash的是电源管理算法、日志打印、现场升级这些应用层代码。2.2 和独立PD控制器相比MCU方案赢在灵活做一个简单对比方便判断自己适合哪种方案。方案优点缺点独立PD控制器开发简单、协议成熟、认证好过灵活性低、多芯片成本高、EPR支持依赖具体型号STM32G071 UCPD成本低、单芯片、软件可定制协议栈要自己维护、调试难度高更高级MCU如G474主频高、外设更强、跑复杂协议更从容价格贵、对普通应用浪费做EPR request这种定制化需求MCU方案的最大好处是报文可以随便改甚至在实验室里自己构造一个Source来模拟外设这在量产产品的调试阶段是救命的。独立PD控制器的行为是固化的你很难让它输出一个带自定义字段的报文来测试边缘情况。G071这种方案只要协议栈是自己维护的想怎么打点就怎么打点。3. 硬件设计上不能省的地方3.1 CC引脚的接口电路直接影响EPR通信UCPD外设的CC1/CC2引脚连接Type-C连接器在做Sink时一般配置为Rd下拉做Source时配置为Rp上拉。G071的UCPD内部集成了可编程的Rd/Rp直接配置寄存器就行省了外部电阻。但死电池模式要考虑如果整机没电但VBUS已有电压Sink端需要让CC呈现Rd状态从而让Source认为线缆已连接并开始供电。EPR模式下CC引脚上的BMC信号频率、边沿要求并没有变但因为系统电压高了很多CC线更容易受到VBUS上浪涌的干扰。一定要在CC线上加合适的TVS管并且尽量缩短CC走线减少对地电容。我之前吃过一个亏CC走线穿了好几个过孔寄生电容偏大BMC波形上升沿变慢偶尔收发失败后来改线才稳定。EPR对信号完整性的要求比SPR更苛刻因为整个系统的工作电压高开关噪声也大CC线是最容易受干扰的薄弱环节。3.2 VBUS高压回路和过压保护EPR最高48V比传统20V高了一倍还多。VBUS路径上的MOSFET耐压至少留50%以上余量比如选60V甚至80V的管子TVS的钳位电压也要对应调整。同时必须做VBUS的过压、过流和过温保护一旦异常要快速断开MOSFET。G071片上有比较器和运放可以用来做模拟保护不需要外加比较器芯片。一个常见做法是用电阻分压采样VBUS到比较器输入超过阈值时触发一个刹车信号关断主MOSFET这个动作不依赖固件响应速度快。这个电路在EPR下尤其重要因为48V直接短路时能量非常大固件根本来不及反应。做过电源的人都知道保护电路一定要有硬件级冗余不能只靠ADC采样加软件判断软件再快也有几个毫秒的延迟硬件比较器几微秒就能关断。4. 代码层面实现EPR request的流程4.1 CubeMX里的UCPD配置在STM32CubeMX里选择STM32G071使能UCPD外设。UCPD需要选择工作模式Source、Sink还是DRP并配置对应的CC电阻。时钟上UCPD需要符合协议要求的时钟一般从PLL输出配置一个约50%占空比的时钟具体要看参考手册的频率要求配置时不要用内部低速时钟否则BMC位定时会漂移通信不稳定。如果使用ST的X-CUBE-TCPP软件包可以直接基于其模板工程生成。但我建议先跑通官方UCPD blink例程确认CC检测能正常翻转再接复杂协议栈。很多问题在最小系统下5分钟就能定位一上协议栈就找不到南北。CubeMX生成的初始化代码只解决外设底层配置PD状态机还是要靠协议栈和应用层配合。4.2 在协议栈里拦截EPR_RequestST的USB PD库分层比较清楚PRL物理层、Policy Engine策略引擎、DPM设备策略管理器。对EPR request来说主要关注三个地方。PE负责处理EPR状态机在收到EPR_Request后进入EPR Accept状态。DPM层提供接口决定是否允许进入EPR模式比如检查温度、输入电压、协议版本。APDO/PDO管理数组需要按EPR模式更新不能还停留在SPR的PDO列表。一个Source端收到EPR_Request的简化逻辑可以这样写if (epr_request_received) { if (dpm_check_epr_allowed(VBUS_48V, PDO_SLOT_3)) { // 允许回复EPR_Accept ucpd_send_msg(MSG_EPR_ACCEPT); pe_set_state(PE_EPR_ACCEPTED); // 告诉电源环路准备切换 pwr_set_vout_target(48); } else { // 不支持则回Reject保持SPR ucpd_send_msg(MSG_REJECT); } }这里需要注意真实工程还需要处理消息重传、超时、GoodCRC配合不能只发一条消息就完事。Sink端则相反先等Source_Capabilities解析出EPR能力位再发送EPR_Request进入EPR模式后重新请求目标电压。整个流程用状态机实现比较清晰用简单的if-else堆业务逻辑很容易在异常场景下卡死。4.3 协议栈和电源环路的联动EPR模式切换不只发几条报文就完事。当Sink请求48V时Source要把VBUS从之前档位升到48V这个过程要软启动不能瞬间硬切。G071如果同时控制一个Buck/Boost电路可以使用片内高级定时器配合比较器做恒压恒流协议栈通过一个标志位通知电源环路“目标电压变了”电源环路再平滑调整参考电压。这里最常见的问题是时序。EPR_Accept发出后Source需要在规定时间内调整VBUS并发送PS_RDY否则Sink会超时断开。因此在代码里收到EPR_Request之后要先把电源环路“抢占”过来再去回Accept再切电压最后发PS_RDY。如果电源环路被其他任务占用比如按键扫描或显示刷新一个调度不及时PD通信就失败了。我建议把电源环路和PD状态机放在同一个高优先级上下文中或者通过中断标志快速切换。5. 调试EPR request时的实战记录5.1 现象EPR_Request发出后对方一直不回复有一次我在Sink端发EPR_Request逻辑分析仪抓包发现Source没回任何消息。查协议发现Sink必须在收到Source_Capabilities且其中包含EPR支持标志后才能发EPR_Request。我那个板子的协议栈在解析扩展PDO时不完整把EPR能力位漏掉了条件不满足自然没发。解决方法是先把Source_Capabilities报文完整解析出来把每个PDO的电压、电流、EPR能力位打印到串口确认解析无误再继续。建议所有做PD的人都要学会在串口打印完整PD报文比盲目猜测快得多。后来我在协议栈里加了一个debug接口把收发报文都格式化打印出来定位问题的时间缩短了至少一半。这也是一个老经验先能看到数据再去分析数据。5.2 现象进入EPR模式后Request被NACK另一个问题EPR模式已经建立但Sink请求48V时Source回了NACK。后来发现是Source端的PDO槽位索引对不上。原来EPR模式下的Source_Capabilities用的是扩展消息格式PDO数量可能和SPR阶段不一样Sink盲用SPR阶段的Object Position去请求结果位置全错。排查方法是抓取Source在EPR模式下再次发送的Capabilities消息确认要请求的目标电压在第几个槽再修改Request里的Object Position字段。这个坑非常容易踩建议在代码里不要假设PDO编号固定每次切换模式后都重新解析能力报文并保存到结构体。我后来干脆写了一个函数叫refresh_pdo_list每次收到Source_Capabilities就重建PDO索引表后面不管是SPR还是EPR统一查表省了很多麻烦。5.3 现象48V切换瞬间通信中断这个是最严重的。VBUS升到48V的瞬间CC上干扰巨大偶尔出现CRC错误甚至UCPD无响应。原因有两个一是负载瞬态导致地弹二是TVS管在高压动作时产生强烈电流突变。后来加了软启动先把电压升到28V再升到48V并在CC线上串联一个小电阻配合TVS问题大幅减少。另外MCU的供电如果直接从VBUS取电48V切换时电压跌落可能导致MCU复位我给MCU供电加了独立的LDO并加大储能电容复位问题就消失了。这个问题给我们的教训是调试EPR不能只盯着协议层开关电源的瞬态特性、PCB布局、地平面完整性都会反过来影响PD通信。数字电路和功率电路做在同一块板上隔离和分区做不好协议层再对也会被干扰打崩。6. 一些经验和建议6.1 用好的工具省一半调试时间做EPR协议调试示波器是必需的至少200MHz带宽能看到BMC波形的细节同时强烈建议买一个带PD分析功能的USB PD协议分析仪比如CY4500或类似设备抓报文效率极高。用逻辑分析仪虽然也能抓但PD报文的解析比较麻烦尤其EPR消息是扩展消息手动解析非常痛苦。有分析仪之后一次抓包直接列出消息类型、方向、电压数据哪里卡住一眼就能看出来。6.2 研发阶段从低压开始EPR听起来高大上但调试时千万不要一开始就上48V。先把系统跑在20V/100W把所有报文和状态机调通再切换到EPR模式最后才把功率往上升。这样万一硬件有设计失误损失可控调试也方便。我之前见过有人直接拿48V/240W调试PCB走线载流不够
返回列表