
直接用 PCA9422 配 STM32L081CB 做完整电源管理这个组合在低功耗穿戴设备和物联网传感器节点里非常常见。一根电池线进来PCA9422 负责充电、升降压和动态调压STM32L081CB 负责跑应用、协调低功耗模式、通过 I2C 随时调整各路输出电压。这篇文章我会把整个设计从需求拆解到寄存器配置、从硬件电路到固件状态机全部过一遍重点是我实际调试中踩过的坑和最终测出来的功耗数据希望能给正在做类似方案的人省点时间。1. 项目定位与电源管理设计思路1.1 这套组合解决了什么问题先说清楚这套方案到底在解决什么场景的问题。我这边做的是一个腕带式健康监测设备主控就是 STM32L081CB外设包括一颗加速度计、一颗光学心率传感器、一个 128x64 的 OLED 屏和一颗蓝牙射频芯片。设备用一颗 500mAh 的锂聚合物电池供电但系统内部一共有四路不同电压的需求主控核心逻辑1.8VSTM32L081CB 的工作电压下限支持到 1.65V但官方手册推荐 1.8V 附近波动不会引入额外风险IO 和传感器数字部分3.3V加速度计和蓝牙芯片的数字接口都跑 3.3V 电平模拟传感器供电2.8V光学心率传感器对电源纹波比较敏感它内部有自己的一级 LDO但输入电压不能超过 3.0V屏幕背光或对比度泵5VOLED 屏内部 DC-DC 虽然能自己产生负压但我用的是需要外部升压的模组以前的做法是拿一颗充电管理芯片加一颗 LDO 阵列再加一颗 DC-DC电路板面积大、器件多、BOM 成本高。这次直接选 PCA9422就是因为这颗 PMIC 把锂电充电、两路降压 DC-DC、一路 LDO 和一个 5V 升压路径全部集成在一起了而且所有输出电压都可通过 I2C 寄存器在线调整。STM32L081CB 在这里承担的角色不只是应用处理器它本身就是整个电源管理的大脑。PCA9422 的上电时序、工作模式切换、输出电压动态调节全部由 STM32L081CB 通过 I2C 控制。设备休眠时STM32 进入 Stop 模式同时通知 PCA9422 关闭非必要路输出整机待机电流可以压到 10μA 以下设备运行时STM32 根据当前负载动态调整 Buck 输出电压保证性能和功耗的平衡。1.2 方案选型背后的权衡选 PCA9422 而不是单独用充电 IC 加多个 DC-DC核心权衡是面积和灵活性。PCA9422 封装是 2.5mm x 2.5mm 的 WLCSP比我之前用的充电 IC 双 DC-DC 单 LDO 方案至少省掉 40% 的 PCB 面积。对于腕带设备这种对板面积极度敏感的产品这个差异是决定性的。但面积换取的是配置复杂性。PCA9422 的设置全部通过 I2C 寄存器完成一上电如果不写初始化序列它的默认输出可能并不匹配你的电路设计。这意味着你必须保证 STM32L081CB 在 PCA9422 之后上电并且能够在系统启动早期就对它完成配置。好在 STM32L081CB 支持多种低功耗唤醒方式你们可以让 I2C 的配置任务在系统初始化阶段优先执行后面会细说。另一个要考虑的是芯片等级。PCA9422 的充电电流上限是 800mA我这边实际设计的是 500mA 充电电流留了余量。如果你做的产品需要 1A 以上的快充这颗芯片就不适合了。所以选型时先列需求矩阵输入电压范围、电池节数、充电电流、输出路数、动态调压速度每项都框好再选型不要只盯着参数表最亮眼的那一行。STM32L081CB 的选型也有讲究。L0 系列主打超低功耗但 L081 这一款是 192KB Flash 20KB RAM 的高配版本它比 L071 多了一个 USB 设备控制器。如果你的设备不需要 USB可以降级到 L071 或者 L051 来省成本但如果你的应用需要 USB 枚举来做固件升级或者日志导出L081 就是性价比不错的选择。我这次保留 USB 是为了产测阶段的高速日志输出量产固件里可以把这部分关掉以节省功耗。2. PCA9422 核心特性与配置细节2.1 引脚与内部结构要点PCA9422 的内部结构大致可以分为五个功能区块电池充电管理、两路 Buck 转换器、一路 LDO、一路 Boost 升压、以及 I2C 控制和状态监测逻辑。充电管理部分支持 4.2V 单节锂电的线性充电最大充电电流 800mA输入电压范围是 3.6V 到 6.0V。它内部有完整的充电状态机预充、恒流充电、恒压充电、充电完成、待机。状态机迁移的阈值是可以通过寄存器配置的比如预充电流、恒流转恒压的电压点、充电完成电流、重新充电的电压回滞。两路 Buck 是 PCA9422 的供电主力。Buck1 输出电压范围比较宽可以从 1.0V 调到 3.3V步进是 50mVBuck2 同样是 1.0V 到 3.3V 范围。两路 Buck 的开关频率都是 2MHz这意味着外部电感可以选得非常小我用的是一颗 2.2μH 的电感尺寸是 1.0x0.5mm对板面积贡献很小。LDO 的输出电压范围是 1.8V 到 3.3V最大输出电流 100mA用于噪声敏感的模拟电路供电。Boost 升压部分输出电压默认是 5V可以给屏幕或小电机供电输出能力在 100mA 级别。所有这些电压通道的启停都由 I2C 寄存器控制PCA9422 的 I2C 从机地址是 0x607 位地址支持标准模式和快速模式最大速率 400kHz。I2C 引脚是开漏输出需要外部上拉电阻。还有一个值得注意的接口是它的中断输出引脚。PCA9422 内置了充电状态变化、电池欠压、过热保护等事件的中断源可以配置通过中断引脚上报给 STM32L081CB这样主控不需要轮询寄存器能进一步降低功耗。2.2 关键寄存器与初始化序列PCA9422 的寄存器映射分两大块系统控制寄存器和各路输出通道的配置寄存器。在实际项目中我总结了一套完整的上电初始化流程按顺序写入可以避免很多奇怪的启动问题。第一步是软复位并等待器件稳定。PCA9422 上电后会有一个内部延时确保输入电压稳定后才开始响应 I2C。初始化代码可以在 STM32 启动后延时 10ms 再开始配置这个延时非常关键太短可能读到随机值。第二步配置系统控制寄存器。这里主要是选择 buck 的工作模式强制 PWM 还是自动 PFM/PWM 切换设置中断使能配置充电状态机的关键参数。PFM 模式在轻载时效率更高但在重载切换瞬间会有电压波动我推荐系统在运行态用强制 PWM在轻载待机态切到自动 PFM。第三步按顺序配置 Buck1、Buck2、LDO、Boost 的输出电压。我遇到的一个坑是 Buck1 和 Buck2 的输出电压寄存器写入后并不会立刻生效需要等待大约 500μs 的暂态如果连续快速写入两个通道后写的通道可能因为前一个通道的瞬态还在进行而出现写入不成功的现象。所以每写一个通道后要加至少 1ms 的延时。给出一段参考代码基于 STM32L081CB 的 HAL 库重点是配置逻辑#include stm32l0xx_hal.h #define PCA9422_ADDR 0x60 #define REG_SYS_CTRL1 0x01 #define REG_BUCK1_CFG 0x04 #define REG_BUCK2_CFG 0x07 #define REG_LDO_CFG 0x0A #define REG_BOOST_CFG 0x0C uint8_t pca9422_reg_write(uint8_t reg, uint8_t val) { uint8_t buf[2] {reg, val}; // 使用阻塞式I2C写HAL_I2C_Master_Transmit return HAL_I2C_Master_Transmit(hi2c1, PCA9422_ADDR 1, buf, 2, 100); } void pca9422_init(void) { // 等待PCA9422上电稳定 HAL_Delay(10); // 系统控制 // bit1:0 PWM/PFM自动切换 // bit3 使能Buck1 // bit4 使能Buck2 // bit5 使能LDO // bit6 使能Boost uint8_t sys_ctrl 0x00; sys_ctrl | (0x01 1); // auto PFM/PWM sys_ctrl | (0x01 3); // Buck1 on sys_ctrl | (0x01 4); // Buck2 on pca9422_reg_write(REG_SYS_CTRL1, sys_ctrl); HAL_Delay(5); // 配置Buck1输出为1.8V计算方式base1.0Vstep50mV // 电压档 (1.8 - 1.0) / 0.05 16 0x10 uint8_t buck1_cfg 0x00; buck1_cfg | (0x10 0x3F); // 输出目标电压编码 buck1_cfg | (0x01 6); // 强制PWM使能位 pca9422_reg_write(REG_BUCK1_CFG, buck1_cfg); HAL_Delay(1); // 配置Buck2输出为3.3V档位 (3.3 - 1.0) / 0.05 46 0x2E uint8_t buck2_cfg 0x00; buck2_cfg | (0x2E 0x3F); buck2_cfg | (0x01 6); pca9422_reg_write(REG_BUCK2_CFG, buck2_cfg); HAL_Delay(1); // 配置LDO输出为2.8VLDO步进也是50mV档位 (2.8 - 1.8) / 0.05 20 0x14 uint8_t ldo_cfg 0x00; ldo_cfg | (0x14 0x1F); pca9422_reg_write(REG_LDO_CFG, ldo_cfg); HAL_Delay(1); // 配置Boost输出为5V配置位按数据手册默认就是5V则可以直接写0x00 pca9422_reg_write(REG_BOOST_CFG, 0x00); }写这段代码时有一个容易忽略的点I2C 地址是 7 位地址 0x60在 HAL 库中需要左移一位变成 0xC0 作为设备地址传入。这个错误非常隐蔽因为 I2C 协议层看不到地址是否被正确匹配你只会发现所有写操作都返回超时排查半天才发现是地址没有移位。3. STM32L081CB 低功耗协同工作3.1 低功耗模式与电源状态映射STM32L081CB 有六种主要工作模式从高到低分别是Run、Low-power Run、Sleep、Low-power Sleep、Stop 和 Standby。其中 Stop 模式又分为带 RTC 的 Stop with RTC 和不带 RTC 的 Stop 2 模式。在设计电源管理方案时最核心的工作就是把设备的业务状态映射到 STM32 的功耗模式和 PCA9422 的输出通道上。我最终定义了三套电源状态状态 A 是运行态对应 STM32 的 Run 模式CPU 跑 16MHzPCA9422 的全部输出通道打开给传感器、屏幕、蓝牙供电。这个状态只有在用户主动交互或者数据同步时才进入。状态 B 是待机态对应 STM32 的 Stop with RTC 模式CPU 停住RTC 和部分外设保持工作。此时 PCA9422 的 Boost 关闭屏幕供电断开LDO 关闭但 Buck1 和 Buck2 保持输出保证加速度计还能工作可以检测运动唤醒事件。状态 C 是深度睡眠态对应 STM32 的 Standby 模式只有复位引脚和 RTC 唤醒源生效。PCA9422 只保留 Buck1 输出给 STM32 的备份域供电其余通道全部关闭。这三套状态的切换不是简单的 STM32 模式切换还需要同步操作 PCA9422。有一次我在测试中发现从状态 B 切换到状态 A 时传感器上电后立即读取数据会返回错误后来定位是因为 PCA9422 的 LDO 输出缓启动时间比预期长MCU 已经跑起来了但传感器电源还没稳定。解决方法是传感器的上电初始化代码加一个 10ms 延时或者等 PCA9422 的中断引脚电平拉高后再开始访问外设。3.2 I2C 通信与动态调压逻辑PCA9422 与 STM32L081CB 之间只有一条 I2C 总线而 I2C 本身是全双工或者半双工的不重要关键点是这条总线要稳定、可靠、不拖后腿。我在设计时给 I2C 总线配了 4.7kΩ 上拉电阻到 Buck2 的 3.3V 输出。这里有个细节PCA9422 的 I2C 供电是从 VDDIO 引脚过来的而 VDDIO 我直接接到了 Buck2 的输出上。这意味着如果 Buck2 被关闭PCA9422 的 I2C 也同时失效。所以我在任何固件代码中都有一条纪律关闭 Buck2 前必须先把 PCA9422 的系统控制寄存器中 Buck2 使能位保持为 1只关负载端的负载开关不要直接在 PMIC 层面关掉 Buck2。动态调压是本方案的重点功能。STM32L081CB 的功耗与核心电压直接相关高电压下漏电增加低电压下高频运行容易触发硬件错误。我实测了不同核心电压配置下的功耗核心电压设置频率待机电流含外设运行电流跑 while 循环1.65V16MHz8.2μA1.85mA1.80V16MHz9.6μA2.10mA1.95V16MHz12.4μA2.40mA2.10V32MHz14.8μA3.75mA这个数据说明动态调压确实能带来百分之十几的功耗节省但前提是频率也要跟着调。如果电压降到 1.65V 而频率还跑 32MHz芯片内部路径延迟不够会出现随机死机排查起来非常痛苦。我的做法是做一个 crm 表把系统频率和核心电压打包成档位切换时先降频再降压升压时先升压再升频顺序反了就会出问题。I2C 通信速度方面实测下来 PCA9422 在 400kHz 的快速模式下工作稳定不需要启用 STM32 的时钟延展功能。但要注意I2C 中断处理函数里不要做耗时操作否则会影响 PMIC 的实时响应。我在生产代码里把调压操作放在一个无阻塞的任务调度器里预期延迟不超过 2ms。4. 硬件电路与固件实现4.1 供电电路设计要点硬件设计上首先要明确整个电源树电池经过 PCA9422 的 BAT 引脚进入充电管理部分PCA9422 的 SYS 引脚输出系统主电源即电池直接供到系统。PCA9422 的 Buck1 输出接 STM32L081CB 的 VDD 和 VDDABuck2 输出接所有 3.3V 外设LDO 输出接光学传感器的模拟供电Boost 输出接 OLED 屏。这样做的好处是系统所有电压轨都由 PCA9422 管理BOM 简单而且可以在固件中灵活控制每一路的开关和电压。PCB 布局上要注意电感的位置。两路 Buck 的电感必须远离 STM32 的晶振引脚我实测如果电感靠近 32.768kHz 晶振超过 5mm晶振起振时间会明显变长偶尔还会出现不起振的情况。后来我把晶振移到 PCB 边缘电感控制在另一侧问题就没有再出现。PCA9422 的 WLCSP 封装属于很难手工焊接的类型样机阶段需要找支持 WLCSP 的焊接渠道。另外芯片底部的散热焊盘必须良好接地我第一版 PCB 没开足够散热过孔充电 500mA 时 PMIC 表面温度实测到 72 度后来增加了六个过孔后温度降到 48 度效果非常明显。电池端的输入滤波电容我用的是 10μF 陶瓷电容加 1μF 电容并联分别对应高频和低频抑制。陶瓷电容选 X5R 或 X7R 材质不要用 Y5V后者的容量随温度变化太剧烈零下低温和高温环境实测容量会掉到原本的 30% 以下对充电环路的稳定性影响很大。4.2 固件状态机设计固件部分的架构我用了非常简单的状态机不引入 RTOS因为这种低功耗设备的任务切换不算复杂用一个大循环加中断标志位就足够了。状态机定义五个状态SYS_INIT系统初始化包括 PCA9422 配置、STM32 时钟配置、外设初始化SYS_MEASURE采集传感器数据处理算法SYS_SYNC蓝牙连接同步数据SYS_SLEEP_DEEP深度睡眠仅 RTC 运行SYS_SLEEP_LIGHT待机态加速度计可唤醒状态迁移的事件来源有三个定时器超时、传感器中断、RTC 唤醒。其中进入深度睡眠是一个严格的流程顺序不能乱void enter_deep_sleep(void) { // 1. 暂停外设访问 sensor_disable(); display_disable(); // 2. 关闭Boost和LDO pca9422_reg_write(REG_SYS_CTRL1, PCA9422_BUCK1_ON | PCA9422_BUCK2_ON); // 3. 配置RTC唤醒 RTC_SetAlarm_IT(WAKE_UP_PERIOD_S); // 4. 将引脚统一配置为模拟输入避免浮空灌电流 HAL_GPIO_DeInit_all_pins(); // 5. 进入Standby模式 HAL_PWR_EnterSTANDBYMode(); // 代码不会继续执行复位后从头开始 }这套顺序中我踩过的坑是第一步和第二步之间没有留时间。传感器和屏幕关电瞬间会在 PCA9422 的输出端产生一个电压跌落如果此时 STM32 还在执行引脚的读写操作可能导致 GPIO 电平翻转产生毛刺。正确做法是先关闭外部设备的访问延时至输出稳定后再关闭 PMIC 通道。醒来的反向流程也需要注意。STM32L081CB 从 Standby 唤醒后CPU 是冷启动所有 SRAM 数据都丢失了但只要备份域寄存器没有复位RTC 时间依然有效。如果需要在唤醒后快速恢复业务可以把必要的上下文放到备份寄存器中12KB 的备份 SRAM 在这个场景下非常好用。固件中还要处理充电状态机与系统状态机的耦合。PCA9422 的充电状态变化会产生中断STM32 收到中断后需要读取充电状态寄存器。我一开始用轮询方式每 100ms 读一次充电状态电池电压导致轻载态下功耗多了 30μA。改成中断驱动后只在状态变化时唤醒读取功耗明显下降。5. 实测数据与排查经验5.1 常见问题速查表在实际调试过程中我把遇到的问题分成了几类做成了一个速查表方便快速定位症状可能原因排查手段I2C 写超时地址未左移/上拉电阻缺失/PMIC未使能VDDIO检查地址位示波器看SCL/SDA时序确认Buck2输出Buck 输出电压偏高强制PWM档位下PFM被禁用空载电压升高读取Buck配置寄存器配置自动PFM/PWM传感器上电读不到 IDLDO 缓启动时间过长/负载过大导致输出欠压上电初始化加延时测量上电时序波形深度睡眠电流居高浮空GPIO/未关闭Boost/PMIC内部使能未改逐路驱动检查测量各电压轨电流充电电流达不到设定值适配器限流/电池电压低/系统负载分走电流用电子负载校准检查PCB铜箔宽度唤醒后 I2C 无响应PMIC 处于低功耗模式/I2C bus lock释放总线或切换起始位检查时钟屏幕闪烁Boost 输出带载不佳/负载突变更快在Boost输出端加100μF电解电容升级电感选型其中第二条的 Buck 输出电压偏高问题是我调试时印象最深的一个。PCA9422 在 PFM 模式下轻载时输出电压会略高于目标值允许范围一般是 ±3%但我第一次测的时候用的是 3.3V 档位加上空载输出到了 3.42V超出我的预期。后来发现是强制 PWM 模式导致的PFM 模式下空载电压就没这个问题。所以设计时要根据负载链路对电压的敏感程度来选模式对电压精度敏感的模拟电路尽量用自动 PFM/PWM 模式数字电路反而无所谓。5.2 优化后的实测功耗表现最后放一组完整系统在三种状态下的实测数据。测量方式是采样电阻法在电池端串入一个 10mΩ 采样电阻用示波器高分辨率模式记录电流波形积分后取平均值。注意电池端的瞬时电流会受 PCA9422 开关频率影响测量带宽要设到 20MHz 以上否则数据会偏小。深度睡眠态Standby 仅 Buck1 供电 RTC 运行整机电流 8.6μA其中 STM32L081CB 的 Standby 功耗约 1.2μAPCA9422 的静态电流约 2.3μABuck1 在 PFM 模式下的损耗约 3.5μA其余是电阻网络和电池保护板漏电流。待机态Stop with RTC Buck1 和 Buck2 供电 加速度计运行整机电流 47μA加速度计占 15μASTM32 Stop 模式占 4μABuck2 带传感器负载约 12μA剩下的是各类静态损耗。运行态Run 16MHz 全部外设开启 4Hz 心率采样平均电流 32.4mA峰值电流 58mA。其中屏幕刷新瞬间电流占了大多数传感器和蓝牙各占 5mA 左右。最终的续航测算500mAh 电池假设一天中深度睡眠 20 小时、待机 3 小时、运行 1 小时平均每天耗电约 32.4mAh理论续航约 15 天。这个数据在我们同类设备中属于中等偏上水平。如果你要做进一步的功耗优化我建议按顺序检查这几个方向一是把 PCA9422 的充电管理部分在系统深度睡眠时关闭这会省掉充电检测电路的约 1μA二是将加速度计的采样频率从 30Hz 降到 15Hz功耗可以减半三是屏幕上增加按键唤醒和自动熄屏逻辑运行态的平均功耗能再降一半。这几项做完续航到 20 天问题不大。还有一个小经验SCL 和 SDA 的 GPIO 在深度睡眠前要配置为模拟输入不要配置为推挽输出高电平。有一次我为了省外部上拉电阻想让 MCU 的 GPIO 在睡眠时维持高电平给 PCA9422 的 I2C 供电结果漏电流非常大整机休眠电流飙到 150μA。排查到最后发现是 GPIO 在输出高电平时会有大量漏电。后来规规矩矩用外部 4.7k 上拉电阻睡眠前把 GPIO 置为模拟输入电流就恢复正常了。整个方案从画原理图到出实测数据前后大概三周中间最耗时的是低功耗电流的逐路压测。只要能复现我上面的初始化流程和状态切换顺序这套设计基本可以一次跑通。最后再提醒一次PCA9422 的 I2C 地址移位问题和 Buck 启动延时是我统计下来最容易出问题的两个点代码里记得留好注释方便后来接手的人少走弯路。