MPM54524号在不在?我拿你搓了一个桌面开源可调电源(正餐)

还记得刚刚前菜我们吃了这个
接下来吃点好的↓

这个芯片不麻烦,但是上位通讯复杂些,我这里使用了标准的HID库来进行封装,在封装前要再看一下通讯协议:

START
→ 发送从机地址 + 写 (0x25<<1 | 0 = 0x4A)
→ 发送寄存器地址 (如 0x15)
→ 发送数据 (如 0x88 设置电压值)
→ STOP

2 个赞

读取流程(典型读寄存器)

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()
1 个赞

使用示例:

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()

image

成功

1 个赞

若你只关心电压设置(例如 BuckA):

dev.write_reg(0x15, 0x88)  # 设置 BuckA 输出电压(示例值)

只关心故障检测:

status = dev.read_reg(0x00)
if status & 0x40:
    print("过温故障")
if status & 0x20:
    print("Buck A 输出异常")

image
输出都是正确的

OK,万里长征第一步,接下来激素封装这个寄存器库了。

写一个完整的 MPM54524 Python 控制类,已封装所有主要寄存器操作,并支持:

读取/写入任意寄存器(byte)

快捷读写特定功能寄存器(STATUS、ENABLE、电压设定等)

错误处理

可拓展性强(后续支持 word/block)

1 个赞

完整 Python 控制类 MPM54524.py

import 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 过压")
1 个赞

示例用法

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路控制


最后一版是功能最多的,有功耗计算以及寄存器读写

文末小彩蛋,众所周知起名字最难了:


玩笑归玩笑,前级确实还可以拓展LBO,也可以直接当多路电源去用

程序什么的,我整理好再发出来。
所以就是说这篇帖子,还有补篇
欢迎讨论,一起玩!

1 个赞

大哥威武,实力行动派


这是一个简单的视频记录(哇哇哇!竟然可以直接传视频啊,以前是不是没有哇!)