一觉醒来不知道谁送了我一颗 MPS的 MPM54524(属实是掩耳盗铃了),这颗也是 FPGA 供电以及多路大电流应用的王者,那今天的小朋友就它了!
我就在想可以做点什么,直到在闲鱼看到了这个:

一个降压的PD输出电源,这小体积,可以控制,不就是梦中情机吗?

54524还支持4路输出,玩法更多

老哥也给出了一个上位机,当然我也给出了一个简版的上位机
提前看效果:
这个是初版
后面又加了一些功能:
较为完善的demo
(怕有人不看下面的文字,所以提前上视频)
因为MPM54524 是一款带I2C接口的全集成、5A、4 路输出电源模块。它内置启动与关断排序控制,同时具备可调软启动 (SS)、补偿功能和多个保护阈值,提供了一个完整的电源解决方案。

蛮合适的

4路输出正好满足一些调试需求,如果不够可以扩展
在3.3V下效率还更高。

以往电源需要很多外置的元件来辅助,现在一颗芯片就都完成
保护功能齐全,只要前面搞个二极管就可以给电池供电了:
功能简称 | 全称 | 作用 | 应用意义 |
|---|---|---|---|
OCP | Over Current Protection | 过流保护 | 防止短时电流过大烧坏芯片 |
SCP | Short Circuit Protection | 输出短路保护 | 输出接地等极端场景自我断电 |
OVP | Over Voltage Protection | 过压保护 | 防止反馈失控或外部干扰导致高压输出 |
OTP | Over Temperature Protection | 过热保护 | 芯片内部温度过高时主动关闭输出 |
UVLO | Under Voltage Lockout | 欠压锁定 | 输入电压不足时延迟启动,避免不稳定工作 |

EVL板也很简洁,这次也是使用它来运行最小的demo
MPS官方有个GUI可以完成这个功能的,但是调试器太贵了,我这里给出了廉价的方案:

就是这个

360+

这个接口要用,PUSH一下
以及为了后面的兄弟可以复用,减少对环境的依赖性,我这里使用了Python的接口(调死我了):

CP2112

是一款完美的小芯片,调试其它的IIC设备也可以
最终的样机是这样:

测试
正点原子做主供电,因为是MPM54524(点击直达这颗料)是降压输出,电流最大到5A:

这里最大的电流也就是这样设置了
控制的架构是这样的:
┌────────────┐ I²C (通过桥接器)
│ 上位机 │◄────────────────────┐
│ (Python/Qt)│ │
└────────────┘ ▼
↑ GUI控制 + 显示 ┌────────────┐
│ │ USB-I2C桥接 │ (如 CH341, MCP2221, FT4222)
└─────────────串口/USB────▶│ 或 MCU转发 │
└────────────┘
│
I²C 总线
▼
┌────────────────┐
│ MPM54524GCQ │
└────────────────┘
这颗芯片还是很有特点的,稍微讲一下我看到有趣的功能:
Buck A 和 B 可并联支持 10A 输出,并支持交错相位以优化纹波(Interleaving)。
交错相位是一种控制策略,它使得多个降压通道(Buck A/B/C/D)的开关时序错开固定角度(通常为90°或180°),实现以下目标:
使各通道的导通(On-Time)均匀分布在一个周期内,从而分散输入/输出电流脉冲,降低系统纹波。
假设系统总频率为 1MHz(周期 = 1µs):
四个 Buck 通道同时工作但 分布在不同相位:
Buck A: 0°
Buck B: 90°
Buck C: 180°
Buck D: 270°
这意味着它们的开关事件间隔为:1μs ÷ 4 = 250ns→ 所有通道平均分布在每个周期,电流纹波合成后会部分抵消,而不是集中在同一时刻叠加。
在数据手册第 18–19 页中有如下关键描述:
“Figure 4 shows that Buck A/B/C/D are frequency-locked with fixed 90° phase shift.”

这里
默认状态下,A-B-C-D 四通道交错工作,相位间隔为 90°;
如果启用并联模式(A+B),则 A 和 B 之间使用 180° 相移(见 Figure 5),以便互补导通达到交错均流效果。

