资讯详情

资讯详情

基于PCA9422与TM4C129的低功耗设备电源管理实现

做电池供电的低功耗设备有个环节永远躲不过去系统能跑多快是一回事能不能把宝贵的电池容量按需分配给不同负载是另一回事。这个项目用 PCA9422 做电源管理芯片用 TM4C129EKCPDT 做系统主控把“完整电源管理”这件事从头到尾做了下来包括电源树规划、I2C 配置、电压动态切换、低功耗状态机、异常保护和产测注意项。这篇文章适合两类人看一类是正在做电池供电、又带以太网或本地交互功能的嵌入式设备另一类是刚接触可配置电源管理芯片、被数据手册里几十个寄存器搞得不知道从哪里下手的硬件/固件工程师。我会把硬件连接、固件状态机、实测数据、排查思路都串起来讲尽量不写那些“按手册抄一遍”的空话。1. 为什么选择这个组合电源管理不该是固定电压的堆叠1.1 传统分立方案的局限性以前做这类单板最常用的是“一颗 DC-DC 转 3.3V 一颗 LDO 转 1.8V 一颗充电 IC 一堆 RC 延时电路”的组合。这套方案不是不能用而是到了低功耗场景会很别扭。首先是静态电流。几路独立电源芯片待机时的静态电流加起来经常走到几百微安甚至毫安级。对需要靠锂电池撑几个月现场运行的产品来说这几乎是在浪费大半能量。其次是时序控制。多路电源的上电顺序要靠软件去延时或者用 RC 硬调一旦要加路、改轨就是重新画板子。更麻烦的是系统进入低功耗时想让某一路电压下降、某些外设断电靠分立芯片很难做到“动态”调节。再就是深度休眠。很多 DC-DC 负载轻到一定程度会进入轻载模式但如果你希望系统休眠时把某一路完全关断还是得加 MOSFET 开关或者额外使能信号。板子上会多出一堆离散元器件出故障的概率也随之上升。1.2 PCA9422 和 TM4C129EKCPDT 各管什么选 PCA9422 的主要原因是它把多路电源输入切换、降压通道、LDO 通道、充电管理、电源状态监测和中断输出都做到了一颗芯片里而且每一路输出电压、工作模式、上下电时序都可以通过 I2C 实时配置。换句话说它不是“固定输出的电源模块”而是一个可以被系统主控精细控制的“电源外设”。TM4C129EKCPDT 这边是一颗带硬件以太网 MAC/PHY 的 Cortex-M4F 主控主频 120MHz外设丰富片上 Flash 和 RAM 都够用。它的低功耗模式不少从 SLEEP 到 DEEP-SLEEP还有一些模块可以单独关闭。最合适的地方在于它作为系统主控本来就要跑协议栈、维护业务逻辑。把电源管理状态机放在它身上正好能把“什么时候该睡、什么时候该醒、醒了以后让哪路电压上来”这套逻辑跟业务联动起来。两颗料凑到一起效果是这样的角色芯片职责电源执行层PCA9422输入源切换、电池充电、DC-DC/LDO 输出、电压监测、过流过温保护、中断上报系统决策层TM4C129EKCPDT运行电源状态机、I2C 配置电源参数、感知用户按键/网络事件/定时唤醒、记录电量信息分工清楚之后软件写起来就顺了。主控不需要关心电流怎么转的只需要告诉 PMIC“我现在要睡觉你关掉这两路有人按了键你要第一时间把我叫醒”。1.3 这套方案能解决哪些实际问题这个组合比较适合做几类产品带以太网的远程采集终端、工业现场的便携调试器、有按键和屏幕但大部分时间在待机的电池设备。共同点是“平时不干活但一旦唤醒就要快速负载工作”。我之前遇到过的实际场景是这么一台终端需要定时上报传感器数据同时接收远程下发的配置。平时系统百分之九十九的时间都在等下次上报如果硬件把 3.3V、1.8V 全部拉满光是维持各路电源和主控正常运行待机电流就会吃掉大半电池。让 PMIC 在主控休眠前把重载轨断掉、只保留唤醒逻辑供电待机电流可以从毫安级直接掉到几十微安。这就是“完整电源管理”的核心价值。2. 硬件电源树设计与关键连接2.1 系统电源拓扑我没有用现成的开发板而是单独画了核心板方便把每一路引出来测试。整个电源树的思路是这样的外部适配器或者 USB 5V 进来经过输入保护电路后进 PCA9422 的 VBUS锂电池单节接在 VBAT 管脚PCA9422 输出两路降压通道和一路 LDO 通道。具体电源轨分配如下表电源轨来源通道默认电压用途说明3V3_SYSDC-DC 通道 13.3V主控、以太网、传感器供电动态可关断1V8_IODC-DC 通道 21.8VSD 卡、电平转换、部分外设休眠时关断1V0_AONLDO 通道1.0V唤醒逻辑、待机监测电路常开这里的“动态可关断”很重要。系统休眠时3V3_SYS 和 1V8_IO 通过 I2C 写寄存器就能直接关闭但 1V0_AON 要一直保持。这样 PMIC 还能在外部有按键或者输入插拔时给主控一个唤醒中断而不需要给整个大电源轨供电。2.2 输入切换与电池充电设置PCA9422 内部集成过输入源选择逻辑VBUS 存在时优先用外部电源同时给电池充电VBUS 拔掉以后自动切到电池。硬件上需要做的主要工作是VBUS 输入加一个低阻保护电阻和若干电容防止热插拔瞬间的尖峰损坏 PMIC。电池端直接接 VBAT尽量靠近芯片放一个 0.1μF 陶瓷电容做高频去耦。充电电流按电池容量设置。我当时用的是 2000mAh 聚合物电池取 0.2C 也就是 400mA 作为标准充电电流这样发热小也不会对电池循环寿命造成太大压力。充电过程建议通过 PMIC 寄存器读取状态而不是只在硬件上用指示灯猜。因为不同阶段充电电流不一样靠肉眼分辨“充满没充满”完全不靠谱。软件里读回充电状态位当状态变成充电完成时再记录当前容量百分比做远程上报才有意义。2.3 与主控连接时要处理的几个细节PCA9422 和 TM4C129EKCPDT 之间的连接不算复杂但有几个点容易踩坑。I2C 的 SCL/SDA 要分别接上拉电阻阻值看总线上挂了多少设备。如果总线上只有 PMIC 一颗从机标准 4.7kΩ 没问题如果还挂了传感器之类建议降到 2.2kΩ保证上升沿够快。上拉电源尽量用 3V3_SYS不要用电池直接拉否则休眠时上拉电阻会白白耗电。中断脚要接一颗真的可以唤醒主控的 GPIO。TM4C129EKCPDT 的低功耗唤醒源比较多但不同封装、不同模式下 GPIO 能力不完全一样我画板时特意预留了几个空闲引脚备用。建议硬件上把 INT 引到主控的 GPIO 下降沿中断软件里再配置成只能由这个脚唤醒。还需要考虑 PMIC 的复位引脚。有些板子会把 PMIC 的 RESET 脚直接接地导致 PMIC 一直处于复位状态I2C 操作全部失败。正确做法是用主控的一个 GPIO 控制这个脚这样系统死机时还能强制复位 PMIC让整个电源链重来一遍。2.4 PCB 布线的取舍电源管理芯片的布局比想象中敏感。我的经验是输入电容和输出电容不要离 PMIC 太远尽量贴管脚放置尺寸上主电容用 10μF 陶瓷高频滤波再并 0.1μF。电池走线要稍宽至少按 1A 载流设计不然大电流充电时线路压降会直接导致低压保护误触发。采样检测点要从 PMIC 管脚独立走线不要跟功率回路线共享否则测出来的电压总是偏低。我还在 3V3_SYS 和 1V8_IO 的输出路径上串了 0Ω 电阻方便调试时用电流表串入测量。这个习惯帮我省了不少排查时间。3. 固件I2C 驱动、配置顺序与电源状态机3.1 最小化的 I2C 读写函数PCA9422 本质上是一个标准 I2C 从设备。固件驱动不需要做得很复杂稳定可靠就行。我直接基于官方库封装了两个函数底层只要保证带超时和重试逻辑/* 写单字节寄存器 */ int pca9422_write8(uint8_t reg, uint8_t val) { uint8_t buf[2] { reg, val }; return i2c_master_transmit(I2C0_BASE, PCA9422_I2C_ADDR, buf, 2, 50); } /* 读单字节寄存器 */ int pca9422_read8(uint8_t reg, uint8_t *val) { return i2c_master_transmit_then_receive(I2C0_BASE, PCA9422_I2C_ADDR, reg, 1, val, 1, 50); }这里PCA9422_I2C_ADDR要通过硬件上的地址引脚决定不同接法对应不同地址。我是用一上电就扫描 I2C 总线、读回芯片 ID 的方式确认的而没只靠数据手册里的默认值。#define PCA9422_I2C_ADDR 0x44u /* 示例值以实际硬件地址为准 */ #define PCA9422_REG_CHIPID 0x00u #define PCA9422_REG_PWR_CTRL 0x01u #define PCA9422_REG_IRQ_MASK 0x02u #define PCA9422_REG_IRQ_STATUS 0x03u #define PCA9422_REG_VOUT1 0x10u #define PCA9422_REG_VOUT2 0x11u #define PCA9422_REG_LDO1 0x12u不要在代码里写死地址后就不管了。我见过有人把 PMIC 的 A0/A1 引脚接反导致整个系统上电后 I2C 完全不通最后用扫描方式才发现从机地址压根不是头天以为的那个。芯片数据手册永远是第一手依据工程代码里的宏定义反而可能因为版本变更出现过时问题。3.2 上电之后的初始化顺序PMIC 默认输出并不一定符合你的系统电压需求。上电后主控和 PMIC 都工作了第一件事不是急着跑业务而是重新配置电源参数。我在项目里按这个顺序做读取 CHIPID 寄存器确认 PMIC 在线且型号正确。把 IRQ_MASK 寄存器配好屏蔽不关心的中断打开欠压、过压、过温、充电完成这几类关键中断。配置 VOUT1、VOUT2、LDO1 的电压和模式。先写模式再写目标电压最后使能输出。回读所有配置寄存器跟预期值比对。如果某一位没写进去立刻告警不带着错误配置往下跑。读取 PWR_STATUS确认各路输出状态正常再置一个“电源系统就绪”标志。这个顺序看起来简单但很有必要。有一次我在现场临时改了需求想把 VOUT2 从 1.8V 改成 1.5V结果直接在业务代码里写寄存器忘了先关输出。那一瞬间系统直接掉电重启后来查日志才发现是输出电压跳变时跌破了下限保护。正确做法就是先把通道置于安全模式再改电压改完确认无误再使能。3.3 电源状态机的实现整个系统跑下来我建议把所有电源状态用状态机方式管起来。状态不要分散在业务代码里到处改容易乱。typedef enum { PWR_BOOT 0, PWR_ACTIVE, PWR_SLEEP, PWR_DEEP_SLEEP, PWR_FAULT } pwr_state_t; typedef enum { EV_NONE 0, EV_BOOT_COMPLETE, EV_WORK_DONE, EV_WAKEUP_TIMER, EV_WAKEUP_GPIO, EV_PMIC_FAULT, EV_USB_PLUGIN } pwr_event_t;状态机框架直接用一个 switch 控制void pm_event_handler(pwr_event_t ev) { switch (pm_state) { case PWR_BOOT: if (ev EV_BOOT_COMPLETE) { pca9422_write8(PCA9422_REG_VOUT1, VOUT1_ACTIVE_CFG); pca9422_write8(PCA9422_REG_VOUT2, VOUT2_ACTIVE_CFG); pm_state PWR_ACTIVE; log_info(enter active); } break; case PWR_ACTIVE: if (ev EV_WORK_DONE || ev EV_WAKEUP_TIMER) { pca9422_write8(PCA9422_REG_VOUT1, VOUT1_SLEEP_CFG); pca9422_write8(PCA9422_REG_VOUT2, VOUT2_OFF_CFG); pm_state PWR_SLEEP; } break; case PWR_SLEEP: if (ev EV_WAKEUP_GPIO || ev EV_USB_PLUGIN) { pca9422_write8(PCA9422_REG_VOUT1, VOUT1_ACTIVE_CFG); pm_state PWR_ACTIVE; } break; default: break; } }核心思路是所有产生硬件动作的电源切换都必须在状态机里完成不允许业务逻辑直接写 PMIC 寄存器。这样以后要加低功耗模式、加看门狗保护、加远程唤醒都只需要在状态机里加新事件和分支而不用满代码库去找谁改了电源配置。3.4 让 MCU 休眠和 PMIC 关电轨道同频这里最容易被忽略的是时序。让设备进入低功耗时不要先让主控进 DEEP-SLEEP再让 PMIC 断电。主控一旦睡着就没法再去写 I2C 了。正确顺序是业务层上报“我要休眼了”。主控先把需要保存的数据落盘停掉以太网任务。状态机把 PMIC 的 VOUT1、VOUT2 关了只留 LDO1 和唤醒逻辑。等待 PMIC 返回配置完成标志。主控再进入 DEEP-SLEEP唤醒源设置为 GPIO 和定时器深度唤醒。反过来唤醒流程是外部按键或者定时器唤醒主控。主控先从 DEEP-SLEEP 恢复到浅睡眠状态。通过 I2C 打开 PMIC 的 VOUT1、VOUT2。等各路输出电压稳定读到 PWR_STATUS 正常。再把主控外设和协议栈初始化回到 ACTIVE。这个顺序看起来多了一步但少做任何一步都会遇到“莫名其妙死机”的怪问题。尤其是断电后立刻上电PMIC 的输出电容还没放完电主控的复位时序容易乱。我加了一小段延时等待逻辑实测下来稳定多了。4. 实测功率优化与数据对比4.1 各状态功耗怎么测不少朋友以为低功耗设备只要用万用表量一下电流就行实际上误差很大。我建议备一个带数据记录功能的电流表或者更直接一点在电源路径上串一个 0.1Ω 采样电阻用示波器抓电压波形换算成电流。测量时要注意采样点位置。如果直接用台式直流电源的电流显示分辨率往往不够而且动态电流下显示的数字是平均值看不出瞬间尖峰。我最终是在电池输出端和 PMIC 之间引出一根采样线用差分探头测采样电阻上的电压。整个系统分四个状态测状态软件配置实测电流说明BOOTPMIC 全输出、主控跑初始化约 460mA 峰值上电瞬间主要耗在电容充电和主控启动ACTIVE主控 120MHz以太网连线部分传感器工作约 240mA最大连续工作状态SLEEPVOUT2 关闭主控浅睡眠以太网断开约 12mA仍保留 VOUT1 供电DEEP_SLEEPVOUT1/VOUT2 关闭仅 LDO1 供电主控深度休眠约 46μA接近理想待机状态测下来最有价值的结论是DEEP_SLEEP 比 SLEEP 省了两到三个数量级。如果产品业务允许尽量直接进 DEEP_SLEEP而不是从 SLEEP 慢慢降。4.2 优化前后的待机时间估算电池容量我按 2000mAh、平均电压 3.7V 估算可用能量约 7.4Wh。假设设备白天平均每小时工作 5 分钟大约 12% 的占空比其余时间待机。用优化前的方案待机电流大约 20mA那么一天的耗电是工作部分240mA * 5min/h * 24h / 60 480mAh待机部分20mA * 22h 440mAh合计接近 920mAh满打满算两天多一点就没电了。优化后待机压到 46μA一天的耗电变成工作部分同样 480mAh待机部分0.046mA * 22h 1mAh合计约 481mAh能用四天以上。如果再把工作时间压缩比如一天只工作两次每次十几秒设备续航至少能拉到两三周。这个收益全部来自电源状态机的合理配置而不是代码层面的花哨优化。4.3 PFM/PWM 模式切换PCA9422 的 DC-DC 通道一般可以在 PFM 和 PWM 两种模式之间配置。PWM 模式开关频率固定纹波小适合对模拟电路敏感的场景但低负载时PWM 的开关损耗会让效率明显下降。PFM 模式在轻载时会降低开关频率待机功耗很低但纹波会变大。我没有把某个通道锁死在一种模式里而是按系统状态动态切ACTIVE 状态下VOUT1 用 PWM保证主控和以太网稳定。SLEEP 状态下VOUT1 切成 PFM因为负载很低提高效率。DEEP_SLEEP 状态下VOUT1/VOUT2 直接关闭不需要再考虑模式。切换模式也是一样的原则先更新寄存器再确认回读值。PMIC 的寄存器往往有“配置生效”和“实际状态”两个层面不能写了就当已经切过去了。5. 常见故障排查实录5.1 板子上电后各路输出全无这个问题我第一次调试就遇到了。查了一圈发现是 PMIC 的输入 VBUS 电压正好卡在内部欠压保护阈值附近因为适配器线材压降太大到了 PMIC 输入端只有 4.6V 左右PMIC 认为输入不可靠拒绝启动。排查方法是在 VBUS 输入脚用示波器直接测实时电压。只要看到输入电压纹波大或者静态值偏低就说明问题在输入链路而不是负载侧。换了一根更粗的 USB 线以后电压恢复到 5.05V输出立刻正常。还有一种常见情况EN 脚没有拉高。PMIC 不少通道默认是关闭的如果硬件上把 EN 引脚悬空又没有靠软件配置开启自然不会有输出。设计时应该给每个 EN 脚做一个默认上拉或者下拉到已知安全电平不要悬空。5.2 I2C 扫描不到从机I2C 问题的排查顺序不要乱。先量 SCL/SDA 静态电平是否正常再确认主控和 PMIC 的地有没有真正共地。有一次是 PCB 上两个地平面之间只有很窄的铜皮相连导致地电位不一致I2C 信号进 PMIC 就失效。检查完物理层以后再用 I2C 扫描程序跑一遍地址。地址如果没有按预期出现用 GPIO 软模拟 I2C 时序去读能进一步确认是主控外设配置问题还是 PMIC 本身没起来。我建议在设计里给 PMIC 的复位引脚留一个 GPIO 控制必要时可以单独复位 PMIC而不用把整个板子断电。5.3 休眠电流始终降不下来休眠电流偏大一般来说不是主控的问题而是“看似关了其实没关干净”的电路在偷偷耗电。最典型的几只“电老鼠”I2C 上拉电阻还接在常供电轨上、LED 指示灯没关、电平转换芯片处于高阻状态但内部还有功耗、传感器模块的使能脚没有真正拉低。排查方法很笨但很有效把板子上所有可以拆的排针、跳线、0Ω 电阻都考虑进去用断开电路的方式一步步缩小范围。先断开传感器再断开电平转换逐个排除。我发现休眠时漏电的元凶往往不是最显眼的芯片而是某个不起眼的测速指示灯驱动三极管基极漏了一路小电流到地常态下没人注意待机时就成了大头。5.4 寄存器写入成功但输出没有变化这个问题通常是两种原因。一是 PMIC 的配置存在“影子寄存器”和“应用寄存器”两层写入后需要一条“启动应用”命令才生效。二是写保护没解除PMIC 认为你在操作不安全的寄存器直接忽略了写入。解决办法是先看数据手册里有没有 KEY 寄存器或者解锁寄存器上电初始化时先完成解锁操作每次写完关键配置后强制读回同一寄存器确认不是只写进了缓存。我还在固件里加了配置校验如果三秒钟内没读到正确值主动触发一次 PMIC 复位重新初始化避免系统带着错误电源配置继续运行。6. 生产阶段也要为电源管理留后门6.1 产线自测固件怎么做批量生产时不能只靠目检和高低温抽测。我在产线固件里加了一段电源自检逻辑开机后自动执行以下流程读取 PMIC 芯片 ID判断通信链路是否正常。依次配置每路输出并用板载 ADC 或电压检测点测量输出电压。回读 PMIC 的电源状态寄存器。将结果通过串口打印测试工装根据关键字自动判断 PASS/FAIL。这个做法比单纯测整机功耗靠谱得多。因为有问题的板子故障可能发生在上电瞬间整机功能测试会被主控初始化掩盖掉但专门针对 PMIC 的寄存器回读测试能在底层抓住虚焊、错料、I2C 线序接反这类问题。6.2 一致性数据要留下每块板子在出厂前最好都把 VOUT1、VOUT2、LDO1 的实际电压记录下来保存到本地或者服务器。这样后期如果某一个批量批次出现待机异常可以先对比数据而不是拆开整机从零开始排查。我在这套项目里做了一件小事在测试脚本里加入了“最大偏差不超过 2%”的判断如果某一路电压偏差太大直接把设备标记为 DA 挡板。同时把测试时间和操作工位号打了标记方便追溯。这样做短期内会增加一点时间但长期来看能省掉大量售后排查成本。7. 几点实操体会这里分享几个这次项目里的具体感受未必每条都能在数据手册里找到但遇到类似问题时可以少走弯路。电源状态机的代码要跟业务解耦。我最早也图省事直接在以太网任务里判断是否空闲然后顺手关掉 PMIC 输出。结果业务代码一变电源切换时机就不对了经常出现网络包还没发完就掉电的情况。后面改成消息队列驱动状态机以后所有电源切换都只发生在事件触发点代码好维护多了。输出电容不要一味加大。有些朋友为了压纹波每个通道都放一个 22μF 甚至 47μF 陶瓷电容。但 PMIC 上电瞬间要给这些电容充满电充电电流尖峰会很大容易触发输入端的过流保护。我实测在 3V3_SYS 输出放了 22μF 陶瓷电容后冷启动峰值电流比 10μF 时高了几乎一倍。最后还是换回 10μF 0.1μF 的组合纹波数据没有明显变差。PMIC 的寄存器配置最好做成可回滚的版本。我在固件里存了一个电源配置表每个版本都有独立的配置参数。上电后先按配置表初始化同时留一个跑裸机小程序直接改寄存器的入口这样现场调试时可以手动微调电压不需要重新烧 CPU 固件。这个能力在 eval 电源波形、测低功耗阈值的时候特别有用。最后再分享一个救过我多次的土办法新板子第一次上电之前先把 PMIC 的输出电源轨断开用可调电源单独给主控供电把 I2C 与固件部分跑通了再接通 PMIC。这样就算 PMIC 侧有什么问题也不会把主控拖进死循环。电源管理要做得完整离不开这种“先把大地清扫干净再盖房子”的思路。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →