6. PMBus
6.1. 概述
PMBus是一种总线协议,用于在计算机系统中管理和监控各种物理设备,如处理器、内存、存储设备等。PMBus协议定义了一组标准的命令和寄存器,用于读取和写入设备的状态信息,以及执行各种管理操作。PMBus总线通常与SMBus总线兼容,因此可以在许多不同的计算机系统中使用。
PMBus协议的主要目标是提供一种统一的接口,使得不同的物理设备可以通过相同的总线进行通信和管理。它支持多种设备类型,如处理器、内存、存储设备、网络接口等。PMBus协议还支持设备的热插拔和热插拔事件的检测,以及设备的故障诊断和故障恢复。
PMBus协议的实现通常由硬件和软件组成。硬件部分包括物理总线和设备,软件部分包括驱动和库函数。
驱动负责将PMBus协议转换为SMBus协议,并将SMBus协议转换为物理总线的信号。(依赖smbus组件)
本组件则提供了一组API,用于读取和写入设备的状态信息,以及执行各种管理操作。
本组件完整支持PMBus 1.2规范定义的200+个标准命令码(如电压/电流/温度监控、故障响应等)
提供命令参数配置表(pmbus_cmd_param_table),定义每个命令的:
typedef struct { uint8_t command_code; /* PMBus命令码 */ uint32_t data_length; /* 数据长度(0表示无数据) */ pmbus_transaction_type_t read_transaction_type; /* 读操作类型(字节/字/块) */ pmbus_transaction_type_t write_transaction_type; /* 写操作类型 */ } hpm_pmbus_cmd_param_t;
系统集成功能
支持主机/从机模式(通过底层I2C/SMBus驱动)
制造商扩展命令支持(MFR_SPECIFIC_00-45)
从机模式使用中断回调方式响应命令并处理数据。
6.2. 相关枚举和结构体介绍
枚举介绍
PMBUS通信中的事务类型,要用在PMBUS协议通信中,用于区分不同的数据传输类型。每个枚举值对应PMBUS规范中定义的标准事务类型,包括:字节/字/块级的读写操作、特殊单字节传输、以及厂商自定义和扩展命令的处理。
typedef enum { none = 0, /**< 无操作 */ write_byte = 1, /**< 写入一个字节 */ read_byte = 2, /**< 读取一个字节 */ write_word = 3, /**< 写入一个字(两个字节) */ read_word = 4, /**< 读取一个字(两个字节) */ write_block = 5, /**< 写入数据块 */ read_block = 6, /**< 读取数据块 */ send_byte = 7, /**< 发送单字节 */ mfr_defined = 8, /**< 厂商自定义命令 */ extended_command = 9, /**< 扩展命令 */ } hpm_pmbus_transaction_type;
PMBUS状态码,定义了PMBUS组件的错误状态码,主要用于标识电源管理总线通信中的特定错误类型。
enum { status_pmbus_not_support_cmd = MAKE_STATUS(status_group_pmbus, 1), /**< 不支持的PMBus命令 */ status_pmbus_not_transaction_type = MAKE_STATUS(status_group_pmbus, 2), /**< 不支持的事务类型 */ };
定义回调函数类型 hpm_pmbus_complete_cb_t,此回调函数会在 PMbus 操作完成后被调用,允许用户实现特定的完成处理逻辑。
typedef void (*hpm_pmbus_complete_cb_t)(I2C_Type *base, hpm_pmbus_complete_cb_cfg_t *cfg);
参数说明
参数名
类型
描述
base
I2C_Type *指向 I2C 控制器的基地址,用于标识正在进行操作的 I2C 控制器。
cfg
hpm_pmbus_complete_cb_cfg_t *指向 PMBUS 命令完成回调配置结构体的指针,用于提供操作完成的详细信息,包括命令码、数据长度、操作方向、PEC 校验状态以及数据缓冲区指针。
结构体介绍
PMBUS命令完成回调配置结构体,用于在PMBUS命令传输完成后,向回调函数传递完整的操作上下文信息。
typedef struct { uint8_t command; /**< 当前处理的PMBus命令码(如VOUT_COMMAND=0x21) */ uint32_t len; /**< 本次传输的有效数据长度(单位:字节) */ bool read; /**< 操作方向标志:true=读操作,false=写操作 */ bool pec_check; /**< 是否启用了数据包错误校验(PEC) */ uint8_t *data; /**< 数据缓冲区指针: - 写操作:指向已发送的数据 - 读操作:指向接收数据存储位置 */ } hpm_pmbus_complete_cb_cfg_t;
PMBus命令参数结构体,用于存储PMBus命令的相关参数,方便在PMBus通信中使用。
typedef struct { /**< 命令码,用于标识特定的PMBus命令 */ uint8_t command_code; /**< 写事务类型,指示写操作的具体类型 */ hpm_pmbus_transaction_type write_transaction_type; /**< 读事务类型,指示读操作的具体类型 */ hpm_pmbus_transaction_type read_transaction_type; /**< 数据长度,指示命令关联的数据长度,单位为字节,0表示无数据 */ uint32_t data_length; } hpm_pmbus_cmd_param_t;
PMBus从机配置结构体,用于存储PMBus从机设备的运行时配置。
typedef struct { bool is_valid; /**< 从机配置有效性标志 */ uint8_t *wdata; /**< 指向待写入数据的指针(主机→从机) */ uint8_t *rdata; /**< 指向读取数据缓冲区的指针(从机→主机) */ uint32_t data_length; /**< 数据传输长度(单位:字节) */ hpm_pmbus_complete_cb_t callback; /**< 数据传输完成回调函数指针 */ } hpm_pmbus_slave_cfg_t;
6.3. API调用流程介绍
6.3.1. PMbus初始化
6.3.1.1. 主机模式
调用
i2c_init_masterAPI 来初始化 I2C为主机模式。该API在hpm_i2c_drv驱动中定义。i2c_init_masterAPI原型:hpm_stat_t i2c_init_master(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址的指针
src_clk_in_hz
uint32_t
I2C时钟源频率
config
i2c_config_t*
指向I2C配置结构体的指针
返回值:
status_success: 成功status_invalid_argument: 无效参数
举例: 实例化I2C0,设置I2C0为主机模式,100Khz速度,7bit地址模式。
#define TEST_PMBUS HPM_I2C0 #define TEST_PMBUS_CLOCK_NAME clock_i2c0 i2c_config_t config; /* 定义I2C配置结构体 */ board_init_i2c_clock(TEST_PMBUS); init_i2c_pins(TEST_PMBUS); config.i2c_mode = i2c_mode_normal; config.is_10bit_addressing = false; freq = clock_get_frequency(TEST_PMBUS_CLOCK_NAME); stat = i2c_init_master(TEST_PMBUS, freq, &config); if (stat != status_success) { return stat; }
6.3.1.2. 从机模式
除了需要
i2c_init_slaveAPI初始化I2C外设基本的配置之外,还需要使用hpm_pmbus_slave_initAPI初始化PMBus从机设备开启相关中断,为PMBus从机设备准备好通信基础环境。中断函数中使用hpm_pmbus_isr_handler来处理I2C从机地址匹配和传输完成事件。调用
i2c_init_slaveAPI 来初始化 I2C为从机模式。该API在hpm_i2c_drv驱动中定义。i2c_init_slaveAPI原型:hpm_stat_t i2c_init_slave(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址的指针
src_clk_in_hz
uint32_t
I2C时钟源频率
config
i2c_config_t*
指向I2C配置结构体的指针
返回值:
status_success: 成功status_invalid_argument: 无效参数
调用
hpm_pmbus_slave_initAPI 来初始化 PMBus从机设备。该API在hpm_pmbus中定义。主要的作用是启用I2C的中断事件:地址命中和传输完成,这样当从机地址匹配或传输完成时,会触发中断,确保从机能正确响应主机的请求,接着在中断回调处理请求相关业务。hpm_pmbus_slave_initAPI原型:hpm_stat_t hpm_pmbus_slave_init(I2C_Type *ptr, uint8_t slave_addr);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址的指针
slave_addr
uint8_t
从机设备地址
返回值:
status_success: 成功status_invalid_argument: 无效参数
中断回调函数原型:
void hpm_pmbus_isr_handler(I2C_Type *ptr);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址的指针
举例: 实例化I2C0,设置I2C0为从机模式,100Khz速度,7bit地址模式,从机设备地址为0x16。
#define TEST_PMBUS HPM_I2C0 #define TEST_PMBUS_CLOCK_NAME clock_i2c0 #define TEST_I2C_IRQ IRQn_I2C0 #define TEST_PMBUS_SLAVE_ADDRESS (0x16U) SDK_DECLARE_EXT_ISR_M(TEST_I2C_IRQ, i2c_isr) void i2c_isr(void) { hpm_pmbus_isr_handler(TEST_PMBUS); } i2c_config_t config; /* 定义I2C配置结构体 */ board_init_i2c_clock(TEST_PMBUS); init_i2c_pins(TEST_PMBUS); config.i2c_mode = i2c_mode_slave; config.is_10bit_addressing = false; config.slave_address = 0x16; freq = clock_get_frequency(TEST_PMBUS_CLOCK_NAME); stat = i2c_init_slave(TEST_PMBUS, freq, &config); if (stat!= status_success) { return stat; } intc_m_enable_irq_with_priority(TEST_I2C_IRQ, 1); hpm_pmbus_slave_init(TEST_PMBUS, TEST_PMBUS_SLAVE_ADDRESS);
6.3.2. 读写操作,支持主从机模式
6.3.2.1. 主机模式
6.3.2.1.1. 写操作
使用
hpm_pmbus_master_writeAPI执行写操作该API关键功能说明:
通过pmbus_cmd_param_table[command]获取预定义的命令参数配置,包含:
事务类型(字节/字/块)
预期数据长度
其他协议参数
多事务类型支持
支持5种写操作模式:
send_byte: 仅发送命令字节(无数据),用于简单控制命令
write_byte: 命令+1字节数据(如设置使能位)
write_word: 命令+2字节数据(如设置电压值0x12 0x34)
write_block: 命令+长度字节+数据块(用于大数据传输)
当处理块写入时:
0xFFFFFFFF表示动态长度模式,使用调用者传入的len参数
其他值表示使用预定义的固定数据长度
自动处理PMBus协议要求的长度字节前缀
返回标准化的错误代码:
status_pmbus_not_support_cmd: 遇到未实现的命令类型
status_pmbus_not_transaction_type: 无效的事务类型配置
API原型:
hpm_stat_t hpm_pmbus_master_write(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t len);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址
slave_address
uint8_t
从机设备地址(7位)
command
uint8_t
PMBus命令码
data
uint8_t*
待写入数据指针(根据命令类型选择字节/字/块数据)
len
uint32_t
数据长度(仅块写入时生效)
- 返回值:
status_success: 操作成功status_pmbus_not_support_cmd: 不支持的PMBus命令status_pmbus_not_transaction_type: 无效的事务类型
示例:设置输出电压为3.3V(写入字数据0x0D 0x00)
/* PMbus初始化,不做举例 */ uint16_t voltage = 0x0D00; hpm_stat_t status = hpm_pmbus_master_write(I2C0, 0x5A, PMBUS_CODE_VOUT_COMMAND, (uint8_t*)&voltage, 2);
6.3.2.1.2. 读操作
使用
hpm_pmbus_master_readAPI执行读操作该API关键功能说明:
多模式支持,处理三种标准读取操作:
字节读取:用于读取状态寄存器等单字节数据
字读取:用于读取电压/电流等16位测量值
块读取:用于获取日志信息等大数据块
长度处理策略
字节/字读取:固定返回1/2字节
块读取: - 0xFFFFFFFF表示动态长度模式,使用调用者传入的*len作为缓冲区容量 - 其他值表示使用预定义长度,自动校验数据完整性
返回标准化的错误代码:
status_pmbus_not_support_cmd: 遇到未实现的命令类型
status_pmbus_not_transaction_type: 无效的事务类型配置
API原型:
hpm_stat_t hpm_pmbus_master_read(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t *len);
参数说明:
参数名
类型
描述
ptr
I2C_Type*
指向I2C控制器基地址
slave_address
uint8_t
从机设备地址(7位)
command
uint8_t
PMBus命令码
data
uint8_t*
数据接收缓冲区指针
len
uint32_t*
输入:缓冲区最大容量 / 输出:实际读取长度
- 返回值:
status_success: 操作成功status_pmbus_not_support_cmd: 不支持的PMBus命令status_pmbus_not_transaction_type: 无效的事务类型
示例:读取输出电压值
/* PMbus初始化,不做举例 */ uint8_t vout_data[2]; uint32_t read_len = 2; hpm_stat_t status = hpm_pmbus_master_read(I2C0, 0x5A, PMBUS_CODE_VOUT_COMMAND, vout_data, &read_len); if (status == status_success) { float voltage = (vout_data[0] | (vout_data[1] << 8)) * 0.001; /* 转换为电压值 */ }
6.3.2.2. 从机模式
6.3.2.2.1. 从机命令事务管理
6.3.2.2.1.1. 命令事务安装
使用
hpm_pmbus_slave_command_transaction_install配置从机命令响应关键功能:
预绑定PMBus命令与数据缓冲区
注册事务完成回调函数
支持标准命令码(0x00-0xFF)
自动处理PEC校验字节空间分配
API原型:
hpm_stat_t hpm_pmbus_slave_command_transaction_install( I2C_Type *ptr, uint8_t command, uint8_t *wdata, uint8_t *rdata, uint32_t len, hpm_pmbus_complete_cb_t callback );
参数说明:
参数
类型
描述
ptr
I2C_Type*
绑定的I2C控制器实例(如HPM_I2C0)
command
uint8_t
PMBus标准命令码
wdata
uint8_t*
主机写操作数据缓冲区(从机接收用),需预留PEC字节空间
rdata
uint8_t*
主机读操作数据缓冲区(从机发送用),需预留PEC字节空间
len
uint32_t
缓冲区总长度(包含数据+PEC校验字节)
callback
hpm_pmbus_complete_cb_t
事务完成回调函数指针
- 返回值:
status_success: 配置成功status_invalid_argument: 空指针/缓冲区长度不足status_pmbus_not_support_cmd: 不支持的命令类型
6.3.2.2.2. 命令事务卸载
使用
hpm_pmbus_slave_command_transaction_uninstall移除命令配置关键功能:
释放命令槽位资源
清除关联的回调函数
禁用指定命令的响应
API原型:
hpm_stat_t hpm_pmbus_slave_command_transaction_uninstall( I2C_Type *ptr, uint8_t command );
参数说明:
参数
类型
描述
ptr
I2C_Type*
I2C控制器实例(需与安装时一致)
command
uint8_t
需要移除的PMBus命令码
- 返回值:
status_success: 卸载成功status_invalid_argument: 非法控制器指针
6.3.2.2.3. 应用示例
从机电压监控示例(响应READ_VOUT命令)
/* 定义命令参数 */
#define VOUT_CMD PMBUS_CODE_VOUT_COMMAND /* 0x8B
#define DATA_BUF_LEN 3 /* 2字节数据 + 1字节PEC */
uint8_t vout_data[DATA_BUF_LEN] = {0}; /* 电压数据存储(小端格式)*/
/* 电压读取完成回调 */
void vout_callback(I2C_Type *base, hpm_pmbus_complete_cb_cfg_t *cfg)
{
if (cfg->read) {
printf("主机读取了%d字节电压数据\n", cfg->len);
} else {
printf("主机写入了%d字节配置\n", cfg->len);
}
}
/* 系统初始化 */
void pmbus_slave_init(void)
{
/* PMbus初始化,不做举例 */
/* 安装电压读取命令事务 */
hpm_pmbus_slave_command_transaction_install(
TEST_PMBUS,
VOUT_CMD,
NULL, /* 主机写操作不处理 */
vout_data, /* 读数据缓冲区 */
DATA_BUF_LEN,
vout_callback
);
/*填充初始电压值(11.5V = 0x47E)
vout_data[0] = 0xE0 | (0x47 & 0x1F); /* 指数部分 */
vout_data[1] = (0x47 >> 5); /* 尾数部分 */
}
/* 停止监控时卸载 */
void pmbus_slave_deinit(void)
{
hpm_pmbus_slave_command_transaction_uninstall(TEST_PMBUS, VOUT_CMD);
}