就是保证一个周期内队外输出不这么变,内部交替进行
寄存器地址:14h, bit[5] = 1 → 启用 Buck A 和 Buck B 的并联交错模式(Interleaved Dual-Phase Mode);
并联模式下,需强制绑定反馈点(VSA+ = VSB+);**VSA+ 必须连接 VSB+**,表示这两个输出电压完全一致,共用反馈。
Buck C 和 D 不支持并联工作,仅交错控制;交错模式适用于大负载或动态电流需求场景,不建议在极轻负载下启用并联。
所以我这次就没有设置这个选项,因为样板上面好像没有感测线的接口。
AVP(Active Voltage Positioning)功能:输出电压随负载电流下调(VDROOP = IOUT × RDROOP),有助于电流自动均流。
核心思想是:
随着负载电流增加,输出电压按比例下调,从而实现更佳的瞬态响应和并联均流性能。
换句话说:负载电流越大,输出电压 VOUT 自动下降;有点类似“动态压降”或“虚拟阻抗控制”。这个功能可以上负载来看
AVP 功能遵循以下两个公式:
:压降值;
:实际输出电流;
:设定的等效电阻,典型值为 40mΩ。
当负载突增时,VOUT 本来就预留压降空间,减少过冲;可以做瞬态抑制。也可以多个通道(如 A/B/C/D)并联时,AVP 会自动调节电压大小,根据负载电流自动趋向均衡;降低大负载下的功耗与散热压力;最后因为系统不再强依赖容性响应,减小 VOUT 振幅,可用更小电容。
MPM54524 支持对 Buck A/B 和 C/D 分别独立启用 AVP。
寄存器地址 71h:bit[7] = 1:开启 Buck A/B 的 AVP
寄存器地址 79h:bit[7] = 1:开启 Buck C/D 的 AVP
当多个 Buck 输出并联(如 Buck A 和 B、或者全部四路 A+B+C+D)时:
各通道根据自身电流大小会形成不同压降;
压降大 → 电压低 → 分担电流少;
压降小 → 电压高 → 分担电流多;
最终达到被动均流(通过电压调节驱动电流)。
所以 AVP 实现的是负载自适应电压调节 + 被动电流均流,而不是主动控制电流。
我们来发挥传统艺能,看看可视化的操作:

展示了 MPM54524 在启用 AVP(Active Voltage Positioning)时,不同参考电压 下,输出电压 随负载电流 的线性下降关系。
每条曲线代表一个不同的设定参考电压(1.0V、1.2V、1.5V、3.3V);
横轴是输出电流(从 0A 到 5A);
纵轴是实际输出电压;
斜率是固定的,由内部设定的 决定;
说明随着负载电流增加,输出电压按比例线性下调。
轻载时电压较高,重载时自动压降;改善并联电源之间的均流分配;帮助缓冲负载突变下的电压跳变;降低对大电容的依赖(减小COUT)。
上面说了四通道的事情

四通道并联时的电流分担
这张图展示了 MPM54524 在 AVP 模式下四通道并联时的电流分担和总输出电压的变化趋势。
Channel A/B/C/D Current(彩色实线):代表每个通道均匀分担总电流 ,从 0A 到 20A,每个通道上限为 5A;
Shared VOUT(虚线):是所有通道输出一致的电压,其值随总电流线性下降,反映了 AVP 机制的作用。
这里的数据可能有点错误,但是趋势没有问题,就是电流大,电压小因为功率一定。
很多的电源芯片有IIC接口,但是详细说明的不多:

芯片还有两个额外的地址线

这个是限制,需要加限流的上拉电阻

框图如此

官方的板子都是AD绘制的,ADDR1和2都拉高的
如果在使用过程中有问题可以去论坛问:

MPS老哥现场安排

