首页 / 资讯中心 / 文章详情

PMIC+MCU协同构建便携设备完整电源管理方案

PMIC+MCU协同构建便携设备完整电源管理方案 ★ FEATURED ARTICLE
最近在整理一台便携式设备的主控板电源部分卡了几天最后定下来的方案是PCA9422这颗PMIC搭配PIC18F46K42这颗8位单片机把电池充电、多路电压轨、上电时序、动态调压、电压监测和低功耗唤醒全串在了一起。整套组合做完之后整块主控板的电源管理脉络一下就清楚了功率级的变换和保护交给PCA9422策略级的决策和监测交给PIC18F46K42中间用I2C串起来。之所以说“完整”是因为电源管理从来不只是把电压转出来这一件事它还牵扯到什么时候上电、按什么顺序上电、负载变轻了要不要主动降压、电池什么时候该进入充电、充电充到多少算满、系统异常了怎么保护。这些事情一层一层叠起来单靠硬件或者单靠软件都做不干净所以PMIC加MCU的组合在电池供电产品里越来越常见。这篇文章把我这次从选型、架构设计、初始化、软件状态机到调试踩坑的完整过程整理出来适合正在做便携设备、手持仪表、传感器节点或者各类电池供电终端的工程师参考。1. 方案由来与器件选型1.1 为什么偏偏是“PMICMCU”组合很多人一开始做电源管理会自然想到分立方案一颗DC-DC给主控供电一颗LDO给传感器供电再来一颗专用充电IC负责锂电池充电。这个方案不是不行但问题会随着需求增多而暴露。第一物料太多每一路都有自己的反馈环路、使能引脚和保护逻辑PCB面积在电源部分就吃掉一大块第二上电时序很难精确控制用RC延时凑出来的时序批量一生产就发现有些板子复位不稳定第三没有状态回读能力系统里某个电压掉了你根本不知道是为什么掉的只能拿示波器慢慢抓第四几乎没有动态调节能力负载变轻的时候电压也不会自己降下来白白浪费电池。PMIC加MCU的组合把这些问题分开解决。PMIC承担功率变换、充电管理和硬件保护这些都是模拟电路更擅长的事。MCU承担策略控制、状态监测和动态调节这些是需要逻辑判断的事。两个角色一分工电源系统就从“一堆独立芯片”变成“一个有管理能力的子系统”。调试的时候思路也清晰硬件问题查PMIC策略问题查MCU代码I2C是中间的调试通道。这套方案最早的出发点其实很简单就是希望电源部分能“软件可配置”。板子已经贴上去了想改电压不想重新画板想调充电电流不想换电阻想加一路时序延时不想改RC。这些需求靠分立方案做不到但是用PMIC配合MCU基本上就是改几个寄存器的事。1.2 PCA9422解决电源的“硬件层”PCA9422这类PMIC的核心价值在于它把常见的电源功能集成在了一颗小封装芯片里。从功能模块来看它内部有多路降压稳压输出适合给MCU、射频模组这类对效率敏感的数字负载供电也有线性稳压器输出适合给RTC、备份域这类小电流常开负载供电还集成了锂电池充电管理涓流、恒流、恒压这几个阶段由内部状态机处理MCU只需要读状态寄存器就行。对电源管理来说更关键的是它的寄存器可配置能力。芯片内部有一份OTP默认配置上电瞬间不依赖MCU就能按默认时序输出系统就能正常启动。等MCU跑起来之后再通过I2C去修改输出目标电压、充电电流、保护阈值这些参数。这个“默认配置先跑、运行中再优化”的特性非常重要因为它保证了系统上电的自举能力不会出现“MCU想配置PMIC但MCU自己还没有电“这种死锁。还有一个容易被忽略的点PMIC的中断输出。电源侧一旦出现输入过压、欠压、充电完成、过温这些事件PMIC会通过中断引脚通知MCU。这比MCU自己轮询状态寄存器高效得多尤其在低功耗场景下MCU可以一直休眠电源异常时再由中断唤醒处理。注意具体到PCA9422这颗料它内部有几路Buck、几路LDO、充电电流上限是多少这些参数请以你手上的数据手册为准。不同后缀批次之间的OTP默认配置可能有差异调试前先对着芯片丝印确认型号。1.3 PIC18F46K42负责电源的“策略层”PIC18F46K42是PIC18-Q系列里的8位MCU做主控和电源策略管理都够用。很多人觉得电源管理必须上32位其实真不一定。电源管理本质上是状态判断和寄存器读写对算力要求很低但是对外设配置的灵活性要求很高而这恰好是这颗芯片的强项。它最吸引我的是几个外设特性。一是12位ADC带硬件计算功能可以对采样结果自动做平均MCU从休眠醒来之后不用花太多时间在滤波计算上二是I2C主机外设支持标准模式和快速模式在400kHz下和PMIC通信非常稳定三是外设引脚选择功能I2C、UART这类外设引脚可以映射到不同的IO上画PCB的时候就不用为了迁就引脚定义绕线四是休眠电流很低整个系统待机时MCU这部分几乎不消耗多少能量。而且8位机的成本优势很明显一颗PIC18F46K42能搞定的事情没必要用一颗带浮点单元的高端芯片。开发环境成熟官方IDE自带代码生成插件外设初始化代码可以自动生成剩下要手写的主要是应用逻辑和I2C控制序列。对做产品来说后期维护和改版都方便。2. 电源架构与系统行为设计2.1 先搭电压轨动软件之前一定要先把整板电压轨表列清楚。这个步骤偷懒不得后面所有时序配置、PCBLayout、低功耗设计都以这张表为基准。我这次方案里大致规划了这样的电压轨电压轨电源来源目标电压主要负载设计要点VBAT锂电池3.0~4.5VPMIC输入、高频大电流外设走线短粗靠近电池座VDD3V3Buck13.3VMCU、数字传感器主数字轨电容要足VDD1V8Buck21.8V射频模组、逻辑IO支持动态调压降功耗VDD_RTCLDO3.0V备份RTC、唤醒逻辑常开低噪声每个轨都要预估最大电流。比如说VDD3V3这一路MCU运行状态大概十几毫安几个传感器加起来几十毫安再加上其它数字逻辑留够1.5倍余量即可。VDD1V8主要给射频模组射频发射瞬间电流可能冲到上百毫安这一路的输出电容要按瞬态响应来选。VDD_RTC是常开轨电流很小用LDO供电合适线性稳压的静态功耗和噪声控制都容易做。电压轨分清楚之后再去看每路的去耦电容。电源管理芯片输出端的电容不仅仅是滤波还承担环路稳定性的一部分责任容量不能随便拍脑袋。我一般按数据手册推荐的容值起步然后根据实测纹波微调尽可能不超出手册建议范围。电容的ESR特性也很关键小封装陶瓷电容在高温下容值会打折这些细节会在批量验证时暴露出来。2.2 上电时序怎么定上电时序的设计思路核心是“让每个器件上电时都处于已知状态”。比如射频模组如果VDD1V8还没稳定就给使能信号它可能进入错误状态之后怎么复位都拉不回来。所以惯例是输入电源先稳定PMIC各输出轨按默认时序上电MCU最后起来再由MCU逐路去使能那些对外部时序有要求的器件。具体实现可以从两个层面来做。第一层是在PMIC侧配置各输出轨的上电延迟有些PMIC的寄存器里带有输出时序编排功能可以设置Buck1先上、LDO后上这种顺序。第二层是靠MCU的GPIO控制负载开关或外设使能脚MCU检测到VDD3V3稳定后再去拉高某个外设的EN引脚。实际调试时我会用示波器同时监测VBAT、VDD3V3、VDD1V8和MCU复位脚看它们之间的相对时序。慢上电、快上电、边沿有毛刺的情况都要测一遍。上电时序的问题经常不是设计时想出来的而是实测时看到的比如Buck2比Buck1晚了几毫秒结果某颗IC先看到VDD1V8后看到VDD3V3内部IO钳位二极管产生漏电路径把某个引脚拉成低电平。这类问题只有上波形上才能确认。2.3 电池充电和状态监测的设计电池充电策略上PCA9422内置的充电管理覆盖了涓流、恒流、恒压三个阶段。MCU需要做的事情是读取充电状态寄存器判断当前处于哪个阶段在充电完成之后通过中断或轮询方式知道充满然后把系统切换到正常工作或断开充电路径。充电电流和充满电压可以在初始化时写寄存器配置不需要外接检测电阻。温度和电池安全的关系一定要重视。如果电池组里有NTC强烈建议把NTC接到PMIC对应的温度检测引脚上这样充电过程中电池过热时PMIC能主动降流或停机。没有温度保护的锂电池充电在量产产品里是隐患一定不能省。电池电压监测我用的是PIC18F46K42的ADC去采集分压电阻的电压。分压电阻阻值选择要特别考虑静态电流。两个1M电阻串联做分压在4.2V电池电压下静态电流只有2.1微安对电池寿命影响极小。但阻值大了之后ADC输入端的采样保持电容充电时间变长配置采样时间时必须留够余量否则采样值会偏低。这个坑我后面在ADC部分详细说。3. PCA9422初始化与控制实现3.1 I2C链路的基础检查I2C链路是这套方案里的“神经系统”它出了问题后面所有寄存器配置都是空谈。硬件上最基本的检查点是上拉电阻。SDA和SCL都必须有上拉电阻典型值从1k到10k都可以取决于总线电容和通信速率。我这次用了2.2k在400kHz下波形干净设备数量少、走线短的情况下不需要调整。电平匹配是另一个容易踩的坑。PMIC的I2C逻辑电平如果和MCU不在同一个电压域直接相连会导致高电平识别不稳通信时好时坏。我这次先量了PMIC的VDDIO引脚供电电压确认和PIC18F46K42的I2C电平兼容后才放心接线。如果电平不匹配中间要加电平转换电路不能指望芯片内部的钳位二极管来兜底。上电后先别急着初始化寄存器先做一次地址扫描。在0x00到0x7F范围内逐个发送地址字节等待ACK来判断设备实际响应地址。这个步骤能一次性排除地址错误、虚焊、上拉缺失、电平不匹配这几类问题。void i2c_scan_bus(void) { uint8_t addr; for (addr 0x00; addr 0x80; addr) { i2c_start(); if (i2c_master_write(addr 1 | 0) I2C_ACK) { // 记录该地址有设备响应 log_address_found(addr); } i2c_stop(); } }注意扫描I2C地址时只发送地址字节不要附带寄存器地址和数据避免对未知设备的意外写入。扫描结果和手册对照之后再把设备地址固定下来。3.2 寄存器的读写套路PCA9422的寄存器访问方式是标准的I2C寄存器读写写操作是发送设备地址加写位、寄存器地址、数据读操作是发送设备地址加写位、寄存器地址然后重启START再发设备地址加读位接收数据字节。这套时序在任何I2C设备上都通用封装成两个函数之后上层逻辑就只需要关心“读哪个寄存器、写什么值”。读取状态时要特别留意寄存器地址的自增模式。有些PMIC支持连续读多个寄存器有些则必须在每次读之前重新指定寄存器地址。如果读取到的数据永远是同一份大概率是设备不支持连续读而你用了自增读的方式。我这里给出一个通用的寄存器写函数逻辑非常直接uint8_t pmic_reg_write(uint8_t reg, uint8_t value) { i2c_start(); if (i2c_master_write(PMIC_I2C_ADDR 1) ! I2C_ACK) { i2c_stop(); return 1; } if (i2c_master_write(reg) ! I2C_ACK) { i2c_stop(); return 1; } if (i2c_master_write(value) ! I2C_ACK) { i2c_stop(); return 1; } i2c_stop(); return 0; }很多初学者写完寄存器之后立刻读回希望确认写入成功结果发现读回来的还是旧值就怀疑是通信问题。实际上部分PMIC在收到配置命令之后需要几个毫秒的生效时间尤其是电压切换和模式切换这类操作。所以写入后加一个短延时再读回校验会更稳妥。3.3 动态调压的一次完整操作动态调压是这套方案里最有价值的功能。系统正常运行的时候VDD1V8按1.8V输出给射频模组系统进入浅休眠时射频模组断电但VDD1V8这一轨还要给一些保持唤醒状态的逻辑供电这时候把电压降到1.2V能明显减少这一轨的功耗。动态调压的流程是这样的先读当前Buck配置寄存器确认当前电压档位根据目标电压查表得到新配置值写入寄存器延时等待电压稳定读回配置寄存器和输出电压监测寄存器确认切换完成。在软件上这个操作被封装成一个接口函数传入目标电压值函数内部完成查表和写入。uint8_t pmic_set_buck1_voltage(uint16_t mv) { uint8_t buck_cfg pmic_reg_read(PMIC_BUCK1_CFG); uint8_t voltage_code mv_to_buck1_code(mv); // 查数据手册的电压码表 buck_cfg BV_CONFIG_MASK; buck_cfg | voltage_code; if (pmic_reg_write(PMIC_BUCK1_CFG, buck_cfg) ! 0) { return 1; } delay_ms(PMIC_VOLTAGE_SETTLE_MS); return 0; }动态调压最大的风险不是PMIC本身而是下游负载。某个传感器如果工作电压范围标称1.62V~1.98V你把电压降到1.2V它直接不工作系统表现成随机通信失败。所以在规划电压档位时先逐个确认每轨负载的最低工作电压再决定可以降到哪一档。软硬件规格之间的一致性检查必须做在调压功能之前。4. PIC18F46K42的软件框架4.1 初始化和外设分配软件部分我用的IDE自带代码生成插件来初始化外设节省了不少时间。时钟配置上用内部振荡器跑32MHz足够I2C和ADC使用。I2C主机模式配置为400kHz标准模式ADC配置为12位分辨率内部参考电压选择2.048V这样分压后的电池电压采样可以覆盖整个范围。引脚分配要提前规划我这次用了外设引脚选择功能把I2C和ADC映射到指定引脚上PCB布线方便了很多。给一个参考分配表引脚功能方向连接目标说明RA0PMIC_INT输入PCA9422中断输出下降沿唤醒MCURA1PMIC_EN输出PCA9422使能脚软件控制PMIC开关RC3I2C SCL输出PCA9422 SCL开漏带上拉RC4I2C SDA双向PCA9422 SDA开漏带上拉RC5ADC_BAT输入电池分压点采样电池电压GPIO里的PMIC_EN在初始化阶段不能随手拉低要确认PMIC此时是否已经在跑。如果PMIC已经在通过OTP默认配置输出电压MCU再拉低EN把它关了会造成一次电压跌落系统就会重新上电。正确的做法是读取当前电源状态后再决定是否操作EN避免初始化阶段引发无谓的上下电循环。4.2 电源状态机怎么跑电源管理软件的核心不是一堆分散的寄存器读写而是一个清晰的状态机。我用了一个简单但够用的四状态模型起始STARTUP、运行RUN、低功耗LOW_POWER、故障FAULT。每个状态实现为一个独立函数状态之间的迁移条件集中在状态机调度里方便后续增加新模式。上电后进入STARTUP这个阶段做PMIC初始化、写入默认电压配置、读取电源状态确认各轨输出正常。确认OK后切到RUN。RUN状态下周期性采样电池电压、读取PMIC故障寄存器同时响应中断。当系统需要进入休眠时先降低VDD1V8关闭非必要外设电源再让MCU进入休眠。PMIC的中断引脚会在下一事件到来时唤醒MCUMCU恢复后先把VDD1V8调回1.8V再进入完整RUN状态。状态机框架大致长这样void power_state_machine(void) { switch (power_state) { case PWR_STARTUP: pmic_init_sequence(); if (pmic_all_rails_ok()) { power_state PWR_RUN; } break; case PWR_RUN: battery_voltage_monitor(); pmic_fault_check(); system_sleep_check(); break; case PWR_LOW_POWER: pmic_low_power_entry(); // 进入休眠等待中断唤醒 break; case PWR_FAULT: pmic_fault_handle(); break; } }写这套状态机时最需要注意的是一次只能有一个状态在“进入过程中”。如果STARTUP还没完成就来中断中断处理函数里又去切状态状态变量会被来回改动最终卡在错误分支。我在中断入口处加了一个正在初始化标志位初始化期间屏蔽电源相关状态切换这个问题就消掉了。4.3 ADC监测和数据处理ADC监测电池电压不能拿来即用原始采样值必须经过处理。首先是软件滤波。我做了16次采样的滑动平均这个数值在实时性和平滑度之间比较均衡。其次是分压比例校准。分压电阻标称值和实际值有误差我用万用表实测电池电压再对比ADC计算值得到一个修正系数在程序里把修正系数存成常量。采样时序上有个容易被忽略的问题ADC转换期间如果MCU内部高频数字电路或者通信外设刚好在活动采样结果可能带毛刺。我试过在同一时刻既做I2C读操作又做ADC采样读回来的电池电压明显跳变。解决办法很简单把I2C通信和ADC采样分在不同的时间片执行或者采样时暂停一下其它数字活动。电池电压的阈值判断也要预留迟滞。比如3.6V进入低电量提示3.3V进入强制低功耗如果这两个阈值之间没有迟滞区电池在3.3V附近轻微波动时系统会在低功耗和运行状态之间来回切换功耗反而更高。我在软件里加了大约60mV的迟滞区间这个问题实测就消失了。5. 调试实录与问题排查5.1 上电不干活先看时序第一次把板子点亮时遇到一个奇怪的问题MCU有时候能正常启动有时候卡在复位循环。用示波器把VDD3V3的上升沿整个抓下来之后发现这一轨电压在上升过程中曾经跌落到MCU复位置位阈值附近产生了二次复位的毛刺。原因是MCU启动瞬间充电电流太大Buck1的输出电容被瞬间抽走大量电荷环路还没来得及响应电压就先掉了一截。处理方法有三个方向加大Buck1输出电容、调整PMIC的软启动参数、或者在MCU电源引脚旁增加一级RC供电缓冲。我最后采用了加大输出电容和延长软启动时间两个措施并用VDD3V3的上升沿变得平滑复位电路不再误触发。这个案例说明上电时序不能只看各轨之间的先后顺序还要看每一轨自身的上升沿质量。排查上电问题我固定用这样的步骤示波器调到余辉模式同时测VBAT、VDD3V3、VDD1V8、复位脚连续触发几十次看每次上电的差异。如果只有偶发失败这种累计观察方式能把异常边沿抓出来。5.2 I2C设备丢了问题往往不在代码有次调试中PMIC从I2C总线上“消失”了发送地址后始终没有ACK。代码检查了很多遍逻辑没问题。后来用万用表量SDA和SCL的静态电平发现SCL只有0.9V明显没被拉到高。排查发现是两块板子共用同一个调试电源某块板上的另一个I2C设备在SCL上形成了额外的漏电流路径把电平拉低了。还有一次通信时好时坏波形看起来也完整后来发现是逻辑分析仪的接地夹子没夹好地电位差异导致采到的波形时序全部失真。这类问题不在代码逻辑里而在物理链路和测试环境上排查时一定要先确认测量仪器本身没问题。排查I2C问题我建议的顺序是量静态电平确认SDA/SCL都在高电平用示波器抓START、地址字节、ACK位确认时序完整最后再看代码逻辑。硬件波形干净的条件下程序问题会变得很容易定位。5.3 低功耗电流压不下去的几类原因低功耗调试是这套方案里最磨人的环节。满怀期待地用uA级电流表量系统总电流结果发现比预期高了十倍。逐项排查后问题往往集中在几个地方。分压电阻就是最典型的嫌疑人早期调试时随便用了两个10k电阻做电池分压静态电流几百微安直接把整个低功耗设计废掉了。换成1M以上电阻后电流立刻降下来。第二类问题是外设电源没切断。有些传感器模块的电源虽然由MCU的GPIO控制但GPIO只是关掉了LDO的使能脚LDO本身空载时还会有静态电流。更隐蔽的是某些模组即使内部掉电IO引脚上如果还保持高电平会通过内部保护二极管往外漏电。处理方法是睡觉前把所有相关IO统一放到确定的电平上去。第三类问题是GPIO悬空。未使用的引脚如果被配置成输入且没有上拉下拉会感应环境噪声在输入缓冲之间形成半开状态产生贯穿电流。把闲置引脚全部配置成输出并拉低或拉高能立即消除这部分漏电。这个点常规调试很少有人提但影响确实不小。5.4 常见问题速查表把这段时间遇到的和同行分享过的问题整理成一张表方便大家对照排查。现象可能原因处理思路I2C扫描不到PMIC设备地址错误、上拉缺失、电平不匹配先量静态电平再逐项核对手册上电后MCU反复复位VDD上升沿跌落、负载过重、复位电路阈值加大输出电容、调整软启动Buck输出纹波偏大输出电容偏小、环路布局地线过长按手册推荐补电容、优化布局充电电流怎么都上不去输入限流、电池温度降额、配置值不对查输入源能力、读温度寄存器、核对配置休眠后系统电流过高分压电阻偏小、外设未断电、GPIO悬空逐一断开电源轨、统一IO状态动态调压后设备偶发失灵负载工作电压低于最低标称值确认每轨负载的电压范围再降压PMIC中断一直触发中断寄存器未清除、外部信号毛刺读取并清中断标志检查引脚滤波除了查表我还想强调一个排除故障的通用思路先把PMIC和MCU之间的交互切断单独验证每一颗芯片。比如只给PMIC供电用外部I2C工具去读寄存器确认PMIC本身工作正常再把MCU单独跑一个点灯程序确认MCU自身没问题。两个模块分别验证之后再合在一起调试问题立刻缩小到通信环节。6. 收尾几句经验这套方案完整跑通之后我最大的体会是PMIC加MCU的真正难点不在芯片本身而在于把电源行为当成一个系统来设计。电压轨规划、上电时序、充电策略、低功耗切换这些需求必须提前在架构层面想清楚而不是等画完PCB再拿软件去“填坑”。前期多花一天把时序和状态机画出来后面调试能省下一周。另外一个小建议把PMIC的初始化序列和电压配置封装成独立接口这样之后换用同系列其它PMIC或者调整电压方案时上层状态机代码可以原封不动只需要改底层实现。我在这次项目里就是这样做的后来因为射频模组换了供电电压只改了一个查表函数其它逻辑基本没动。还有一个经验是日志一定要打。电源问题的复现概率往往不高靠肉眼盯示波器等半天不如在MCU里做一个环形日志缓冲把每次状态切换、寄存器写入、PMIC中断事件都记录下来出问题时导出这段日志就能还原现场。这个操作成本很低但对排查复杂电源问题帮助极大。如果你也在做类似的电池供电产品建议从第一天就把这套记录机制加进去。
阅读完成 · 觉得有帮助?
咨询建站