直接说结论:这块板子做完之后,我的待机电流从改方案前的几十毫安级别压到了个位数微安级别,充电、电压轨、电量显示全部走一颗芯片和一条 I2C 总线管起来。如果你也在做带锂电池的便携设备,手头又有一颗 STM32F746ZG 这种高性能主控,PCA9422 这颗 PMIC 值得认真看一看。下面把从选型、硬件搭电源树、寄存器配置,到软件状态机和实测避坑的完整过程拆开讲。
我用 PCA9422 和 STM32F746ZG 做的这块控制板,目标是带着 480×272 TFT 屏、一段简单的 GUI、几个传感器,还要承担部分信号处理的活。性能要求不低,但设备又是电池供电,用户还明确要求“关机后要能靠 RTC 唤醒且放置一个月不亏空”。这种需求如果继续用“主芯片 + 一堆分立 LDO + 独立充电板”的老路子,PCB 面积撑不住,待机电流也没法看,最后才定下了这套 PMIC 方案。
1. 为什么是 PCA9422 + STM32F746ZG
先回答一个最常见的问题:STM32F746ZG 这种 216MHz 的 Cortex-M7 芯片,本身功耗就不低,拿它做电池设备是不是自找麻烦?
这得分场景。如果设备是手环、电子标签这类纯低功耗节点,我当然不会选 F746。但这块板的定位是便携检测仪表——平时开机干活,跑 GUI、处理数据;不用的时候整个系统进入深度待机,除了 RTC 和唤醒按键,其余全部断电。这种情况下,主控在运行时的绝对功耗反而不是第一矛盾,待机功耗和“说关就关、说开就开”的电源管理能力才是。
再看电源这一侧,当时摆在我面前有三条路:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 全 LDO | 便宜、电路简单、纹波干净 | 压差损耗大,3.7V→1.8V 发热明显;没有任何充电管理能力 |
| 分立 DCDC + 充电芯片 | 效率高、每个模块都能选到合适的料 | 三四个芯片挤在一起,I2C 配置各异,启动时序全靠硬件设计拉,PCB 和调试成本都高 |
| PMIC 单芯片 | 充电、多路 DCDC、LDO、ADC、保护集成在一起,一个 I2C 地址搞定所有 | 需要花时间吃透寄存器,一旦固件没写好,整机电源都会出问题 |
我最终选了第三种。PCA9422 内部集成了两路 BUCK、一路 LDO、线性锂电池充电器、多路 ADC、负载开关逻辑和中断管理。对于一块主控外设不算特别复杂的便携板来说,一颗芯片刚好覆盖全部电源需求,剩下的就是把它和 STM32 的 I2C 接在一起。
还有个很重要的匹配点:STM32F746ZG 的 VDD 范围支持 1.7V~3.6V,绝大多数外设和 LCD 逻辑也用 3.3V,所以 PCA9422 的第一路 BUCK 直接出 3.3V 就能喂饱整块数字系统;LDO 常开输出喂 STM32 的 VBAT 备份域,这样 RTC 在整机断电时也不会停。两边电压域严丝合缝,不需要额外电平转换。
2. 硬件设计:电源树怎么搭
2.1 先把 PCA9422 的家底盘清楚
拿到任何一颗 PMIC,我习惯先花半天把内部模块和寄存器表通读一遍,用表格把每个模块的职责列出来,再动笔画原理图。PCA9422 的核心模块大致是这些:
- BUCK1:高效率 DC-DC,输出范围大致覆盖 0.6V~3.3V,适合做主电压轨。我拿来出 3.3V 系统主电源。
- BUCK2:第二路 DC-DC,适合给 1.8V 或 3.3V 外设供电,也可以按需关闭。我这里给 SD 卡和电平转换电路用。
- LDO:低噪声线性稳压,适合常开电源域。我拿它出 3.0V,专门供给 STM32 的 VBAT 备份域和 RTC。
- 线性充电器:内置充电管理,支持涓流、恒流、恒压、截止四个阶段,充电电流可通过寄存器设置。线性充电方案在小电流场景下非常合适。
- ADC 与电量监测:内部 ADC 可以采样电池电压等节点,相当于给了 MCU 一个原生的“看电量”通道。
- 中断与保护:支持 VBUS 过压、过温等保护,并有中断引脚可以把充电完成、电压异常等事件通知 MCU。
有一点必须强调:以上模块分工是这颗芯片的典型使用方式,具体每一路可调范围和寄存器地址,以你手里那版数据手册为准。芯片资料里的寄存器表就是“法律”,写驱动前先把它打印出来或做成 Excel,绝对值得。
2.2 最终电源树方案
我定下来的电源树是这样的:
| 电源网络 | 来源 | 默认电压 | 去向 | 控制策略 |
|---|---|---|---|---|
| VBAT | 1S 锂聚合物电池 | 3.0~4.2V | PCA9422 主输入 | 系统唯一能量来源 |
| SYS_3V3 | BUCK1 | 3.3V | STM32 VDD、LCD 逻辑、传感器、IO 上拉 | 开机即上,关机全断 |
| SYS_1V8 | BUCK2 | 1.8V | SD 卡、电平转换 | 按需开启,不用即关 |
| RTC_3V0 | LDO | 3.0V | STM32 VBAT 备份域 | 常开,关机保持 |
| CHG_USB | USB 5V | 5V | 充电输入 | 带 TVS,防倒灌 |
这里有两个设计决策值得展开。
第一个,为什么主轨一定要从电池经过 BUCK 变成干净的 3.3V,而不是直接用电池电压?锂电池电压在 3.0V~4.2V 之间波动,如果直接接 STM32 的 VDD,ADC 采样参考会跟着跳,传感器供电也不稳,而且电池低压时可能跌破 MCU 最低工作电压导致突然复位。BUCK 输出 3.3V 之后,输入电压变化被稳压电路吸收,全系统供电稳定。
第二个,为什么 RTC 备份域用 LDO 而不是 BUCK?因为备份域电流只有微安级别,DC-DC 在这种负载下效率反而不如 LDO,而且 BUCK 的静态电流通常比 LDO 大。LDO 在这里虽然效率低,但胜在“永远在线、足够省电、噪声小”。一颗 LDO 常年吃几个微安,换来关机状态下 RTC 不停摆,完全划算。
2.3 STM32 侧硬件连接与 PCB 要点
接线本身不复杂,关键是考虑好引脚功能和抗干扰。我的连接如下:
| PCA9422 信号 | STM32F746ZG 引脚 | 说明 |
|---|---|---|
| SCL | PB8 (I2C1_SCL) | 400kHz 快速模式,4.7kΩ 上拉到 SYS_3V3 |
| SDA | PB9 (I2C1_SDA) | 同上 |
| INTB | PI3(任意 EXTI 引脚均可) | 下降沿触发,通知 MCU 充电/异常事件 |
| EN | PF5(任意 GPIO) | 控制 PMIC 整体使能,硬件上预留测试点 |
| RTC_3V0 | STM32 VBAT | 常电备份域 |
| SYS_3V3 | STM32 VDD/VDDA | 所有 VDD 引脚就近放 100nF 去耦电容 |
PCB 上有几个细节,吃过亏之后才长记性:
- BUCK 的电感要靠近芯片,开关节点(LX)走线尽量短而粗,不要穿过其它信号线,否则辐射噪声会让 ADC 采样乱跳。
- 输入输出电容按手册推荐的容值放,至少要在 VBAT 输入并联一个 10μF 陶瓷电容吸收瞬态,否则大电流负载切换时电压会瞬间掉落。
- I2C 上拉电阻我选了 4.7kΩ。如果总线速度快或者线太长,可以换 2.2kΩ,但要同时考虑上拉灌电流不能超过器件规格。
- 给每一路电源输出预留 0Ω 电阻位或磁珠位,调试时想单独测某一轨电流,直接拆电阻就能切断,非常方便。
- 充电输入 USB 5V 线上加 TVS 管和 π 型滤波,别省,实验室里稳压电源反接一次你就知道值不值。
3. STM32 侧工程搭建:I2C 与开机时序
3.1 I2C 资源分配与 CubeMX 配置
STM32F746ZG 片上 I2C 外设有好几个,我选 I2C1,因为 PB8/PB9 在板卡布局上离 PMIC 最近,走线最顺。CubeMX 里的配置没什么稀奇,但有几个点要注意:
- I2C 速度选 Fast Mode,400kHz。PMIC 通信量不大,400kHz 足够,没必要上 1MHz 给自己找信号完整性的麻烦。
- I2C1 的时钟源来自 APB1,如果你后面改动系统主频,记得重新检查 I2C 时序参数,不然可能出现“能配置但通信偶发失败”这种玄学问题。
- EN 引脚配置成 GPIO 输出,初始电平按需求来。我这边想让“电池一接上 PMIC 就保持待机,由 MCU 决定何时开机”,所以默认拉低。
- INTB 引脚配置成外部中断,下降沿触发,抢占优先级不要太高,因为中断里只置标志位、唤醒 RTOS 任务,不做耗时操作。
PCA9422 的 7 位 I2C 地址由 ADDR 引脚或芯片内部配置决定,我手里的样片实测地址是 0x10。你拿到自己那颗芯片以后,第一件事就是写一个扫描代码把地址打出来,别想当然沿用网上别人的值。
3.2 上电开机时序设计
电源管理的核心不仅仅是“给电压”,更重要的是“按什么顺序给”。我的开机流程是这样设计的:
- 电池接入,VBAT 建立。PCA9422 默认状态下 BUCK1/BUCK2 关闭,只有 LDO 常开,输出 RTC_3V0 给 STM32 VBAT,备份域开始工作,RTC 走时。
- 用户短按开机键,按键信号通过唤醒电路传给 STM32(也可能是 PMIC 的 GPIO 触发中断)。
- 固件确认开机条件后,通过 PF5 拉高 PMIC 的 EN,或者直接通过 I2C 配置寄存器使能 BUCK1。
- BUCK1 输出 SYS_3V3 稳定后,STM32 VDD 上电,复位释放,MCU 从 Flash 启动。
- 固件继续初始化其它外设电源:打开 BUCK2 供 SD 卡、配置 ADC 开始监测电池电压。
关机逻辑则是反过来:先记录系统状态到备份 SRAM,关闭外设,写寄存器关掉 BUCK2,最后拉低 EN。不要在还有大负载电流的时候直接切 EN,否则电源轨跌落过程容易把 Flash 写操作打断,真遇到过配置参数写一半掉电导致下次启动校验失败的问题。
4. 软件实现:充电、电量与待机
4.1 寄存器读写封装
软件上第一步是把 I2C 寄存器读写封装成两个底层函数。PCA9422 的寄存器是 8 位地址、8 位数据,支持自动地址递增,所以用标准库或者 HAL 的 Mem_Read/Mem_Write 接口就行。核心代码如下:
// pmic.c —— 基于 STM32 HAL 的 PCA9422 驱动底层 #include "pmic.h" #define PCA9422_I2C_ADDR (0x10 << 1) // 7 位地址左移一位,具体以芯片 ADDR 配置为准 #define PMIC_I2C_TIMEOUT 100 // 单位 ms static I2C_HandleTypeDef *pmic_i2c = &hi2c1; uint8_t pmic_read_reg(uint8_t reg, uint8_t *val) { return HAL_I2C_Mem_Read(pmic_i2c, PCA9422_I2C_ADDR, reg, I2C_MEMSIZE_8BIT, val, 1, PMIC_I2C_TIMEOUT); } uint8_t pmic_write_reg(uint8_t reg, uint8_t val) { return HAL_I2C_Mem_Write(pmic_i2c, PCA9422_I2C_ADDR, reg, I2C_MEMSIZE_8BIT, &val, 1, PMIC_I2C_TIMEOUT); }一个细节:读寄存器之后,如果值跟预期不符,我会再读一次确认。I2C 总线在噪声环境下偶尔会丢字节,尤其是 PMIC 这种“写错了就会改变电压输出”的设备,驱动里加一层“写后回读校验”能省掉很多诡异故障排查时间。代价只是几十微秒,非常值得。
4.2 初始化与工作模式切换
初始化流程按照“先建立通信、再验证身份、然后逐路使能输出”的顺序来。伪代码流程如下:
typedef enum { PMIC_OK = 0, PMIC_ERR = 1, PMIC_NACK = 2, } pmic_status_t; pmic_status_t pmic_init(void) { uint8_t dev_id = 0; // 1. 读取设备 ID,确认 I2C 通信正常 if (pmic_read_reg(PMIC_REG_DEV_ID, &dev_id) != HAL_OK) { return PMIC_NACK; } // 实际 ID 值以数据手册为准,这里做合法性判断 if ((dev_id & 0xF0) != 0x30) { return PMIC_ERR; } // 2. 配置 BUCK1 输出 3.3V,使能输出 // 电压码表见手册 Voltage 寄存器段 pmic_write_reg(PMIC_REG_BUCK1_VOUT, 0x19); pmic_write_reg(PMIC_REG_BUCK1_CTRL, 0x01); // enable BUCK1 // 3. 配置 BUCK2 输出 1.8V,先不使能,等外设需要时再开 pmic_write_reg(PMIC_REG_BUCK2_VOUT, 0x29); // 4. 配置 LDO 输出 3.0V,常开 pmic_write_reg(PMIC_REG_LDO_VOUT, 0x33); pmic_write_reg(PMIC_REG_LDO_CTRL, 0x01); // 5. 设置充电电流 300mA,开启充电功能 pmic_write_reg(PMIC_REG_CHG_CTRL, 0x2C); // 6. 使能内部 ADC 连续采样,用于电池电压监控 pmic_write_reg(PMIC_REG_ADC_CTRL, 0x01); return PMIC_OK; }寄存器地址我这里用代号代替,因为不同芯片版本可能略有差异,实际开发时直接把手册里的地址填进去就行。关键要点是:先稳压,再使能输出,最后开 ADC。如果先开 ADC 再使能 BUCK,初始化期间 ADC 会采到一堆奇怪的中间电压,容易误报低电压触发保护逻辑。
4.3 充电状态机
充电管理这块,PCA9422 内置硬件充电器已经处理了涓流、恒流、恒压、截止的切换,MCU 做的事情主要是:周期读取充电状态,根据状态更新 UI 电量图标、控制充电指示灯、处理异常。我写了一个标准状态机:
typedef enum { CHG_IDLE = 0, CHG_PRE_CHARGE, CHG_CC, CHG_CV, CHG_DONE, CHG_FAULT } charge_state_t; static charge_state_t charge_state = CHG_IDLE; void charge_task_1s(void) { uint8_t status = 0; if (pmic_read_reg(PMIC_REG_CHG_STATUS, &status) != HAL_OK) { return; } switch (charge_state) { case CHG_IDLE: if (status & CHG_STAT_PRE_CHARGE) { charge_state = CHG_PRE_CHARGE; } else if (status & CHG_STAT_CC) { charge_state = CHG_CC; } else if (status & CHG_STAT_FAULT) { charge_state = CHG_FAULT; } break; case CHG_PRE_CHARGE: if (status & CHG_STAT_CC) { charge_state = CHG_CC; } else if (status & CHG_STAT_FAULT) { charge_state = CHG_FAULT; } break; case CHG_CC: if (status & CHG_STAT_CV) { charge_state = CHG_CV; } else if (status & CHG_STAT_DONE) { charge_state = CHG_DONE; } else if (status & CHG_STAT_FAULT) { charge_state = CHG_FAULT; } break; case CHG_CV: if (status & CHG_STAT_DONE) { charge_state = CHG_DONE; } else if (status & CHG_STAT_FAULT) { charge_state = CHG_FAULT; } break; case CHG_DONE: // 充电完成,保持轻负载,等待电量下降后重新充电 if (status & CHG_STAT_CC) { charge_state = CHG_CC; } break; case CHG_FAULT: // 故障自理,比如过温、电池断开;记录日志 break; } update_charge_led(charge_state); }充电完成判定的依据通常是充电电流降到截止电流以下,典型值 10% 恒流值左右。如果你设了 300mA 充电电流,截止电流大约 30mA 上下,实际值看手册。这里有个经验:不要只靠一次状态位就判定充满,连续两次读取到“DONE”再通知 UI,防止充电末端电流抖动导致图标来回跳。
充电电流的选择也要结合硬件散热评估。我的板子整机充电场景下目标功耗很低,所以设置 300mA。如果你的充电输入是 5V,电池电压 4.2V,线性充电器的压差就是 0.8V,300mA 下芯片要吃掉约 240mW 的热量。如果充电电流设成 500mA,发热接近 400mW,PCB 上必须留足够散热铜皮,否则芯片温升很容易触发过温保护。
4.4 电量估算
PCA9422 内置 ADC 可以采样电池电压,MCU 直接读寄存器就能拿到一个 8 位或 10 位原始值(取决于芯片配置)。我在电量显示上先做了简单版本:把电池电压映射成百分比。
简单 OCV 查表法可以快速上线,代码如下:
#define VBAT_EMPTY_MV 3000 #define VBAT_FULL_MV 4200 static uint32_t vbat_filtered_mv = 3700; uint32_t pmic_get_battery_soc(void) { uint32_t pct = (vbat_filtered_mv - VBAT_EMPTY_MV) * 100 / (VBAT_FULL_MV - VBAT_EMPTY_MV); if (pct > 100) pct = 100; if (pct < 0) pct = 0; return pct; }电压要经过一阶低通滤波再映射,不然负载一变化电量百分比跟着跳,用户观感很差:
void vbat_filter(uint32_t new_mv) { // 滤波系数 8,等效时间常数由采样周期决定 vbat_filtered_mv = (vbat_filtered_mv * 7 + new_mv) / 8; }但必须说清楚:纯电压法在系统电流变化大的场合误差不小。满电 4.2V 时带载 200mA 电压可能掉到 3.9V,如果直接查表会被当成 80%,实际上电量还是满的。我后面做了两个补偿手段:静态时(待机/休眠)才用电压查表校准,运行时只依赖相对变化做趋势指示;充电完成时强制把 SOC 拉 100%,低压保护点强制拉 0%。如果设备对电量精度要求苛刻,直接在系统里加一颗专用的库仑计芯片和采样电阻效果更好,PCA9422 的 ADC 精度做日常电量提醒是够用的。
4.5 低功耗待机实现
这块是我整个方案里最看重的地方,也是最终待机电流能压到个位数微安的真正原因。完整待机链路分三部分:
- 系统状态保存:进入待机前,把需要维持的变量写入 STM32 备份寄存器或备份 SRAM,然后把不必要的时钟、外设全部关闭。
- PMIC 电源切换:通过 I2C 把 BUCK1 和 BUCK2 关闭,保留 LDO 常电输出 RTC_3V0。注意写入顺序:先关外设电源、再关主电源,最后拉低 EN 或保持使能但输出全关。
- MCU 进入低功耗模式:STM32 进入 STANDBY 模式,等待 RTC 闹钟或外部唤醒引脚。
我最终采取的是 STM32 STANDBY + PMIC 主输出电压全关的方案。在这个状态下,STM32 的 VDD 完全没电,只有 VBAT 备份域靠 LDO 维持 RTC,整机电流只包含 LDO 的静态损耗、RTC 电路、以及 PCA9422 自身待机损耗,实测下来大约是 9μA 左右。按这个电流算,一块 500mAh 的电池放置一年,理论消耗只有 70~80mAh,完全满足“放置一个月不亏空”的需求。
唤醒路径是:RTC 闹钟或者用户按键触发 STM32 唤醒引脚,MCU 复位启动后第一件事就是初始化 I2C、重新使能 BUCK1,让 SYS_3V3 恢复,整个系统重新进入工作状态。这里有个容易被忽略的坑:PMIC 关断期间不要尝试通过 I2C 读取任何东西,因为 BUCK1 关了就相当于 MCU 主域断电,I2C 引脚电平都不存在了,读回来的只会是垃圾。唤醒后的 PMIC 初始化必须做软件延时,等 BUCK1 输出稳定再访问寄存器。
5. 实测数据与优化:数字会说话
5.1 测量方法
电源管理优化不看数据等于白干。我先说明我的测量手段,不然下面的数据没法复现。
最准确的做法是在电池正极和 PCA9422 的 VBAT 之间串联一个 0.1Ω 采样电阻,用差分探头测电阻两端压降,再用电流等于压降除以电阻算出来。日常调试我用的是一块能测微安的台式万用表,串联在电源回路里。测大电流时用电流挡,测待机微安级电流时切到微安挡,但这个切换操作会让系统断电再上电,实测时必须注意。
这块必须强调:测量待机电流时,千万不要把万用表大电流挡直接串进去然后等系统睡。大电流挡的内阻很低,万用表的压降可以忽略,但挡位分辨率太差,微安级电流根本看不出来。反过来,微安挡内阻高,系统一启动拉几百毫安,压降会把它直接打断复位。所以标准流程是:系统进入待机后再把表切换到微安挡读取,或者用开关并联大电容的方式过渡。
5.2 各模式功耗实测
实测数据如下,所有电流都是 VBAT 入口的整机电流:
| 工作模式 | 测试条件 | 整机电流 |
|---|---|---|
| 满载运行 | 216MHz,全速跑 DSP 运算,LCD 背光 100% | 约 420mA |
| 常规运行 | 216MHz,GUI 显示,背光 10%,传感器间歇采集 | 约 260mA |
| 睡眠 | STM32 进 SLEEP(WFI),主轨 3.3V 保持 | 约 8mA |
| STOP2 | STM32 进 STOP2,主轨保持,唤醒等待 | 约 350μA |
| STANDBY | PMIC 关闭 BUCK1/BUCK2,仅 LDO 供 RTC | 约 9μA |
看到 STOP2 那行的 350μA 可能会疑惑:为什么比 STANDBY 高了两个数量级?因为 STOP2 模式下 STM32 VDD 依然有电,内部 LDO 还在维持核心电压,加上各种本来就有静态损耗的电源域都活着。350μA 已经不算差,但如果目标是续航几个月,就必须走到“PMIC 全关”这一步,用硬件把主域彻底切掉。
5.3 进一步优化方向
实测完一轮,我又做了几个针对性优化,效果非常直接:
- 背光 PWM 化:屏幕背光从固定线性供电改成 20kHz PWM 调光,10% 亮度时背光电流从 80mA 降到 20mA 左右,这是整机电流的最大单项来源,优化收益最明显。
- 动态降频:系统空闲时把主频从 216MHz 降到 64MHz,跑空闲任务和通信业务的电流可以再降 30% 左右。唤醒和重负载时再升回去,代码上用 PLL 重新配置即可。
- 外设电源按需开关:SD 卡、传感器这类外设全部挂在 BUCK2 或独立的 GPIO 负载开关后面,不用就断电。很多传感器静态电流看着不高,但常年通电累积起来也相当可观。
- 充电完成后的电流控制:充电完成后不要继续让充电器保持高功耗状态,确认状态机进入 IDLE 后,把相关 ADC 周期降下来,甚至关闭,只保留中断唤醒。
6. 排查实录:我踩过的 5 个坑
6.1 I2C 一直 NACK,扫描地址扫不到
这是最常见的起步问题。排查时先量 VBAT 有没有电,再量 PCA9422 的输入电压;如果电压正常,查 I2C 上拉电阻是不是接到了正确的电源域,SDA/SCL 是否接反。我那次最后发现是 PCA9422 的 ADDR 引脚悬空导致地址和预设不一致,后来按手册把 ADDR 引脚拉到了正确的电平,地址才稳定。焊完电路板后先用一个全局 I2C 扫描例程确认地址,再写正式驱动,能省至少一个下午。
6.2 BUCK1 一上电,系统就在加载瞬间复位
现象是固件跑起来没多久就复位,示波器看 SYS_3V3 在负载跳变时会瞬间跌到 2.8V 以下。原因是输入侧 VBAT 到 PCA9422 之间的走线太长、太细,电池供电能力被线阻削弱。解决办法:加粗和缩短输入走线,在 VBAT 引脚旁边并了一颗 10μF 陶瓷电容,问题立刻消失。大电流瞬态下,电源走线压降造成的电压跌落是很多复位问题的真凶,别一上来就怀疑固件。
6.3 充电发热严重
我最初把充电电流设到 500mA,结果充电半小时芯片烫手。前面算过账:线性充电器在 5V 输入、4.2V 电池电压下,0.5A 的功耗就是 0.4W,对一颗小型封装 PMIC 来说已经不小。后来把充电电流降到 300mA,同时给充电器下方的 PCB 做了大面积铺铜辅助散热,温度从烫手降到温热。选线性充电方案时,充电电流和散热条件必须一起设计,不能只看手册上的最大电流参数。
6.4 待机电流越测越大,甚至测出几十毫安
有一次待机电流怎么都压不下去,后来发现是万用表电流挡内阻导致的复位重连。PMIC 关闭 BUCK1 后 MCU 断电,但万用表切换挡位时回路瞬断,残余电压让 MCU 重新上电进入了某种半工作状态。解决方法是待机电流测量采用“先用微安挡位,并在回路并联一个低漏电大电容做启动电流缓冲”的方案,实测出来的 9μA 才是真实值。测量基础设施不干净,数据再好看也没用。
6.5 电量百分比跳变严重
刚开始用电压查表法,负载一变化电量显示就从 80% 跳到 60%。后来加了滤波和“仅在固定负载条件下校准”的策略,跳变才缓解。另外充电末端电压变化非常缓慢,不能单纯靠电压判断充满,要以充电状态寄存器的 DONE 位为准。电量显示是用户最直观的体验点,宁可保守也不要乐观,跳来跳去的电量图标比低电量本身更容易招投诉。
最后再分享一个小技巧
调试 PMIC 的时候,别把 MCU 一上来就焊满。我的流程是:先焊 PCA9422 和电源部分,用可调电源代替电池,上电后用万用表确认每一路输出都符合预期,再焊 STM32。这样万一电源有问题,不会把主控牵扯进来,排障范围缩小一大半。另外,建议在电源树的关键节点上多留几个测试点,包括 VBAT、SYS_3V3、SYS_1V8、RTC_3V0,最好再加上 GND 焊盘。调试时探针没地方下才是最痛苦的。
电源管理芯片本身不复杂,复杂的是它周围的系统和时序。把硬件接法、寄存器配置、状态机逻辑和测量手段这四样东西都理清楚,PCA9422 加 STM32F746ZG 这套组合就能稳稳地扛起便携设备的供电大旗。