大概五分钟内回复吧,这里是发帖的时候写出标题了
“Two ADDR pins are available to configure bit[0] to bit[3]...”
MPM54524 支持最多 8种地址配置,通过两个引脚 ADDR1 和 ADDR2 设定 I²C 地址的低四位(bit[0]~bit[3]):
ADDR1 | ADDR2 | I²C 地址(0XXX xxxx) |
|---|---|---|
Low | Low | 0XXX 1001 |
Low | Float | 0XXX 1100 |
Low | High | 0XXX 1110 |
Float | Low | 0XXX 1010 |
Float | Float | 0XXX 1000 |
Float | High | 0XXX 1111 |
High | Low | 0XXX 1011 |
High | Float | 0XXX 1101 |
High | High | 0XXX 0111 |
表中 “0XXX” 的高位部分可以通过写入寄存器 0x73h 设置 bit[4]~bit[6],实现地址扩展(详见手册注释 XXX refers to portion configurable by customer)。
如果不使用IIC控制的话,默认的0xxx其实就是0x000,EVL也就是0x07,使用的时候记得算对。
还是算一下吧!
bit[6:4] = 0b000(默认上电值)
ADDR[3:0] = 0111(由 High, High 决定)
完整地址为:0b00000111 = 0x07
使用时:
写地址(8 位) = 0x07 << 1 | 0 = 0x0E
读地址(8 位) = 0x07 << 1 | 1 = 0x0F
但是这个IIC不是纯IIC,而是专门电源管理的PMBUS:

在这里

STM32F401
以前老不知道这个PMBus是什么,这次就解惑了。
类型 | 含义 |
|---|---|
R | 只读(Read Only) |
W | 只写(Write Only) |
R/W | 可读可写 |
Send | 写入命令后立即执行,无需数据 |
主要是这个Send命令是不一样的,其实就直接清楚寄存器位而已。

也就是这个
我们知道这些知识就可以了!
这个芯片不复杂,但是上位通讯麻烦,我这里使用了标准的HID库来进行封装,在封装前要再看一下通讯协议:
START
→ 发送从机地址 + 写 (0x25<<1 | 0 = 0x4A)
→ 发送寄存器地址 (如 0x15)
→ 发送数据 (如 0x88 设置电压值)
→ STOP
START
→ 发送从机地址 + 写 (0x4A)
→ 发送寄存器地址 (如 0x15)
→ RESTART
→ 发送从机地址 + 读 (0x4B)
→ 读取数据(如读回寄存器值)
→ STOP
为了最精简地控制 MPM54524GCQ 电源芯片,只需要保留 I²C 的字节级读写功能,并去除多余功能,构建一个轻量的控制类即可。
读任意寄存器:read_byte_data(addr, reg)
写任意寄存器:write_byte_data(addr, reg, val)
然后代码我传到了GitHub,这里也写一下重要的部分:
import hid
import time
class MPM54524:
def __init__(self, address=0x25):
self.h = hid.device()
self.h.open(0x10C4, 0xEA90) # CP2112 的 VID, PID
self.address = address # 默认 I2C 从地址
def write_reg(self, reg, val):
"""向寄存器写入一个字节"""
self.h.write([0x14, self.address << 1, 0x02, reg, val])
def read_reg(self, reg):
"""读取寄存器一个字节"""
self.h.write([0x11, self.address << 1, 0x00, 0x01, 0x01, reg]) # Write+Read 请求
for _ in range(10):
self.h.write([0x15, 0x01]) # 查询状态
resp = self.h.read(7)
if resp[0] == 0x16 and resp[2] == 5:
self.h.write([0x12, 0x00, 0x01]) # 强制读取
resp = self.h.read(4)
return resp[3]
raise IOError("Read timeout or failure")
def close(self):
self.h.close()
if __name__ == '__main__':
dev = MPM54524(address=0x25) # 从机地址视 ADDR1/ADDR2 引脚而定
val = dev.read_reg(0x00) # 读取 STATUS_0
print(f"STATUS_0 = 0x{val:02X}")
dev.write_reg(0x0C, 0x0F) # 启用 Buck A~D 输出
dev.close()

成功
dev.write_reg(0x15, 0x88) # 设置 BuckA 输出电压(示例值)
status = dev.read_reg(0x00)
if status & 0x40:
print("过温故障")
if status & 0x20:
print("Buck A 输出异常")

