ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

低功耗多电源轨设备电源管理实战:PMIC+MCU构建可控供电系统

低功耗多电源轨设备电源管理实战:PMIC+MCU构建可控供电系统 做一版便携数据采集设备CPU、传感器、无线模块、屏幕各自需要不同电压板子上原本放了三颗LDO加两颗DCDC抄来的参考设计第一次能跑可一到低功耗验证就出问题各路电源的上电顺序靠RC延时硬凑动态调压根本没留口子深度睡眠时那几颗LDO的静态电流还赖在板子上不走。后来把电源系统整个推翻改用一颗多路电源管理芯片PCA9422再配上一颗PIC18F86J50单片机专职做电源管家才算把整个供电链路收拢成一套可控、可监控、可上报异常的子系统的。这篇把整套方案从头讲一遍包括选型逻辑、PCA9422的电压轨配置、PIC18F86J50的I2C驱动与告警处理、上电时序状态机以及实测电流和调试中遇到的坑。适合正在做低功耗多电源轨设备的硬件工程师、嵌入式软件工程师参考哪怕你用的不是这两颗料这套MCU做电源策略大脑的思路一样能搬过去用。1. 为什么把电源轨交给 PMIC而不是继续堆分立电源芯片1.1 分立案的痛点与 PMIC 的边界我以前做多电源系统时习惯是一路DCDC加一路LDO需要几路就堆几个。这种分立案最大的问题不是成本而是上电时序没法好好管。RC延时看着能错开各路输出时间但温度一变、负载一拉时序余量就剩不下多少了。更麻烦的是保护逻辑输入欠压、过流、输出短路这些异常全靠MCU上的普通IO去检测等于把电源安全和业务代码绑在了一块稍不留神就会漏报。PMIC的思路是把这些电源基础设施收拢到一颗芯片里。以PCA9422为例它内部集成多路降压转换器和LDO输出优先级、电压目标、使能时序都可以通过I2C配置还把输入欠压、过流、过温、电源正常信号这些状态集中上报。硬件上板子省出一大片面积软件上你不再跟一堆使能引脚和分压反馈网络打交道只需要跟寄存器打交道。但我不建议把所有事都丢给PMIC。PMIC擅长的是执行——按配置调压、按引脚或寄存器使能、上报状态。它不擅长也不需要去做系统级的电源策略什么时候进深度睡眠、哪路轨先关、欠压后是重试还是停机这些决策跟业务场景强相关得有个脑子来拿主意。1.2 什么场景适合 PMIC 独立 MCU如果你用的是带完整电源管理协议栈的应用处理器平台配套PMIC通常直接挂在主控侧由主控统一调度不需要再插一颗独立MCU。但如果你的主控是普通MCU、FPGA或者设备里有多颗芯片要协同供电这时候独立电源管家就很有价值了。我这次选PIC18F86J50而不是随便拿一颗8脚小单片机考虑了三点。第一电源管理固件里要放电压配置表、状态日志、异常恢复策略Flash太小写起来缩手缩脚。第二这颗MCU要跟主处理器做握手通信串口加GPIO事件都要有普通小封装芯片引脚不够布置。第三项目后期可能还要加电量估算和电池曲线校准留一点性能余量没坏处。这套组合的核心理念很简单PCA9422负责把电压做出来、把异常报出来PIC18F86J50负责决定什么时候要什么电压、异常来了怎么处理。2. PCA9422 的电源域划分与寄存器控制基础2.1 先画电源树各路输出的角色划分设计任何电源系统第一步都是先把电源树画出来而不是急着看寄存器手册。我这版设备的电源树比较典型整理成表格方便对照电源轨典型输出主要负载配置方式备注DCDC13.3V主控MCU IO、传感器、无线模块I2C配置后常开待机时可通过寄存器关断DCDC20.8V-1.3V可调应用处理器核心电压I2C动态调压跑高频时抬压空闲时降压LDO11.8VRTC域、备份内存、休眠唤醒逻辑常开深度睡眠时唯一保留的轨负载开关5V外设电源USB外设、模拟前端由GPIO控制适合在休眠时硬切PCA9422具体通道命名、开关管压降、最大带载电流不同封装批次和型号后缀略有差异我在这里只说角色划分思路。每路输出要承担什么任务先定死再去手册里翻对应通道的能力。比如RTC域那一路一定要选静态电流极低的LDO通道而不是用DCDC否则深度睡眠功耗永远压不下去。电源树确定之后PCB布局也能跟着定了。DCDC1的输入电容、电感、输出电容尽量靠近芯片反馈走线远离电感下方LDO1的输入输出电容可以小一些但距离也不能拉太远。这个阶段多花十分钟摆电容位置后面纹波测试能省半天时间。2.2 寄存器操作的核心逻辑PCA9422这类PMIC的寄存器基本就三大类配置区、状态区、中断区。配置区管电压目标、使能位、上电顺序、开关频率状态区反映当前各路输出是否到达目标、芯片温度、输入电压是否正常中断区负责把异常事件映射到INT引脚上。最核心的寄存器是输出电压选择寄存器和使能控制寄存器。调压逻辑其实就是写VSEL寄存器但有一点必须注意给内核供电的那路DCDC不要从最低电压一步跳到最高电压尤其是负载上有跑着任务的处理器。电压突变超过负载容许范围轻则触发欠压复位重则损伤逻辑电路。我一般分三到五步每步等PGOOD反馈稳定后再写下一档。写寄存器时要做回读校验。PMIC挂在同一条I2C总线上周围还有传感器、EEPROM之类的设备寄存器被意外改写这种事我遇到过一次。回读校验不复杂但能直接避免配置写飞了、设备还在跑的隐患。// 写PCA9422寄存器并回读校验返回0表示成功 uint8_t pca9422_write_reg(uint8_t reg, uint8_t val) { uint8_t rv 1; i2c_start(); if (i2c_write(PCA9422_ADDR_W) 0) { if (i2c_write(reg) 0) { if (i2c_write(val) 0) { rv 0; } } } i2c_stop(); if (rv 0) { // 回读校验读回同一寄存器比较写入值 uint8_t back pca9422_read_reg(reg); if (back ! val) { rv 1; } } return rv; }2.3 上电先读 ID固件别猜芯片状态我习惯在初始化PMIC之前先读一次芯片ID寄存器。有人觉得这是多此一举但它的作用不是验证芯片存在而是确认I2C地址配置和总线通路都正常。如果读ID这一步就超时或返回错误那后面所有配置都不用做了直接撒网查硬件。有一次原型板拿回来PMIC死活没响应读ID一直NACK。查来查去发现是ADDR引脚的上下拉电阻焊接反了芯片I2C地址从默认地址变成了另一个地址MCU按默认地址访问当然找不到它。从那以后我所有PMIC驱动代码都要求上电先读ID读不到就亮错误灯绝不让系统带着错误的电源配置跑起来。初始化顺序可以固化成一个函数先读ID比对再发软件复位或默认配置然后逐路写电压目标最后统一使能。不要一边使能一边写电压某些轨在使能瞬间会把未期望的电压送给负载。3. PIC18F86J50 侧 I2C 驱动与电源告警处理3.1 I2C 主机通信的初始化细节PIC18F86J50的MSSP模块做I2C主机很成熟直接操作寄存器就能用。需要注意的第一件事是引脚配置SDA和SCL必须设成输入模式同时关闭对应的模拟输入功能否则引脚仍处于模拟采样状态通信时序会被拖坏。上拉电阻的选择也很关键。I2C是开漏总线SCL和SDA各需要一颗上拉电阻。标准快速模式400kHz下常见取值是2.2k到4.7k具体要看总线电容。总线长度短、器件少4.7k就够如果线上挂了四五颗芯片或者PCB走线较长建议降到2.2k。取值太小会让信号边沿更陡但会增加静态电流取值太大会让上升沿过缓高速通信时容易误采样。MSSP的时钟分频不是在主频里随便配个分频系数就完事。I2C主模式波特率公式一般是Fosc与SSPADD的函数不同型号略有差异。举个比较典型的情况系统主频48MHz、目标SCL100kHz时分频值可以大致落在0x77附近如果目标SCL400kHz分频值接近0x1D。但千万别直接抄要以数据手册里的公式为准专门花两分钟算一下免得SCL频率超了PMIC规格上限。void i2c_master_init(void) { // SDA/SCL引脚设为输入关闭模拟功能 // TRIS对应位和ANSEL对应位根据你的原理图配置 // MSSP使能I2C主机模式 SSPCON1 0x28; // SPIEN? 这里按MSSP寄存器定义 SSPCON2 0x00; // 按实际主频计算分频值下面数值只是示例 SSPADD 0x1D; // 目标400kHz时的示例值 // 清除总线冲突等标志 SSPCON1bits.SSPEN 1; }I2C时序还有一个容易忽略的坑PMIC对上电时序的要求不一定苛刻但SCL的高低电平宽度有最小时间限制。MCU主频越高如果不小心把SCL频率推到1MHz以上PMIC可能直接不响应。宁可把I2C降到100kHz模式也要保证通信稳定。电源管理这种底层子系统稳定性永远优先于通信速率。3.2 电源告警INT引脚与事件上报PCA9422的异常事件可以通过INT引脚主动通知MCU而不是让MCU轮询状态寄存器。这个引脚必须接对它能省大量功耗——平时MCU在Sleep里输入欠压或者过温发生了INT一脚踹醒MCU来处理。INT引脚在多数PMIC上是漏极开路输出所以外部必须加上拉电阻而且不能用内部上拉偷懒。我这版板子最初就没加这颗上拉结果PMIC的INT引脚电平在边缘状态飘MCU的外部中断时不时误触发一次最后定位到根因才发现是外部上拉缺失。加上4.7k上拉电阻后误触发立刻消失。MCU侧的中断处理我建议做两件事而不是直接在ISR里干重活。第一ISR里只设置一个电源事件待处理标志并记录时间戳第二主循环或定时器任务里读取PCA9422的中断状态寄存器确认具体事件源再清中断标志。这样能避免中断嵌套和长时间占用ISR也能保证事件处理过程可追踪。void __interrupt() high_isr(void) { if (INT_PIN_IF) { INT_PIN_IF 0; // 清除外部中断标志 pmic_event_pending 1; // 置位事件标志 event_timestamp tick_now(); } }清中断标志这个动作一定要做而且要清得彻底。有些PMIC的中断标志在读状态寄存器时自动清零有些则必须写特定寄存器位读一百遍都不清。如果状态寄存器没清零INT引脚会一直被拉低MCU的唤醒源就一直挂着功耗反而更高低功耗设计直接泡汤。4. 上电时序与休眠/唤醒状态机的设计边界4.1 上电时序先硬件后软件分立案里爱用RC延时错开上电PMIC方案里则有两种手段一种是靠芯片内部的使能优先级和软启动斜坡另一种是靠外部PGOOD信号级联。我实际用下来最稳妥的是把两者结合起来PMIC内部做主时序PIC18F86J50在复位后第一时间接管并做二次确认。MCU复位后的第一件事不是跑业务逻辑而是初始化PMIC并逐路确认状态。我的固件里上电流程固定为读ID、配置电压目标、禁止全部输出、等待输入电源稳定、逐路使能、每路等待PGOOD确认、全部完成后向应用处理器释放复位。顺序不能乱尤其是先禁止全部输出这一步防止上一次运行残留的配置把负载意外拉起来。这里要提一个容易栽的地方PMIC的软启动斜坡时间虽然能避免浪涌电流但多路电源轨同时启动时输入端电压可能被瞬间拉低。如果输入电源裕量不够上电瞬间VIN跌破欠压阈值PMIC会直接关断所有输出形成反复重启。硬件上得确保输入电容足够软件上则要设计启动失败重试计数不能无限重启。4.2 运行状态机与状态切换条件把电源管理做成状态机比散乱的流程控制清晰得多。我这套方案里定义了六个状态每个状态对应一组电源域配置和MCU自身功耗级别状态电源域配置MCU行为进入/退出条件POR全部禁止等待输入稳定上电复位INIT逐路使能等待PGOOD初始化完成RUN全轨供电正常主循环收到业务唤醒事件LIGHT_SLEEP3.3V保持1.2V可降MCU Sleep外部中断/WDT唤醒业务侧进入浅睡眠DEEP_SLEEP仅保留LDO1 1.8VMCU低功耗模式长时间无任务或低电量FAULT按策略关断部分输出记录事件等待恢复PMIC上报过流/欠压/过温这六态不是随便划分的。关键在于每个状态的退出条件必须能在硬件上给出明确信号。比如DEEP_SLEEP态必须有RTC闹钟、充电插入或外部唤醒按键对应的INT事件能拉醒MCU否则MCU睡进去就出不来了。深度睡眠切换是整套流程里最容易被忽视风险的环节。进入DEEP_SLEEP前必须先把DCDC2这类大电流轨关掉让负载完成下电再保留LDO1的1.8V域。关轨顺序错了比如先把主控电源断了但无线模块还在等数据总线电平可能会倒灌到PMIC输出引脚造成逻辑混乱。我建议关轨延迟至少留几十毫秒等前一级负载放完电再动下一级。4.3 动态电压调节的低功耗切换细节动态电压调节是这套方案里最实用的一环。应用处理器在跑高频任务时内核电压抬到1.2V中低频空闲时降到0.9V省电效果立竿见影。但电压切换的时机和顺序不对不如不调。正确的顺序是升频前先升压降频前先降压。因为处理器频率升高时需要更大电流和更稳定的电压如果先提频后提压瞬时功耗冲击可能让内核电压跌出工作范围降频时相反如果先降频后降压高频电路还在跑而电压已经降低同样危险。PCA9422如果支持转换速率配置我一般设置一个中等斜坡速率太快容易在输出端产生过冲太慢会拖长切换时间期间负载若发起总线事务电源波动可能引发异常。每次完成调压后都要读取PGOOD相关状态确认输出稳定后再让上层继续执行。这一步我会写进驱动里做成同步接口上层拿不到PGOOD确认就认为调压失败回滚到安全的默认电压。5. 实测电流、纹波数据与常见坑5.1 各状态实测电流记录整套方案调通后我给不同状态做了整机电流实测。测量方法是电池输入端串采样电阻用低量程万用表多次采样取最小值目的是排除无线模块发射瞬态的干扰尽量读到稳态电流。工作状态整机电流量级说明DEEP_SLEEP约21uA仅LDO1给RTC和唤醒逻辑供电LIGHT_SLEEP约1.3mA3.3V轨保持内核DCDC2已关断RUN 低频模式约36mA内核电压降到0.9V外设大部分关闭RUN 高频模式约58mA内核电压1.2V无线模块广播开启DEEP_SLEEP能压到21uA这个量级关键就是那一路LDO本身静态电流足够低。如果当初让3.3V的DCDC在深度睡眠里继续跑光开关损耗就会吃掉几百微安设备待机时间完全没法看。所以电源树的角色划分越早想清楚后面功耗标定就越顺。低功耗调试有一个很实用的技巧不要只盯平均值要看最小值和唤醒瞬态。设备每次从DEEP_SLEEP唤醒时输入端会有一个比较大的电流尖峰如果电源路径上有压降过大的开关或线缆电压会被瞬间拉低进而影响PMIC的启动判断。我建议在唤醒路径上并一个大容量电容专门吸收这个尖峰别让它一路传到主电源。5.2 纹波与负载瞬态的数据对比DCDC的纹波和瞬态响应是一对矛盾。我在原型阶段对比了两种电感取值一款是2.2uH输出纹波大约22mV20MHz带宽限制下整体更干净另一款是1uH纹波升到36mV但负载瞬态响应更快处理器跑重负载时电压跌落更小。最终选择取决于后级负载对电压精度和瞬态电流的敏感度对无线模块这类射频负载我宁愿让纹波低一点也不去追求极限瞬态响应。电感之外的另一个变量是输出电容。PMIC输出端只放1uF电容时纹波明显偏大换成2.2uF陶瓷电容加100nF高频去耦后纹波明显改善。电容位置也有讲究必须尽量靠近PMIC的输出引脚中间不要过孔否则去耦效果打折扣。测量纹波时示波器探头接地线如果太长会拾取到很大的开关噪声测出来的数据根本不能用。我习惯用探头自带的短接地弹簧或者把探头换成差分方式把带宽限制打开到20MHz这样读到的数值才有对比价值。5.3 调试中踩过的三个坑第一个坑是I2C从机地址冲突。板子上还有一颗传感器默认地址跟PCA9422的某个可选地址撞了。PMIC初始化的写操作一直不成功传感器那边还时不时收到乱数据查了很久才意识到是地址冲突。解决办法是检查PCA9422的ADDR引脚配置改成另一个地址并且在上电时先读ID确认总线上的地址分布。第二个坑是INT引脚浮空误触发前面提过根源是漏极开路输出没加外部上拉。这个坑很有代表性很多PMIC引脚默认是高阻态软件上配了内部上拉也不一定可靠硬件上把上拉电阻放到位才是正解。第三个坑是输入电容不足导致开机瞬间欠压复位。第一版PCB在PMIC输入端只放了一颗1uF电容设备接上满载外设后一开机VIN瞬间跌落触发欠压保护整个系统不断重启。后来在VIN引脚附近加了一颗10uF的X5R陶瓷电容问题消失。输入端的能量储备一定要给足尤其是你的负载里有电机、射频模块这种瞬间冲击大的设备。5.4 调试完成后的几点体会这套方案做完之后我对电源管理的理解从把电压做对变成了把电源当一个子系统来设计。现在回头看最有价值的设计决策不是选用了某颗具体芯片而是把电源策略从业务逻辑里抽离出来交给一颗独立MCU去管。业务代码再乱电源管家依然按自己的状态机运行异常时能独立记录和恢复。即使主处理器死机了电源管家也能把系统带进安全状态。如果你也要做类似方案我建议在原型阶段就把测试点留好每路输出的PGOOD测试点、I2C总线测试点、主电源输入端测试点最好都引出来。后面做功耗标定、纹波测试、故障注入时这几个测试点能省掉大量飞线时间。实测发现飞线本身也会引入噪声和压降测低功耗电流时尤其明显所以测试点设计越早做后面调试越轻松。再分享一个小技巧PMIC的中断事件可以顺手记录成环形日志存进MCU片内Flash不用多复杂几十条足够。设备交付后如果出现莫名其妙掉电或者唤醒失败翻一下日志就能知道是输入欠压、过温还是某路负载过流引起的比现场拿示波器盲测高效得多。我在第二版固件里加了这个功能之后所有电源问题基本都能在几分钟内定位到根因。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进