☰
PMIC+MCU协同管理板卡电源:时序配置与DVS动态调压实战
2026/10/24 6:17:52 网站建设 项目流程

做嵌入式板子的人早晚都会遇到同一个问题:板上的电越来越多,光靠几颗LDO堆已经不是办法了。我上一块板子就是这样败下阵来的——主控、DDR、模拟前端、外设接口互相要不同的电压,还都要求严格的上电时序;单独设计一堆分立电源不但面积大、功耗难看,每次调时序都要熬夜。

后来我换了思路,把整板的电源管理交给两颗芯片去配合完成:主电源轨全部由 PCA9422 这类 PMIC 负责输出,再用一颗 PIC18F85J50 做它的配置和监控大脑。这个组合实际用下来,把原本最心累的电源部分变成了整板可控性最强的部分。这篇文章把硬件接线、固件状态机、DVS 切换以及调试过程中踩过的坑一次性讲清楚,适合正在给主控平台或者多路供电系统配电源管理方案的工程师,尤其是手头有一颗带 I2C 的小 MCU 但还没想好怎么用起来的同行。

1. 项目缘起:板子上的电源为什么需要一个管家

1.1 多路电源轨的三座大山

先说我最初遇到的麻烦。这块板子的后端是一颗较高性能的主控,外挂 DDR、以太网 PHY、传感器接口等等。打开数据手册的电源要求那一页,密密麻麻列了七八路电压:

  • 主控核心电压,大约 0.95V,要求支持动态调压;
  • DDR 和 IO 电压,1.8V,纹波要求很苛刻;
  • 外设总线电压,3.3V;
  • 还有 RTC 备用电源,需要极低功耗的待机轨。

最麻烦的是时序:IO 要先稳定,DDR 再上,最后内核电压才能起来;掉电时顺序反过来。如果用纯硬件方案,把这些时序做出来通常要靠一堆电源监控芯片、延时电容和逻辑门,改一次电压目标就等于改一块板。

1.2 PCA9422 在方案里的角色

PCA9422 是一颗集成了多路同步 Buck 和 LDO 的电源管理 IC,关键是它带了 I2C 接口。这意味着输出电压目标、开关顺序、限流点、软启动斜率都可以用软件配置,不用靠外部电阻分压死磕。

它还内置了 OTP,可以预先固化一组默认配置。所以即使 PIC 这边还没跑起来,PCA9422 上电后照样能按默认参数输出基础电压,不会出现整板断电死锁的情况。我这边最看重的是它的几个特点:

  • 支持动态电压调节(DVS),运行中通过 I2C 写寄存器就能改变 Buck 输出电压;
  • 提供 PGOOD 输出,每一路电源是否稳定可直接感知;
  • 有中断输出,过流、过温、欠压这些故障能主动上报;
  • 内部还带了复位控制逻辑,可以统一管理后端主控的复位信号。

1.3 PIC18F85J50 在方案里的角色

PIC18F85J50 是手头库存里的一颗 8 位 MCU,外设数量足够,I2C、SPI、UART、大量 GPIO 都有。选它当这个电源管家,理由其实很实在:我只需要一个能跑 I2C 主模式、能处理外部中断、能进低功耗睡眠的控制器,不需要跑系统,也不需要复杂的 DSP 计算,8 位 MCU 的性能绰绰有余。

它在方案里的分工是:

  • 上电后通过 I2C 初始化 PCA9422,把各路输出电压、时序、保护阈值写进寄存器;
  • 运行中根据主控的负载状态执行 DVS 切换;
  • 监听 PGOOD 和中断引脚,出现异常时执行关机或降载保护;
  • 处理开机按键,做短按开机、长按强制关机的逻辑。

1.4 为什么不是固定 OTP 或用一堆 LDO

我也对比过其他方案,最后才决定走 PMIC 加 MCU 这条路线:

方案优点缺点
分立 LDO/DCDC 组合成本低、选型灵活时序难做、面积大、没有动态调压、故障保护靠额外加芯片
固定 OTP 的 PMIC上电即工作、不依赖软件每次改电压要烧 OTP,调试周期长;无法做运行中调压
PMIC + 8 位 MCU软件可配置,时序可控,支持 DVS 和故障管理需要额外写固件,多一颗 MCU 的成本

