这段时间做的一台便携式环境监测网关,主控选了 TM4C1299KCZAD,电源管理最终定下来用 PCA9422。说实话,刚拿到这个组合时我心里没底,因为 TM4C1299KCZAD 是带以太网和 USB 的大尺寸 MCU,而 PCA9422 更像是给低功耗可穿戴设备准备的 PMIC,这两颗芯片放在一起有点“大马拉小车”和“小马带大车”同时出现的意思。但需求是电池供电、低功耗待机、还要有完整的上电时序和充电管理,用分立方案反而更啰嗦,于是干脆把 PCA9422 和 TM4C1299KCZAD 做成一套完整的电源管理子系统。这篇把从方案选型、电源架构、硬件连接、软件配置到调试排坑的完整过程写出来,给同样打算用这套组合的工程师做个参考。
1. 先把需求摊开:为什么 TM4C1299KCZAD 需要专门的电源管理
1.1 TM4C1299KCZAD 的供电特征
TM4C1299KCZAD 这颗 MCU 功能很全,但电源侧不是简单“给 3.3V 就能跑”这么想当然。它有独立的 IO 电源域、模拟电源引脚,还有内部 LDO 给内核供电,同时也支持通过特定引脚由外部直接提供内核电压。这意味着系统设计时至少要分清三个电压角色:3.3V 的 IO 主电源、模拟电源以及内核电压。
把负载拆开看,运行模式下整颗 MCU 的电流会明显波动,尤其是以太网收发、USB 插入瞬间,电流尖峰很容易让电源电压向下掉。如果前面直接挂一颗 LDO 或者一个很弱的 DC-DC,MCU 可能跑着跑着就复位。之前我用一颗 3.3V 的 LDO 试着带它,在插网线的瞬间出现过一次复位,后来示波器抓到 3.3V 跌了大概 300mV,持续时间约 1ms,刚好碰到某些外设的欠压点。电源管理并不是“电压数值对”就行,还得响应足够快。
1.2 PCA9422 在这个系统里的角色
PCA9422 属于集成度比较高的 PMIC,典型用途是给电池供电设备做充电、多路电源输出和状态管理。它里面有多个电压转换通道,可以通过 I2C 寄存器调整输出电压、开关通道和低功耗模式。对这台网关来说,PCA9422 承担三件事:一是把锂电池充电管理接住,不再需要额外充电芯片;二是一路输出给 MCU 的 3.3V 主电源,另一路按需输出内核或外设电压;三是通过中断引脚向 MCU 上报充电状态、低电量等信号。
把充电、DCDC、LDO 和状态上报集成在一起之后,整个电源子系统的 PCB 面积比原来“独立充电板+多颗 DC-DC+LDO”的方案小了很多,最关键的是 PMIC 各路输出之间可以协同开关,这正好配合低功耗模式切换。
1.3 这套组合的适用边界
我建议先想清楚使用场景再决定要不要抄这个方案。如果只是 USB 供电、对静态功耗完全无感,那直接用一个质量好一点的 DC-DC 给 TM4C1299KCZAD 供电就够了,PCA9422 反而是多余的。如果是电池供电,并且希望设备有长期待机、充电管理、低电量保护,那么 PMIC 的价值就很明显。
还有一点要注意,PCA9422 单路电流能力不是无上限,TM4C1299KCZAD 在高负载运行时,如果外设全部拉满,某些通道可能接近上限,所以架构设计时要给电流预算留余量。这套组合更适合“电池供电 + 大部分时间低功耗待机 + 周期性短时工作”的物联网节点,而不是一直满负荷跑工业控制的场景。
2. 电源架构设计:从电池到每一路负载
2.1 电压轨划分:先定轨,再连线
我最后用的电源架构大概是这样的:电池输入直接进 PCA9422 的充电端;PMIC 的一路 Buck 配置成 3.3V,给 TM4C1299KCZAD 的 IO 主电源和板上的电平转换电路供电;另一路 Buck 配置成 1.2V,给 MCU 内核电压域供电,前提是 MCU 手册允许外部直接供给内核电压,这一点我拿到板子后用参考手册和勘误表确认过;剩下的一路 LDO 输出固定 3.3V,专门给 Hibernate 模式下需要保持的 VBAT 域和 RTC 电路供电。
| 电压轨 | 目标电压 | 供电对象 | 来源 | 备注 |
|---|---|---|---|---|
| VDD | 3.3V | MCU IO、Flash、部分外设 | Buck1 | 轻载切 PFM,重载切 PWM |
| VDDC | 1.2V | MCU 内核 | Buck2 | 外部直供,需确认手册支持 |
| VDDA | 3.3V | 模拟域、ADC 参考 | Buck1 + LC 滤波 | 避免开关噪声直接窜入 |
| VBAT | 3.3V | Hibernate/RTC | LDO | 常开,保持最低功耗 |
| 外设轨 | 3.3V | 传感器、无线模块 | Buck1 + 负载开关 | 软件单独关断 |
这里有一个值得重点说的选型逻辑:为什么 VDDC 要尽量用外部 Buck,而不是用 MCU 内部 LDO。如果内核电流 100mA,从 3.3V 降到 1.2V,压差是 2.1V,线性 LDO 上损耗就是 210mW;而一颗 1.2V 的 Buck 在这个负载下损耗通常只有二三十毫瓦,效率差距非常明显。对于电池设备,这部分节省直接反映在运行时间上。
不过不是所有型号都允许外部直供 VDDC,有些批次必须靠内部 LDO。所以我的建议是原理图阶段就留好两颗 0 欧电阻的位置,一组连内部 LDO 通路,一组短路到外部 Buck,这样硬件回来之后再根据手册确认决定用哪种方式。
2.2 电流预算:别让 PMIC 单通道顶到天花板
电流预算是整个电源架构里最重要的一步,做不好后面选型和实测都会很被动。我把这颗 MCU 和外设的大致负载拆成三部分来算:
- 运行模式:TM4C1299KCZAD 的 3.3V 电流约 150-200mA,以太网活动时偏上限;1.2V 内核约 80-120mA。
- 外设:传感器平均 20mA,峰值 50mA;负载开关本身静态电流可以忽略。
- 常开 LDO:给 VBAT 和 RTC 供电,待机几微安到几十微安,峰值不超过 10mA。
总预算上,Buck1 按 250mA 平均、350mA 峰值算,Buck2 按 120mA 平均、180mA 峰值算。选型时我要求 Buck1 额定输出至少 500mA,Buck2 至少 300mA,留出 20%-30% 余量。这不是浪费,而是为了应对 MCU 从 Hibernate 唤醒瞬间的电流爬升,这时候内核和 IO 同时启动,负载变化率非常快。
顺便提一句,计算 Buck 峰值电流时不能只看平均值。Ipk = Iavg + ΔI/2,而 ΔI = Vin * D / (f * L),所以电感和开关频率直接决定纹波。实际挑选 PMIC 时,负载瞬态响应比单纯额定电流更重要。PCA9422 这类 PMIC 一般配有 PFM 轻载模式,睡眠时效率高,但在重载时我建议强制 PWM,避免噪声和纹波问题。
2.3 上电时序设计和复位释放
TM4C1299KCZAD 需要电源稳定后再释放复位。我没有把 PMIC 的 PowerGood 直接接到 MCU 的 NRST 引脚,因为多数 PowerGood 是高电平有效,而 NRST 是低电平复位,直接接会乱。我的做法是:在 MCU 固件里用 GPIO 读 PMIC 的电源状态位,等所有目标电压轨就绪后,再通过复位驱动电路或软件延时拉高复位脚完成启动。
顺序上,先让 Buck1 工作,3.3V 起来后 VDDC 再建立。如果外部直供 VDDC,Buck2 要在 Buck1 建立之后才能开启,否则内核先上电、IO 后上电容易引发端口漏电。这个顺序可以通过 PCA9422 的寄存器配置输出延时实现,也可以在硬件上用 GPIO 使能第二路。我用的是寄存器延时,实现起来更干净,也方便批量调整。
3. 硬件搭建要点:原理图、布局和器件选型
3.1 原理图连接里面最容易忽略的引脚关系
PCA9422 这部分要仔细看手册。我这里按通用 PMIC 的连接方式说明。电池正极接芯片的充电输入,USB 5V 进充电器的 VBUS 输入;电池负极和系统地用单点连接,避免充电电流在信号地上形成压差。Buck1 输出 3.3V 的电感选择很重要,电感太小纹波大,太大会让负载瞬态响应变差。我用的电感值在 2.2uH 到 4.7uH 之间,饱和电流必须大于峰值电流,不然电流一大电感感值就掉,输出跟着崩。
I2C 接口要加上拉电阻,一般 2.2k 到 4.7k 到 3.3V,PMIC 的 SDA 和 SCL 属于开漏类型。中断引脚通常也是开漏低有效,需要上拉。这里有个容易被忽略的问题:上拉电阻的电源选择。
如果系统休眠时 3.3V 主轨被关闭,上拉到 3.3V 的 I2C 和中断线都会变成无效状态,PMIC 就无法通过中断唤醒 MCU。我的处理是把上拉放到一个常开的 LDO 输出轨上,或者选择始终维持的 VBAT 轨,这样才能保证休眠状态下通信和唤醒仍然有效。
3.2 PCB 布局与开关噪声控制
PCA9422 的 Buck 开关节点是高 dv/dt 的位置,布局时要从芯片输出脚到电感到输出电容走线尽量短粗,开关节点不要大范围铺铜。反馈采样要尽量靠近输出电容远端,不要靠近电感。PCB 上我把功率地 PGND 和信号地分区域铺,最后在 PMIC 底下用一个 0 欧电阻连接,效果比大面积混铺更容易控制噪声。
TM4C1299KCZAD 是 BGA 封装,电源引脚多且分布广,建议底层留完整的 3.3V 和 1.2V 铺铜平面,过孔阵列要足够。如果 3.3V 和 1.2V 走线太细,BGA 中心和边缘的电压会有毫伏级别差异,对模拟采样会有影响。我在靠近 MCU 的模拟电源引脚处加了 1uF + 0.1uF 的 MLCC,实测 ADC 噪声比之前只用单个电容好一点。
3.3 看起来不起眼却影响很大的器件选型
输出电容建议用 X7R 或更好温度特性的 MLCC,不要用 Y5V,因为 DC 偏压下容量掉得厉害。我之前在原型板上用了一颗 22uF 的 Y5V 电容,常温没问题,温度低一些输出纹波明显变大,换成 X7R 就稳定了。
输入电容也别省。电池到 PMIC 的走线一旦长了,输入阻抗上升,Buck 的动态电流会拉低电池电压,PMIC 可能误判欠压。我在电池正极和 PMIC 输入端之间放了 10uF + 0.1uF,放在离芯片尽可能近的位置。还有一个细节是充电回路的电流检测电阻要选低温漂的合金电阻,不然充电电流会随温度漂移,久而久之电池充满判据就不准了。
4. 软件控制:从 I2C 读写到完整电源状态机
4.1 I2C 读写封装和启动校验
PCA9422 的寄存器地址和数据布局不同批次可能有差异,我的建议是不要直接背地址,按芯片手册建一个映射表。先写一个基础读写函数,带超时和重试,因为 MCU 和 PMIC 之间上电初期可能不稳定。
uint8_t pca9422_read_reg(uint8_t reg, uint8_t *val) { uint8_t buf; if (i2c_write(PMIC_ADDR, ®, 1, 100) != 0) { return ERR; } if (i2c_read(PMIC_ADDR, &buf, 1, 100) != 0) { return ERR; } *val = buf; return OK; } uint8_t pca9422_write_reg(uint8_t reg, uint8_t val) { uint8_t buf[2] = {reg, val}; if (i2c_write(PMIC_ADDR, buf, 2, 100) != 0) { return ERR; } return OK; }这里我简化了 I2C 驱动的实现。实际 TM4C1299KCZAD 的 I2C 外设建议用中断或 DMA 发送,不然 400kHz 下的轮询会占用 CPU。即使这样,读写封装也必须带校验逻辑,不能只写不管。
4.2 上电配置流程:写后读回
上电流程里最重要的原则是写后读回,而不是写完就当作成功。因为 PMIC 如果还没完全准备好,第一次写可能没有生效,寄存器默认值和期望值不一致,系统就可能以错误电压运行。
我的流程是:I2C 初始化 -> 读取 PMIC ID -> 配置 Buck1 到 3.3V -> 配置 Buck2 到 1.2V -> 配置 LDO -> 使能输出 -> 读回所有关键寄存器做比对。校验失败就重试,重试三次仍失败就点亮故障灯。
PMIC 一般会有 ID 寄存器,启动时读 ID 可以避免接错芯片或者 I2C 地址冲突。有一次我在调试中把线序做错,设备地址根本读不到,后来通过示波器抓 I2C 才发现 SCL 和 SDA 接反了。启动校验能很快暴露这类硬件问题。
4.3 运行/待机/休眠三态切换
电源管理不是把 PMIC 配一次就完事了,要配合系统工作状态动态调整。
- 运行态:所有通道开启,MCU 全速跑,传感器周期采集,以太网/无线模块可收发。
- 待机态:关闭传感器负载开关,MCU 外设停止但内核仍保持,Buck 切入 PFM 轻载模式,VBAT 由 LDO 保持。这个状态用于短时间事件等待,可以被定时器唤醒。
- 休眠态:MCU 进入 Hibernate,PCA9422 只保留 LDO 给 RTC 和唤醒逻辑,其余 Buck 全部关闭。
切换时序要小心,关 Buck 前先通知 MCU 停止访问对应电压域上的外设,否则外设会看到电源消失。先切负载、再切电源,顺序不能反。代码里可以用状态机实现:
typedef enum { POWER_RUN, POWER_STANDBY, POWER_HIBERNATE } power_state_t; void system_enter_standby(void) { save_sensor_registers(); disable_sensor_load_switch(); pca9422_write_reg(REG_BUCK_MODE, BUCK_PFM); mcu_disable_peripherals(); } void system_enter_hibernate(void) { save_sensor_registers(); disable_sensor_load_switch(); pca9422_write_reg(REG_EN_BUCK2, 0); pca9422_write_reg(REG_EN_BUCK1, 0); mcu_hibernate_enter(); }上面寄存器名是示意写法,实际要按数据手册确认。切换状态时最好先关中断,防止在电源断掉瞬间外设中断触发,导致状态机跑乱。
4.4 充电管理和低电量保护
充电状态读取可以通过 PMIC 寄存器拿到:正在充电、充电完成、欠压等状态。低电量保护要设置两级阈值。当电压降到预警阈值,系统停止非关键外设,保留数据缓存;到紧急阈值,MCU 保存上下文后进入 Hibernate,PMIC 关闭非关键 Buck。插入充电器后,PMIC 产生中断唤醒 MCU。
注意充电插入瞬间 VBUS 会有抖动,中断处理里要做软件延时去抖,大概等 20-50ms 再读取状态,避免一次插入触发多次唤醒。电池 SOC 估算方面,只靠电压不准,因为锂电池放电曲线有平台期。我用的方法是设备进入休眠前等几分钟测一次开路电压,查 SOC 表做校正;运行期间再用电流积分做短时补偿,精度足够日常指示用。
5. 调试排坑:三个让我反复查电路的案例
5.1 MCU 反复复位的完整排查链路
现象是电池供电时程序跑几秒就重启,但 USB 供电不重启。先怀疑复位电路,示波器抓 NRST 有毛刺。接着抓 3.3V,发现 Buck 在轻载下进入 PFM 模式,纹波偏大但没有跌到复位阈值。继续抓 1.2V,发现问题:1.2V 上升沿很慢,MCU 已经开始启动,内核电压还没完全稳定,等到外设初始化时内核电压才跟上,于是复位。
原因是我用的内部 LDO 生成 VDDC,但 3.3V 输入在 PFM 模式下纹波比较大。解决方法是把 Buck1 配置成强制 PWM 模式,并增加输出电容。换完之后波形明显变好。这个案例让我学到的经验是,不要只看“电压数值正常”,要看“电压上升时间”和“瞬态跌落深度”,这两个参数才是实际影响数字电路启动的关键。
5.2 休眠电流比预期高十倍
休眠电流预期小于 1mA,实测 5mA。先断开外设供电,电流没有明显下降,说明问题出在 PMIC 或 MCU。然后从 PMIC 寄存器逐个读状态,发现 Buck1 在休眠时并没有被关掉,还处于 PFM 工作状态。
原来固件待机流程里只关了外设,忘了通过 I2C 把 Buck1 切成关闭。另一个原因是 TM4C1299KCZAD 的 GPIO 在休眠前没有统一处理,有几个引脚被外部电阻拉到高电平,形成从 GPIO 到电源的低阻路径。后来加了一个统一的“休眠前 IO 状态配置”函数,把所有不用保持电平的 GPIO 全部设为模拟输入或禁用态,问题才彻底解决。
5.3 I2C 配置偶发丢失
表现是冷启动时 PMIC 输出有时正确,有时不正确。示波器抓 I2C 时序,发现 MCU 的 I2C 在 PMIC 稳定之前就开始写入,第一个写事务返回 NACK。固件里如果没做超时重试,配置就静默失败,PMIC 保持默认电压。
解决办法是启动流程里先轮询 PMIC ID,读到正确 ID 后再开始配置,每次写关键寄存器后读回校验。后来加了这个逻辑,连续几十台板子冷启动都没再出现配置丢失。这让我养成了一个习惯:所有 I2C 从设备的上电初始化,都先读 ID,再写配置,再读回验证,三步缺一不可。
5.4 唤醒后 I2C 总线卡死
还有一个和 PMIC 低功耗模式相关的问题:系统从 Hibernate 唤醒后,MCU 试图读取 PMIC 寄存器,结果 I2C 总线一直忙。原因是 PMIC 还在低功耗配置下,I2C 模块可能处于非活动状态,MCU 侧发出的 START 信号没有得到响应,总线被一个异常低电平卡住。
处理方式是在唤醒流程里先对 I2C 外设做软件复位,等 PMIC 的 LDO 输出稳定后再重新初始化 I2C,不要一唤醒就立刻读 PMIC。这个坑比较隐蔽,如果不抓 I2C 波形很难猜到,记录在这里给后来人参考。
6. 实测结果和可以继续挖的方向
6.1 各状态下的功耗数据
完整调试完,我记录了三种状态下的整机功耗。这里的数值是带外设的整机实测,不含电池自放电:
| 状态 | 3.3V 电流 | 1.2V 电流 | 整机功耗 |
|---|---|---|---|
| 运行态(全速+传感器+无线) | 约 230mA | 约 110mA | 约 1.2W |
| 待机态(CPU 保持,外设关闭) | 约 8mA | 约 5mA | 约 40mW |
| 休眠态(Hibernate + PMIC 仅 LDO) | 约 5uA | 0 | 约 16uA 整机电流 |
对比原来的分立方案,休眠电流从约 45uA 降到 16uA,主要原因是把一直挂着的 LDO 换成了 PMIC 的常开 LDO,并关掉了不必要的电压轨。运行态的功耗没有明显下降,但 PCB 面积和充电管理部分的可靠性明显提升。
6.2 后续可以扩展的方向
一个方向是 DVFS:PCA9422 支持 I2C 动态调压,TM4C1299KCZAD 在不同主频下对内核电压的需求不完全一样。之前固定 1.2V,如果低频运行可以适当降到 1.1V,能省一些功率。不过需要确认 MCU 在不同频率下的电压范围,不能盲目降。
另一个方向是做整机功耗曲线:把每个状态切换的时间点和当前电流记录下来,画成一条曲线,定位哪个外设异常耗电。这个对电池供电设备运维很有价值,可以提前发现硬件老化或固件异常。
最后分享一个我后来一直用的调试技巧:在 PMIC 每个 Buck 的输出电感后面留一个测试点,并且串一个 0 欧电阻。调试功耗的时候把 0 欧电阻拿掉,串进电流表,比反复飞线方便得多;测完把 0 欧焊回去即可。这个小改动几乎不占 PCB 面积,但后续定位功耗问题能省很多时间。