ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

低功耗电源管理实战:PIC32搭配PCA9422 PMIC的I2C调压与DVS设计

低功耗电源管理实战:PIC32搭配PCA9422 PMIC的I2C调压与DVS设计 做低功耗设备相关的朋友大概都碰到过这种事板子上的电源轨越来越多主控、传感器、射频、存储各要一路每一路还得按顺序上下电调压和低功耗也不能落下。我以前调一块便携数据采集板时选型主控定了 PIC32MX664F064L电源部分一开始打算用两三个 DC-DC 加 LDO 堆出来越算越难受。后来换用 PCA9422 这颗 PMIC整个电源管理立刻清晰了很多——它通过 I2C 和 PIC32MX664F064L 配合既管多路输出电压也管上电时序和动态调压最后整机睡眠电流也压到了很可观的数值。这篇文章会把从选型、硬件设计、I2C 驱动到低功耗状态机调试的完整过程整理出来重点讲“为什么这么选”“怎么搭最稳”和“实际调板时踩过哪些坑”。如果你想做便携仪表、穿戴设备、传感器节点或者手上正好在用 PIC32 系列 MCU又不想继续被一堆分立电源芯片折磨这篇应该能给你一条可以直接抄作业的路线。1. 整体设计与思路拆解1.1 为什么不用分立 DC-DC LDO改用 PCA9422老式做法很直接MCU 一路 3.3V用一颗小 LDO传感器需要 1.8V再加一颗射频模块需要能调压的大电流轨得上一颗 DC-DC。听起来不难一旦把需求全部列出来问题马上出现。以我那块板子为例系统同时需要 3V3、1V8、1V2 和模拟 2V5 四路电源其中 1V2 还要求 MCU 运行时动态升降压。用分立方案意味着板子上至少堆五六颗电源芯片还要自己搭电平转换、上电使能电路以及为每路做缓启动。更麻烦的是低功耗几路电源各自睡醒的时间不一样总静态电流也很难压到 10µA 级别。PCA9422 这类可编程 PMIC 把多个电源通道收进一颗芯片我真正用到的是内部一路大电流 DC-DC 给主控核心域一路小电流 DC-DC 给传感器域再配内部 LDO 给模拟部分。三路电源共用一颗输入电容、同一个 I2C 总线、同一组状态控制这比分立方案省掉的 PCB 面积肉眼可见。选型时我会特别看三件事一是 PMIC 的静态电流是否足够低睡眠时能不能做到每路通道都关断二是通道数是否匹配目标系统不用追求过多通道三是它是否支持灵活的上电时序和动态电压调节。PCA9422 正好在这几项上都有不错的支持而且 I2C 寄存器配置能力很强基本覆盖了小型 MCU 系统的常见需求。1.2 电源树设计与负载分配这个项目的电源树其实很典型我给各个负载做了分类电源轨供给对象典型负载要求3V3PIC32MX664F064L 数字电源、外部 Flash、按键30~80mA 常态峰值 150mA优先上电纹波小1V8低电压外设、存储卡 Level Shifter 后级10~50mA时序靠近主电源1V2 可调主控高性能域或射频模块峰值可达 500mA支持动态调压2V5 模拟模拟前端、运放、ADC 基准5~20mA纹波和噪声要求高分配负载时要注意一个原则噪声敏感负载尽量不要放在开关噪声大的 DC-DC 输出上除非后级有足够滤波。我就是因为一开始把模拟前端直接挂到了 DC-DC 通道结果 ADC 采集的底噪始终偏高后来改用内部 LDO 通道供电底噪立刻降了下来。这个细节导致我后面再做电源树时都会多问一句“这一路是数字的还是模拟的”1.3 PIC32MX664F064L 在系统中扮演什么角色PIC32MX664F064L 是 64 引脚、MIPS M4K 内核的 MCU跑普通控制逻辑和协议栈完全够用。它在这个项目里做的事不仅是业务控制更像系统电源的“调度中心”上电时通过 I2C 写入 PCA9422 的配置寄存器设定各路电压、模式和上下电顺序运行时根据负载情况动态调整某一轨的电压这就是 DVSDynamic Voltage Scaling进入睡眠前逐路关断不需要的电源通道把 PMIC 置于低静态电流模式通过 PMIC 的中断脚和状态寄存器实时获取电源异常信息。选这颗 MCU 还有个现实原因它的 I2C 模块是支持多主从、速率可调的底层寄存器操作很透明方便我把 PMIC 的初始化过程完整掌控。很多人喜欢直接用库函数但调 PMIC 时我更推荐先用寄存器级 I2C 驱动打底遇到问题能看清楚总线上的每一个 ACK、NACK调试效率高很多。2. PCA9422 硬件设计要点2.1 输入电源、电感电容与 PCB 布局PCA9422 的输入电压范围一般在 3V 到 5.5V 之间我这块板子直接用一个锂电池3.0~4.2V作为输入。输入级先放一个 10µF X7R 陶瓷电容再放一个 1µF 高频去耦电容两个电容要尽可能靠近 PMIC 的 VIN 引脚。千万不要为了省事只放一颗大电容高频开关瞬态电流需要低 ESR 的小电容来吸收。输出电感的选择决定纹波和转换效率。对 1V2 那路大电流通道我选的 2.2µH 电感饱和电流至少是最大负载电流的 1.5 倍到 2 倍。计算方式也不复杂先估算最大负载电流 I_load_max再按电感的纹波电流峰峰值一般控制在负载电流的 30% 左右来选。比如最大 500mA 负载纹波电流设计在 150mA 以内电感感值就要结合开关频率和输入输出来算经验值是 2.2µH 到 4.7µH 这个区间。输出电容同样关键它直接影响动态响应。如果负载会瞬间从 10mA 跳到 200mA输出电容太小电压就会跌出范围。我习惯在每一路 DC-DC 输出并一颗 22µF 陶瓷电容再加一颗 0.1µF 高频电容。示波器测动态负载响应时电压跌落可以控制在设定值的 3% 以内这个指标对 MCU 供电来说够用了。PCB 布线上最忌讳的是把输出电感下面的铜皮随意走线。PMIC 的开关节点SW是噪声源应该尽量短粗并且远离模拟信号。我有一次因为 SW 节点的走线绕了一圈结果 FM 接收模块的信噪比明显变差后来把走线缩短并加宽问题才消失。建议把 PCA9422 放在板子边缘输入电容和电感紧贴芯片反馈采样走线直接从输出电压点独立的细线连回 IC不要经过大电流路径。2.2 上电时序配置先让 MCU 活着再让外设醒小型 MCU 系统经常忽略上电时序实际调起来却很折磨人。PIC32MX664F064L 的电源起来到 Flash 可以访问中间有一个最小时间窗口。如果你在这一路还没稳定时就去操作外设轻则读回全 FF重则锁死总线。PCA9422 的优势在于通道的使能和上电顺序是可配置的。我配置的原则很简单第一优先级先给 MCU 的 3V3 路供电并且让它带缓启动第二优先级给 1V8 外设轨延迟几毫秒再上第三优先级才是传感器和模拟部分。这样 MCU 上电后可以第一时间初始化 I2C再去决定外设轨是否打开而不是被 PMIC 硬件强制把所有路同时拉起来。上电时序的配置通常通过 PMIC 的寄存器完成也可能会配合 EN 引脚。启动时我会先测每组时序之间的间隔用示波器确认各路电源的上升过程没有交叠和倒灌。特别提醒如果 MCU 的 IO 口在 PMIC 上电之前就处于高阻或者不确定状态而某个外设轨已经带电就可能通过 IO 引脚倒灌电流到 MCU 的 VDD。解决办法是在原理图阶段加入 MCU 侧的默认下拉或者在固件初始化时将相关 GPIO 设为输入低电平再统一控制外设电源。2.3 I2C、中断和电平匹配这三点最容易翻车PCA9422 作为从机挂在 I2C 总线上而 PIC32MX664F064L 是主机。I2C 总线物理层看起来简单实际翻车点多首先是从机地址PCA9422 的地址可能由 ADDR 引脚决定也可能固定我踩过一次配置寄存器写不进去查了半天发现是从机地址多了一位。建议第一步用逻辑分析仪抓一下 SDA 线上的地址字节比对着手册数 7 位地址到底是多少比盲改代码靠谱。其次是上拉电阻。3.3V 供电、I2C 速率 400kHz 时上拉电阻选 2.2kΩ 到 4.7kΩ 一般没问题。如果总线过长或者多个从机并联线电容增大2.2kΩ 可能还是偏强导致边沿过冲反之 10kΩ 又会让上升沿太慢。我这边总线上只有 PCA9422 和一个传感器最终用了 4.7kΩ波形干净ACK 非常稳定。电平匹配方面PIC32MX664F064L 的 IO 是 3.3VPCA9422 的 I2C 电压域一般跟它的 VDD 一致所以我直接把 PMIC 的 VDD 接 3V3两者不需要额外电平转换。但如果你板子上 MCU 是 1.8V 供电就一定要确认 PMIC 的 I2C 逻辑电平是否能接受 1.8V 的高电平阈值。这个问题在原理图评审阶段就该查真到贴片回来再发现改起来相当痛苦。中断脚 INT 我接到 PIC32 的一个外部中断引脚并配置为下降沿触发。PMIC 在电源状态异常、过流、温度保护时会拉低 INT。固件里我会在中断服务函数里读取 PMIC 状态寄存器把事件打印到日志方便事后分析。这个脚平时要加上拉电阻防止误触发。3. 基于 PIC32MX664F064L 的固件实现3.1 I2C 驱动打底PIC32 的 I2C 外设可以直接操作寄存器也可以用外设库。我更喜欢寄存器级操作因为每个读写的时序都心里有数。下面是一个精简的 I2C 读写函数模板以总线句柄为核心后续所有 PMIC 操作都基于它#define PMIC_I2C_BAUD 400000 uint8_t pmic_write_reg(uint8_t dev_addr, uint8_t reg, uint8_t val) { // 1. 发起 START // 2. 发送 dev_addr 1 | 0 (写地址) // 3. 等待 ACK // 4. 发送寄存器地址 reg // 5. 发送数据 val // 6. 发送 STOP // 返回 ACK 状态 } uint8_t pmic_read_reg(uint8_t dev_addr, uint8_t reg, uint8_t *buf) { // 1. 发起 START // 2. 发送 dev_addr 1 | 0 // 3. 发送寄存器地址 reg // 4. 重复 START // 5. 发送 dev_addr 1 | 1 (读地址) // 6. 读取数据主机回 NACK然后 STOP }真正写代码时要注意 PIC32 的 I2C 模块在收到 NACK 后会自动产生 STOP这会干扰你手动控制总线。如果调试时总是读不到数据优先看看模块是否已经把总线状态占了很多“卡死”都是因为没有及时清标志位。3.2 PCA9422 初始化与默认配置PCA9422 上电后的默认输出一般已经能让 MCU 跑起来但离一个系统真正能低功耗工作还差很远。我的初始化流程分四步解锁写保护、配置各路电压、设置电源状态和中断、最后验证回读。写保护这件事一定要重视。我之前调另一颗 PMIC 时连续写寄存器十个字节结果只有前两个生效后来才发现后半段被保护位锁住了。PCA9422 这类 PMIC 通常也有类似的保护机制建议先查手册里是否有 PROTECT 或者 LOCK 寄存器把写保护解开再执行后续配置。初始化伪代码如下void pmic_init(void) { // 1. 解锁写保护具体寄存器以手册为准 pmic_write_reg(PMIC_ADDR, REG_PROTECT, AUTH_CODE); // 2. 配置 DCDC1 输出电压与模式 pmic_write_reg(PMIC_ADDR, REG_DCDC1_VOUT, 0x1F); // 目标 1.2V pmic_write_reg(PMIC_ADDR, REG_DCDC1_CONF, 0x01); // 强制 PWM高负载 // 3. 配置 DCDC2 传感器轨 pmic_write_reg(PMIC_ADDR, REG_DCDC2_VOUT, 0x12); // 目标 1.8V // 4. 配置内部 LDO 模拟轨 pmic_write_reg(PMIC_ADDR, REG_LDO1_VOUT, 0x0A); // 目标 2.5V // 5. 配置上电顺序 pmic_write_reg(PMIC_ADDR, REG_SEQ_CTL, 0xA5); // 6. 读回关键寄存器确认配置成功 uint8_t val; pmic_read_reg(PMIC_ADDR, REG_DCDC1_VOUT, val); if (val ! 0x1F) { // 进入错误处理重试或报 log } }注意上面代码里的寄存器地址全部是示意实际地址和默认值一定要翻开对应手册逐条核对。我建议把这份初始化表独立成一个 const 数组方便调试时临时挪动某些配置项而不是把寄存器写在函数里到处改。3.3 动态电压调节 DVS 的固件写法PIC32MX664F064L 在跑大量计算时核心电压高一点能保证主频稳定进入轻负载任务后把电压降下来能省不少功耗。PCA9422 支持通过 I2C 直接写输出电压寄存器DVS 就可以动态改变标称电压。实际操作中我不只是写一个电压值那么简单还会先把 DCDC 调到 PWM 模式等电压稳定后再改目标值。某些 PMIC 如果处于 PFM 轻载模式电压跳变会有比较大的过冲或跌落。代码上可以做一个简单的电压配置函数void pmic_set_dcdc1_voltage(uint8_t target) { // 先设置 DCDC 工作模式保证快速响应 pmic_write_reg(PMIC_ADDR, REG_DCDC1_CONF, 0x01); // 强制 PWM delay_us(10); // 写入目标电压 pmic_write_reg(PMIC_ADDR, REG_DCDC1_VOUT, target); // 可选等待输出电压稳定通过状态位或延时 delay_ms(1); }调 DVS 的速度要跟系统 load transition 匹配。我的经验是任务调度器在切换到高负载任务前先调高电压再启动任务任务结束后过几十毫秒再把电压降回低档。太快降电压会导致高频任务刚开始就跑飞太慢降又省不了多少功耗这个时间窗口要靠实测微调。3.4 低功耗状态机RUN / STANDBY / SLEEP / OFF低功耗电源管理核心是状态机。我把系统分成了四个状态系统状态MCU 状态PCA9422 电源通道目标整机电流RUN全速运行3V3、1V8、1V2、2V5 全开50~150mASTANDBY等待指令低主频只开 3V3 和 1V8关 1V2、2V52~5mASLEEPMCU 睡眠保留 RTC 定时唤醒只保留 3V3 通道其余关断20~50µAOFF深度休眠可外部唤醒全部关断或仅保留唤醒域5µA 以下固件切到 SLEEP 状态的流程很关键不能只让 MCU 进 sleep 就完事。我习惯按这个顺序执行先让所有外设进入待机停止 SPI/UART 通信关闭不用的 GPIO 中断确保没有外设往上拉电源轨通过 I2C 逐路关闭 PCA9422 的 DCDC、LDO 通道等待几毫秒让输出电容掉电再去操作 MCU 进入睡眠唤醒源到来后MCU 先恢复随后初始化 PMIC 到 RUN 状态。这里有个容易踩的坑如果某路外设供电通道已经关闭但它的电源引脚还通过芯片内部二极管往系统倒灌电流睡眠功耗就会飙升。所以原理图阶段对所有外设的电源脚我都检查了“是否存在到 VDD 的内部路径”。对于那些无法断开电源但静态电流又大的芯片我宁愿在软板上加一个负载开关也不让它长期挂在电源轨上。4. 调试实录与常见问题排查4.1 I2C 通信时好时坏PMIC 配置写不进去现象代码跑起来PIC32 读取 PMIC 寄存器有时全 FF有时能读到但写进去不生效有时复位后第一次通信必然失败。排查路径先用逻辑分析仪抓 I2C 波形确认总线上地址字节、寄存器地址、ACK 位都对。最常发现的是地址高位不对——比如 7 位地址是 0x30但代码里写成了 0x30 1而且没统一右移。第二个常见原因是上拉电阻太大或总线走线过长400kHz 速率下边沿太缓导致 PMIC 对 SCL 的识别有问题。第三个原因是 MCU 的 I2C 模块在初始化前总线状态混乱需要手动发送一串 9 个 SCL 脉冲把总线恢复成空闲。解决方法先把 I2C 时钟降到 100kHz确认波形干净了再提速率在驱动初始化开始时执行一次总线清空函数读回验证寄存器时如果失败做一次重枚举而不是直接报错。4.2 输出电压偏低万用表量出来差 0.1V现象寄存器配置 1.2V示波器看输出只有 1.1V而且带负载后更低。排查思路先测 PMIC 的输入电压如果电池已经掉到 3.3V 以下而 DCDC 又设定在较高输出占空比不够自然掉压。再看负载电流输出电流如果已经接近甚至超过电感的额定值压降会很明显。最后也要查寄存器是否有另外的反馈微调位很多 PMIC 除了电压选择还有 trim 校准寄存器出厂默认的校准值不一定适合你的电感电容组合。这类问题我习惯用电子负载做静态测试从 10mA 到最大负载逐级增加记录输出电压曲线。如果负载大的时候电压跌太多优先换饱和电流更大的电感或调高标称电压留余量而不是盲目在寄存器里提高设定值。4.3 睡眠电流下不来整机实测 200µA远高于目标这是所有低功耗项目最容易卡住的问题而且很多时候 PMIC 本身没问题。我的排查法是“通道关断法”把 PMIC 的每一路通道手工关掉同时用万用表串联在电池输入处看电流。先全部关断测出底数再逐路开启看哪一路开启导致电流大增。如果全部关断后底数还是大问题就在 MCU 自身或外部漏电路径。我遇到过三个典型原因PIC32MX664F064L 的某个 GPIO 没有配置成模拟输入还在往外设供电轨输出高电平导致即便 PMIC 关断了外设轨电流也能通过 GPIO 灌出去。解决办法是把所有未用引脚设为模拟输入或输出低并且逐引脚排除。外部上拉电阻挂在 3V3 轨上而 3V3 轨没有真正关闭上拉电阻始终耗电。低功耗设计里上拉电阻要么关断要么选择的阻值足够大可接受损耗。PMIC 的 EN 引脚悬空或被外部拉高导致通道没有真正进入关闭状态而是进了待机模式。需要确认 PMIC 每一路通道都处于 disabled 状态而不只是输出电压为零。4.4 上电偶发失败概率性死机现象冷启动时大约 5% 概率 MCU 跑不起来必须按复位键才能恢复按复位后基本都能正常运行。分析这是典型的上电时序问题。PMIC 的各路输出虽然开始上升了但 MCU 的复位电路、IO 默认状态和外设上电之间存在竞争窗口。如果某个外设轨比 MCU 的 VDD 更早到达工作电压外设就会通过它的 IO 往 MCU 灌电流把 MCU 的内部逻辑锁在不稳定状态。我的解决方案在 PMIC 时序配置里让 MCU 的 3V3 轨严格早于外设轨 5ms 以上把 MCU 的复位控制由简单的 RC 复位改为由 PMIC 或者专用复位芯片控制给所有与外部模块相连的通讯 IO 加默认下拉电阻或软件配置为输入模式避免上电瞬间输出错误电平。调这类问题示波器必须四通道同时看输入电压、MCU 3V3、外设 1V8、复位脚。抓一次冷启动事件的波形基本一眼就能定位是谁先谁后出了问题。最后分享两个实测经验如果让我再调一遍这套方案我不会一上来就调 PMIC 寄存器而是先拿一张纸把电源状态画清楚每个状态要亮哪些轨每路轨的电压目标切换需要多少毫秒。把这些定义清楚之后再去固件里写状态机之后动手调寄存器就很顺。另一个经验是像 PCA9422 这类 PMIC出厂默认配置往往不是为了你的系统准备的但也不是完全不能跑。只要保证默认输出至少能点亮 MCU 的 I2C你就有机会在固件里做完整的二次初始化。这是调试的兜底逻辑不要一上来就依赖配置寄存器实现所有功能。我目前这个组合的实测结果RUN 状态整机约 90mA轻负载 STANDBY 约 3.2mASLEEP 状态可以稳定在 25µA 左右OFF 状态接近 5µA。这个数据在同级别便携设备里属于相当能打的水准。如果你正好也在做类似的便携低功耗项目建议不要纠结于“用哪颗芯片最豪华”先把电源树和状态机想清楚再挑一颗像 PCA9422 这样配置灵活、静态电流低的 PMIC配合 PIC32MX664F064L 这类 IO 和 I2C 都健壮的 MCU整体调试效率会高很多。
RELATED READING

延伸阅读

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