输出都是正确的
OK,万里长征第一步,接下来激素封装这个寄存器库了。
写一个完整的 MPM54524 Python 控制类,已封装所有主要寄存器操作,并支持:
读取/写入任意寄存器(byte)
快捷读写特定功能寄存器(STATUS、ENABLE、电压设定等)
错误处理
可拓展性强(后续支持 word/block)
MPM54524.pyimport hid
import time
class MPM54524:
VENDOR_ID = 0x10C4 # CP2112 VID
PRODUCT_ID = 0xEA90 # CP2112 PID
def __init__(self, address=0x25):
self.h = hid.device()
self.h.open(self.VENDOR_ID, self.PRODUCT_ID)
self.address = address # 7-bit I²C 地址(取决于 ADDR1/2 引脚)
time.sleep(0.1)
def close(self):
self.h.close()
def write_reg(self, reg_addr, value):
"""写 1 字节到寄存器"""
self.h.write([0x14, self.address << 1, 0x02, reg_addr, value])
def read_reg(self, reg_addr):
"""读 1 字节寄存器"""
self.h.write([0x11, self.address << 1, 0x00, 0x01, 0x01, reg_addr])
for _ in range(10):
self.h.write([0x15, 0x01])
resp = self.h.read(7)
if resp[0] == 0x16 and resp[2] == 5:
self.h.write([0x12, 0x00, 0x01])
resp = self.h.read(4)
return resp[3]
raise IOError(f"Read failed for register 0x{reg_addr:02X}")
# ---------- 常用寄存器封装 ----------
def get_status_0(self):
"""读取 STATUS_0 状态寄存器 (00h)"""
return self.read_reg(0x00)
def clear_status(self):
"""清除故障(07h = CLEAR_0)"""
self.write_reg(0x07, 0x01)
def enable_buck_channels(self, enable_mask=0x0F):
"""
控制 BuckA~D 使能(0Ch 寄存器)
bit7~4 控制各 Buck 输出通道:1 = enable,0 = disable
默认 0x0F = 全部开启
"""
self.write_reg(0x0C, (enable_mask & 0x0F) << 4)
def disable_buck_channels(self):
self.enable_buck_channels(0x00)
def set_buck_voltage(self, channel, value):
"""
设置某一路 Buck 输出电压值(寄存器 0x15~0x18)
value = 电压设定值(具体映射查数据手册)
"""
reg_map = {'A': 0x15, 'B': 0x16, 'C': 0x17, 'D': 0x18}
if channel in reg_map:
self.write_reg(reg_map[channel], value)
else:
raise ValueError("Invalid channel. Use A/B/C/D.")
def read_buck_voltage(self, channel):
reg_map = {'A': 0x15, 'B': 0x16, 'C': 0x17, 'D': 0x18}
if channel in reg_map:
return self.read_reg(reg_map[channel])
raise ValueError("Invalid channel. Use A/B/C/D.")
def read_current_monitor(self, channel):
reg_map = {'A': 0x02, 'B': 0x03, 'C': 0x04, 'D': 0x05}
if channel in reg_map:
return self.read_reg(reg_map[channel])
raise ValueError("Invalid channel. Use A/B/C/D.")
def get_temperature(self):
"""读取温度 ADC 值(24h)"""
return self.read_reg(0x24)
def get_device_id(self):
"""读取芯片 ID(31h)"""
return self.read_reg(0x31)
# ---------- 工具辅助 ----------
def print_status(self):
val = self.get_status_0()
print(f"STATUS_0 = 0x{val:02X}")
if val & 0x40: print("过温故障")
if val & 0x20: print("Buck A 输出异常")
if val & 0x10: print("Buck B 输出异常")
if val & 0x08: print("Buck C 输出异常")
if val & 0x04: print("Buck D 输出异常")
if val & 0x02: print("VIN 过压")
if __name__ == "__main__":
dev = MPM54524(address=0x25)
dev.print_status() # 打印 STATUS_0 状态
dev.clear_status() # 清除故障
dev.enable_buck_channels() # 启动 A~D 通道
dev.set_buck_voltage('A', 0x88) # 设置 BuckA 电压(例值)
val = dev.read_buck_voltage('A')
print(f"BuckA voltage setting = 0x{val:02X}")
current = dev.read_current_monitor('A')
print(f"BuckA 电流值(ADC) = {current}")
print(f"温度寄存器 = {dev.get_temperature()}")
print(f"芯片 ID = {dev.get_device_id():02X}")
dev.close()

这是最一开始的UI
这里在之后需要微调,显示不是很正常。

第二版是最稳的版本
左上角的各种芯片信息,也有单路或者4路控制

最后一版是功能最多的,有功耗计算以及寄存器读写
文末小彩蛋,众所周知起名字最难了:

幻想时间
程序什么的,我整理好再发出来。