多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

PMIC加MCU实战:嵌入式低功耗多路电源管理设计全记录

PMIC加MCU实战:嵌入式低功耗多路电源管理设计全记录 做电池供电的嵌入式设备最头疼的往往不是主控逻辑而是电源管理。前段时间我在一个工业采集节点的项目里需要把多路电压分别供给MCU、传感器前端和通信模块同时还要把休眠功耗压到极低。刚开始我用的是分离LDO加MOS开关的方案结果板子一跑起来压降、发热、静态电流和上电时序全都在折磨人调了快一周才勉强能用。后来把方案推倒重来改用PCA9422这颗集成PMIC搭配PIC18LF45K80单片机做完整的电源管理才真正把供电这摊事理顺了。这篇就把我在这个项目里的硬件设计、软件状态机、功耗实测和排查坑点的全过程记录下来想用PMIC加MCU方式做电源管理的同行可以直接参考。1. 为什么我放弃了分离LDO选择PCA9422加PIC18LF45K80的组合1.1 分离方案的三个致命问题最初版的方案是主控一路3.3V传感器一路3.0V接口电平转换一路1.8V全部从电池电压经过LDO获得。LDO的好处是电路简单、噪声低但在这个项目里它的短板被放得很大。第一个是效率问题。电池电压按3.7V算LDO输出1.8V时压差接近2V负载电流如果达到100mA光线性调整管上就要白白耗掉约0.2W。设备放在密封壳体里这0.2W就是实打实的温升对长期运行的可靠性非常不利。第二个是静态电流叠加。我选了几颗号称低静态电流的LDO每颗在空载时也有几微安到十几微安的电流三路加起来就三四十微安。设备大部分时间处于休眠状态这个数值对电池寿命的影响非常明显。第三个是上电时序。系统要求3.3V先起来1.8V后起来传感器电源最后给。分离方案里我靠RC延时加MOS管去凑这个顺序温度和批次一变时序余量就跟着变很难做到可靠。这三个问题叠加起来就形成了一个结论当一个设备需要多路电源、严格时序和低静态功耗时分离LDO方案只是看起来便宜工程上后期花费的时间成本远高于省下的物料钱。1.2 PMIC加MCU之后电源变成了可控子系统把方案换成PCA9422后结构发生了本质变化。PCA9422这类集成PMIC把多路DC-DC和LDO打包到一个芯片里各路输出不再是一颗颗独立的LDO而是可以通过I2C配置的电源通道。我可以通过软件设置每一路的输出电压、软启动时间、限流阈值还能读回各路的状态。PIC18LF45K80在这里扮演的角色是整个电源管理的控制和监控中心。K80系列是低电压版本的8位单片机休眠电流可以做到非常低片内ADC可以直接做电压和电流采样还有多个定时器可以给PMIC配置过程做超时管理。项目中虽然暂时用不到CAN但K80这颗芯片自带ECAN模块所以我保留了后续通过CAN总线上报电源状态的能力这在工业现场很有用。最关键的转变是电源不再是一个不可控的硬件前提而是一个可以被软件编排、监控、报错的子系统。也就是说系统开机时MCU可以先把PMIC配成想要的输出电压系统休眠时MCU可以关掉大部分通道只留必要的供电出现欠压或过流时PMIC通过中断通知MCUMCU再做对应处理。这种设计思维比在PCB上焊一堆稳压器要清晰得多。1.3 这套组合的代价和适用范围任何方案都有代价。PMIC方案的成本比几颗分离LDO高PCB对布局走线也提出了更高要求同时软件侧要额外写一个电源管理模块。我当时的判断标准是只要设备是电池供电、有多路供电输出、有严格的休眠唤醒要求这三条占两条PMIC方案就值得上。我需要的只是把三路电源管好PCA9422的通道数量对我刚好够用。如果你需要的电流更大或通道更多我也会在这篇文章后面给出选型参考方便你在同样思路上替换其他PMIC。2. PCA9422的通道规划和PIC18LF45K80的硬件连接2.1 输入链路和输出通道分配硬件设计我从输入链路开始处理。电池入口处先加一个保险丝然后是ESD保护器件再接一颗大容量输入电容。PCA9422的输入电容我选了47uF陶瓷电容配合100nF高频去耦放在PMIC的电源输入引脚附近。如果输入是外部稳压源而不是电池我也会保留这些电容只是容量可以减少一些。输出通道分配上我手头这颗样片带两路降压转换器和至少一路LDO具体以你自己拿到的版本为准。我的分配方式是通道目标电压负载方预期平均电流BUCK13.3VMCU主电源、EEPROM、电平转换60mABUCK23.0V传感器前端、运放供电25mALDO1.8V无线通信模块的核心供电80mA峰值这个分配方式是仔细想过的DC-DC用于电流较大或对效率敏感的通道LDO用于噪声敏感、电流较小的模拟部分。无线模块用LDO还有一个原因是它发射瞬间电流波动大LDO的纹波抑制能力能帮忙压掉一部分电源噪声避免影响射频指标。2.2 MCU与PMIC之间的控制线怎么接PIC18LF45K80和PCA9422之间的关键信号有四组I2C总线、中断输出、使能控制、电源正常状态检测。I2C总线上拉我用了4.7k电阻接到3.3V这是比较常规的取值速率先按100k跑确认通信稳定再考虑提到400k。PCA9422的中断输出引脚接到MCU的一个RB端口配置为下降沿触发。PMIC发生欠压、过压、过温或其他告警时这个引脚会拉低MCU通过中断去读状态寄存器。不要用轮询方式去看状态位那样既消耗功耗又容易漏事件。使能控制这里要特别注意。我的做法是用MCU的一个GPIO去控制PMIC的使能脚休眠时把这个脚拉低让PMIC进入待机状态关闭除MCU保留通道以外的所有输出。但这里有一个默认值问题MCU自己也需要电源如果PMIC上电默认所有通道关闭MCU就永远跑不起来。所以PMIC必须有某个通道默认输出一个安全电压保证MCU在上电瞬间先跑起来之后再由MCU把各路输出配置成最终需要的电压。这个默认输出状态读PC A9422手册时一定要确认清楚很多所谓“无法启动”的问题都是栽在这里。2.3 PCB布局里容易被忽视的几个点PMIC布局比LDO讲究得多。BUCK电感要尽量靠近PMIC的开关引脚输出电容分高频和低频两颗高频小电容要先靠近负载。反馈采样点要单独拉细线到输出电容正端不要直接连在开关节点附近的大铜箔上否则采到的电压会带开关噪声。I2C的两根线也要注意。SCL和SDA要尽量短不要走太长避免信号线上寄生的耦合如果PMIC和MCU距离超过5厘米上拉电阻可以减小到2.2k补偿走线电容的影响。另外PMIC的散热焊盘一定要过孔连接到内层地或底层的大面积地铜否则高负载下会过热我有一块板子就是因为散热焊盘没处理好满载十分钟后PMIC开始降功率。2.4 电源检测点的设计如果希望MCU能实时看到每路输出是不是都正常可以用电阻分压把BUCK1、BUCK2的输出采样到MCU的ADC引脚。比如3.3V直接采用两个电阻分压到1V以下留出ADC参考电压的余量。PIC18LF45K80的片内ADC分辨率足够分压电阻选100k和47k这种级别漏电流很小。我在PCB上加了一组测试点分别是输入电压、BUCK1输出、BUCK2输出和GND。这四个点不管是调程序时用示波器看波形还是后期做故障定位都特别方便。电源板最忌讳的就是所有测量都压在芯片引脚上探头一上去波形就变形了。3. PIC18LF45K80侧的电源管理状态机与软件流程3.1 状态机设计运行、待机、休眠、唤醒电源管理如果没有一个清晰的状态机代码很快会变成一团乱麻。我把系统分成了四个状态正常运行、待机、深度休眠、唤醒恢复。正常运行状态下所有PMIC通道全部打开MCU全速运行通信模块可以收发。待机状态下虽然系统仍然在工作但我会降低MCU主频关闭无线模块的发射通道只保留接收能力。深度休眠状态下MCU进入sleep指令PIC18LF45K80自身功耗降到极低同时通过I2C把PMIC的BUCK2和LDO关掉只剩给MCU供电的那一路保持低功耗输出。唤醒恢复状态是深度休眠退出的过渡态先把PMIC其他通道恢复再初始化外设最后进入正常运行。这个状态机本身不复杂但有一个原则必须坚持就是每个状态转换都要有明确的触发条件和进入后的第一动作。比如休眠状态第一动作必须是保存当前PMIC寄存器配置到MCU的RAM里唤醒状态第一动作必须是重新验证当前PMIC配置而不是直接假设它没变。3.2 PMIC初始化流程和寄存器配置思路初始化流程我放在MCU上电复位之后的第一步早于所有应用逻辑。大致顺序是初始化I2C外设、读PMIC器件版本寄存器确认通信正常、逐通道配置输出电压、配置软启动时间、配置限流阈值、配置中断屏蔽、最后使能各通道。这里给出一个我实际用的I2C读写函数框架非常通用只要把地址和寄存器号替换成你自己的就行uint8_t pmic_read_reg(uint8_t reg) { uint8_t val 0; i2c_start(); if (i2c_write((PMIC_ADDR 1) | 0)) { // 写方向 // 处理NACK } i2c_write(reg); i2c_restart(); i2c_write((PMIC_ADDR 1) | 1); // 读方向 val i2c_read(I2C_ACK); i2c_stop(); return val; } uint8_t pmic_write_reg(uint8_t reg, uint8_t val) { i2c_start(); if (i2c_write((PMIC_ADDR 1) | 0)) { return 1; // 设备不回应 } i2c_write(reg); i2c_write(val); i2c_stop(); return 0; }配置输出通道时我强烈建议先读后写也就是read-modify-write。PMIC里很多寄存器是多个位段共用的如果你只按数据手册写入某一个电压值可能会覆盖掉其他位段的状态比如使能位或软启动配置意外被清掉。先读回当前值修改目标位段再写回去能避免很多莫名其妙的副作用。软启动时间的配置值得多花一点笔墨。对于电池设备来说输出电容在启动瞬间的充电电流越大电池电压被拉低的风险就越高。我配置BUCK通道的软启动时间在1到2毫秒左右这样上电时输出电压缓慢爬起来不会在电池上造成很大的冲击。调试时我用示波器观察了启动波形确认没有明显的过冲。3.3 休眠与唤醒的关键操作顺序深度休眠这个动作看起来只是执行一条sleep指令但前期的准备一样都不能少。顺序是先通过I2C把PMIC的BUCK2和LDO通道关掉配置MCU的唤醒源把未用GPIO全部设置为输出低电平最后执行sleep指令。GPIO全部设置为输出低这一步千万别省略。浮空输入引脚在这个状态下会因为电压浮动产生漏电流几个引脚加起来可能让休眠电流高出好几倍。我实测过只处理了一半数字引脚和留着另一半浮空时休眠电流从30uA涨到了接近200uA这个教训印象特别深。唤醒源我配置了两个一个外部按键中断一个定时器闹钟。有人可能会问为什么不让PMIC的INT引脚也作为唤醒源当然可以但要注意PMIC在待机模式下中断输出信号是否还能正常拉低这取决于PMIC内部待机状态里中断逻辑是否供电。我后来确认了具体行为后才把它加上建议你也做同样验证。唤醒恢复流程的关键点是唤醒后不要马上访问PMIC。MCU醒来时PMIC可能还在恢复内部状态立刻发起I2C读操作容易出现NACK。我在唤醒函数开头加了一个5毫秒的延时接着做一次读版本寄存器的握手操作如果读不成功就再等5毫秒重试重试三次都失败才进入错误处理分支。这套机制让系统即使遇到PMIC恢复慢的情况也能自动稳定不需要人为干预。3.4 用ADC监控电压电流的思路和标定方法PIC18LF45K80的片内ADC负责采样输入电压、电池电压和某一路关键电流。电压采样通过电阻分压电流采样我用的是低阻采样电阻加运放放大方案这样可以把休眠时的微小电流也测量出来。电阻值选择要兼顾压降和灵敏度我用的采样电阻是0.05欧姆满量程电流下压降只有几毫伏不影响后面电路。标定是一个容易被忽略的环节。ADC的参考电压我用的是单片机内部参考但内部参考在不同温度下会有偏移所以我在每个采样通道上设计了校准系数。方法很简单用万用表实测几组已知电压和电流然后算出每个通道的增益和偏移存到EEPROM里。这样做完之后系统上报的电压值和万用表的误差通常在1%以内。4. 实测波形和调试过程中踩过的最深的三个坑4.1 上电时序不对导致的MCU反复复位第一版样机回来后我遇到了一个典型的“上电乱序”问题。示波器看输入电压上升过程发现BUCK1的输出在输入电压还处于爬坡阶段时已经尝试启动了。PMIC在输入电压不足的情况下输出不稳定导致MCU的电源电压在阈值附近来回穿越复位引脚不停拉低MCU根本无法执行代码。排查链路是这样的先看复位引脚波形确认存在反复复位再测PMIC各通道输出波形发现BUCK1输出和输入电压同时上升接着查数据手册里UVLO的阈值找到原因——PMIC的欠压锁定阈值比MCU的最小工作电压还要低所以输入还没稳定PMIC就开始工作。修复方案有两个一个是配置PMIC的UVLO阈值到更高档位另一个是在输入链路中增加一个延迟启动电路。我最后选了配置阈值因为软件可调不必改动硬件。改完后实测只有当输入电压稳定在设定阈值以上时PMIC才开始输出MCU复位现象彻底消失。4.2 PMIC配置写不进去I2C总线的排查过程另一个让我花了不少时间的问题是I2C写入偶尔失败。现象是十次初始化里有两三次读取版本寄存器返回0xFF之后PMIC的所有配置都没生效。我用逻辑分析仪抓了总线波形看到起始条件正常地址字节正常也收到了ACK但是寄存器数据字节之后没有等到应有的ACK直接出现了停止位。排查路径先怀疑电平不匹配测量PMIC的SDA引脚的逻辑高电平发现只有1.6V左右而MCU是3.3V逻辑。PMIC的电源域来自某个低电压通道在初始化早期部分PMIC内部逻辑还没有完全上电SDA高电平自然拉不起来。确认问题后我把PMIC的I/O电源改为由已经稳定输出的3.3V通道提供同时把上拉电阻也接到了3.3V。改完之后反复做了上百次上电初始化测试再也没有出现配置写失败的情况。这个坑说明了一个通用规律I2C总线报ACK不报错不代表高电平电平满足两边的输入阈值。在混合电压系统里VCCO、上拉电压、通信对象I/O电压三个东西必须画在同一个电路图里检查漏一个都是隐患。4.3 低功耗电流测不准仪器和接法都在骗你休眠功耗调试阶段我用万用表串联在电池输入端测电流数值跳来跳去主控明明进了休眠电流却显示有100多微安。后来才发现问题不在电路本身而在于测量方法。万用表的电流档在微安级别有两个问题一是输入阻抗大二是采样速率低。系统从正常运行切到休眠时电流从几十毫安瞬间掉到几十微安万用表的积分响应跟不上显示的是一个中间态。另外测试用的引线内阻会造成压降影响系统实际供电。我后来用高分辨率电流记录仪配合开尔文接法采样同时用示波器电流探头观察了切换瞬间的波形才真正测准了休眠电流。测准之后又发现休眠电流真的偏高原因之一是前面提到的GPIO浮空原因之二是PMIC在待机模式下默认还有一路高功耗的参考电路在工作。解决方案是调整PMIC的待机模式配置把参考电路关掉只保留唤醒所需的内部逻辑。最终休眠电流从70uA左右降到了15uA以下。4.4 唤醒后的“假死”回归现场最诡异的一次最诡异的故障是系统从休眠唤醒后MCU跑起来了但PMIC通道没有恢复外设全部不响应。代码明明在唤醒恢复里执行了PMIC配置函数单步调试看到函数正常返回了0也就是写寄存器成功但实际输出就是不对。后来我在配置函数里加了一行回读对比发现写入的值和回读的值不一致。具体原因是在唤醒早期PMIC内部某一部分电压域还没稳定虽然I2C帧都完成了寄存器写进去的电压值被PMIC自己的复位逻辑给清掉了。单步调试间隔时间长刚好错过了这个窗口所以看起来像是执行成功了。解决方案就是前面已经提到的唤醒后先延时再做版本寄存器握手最后才做配置。这个改动看着不起眼但它解决了整体系统稳定性问题。从此之后我把所有I2C设备访问逻辑都强制加上了“握手再访问”的约定不只是PMIC。5. 功耗预算核算与这套架构的可扩展性5.1 按运行、待机、休眠三个状态估算电池续航项目接近尾声时我按实测值做了一个功耗预算表用于评估电池规格和续航。设备的工作场景是每天有20次数据上报每次上报持续约5秒其余时间处于深度休眠。关键实测数据如下状态实测电流每天累计时间每天电量消耗正常运行78mA20 × 5秒 100秒2.17mAh待机仅通信接收12mA1小时12mAh深度休眠15uA约23小时0.35mAh每天合计——约14.5mAh按这个消耗量一块1500mAh的锂电池理论续航超过100天实际考虑电池自放电、低温容量衰减和电源转换效率余量能做到两到三个月的免维护周期。这个结果对工业采集节点来说是可以接受的。如果还想再压要么减少待机窗口时长要么选择休眠电流更低的PMIC功能模式没有别的捷径。5.2 后续可以做的几个方向这套架构在后续项目里还可以继续扩展。一个方向是把PIC18LF45K80的ECAN模块用起来让设备通过CAN总线把电源状态上报给上位机比如当前电压、电流、电池电量和低电压告警。这对车载或工业现场设备都很有价值。另一个方向是利用PMIC的中断做更积极的故障处理。比如我在系统里看到电池电压跌到欠压阈值以下PMIC会拉低中断引脚MCU在正常模式下收到中断后立即执行紧急保存操作把关键参数写入EEPROM然后主动进入休眠而不是等到电压彻底掉光导致数据丢失。这个机制在电池供电设备里非常重要哪怕你的系统只用一路电源也应该考虑加上。还有一个方向是把当前这套“MCU PMIC”的架构抽象成一个通用电源管理模块移植到不同主控平台。核心思路不变I2C通道配置、状态机管理、ADC监控、故障中断处理其他平台的差异只在于底层寄存器操作和中断处理方式不同。我后来的几个项目中沿用这个架构最快一次只用了一天就完成了电源管理部分的适配。5.3 选型判断和最终心得如果你正在纠结是否需要引入PMIC我的经验是单路输出、对功耗要求低、对时序无要求那继续用LDO没问题。但如果两条以上需求同时出现建议果断上PMIC加MCU的组合前期多花的那点时间在后期的调试和功耗优化里全都能赚回来。选PMIC的时候不要只盯着通道数量一定要确认PMIC的默认上电状态、I2C寄存器操作是否需要特殊初始化、待机模式是否支持你要保留的唤醒逻辑、以及引脚电平范围是否和MCU匹配。这四点我在项目里全部踩了一遍提前确认能省好几天的调试周期。最后说一个我体会最深的事电源管理做成子系统之后前后端的开发边界也清楚了。硬件归硬件管好阈值和去耦软件归软件管好状态和流程。做出来的设备不仅省电调试起来也比以前那堆分离LDO的板子省心太多。
返回列表