我选择第三种的核心原因是:这套板子的功耗管理需求是变化的。低负载睡眠、高负载性能模式之间的切换,必须靠运行中的代码去改电压,固定配置根本做不到。与其让后端主控自己用 GPIO 模拟,不如专门给电源配一个看得见、管得住的管家。

2. 硬件连接与引脚分工:先解决谁先上电的基本矛盾

2.1 先解决鸡生蛋的问题:PIC的供电从哪来

第一版原理图我犯过一个很典型的错误:想直接用 PCA9422 的一路 3.3V 输出给 PIC 供电。想法是省一颗 LDO,但仔细一想就发现不对——PIC 的任务是在上电后配置 PMIC,可如果 PIC 自己的电是 PMIC 给的,PMIC 没配置之前 PIC 根本没机会跑起来。

正确的做法是给 PIC 单独安排一颗待机 LDO,输入接 5V 或电池端,输出固定 3.3V,不经过 PMIC 的任何输出轨。这样整板上电后 PIC 最先有电,它先跑固件、拉起来 I2C、配置好 PCA9422,之后 PMIC 才把主系统的各路电源放出来。

这时候整板的唤醒流程就理顺了:

  1. 断电状态只有待机 LDO 和 PIC 在工作,整板电流极低;
  2. 用户按开机键,PIC 被唤醒;
  3. PIC 初始化 PCA9422,写配置、使能各路输出;
  4. 检测到 PGOOD 稳定后,释放主控复位;
  5. 主控开始跑系统,PIC 进入监控状态。

这个“PIC 必须先有电”的原则是整个硬件设计的地基,顺序一旦搞反,后面所有调试都会陷入死循环。

2.2 I2C总线接线:关键在电平域与上拉

PCA9422 的 I2C 接口电压域一般和对它供电的输入电压相关,我这边用 3.3V 作为通信参考。PIC 也工作在 3.3V,所以两端电平是兼容的。接线看起来很简单,SCL、SDA 两根线,但有几个细节不注意会折腾很久。

首先是上拉电阻。PMIC 芯片内部一般没有足够强的上拉,需要在板级加外部上拉电阻到 3.3V。我第一版用了 10kΩ,结果 400kHz 速率下波形上升沿很慢,通信偶尔失败;换成 4.7kΩ 之后明显改善。如果总线走线超过 10cm,建议直接上 2.2kΩ,但要注意太小的电阻会让高电平拉电流偏大,睡眠模式下漏电不可忽略。

其次是 PIC 的 I/O 配置。PIC18F85J50 的 SCL/SDA 引脚必须配成开漏输出模式,同时开启弱上拉或者依赖外部上拉。如果误配成推挽输出,I2C 通信时会出现两个设备打架拉死总线的问题,我后面实测中也踩到了这个坑。

最后是地址引脚。PCA9422 的 I2C 地址通常会通过芯片引脚的电平或者一个额外地址位来确定。我在设计时把地址配置引脚用电阻固定到 GND,所有板卡统一地址,避免生产时因为飞线不一致导致烧录程序互相冲突。

2.3 状态信号分配:PGOOD、中断、按钮、复位

PCA9422 的 PGOOD 输出我接到了 PIC 的一个带外部中断功能的 GPIO 上,配置成下降沿触发。正常工作时 PGOOD 是高电平,一旦某路电源掉出阈值范围,PIC 会立刻进中断去做保护处理,不用靠轮询寄存器,响应时间快很多。

中断输出 INT 则接了另一个 GPIO,用于处理过流、过温等非致命故障。PGOOD 和 INT 的区别在于:PGOOD 是电源轨状态的实时镜像,毛刺可能比较多;INT 是芯片内部事件累积产生的脉冲,更适合做状态机跳转的触发源。实际固件里,PGOOD 中断只做标记,INT 中断才会真正改变电源状态。

开机按键的处理我建议走 PIC 的唤醒 GPIO,不要直接连 PMIC 的 ON 引脚。接 PIC 的好处是关机逻辑可以完全由固件决定:短按开机、长按强制关机、按键防抖、双击切换到低功耗模式,这些都写在代码里。如果直接连 PMIC 的 ON 引脚,开关逻辑被芯片内部硬件控制,灵活性差很多。

