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_master API 来初始化 I2C为主机模式。该API在 hpm_i2c_drv 驱动中定义。

    • i2c_init_master API原型:

      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_slave API初始化I2C外设基本的配置之外,还需要使用 hpm_pmbus_slave_init API初始化PMBus从机设备开启相关中断,为PMBus从机设备准备好通信基础环境。中断函数中使用 hpm_pmbus_isr_handler 来处理I2C从机地址匹配和传输完成事件。

    • 调用 i2c_init_slave API 来初始化 I2C为从机模式。该API在 hpm_i2c_drv 驱动中定义。

      • i2c_init_slave API原型:

        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_init API 来初始化 PMBus从机设备。该API在 hpm_pmbus 中定义。主要的作用是启用I2C的中断事件:地址命中和传输完成,这样当从机地址匹配或传输完成时,会触发中断,确保从机能正确响应主机的请求,接着在中断回调处理请求相关业务。

      • hpm_pmbus_slave_init API原型:

        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_write API执行写操作

    • 该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_read API执行读操作

    • 该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);
}