复位信号这条线最容易出问题。我是用 PCA9422 的复位输出统一控制后端主控的复位脚,PIC 只在上电完成后通过 I2C 配置 PMIC 释放复位。复位线上加了 10kΩ 到 3.3V 的上拉和 0.1uF 到 GND 的电容,让信号释放时有个约 1ms 的延时,避免 PGOOD 刚开始抖动的瞬间误触发复位。

2.4 布局与走线的几个常识性避坑

电源板的 PCB 布局比原理图更考验经验。PCA9422 的 Buck 输出电感要靠近芯片放,输入电容、输出电容都要尽量短接回地;反馈采样线要走细线,避开电感下方的开关噪声区。

I2C 总线尽量和时钟线分开走,不要在板边绕一圈。我量过一块测试板的 SDA 波形,走线绕了大半个板子之后,高电平被耦合噪声打得往下凹,400kHz 已经跑不动,降到 100kHz 才稳定。后来重新改版缩短走线,同样固件 400kHz 就通了。

PIC 的待机电源域要单独铺铜,和 PMIC 的输出电源轨隔开,这样测睡眠电流时才能分清楚电流到底消耗在哪一路。这些布局细节虽然不起眼,但直接影响后面调试的难度。

3. 固件实现:电源状态机与I2C配置骨架

3.1 I2C读写驱动:从接口到可靠性

PIC18F85J50 的 MSSP 外设配置成 I2C 主模式之后,读写 PMIC 的代码框架其实不长。我习惯把 I2C 层和 PMIC 层分开,这样以后换不同型号的 PMIC,只需要改上层驱动。

void i2c_start(void) { // 拉低 SDA 后再拉低 SCL,进入 START 条件 // 具体寄存器操作取决于所选 MCU 的头文件 } uint8_t i2c_write_byte(uint8_t byte) { uint8_t ack; // 将 byte 送入 I2C 发送缓冲,等待传输完成 // 读取 ACK 状态返回 return ack; } void pmic_write_reg(uint8_t reg, uint8_t val) { i2c_start(); if (i2c_write_byte(PMIC_ADDR << 1 | 0) == 0) { i2c_write_byte(reg); i2c_write_byte(val); } i2c_stop(); }

注意 PMIC_ADDR 以你数据手册和板上地址引脚的实际配置为准。写操作通常分两步:先写寄存器地址指针,再写数据。有的 PMIC 支持连续写多个寄存器,配置表可以一次传完,读操作则需要先写目标地址,再切换成读模式。

I2C 可靠性是电源管理的底线。我在固件里加了总线恢复逻辑:如果连续多次通信无应答,就在 SCL 上产生 9 个时钟脉冲,让总线上的设备复位释放 SDA,然后再重新尝试。这个恢复机制帮我在调试中省了很多事,尤其是拔插仿真器导致总线悬浮的时候。

3.2 上电初始化:用配置表代替硬编码

PMIC 初始化最忌讳把几十个寄存器写操作硬编码在代码里,那样既难读又难改。我用的是配置表方式:每一条记录一个寄存器地址和对应值,初始化时循环写一遍。

typedef struct { uint8_t reg; uint8_t val; } pmic_cfg_t; static const pmic_cfg_t pmic_init_seq[] = { { PMIC_REG_BUCK1_DVS0, 0x35 }, { PMIC_REG_BUCK1_DVS1, 0x3A }, { PMIC_REG_BUCK2_VOUT, 0x55 }, { PMIC_REG_LDO1_VOUT, 0x62 }, { PMIC_REG_PGOOD_MASK, 0x01 }, // ... { 0xFF, 0xFF } // 结束标志 }; void pmic_init(void) { const pmic_cfg_t *p = pmic_init_seq; while (p->reg != 0xFF) { pmic_write_reg(p->reg, p->val); p++; } // 配置完成后等待 PGOOD 稳定 wait_pgood_ready(); }

寄存器地址和值以你手上的数据手册为准,我这里更想强调的是表的组织方式。我实际上把配置表拆成了几组:基础电压表、时序控制表、保护阈值表,每组单独函数执行。调试时想跳过某个环节,直接把对应函数注释掉就行,不用满屏幕翻寄存器操作。

3.3 电源状态机的设计

电源管理固件的核心不是驱动,而是状态机。我用一个枚举类型定义整板电源状态,所有事件处理都在状态机里收敛:

typedef enum { PWR_OFF, PWR_STARTUP, PWR_RUN, PWR_LOWPOWER, PWR_SHUTDOWN, PWR_FAULT } pwr_state_t;

各个状态之间的转移规则:

  • PWR_OFF 收到按键短按事件,进入 PWR_STARTUP。
  • PWR_STARTUP 执行 PMIC 初始化、等待 PGOOD、释放主控复位,全部成功进入 PWR_RUN;任何超时转入 PWR_FAULT。
  • PWR_RUN 收到低功耗请求,先保存主控上下文,再进入 PWR_LOWPOWER。
  • PWR_LOWPOWER 收到唤醒事件,恢复 DVS 电压,进入 PWR_RUN。
  • PWR_SHUTDOWN 执行关机序列:通知主控保存数据、关闭外设电源、关闭核心电压,最后回到 PWR_OFF。
  • PWR_FAULT 中记录故障原因,根据故障严重程度选择尝试恢复或者彻底关机。

按键事件我放在主循环里做,但 PGOOD 和 INT 中断会直接给状态机置标志位。这样做的结果是:任何时刻只有一个函数在改变电源状态,不存在两个模块互相抢控制权的问题。

3.4 DVS动态调压的实现细节

DVS 是本方案最实用的功能。后端主控在低频运行时可以把核心电压降下来省电,高频运行前再把电压抬上去。我封装了一个函数,传入目标电压值,由函数计算寄存器编码并写入,然后等待 PGOOD 确认:

uint8_t pmic_set_buck_volt(uint8_t buck, uint16_t mv) { uint8_t code = volt_to_code(mv); uint8_t reg = buck_dvs_regs[buck]; pmic_write_reg(reg, code); for (uint8_t i = 0; i < 200; i++) { if (pgood_pin == 1) { return 0; // 目标电压稳定 } delay_ms(1); } return 1; // 超时 }

DVS 切换时间取决于负载电容和 PMIC 的驱动能力。我实测从小电压往大电压切换,如果一次写到位,后级大电容充电会让输出瞬间掉坑,严重时直接触发后级欠压复位。解决办法是把大跨度切换拆成两步:先切到中间电压,等 PGOOD 稳定后再切到目标电压。软件多了一段逻辑,但换来的是系统稳定。

3.5 睡眠模式下的功耗控制

睡眠功耗是这个项目的硬指标之一。我的做法是:

  • 睡眠前先把后端主控调到最低频率,通过 DVS 把核心电压降到最低可工作点;
  • 关掉 PCA9422 中睡眠时不用的 Buck 和 LDO,只保留 RTC 待机轨和通信接口电源;
  • PIC 进入低功耗睡眠,仅保留按键唤醒和定时器唤醒;
  • 睡眠前把 I2C 上拉电阻对应的电源域统一处理,避免漏电。

这里有一个细节容易被忽略:唤醒之后必须先恢复 DVS 电压、使能被关掉的电源轨,等 PGOOD 稳定之后才能通知主控退出睡眠。如果先让主控跑起来再补电,主控上电瞬间就可能在欠压状态,轻则运行异常,重则直接复位。

4. 调试实录:三块绊脚石和完整排查过程

4.1 第一块石头:I2C写不进寄存器

现象很直接:PIC 程序跑起来,读 PMIC 的芯片 ID 读到 0xFF,写任何寄存器都像石沉大海。示波器看 SCL 和 SDA 波形都正常,有 START、有字节、有 ACK 位,但数据就是不对。

我当时的排查链路是这样走的:

  • 先排除地址问题。确认 PMIC_ADDR 是否和地址引脚设置一致,我特意查了原理图上的地址电阻,发现贴片电阻批次贴错位置,地址被拉到了另一档。
  • 再查上拉电平。发现 SCL/SDA 的上拉电阻被接到了系统 5V 上,而 PMIC 的通信引脚是 3.3V 电平域,5V 上拉会通过引脚内部保护二极管向 3.3V 倒灌电流,导致电平被钳位。
  • 最后用逻辑分析仪抓完整波形,才发现 PIC 的 SDA 引脚被配成了推挽输出。推挽输出在输出低电平时没问题,但输出高电平时它会主动拉高 SDA,和外部上拉一起与 PMIC 的开漏输出打架,导致 PMIC 的应答位被破坏。

解决步骤也简单:上拉电阻改到 3.3V,PIC 的两个引脚配成开漏输出,地址电阻重新贴对。这三处改完以后,通信一次就通了。

这个坑告诉我:I2C 不通的时候,不要先怀疑芯片坏了,大概率是电平域、上拉、引脚模式这三个地方组合出了问题。

4.2 第二块石头:DVS一切换系统就复位

DVS 切换功能做出来以后,刚跑通的时候很兴奋,结果每次从 0.9V 往 1.1V 切换,后端主控过几十毫秒就复位一次。用示波器抓 VDD_CORE 的波形,能看到切换瞬间电压先跌到 0.7V 附近,然后才爬升到目标值,显然触发了主控的欠压复位阈值。

分析下来有两个原因叠加:

  • 后级核心电源的电容容量偏大,切换时 PMIC 要给电容充电,瞬态电流超过芯片限制;
  • 我的软件一次写到位,等于瞬间把电压目标抬高,PMIC 内部的环路还没来得及匹配负载已经剧烈变化。

修复方案分软件和硬件两部分。软件上把 DVS 切换改成阶梯式:先从 0.9V 切到 1.0V,等 PGOOD 稳定,再从 1.0V 切到 1.1V。硬件上把原先一颗大容量铝电解电容换成多颗小 MLCC 并联,总容量不变但等效串联电阻更低,瞬态响应更好。

改完之后再看波形,切换过程的电压跌落控制在 40mV 以内,主控再也没复位过。这个经验后来在另一个项目里也复制过,原理都一样:任何动态调压动作,都是让电源环路“小步快跑”,而不是一次性跨大步。

4.3 第三块石头:睡眠电流怎么都降不下来

睡眠电流标称值是 0.3mA,实测却始终在 3.8mA 左右,差了十倍多。刚开始怀疑 PMIC 没进入睡眠模式,于是读寄存器确认各路输出都关了,PIC 也进了睡眠,但电流还是降不下去。

后来用逐路断开电流的排查法,一块块地把供电网络断开测量,最后定位到两个漏电路径:

  • 一路是 I2C 上拉电阻。上拉电阻接在始终供电的 3.3V 网络上,睡眠时 SCL/SDA 电平处于不确定状态,上拉电阻持续流过微安级的电流,两个上拉加一起就有几十微安。
  • 另一路是按键电路。按键引脚在睡眠时悬空,引脚内部的上拉没有关闭,加上按键到地的走线有防静电电容,形成了缓慢放电回路,漏电流比预期大。

解决方式是把 I2C 上拉电阻接到由 PIC 控制的电源开关上,睡眠前切断;按键引脚则明确配置内部弱上拉并加软件防抖,不让它悬空。改完之后睡眠电流降到了 0.31mA,终于和规格书对上了。

这个问题的教训是:低功耗设计不是只看主芯片的睡眠电流,外围电阻、上拉、引脚的电气状态才是大头。画原理图时就要考虑每一根留在电源网络上的通路的睡眠漏电流。

4.4 附带问题:看门狗与PMIC复位线“互咬”

调试过程中还出过一个比较隐蔽的问题:主控死机后外部看门狗会拉低复位脚,主控重启后 PMIC 的 PGOOD 在启动瞬间出现一个短暂的下降沿,PIC 把这个下降沿当作掉电异常,执行了关机流程,结果整板直接断电。

看波形才明白,这是两个复位源在“互咬”:看门狗要复位主控,PGOOD 抖动导致 PIC 要复位整板,两边抢同一根复位线。

解决办法是在 PGOOD 信号进入 PIC 之前加一个 RC 滤波,把时间常数做到 10ms 左右,把短于这个时间的毛刺滤掉;同时固件里对 PGOOD 增加稳定计数,必须连续 16 次采样都是高电平才认为电源正常。这样一来,启动初期的暂态不会再误导状态机,看门狗复位和 PMIC 复位各管各的,互不干扰。

5. 实测数据与这套方案的后续扩展

5.1 板上各路电源的实测数据

方案跑稳定之后,我用电子负载和示波器做了一轮完整的电源测试,几路关键输出的数据如下:

电源轨目标电压实测电压纹波(峰峰值)负载电流
VDD_CORE 高频1.10V1.098V26mV700mA
VDD_CORE 低频0.90V0.902V18mV240mA
DDR_1V81.80V1.802V12mV350mA
IO_3V33.30V3.296V15mV180mA
RTC_VDD3.30V3.305V4mV8mA

各路纹波都控制在后端芯片要求的范围以内,DDR 的 1.8V 轨纹波表现最稳,因为这一路滤波器给了足够的余量。从空载直接阶跃到 1A 负载,VDD_CORE 的跌落大约 55mV,恢复时间约 80us,符合 3% 的负载瞬态要求。

5.2 动态响应与按键开机的实际感受

整板的按键开关机时序最终调成如下状态:按下开机键后,PIC 在约 50ms 内完成 PMIC 初始化,50ms 后各路主电源输出稳定,再释放主控复位,复位释放到主控跑起来大约 120ms。从按下按键到系统完全启动,总耗时约 300ms,体感上是按下去紧接着就有反应。

关机时按住按键超过 3 秒,PIC 先给主控发关机通知,主控保存完数据后主动请求关机;如果主控已经死机不响应,长按 8 秒 PIC 直接关闭核心电源,实现强制关机。这个双级关机逻辑在量产后的实际使用中非常有用,没有出现过用户不知道该怎么关机的尴尬。

5.3 把DVS和主控调频策略绑定

DVS 接口做好之后,下一步就是把它和主控的运行策略绑定。如果后端主控跑的是支持调频的操作系统,可以把 DVS 切换挂到系统的调频回调里:频率升高前先拉高电压,频率降低后再调低电压。

我实际实现的方式是通过 GPIO 方向看门狗做同步:主控在调频前配置好目标频率,然后通过一根 GPIO 通知 PIC 需要对应电压;PIC 先执行 DVS 切换,切换完成后用另一根 GPIO 应答主控,主控收到应答后才真正提升主频。虽然信号多一点,但保证了“电压永远先于频率到位”,实测系统连续切换数千次都没有异常。

如果主控没有操作系统配合,也可以用简单的策略:根据 PGOOD 的状态或者负载电流监测结果,决定何时升高电压、何时降低电压。这个方法适合裸机场景,只是响应速度会慢一些。

5.4 这套方案的适应边界

PMIC 加 8 位 MCU 这种组合,并不是所有项目都适用。如果产品只需要一路固定电压,老老实实用 LDO 最省事,完全没必要引入软件管理。如果产品有多路电压、有动态调压和低功耗模式需求,同时成本允许增加一颗小 MCU,那这套架构就很合适。

还要考虑维护成本。电源管理固件一旦负责了整板的开关机逻辑,就必须纳入版本管理,要和主控侧的驱动统一发布。我后来把 PMIC 配置表独立成一个模块,加上版本号,每块板卡烧录时记录配置版本,后续排查现场问题时能立刻确认是固件问题还是硬件问题,省了很多扯皮。

PCA9422 的 OTP 我也利用起来了:把 PMIC 的基础配置固化一份进去,万一 PIC 固件后续升级失败或者跑飞,PCA9422 还能输出一套安全默认电压让板子进入恢复模式。这个设计在量产阶段多了一层保险,不是所有方案的 PMIC 都支持这个,值得留意。

最后再分享一个小技巧:在 PMIC 的 I2C 总线上留一个排针测试点。调试时用逻辑分析仪直接夹上去就能抓波形,不用飞到芯片引脚上。这个测试点在后续每一个电源异常问题排查中都用得上,成本几乎为零,收益非常大。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询