6. PMBus
6.1. Overview
PMBus is a bus protocol used for managing and monitoring various physical devices in computer systems, such as processors, memory, storage devices, etc. The PMBus protocol defines a set of standard commands and registers for reading/writing device status information and performing management operations. PMBus is typically compatible with SMBus, enabling deployment across various computer systems.
The primary objectives of the PMBus protocol are:
Provide a unified interface for communication between different physical devices
Support multiple device types including processors, memory modules, storage devices, and network interfaces
Enable hot-plug detection and event handling
Implement device fault diagnosis and recovery mechanisms
PMBus implementation consists of:
Hardware components: Physical buses and devices
Software components: Drivers and library functions
Drivers handle protocol conversion between PMBus and SMBus (dependent on smbus component)
This component provides APIs for device status access and management operations
Full support for 200+ standard command codes defined in PMBus 1.2 specification:
Voltage/current/temperature monitoring
Fault response mechanisms
Other power management features
Command parameter configuration table (pmbus_cmd_param_table) definition:
typedef struct {
uint8_t command_code; /* PMBus command code */
uint32_t data_length; /* Data length (0 indicates no data) */
pmbus_transaction_type_t read_transaction_type; /* Read operation type (byte/word/block) */
pmbus_transaction_type_t write_transaction_type; /* Write operation type */
} hpm_pmbus_cmd_param_t;
System Integration Features:
Master/Slave mode support (via underlying I2C/SMBus drivers)
Manufacturer extension command support (MFR_SPECIFIC_00-45)
Slave mode command handling through interrupt callback mechanism
6.2. Enumerations and Structures
Enumerations
Transaction types in PMBUS communication, used to distinguish different data transmission types in PMBUS protocol. Each enumeration value corresponds to standard transaction types defined in PMBUS specification.
typedef enum { none = 0, /**< No operation */ write_byte = 1, /**< Write one byte */ read_byte = 2, /**< Read one byte */ write_word = 3, /**< Write one word (2 bytes) */ read_word = 4, /**< Read one word (2 bytes) */ write_block = 5, /**< Write data block */ read_block = 6, /**< Read data block */ send_byte = 7, /**< Send single byte */ mfr_defined = 8, /**< Manufacturer-defined command */ extended_command = 9, /**< Extended command */ } hpm_pmbus_transaction_type;
PMBUS status codes defining error states for PMBUS component.
enum { status_pmbus_not_support_cmd = MAKE_STATUS(status_group_pmbus, 1), /**< Unsupported PMBus command */ status_pmbus_not_transaction_type = MAKE_STATUS(status_group_pmbus, 2), /**< Unsupported transaction type */ };
Callback function type definition for PMBUS operation completion.
typedef void (*hpm_pmbus_complete_cb_t)(I2C_Type *base, hpm_pmbus_complete_cb_cfg_t *cfg);
Parameter description:
Parameter
Type
Description
base
I2C_Type *Pointer to I2C controller base address
cfg
hpm_pmbus_complete_cb_cfg_t *Pointer to completion callback configuration structure
Structures
PMBUS command completion callback configuration structure.
typedef struct { uint8_t command; /**< Currently processed PMBus command code (e.g. VOUT_COMMAND=0x21) */ uint32_t len; /**< Valid data length in bytes */ bool read; /**< Operation direction: true=read, false=write */ bool pec_check; /**< Packet Error Checking (PEC) enabled */ uint8_t *data; /**< Data buffer pointer: - Write: Points to sent data - Read: Points to received data */ } hpm_pmbus_complete_cb_cfg_t;
PMBus command parameter structure.
typedef struct { /**< PMBus command code */ uint8_t command_code; /**< Write transaction type */ hpm_pmbus_transaction_type write_transaction_type; /**< Read transaction type */ hpm_pmbus_transaction_type read_transaction_type; /**< Associated data length in bytes (0 indicates no data) */ uint32_t data_length; } hpm_pmbus_cmd_param_t;
PMBus slave configuration structure.
typedef struct { bool is_valid; /**< Configuration validity flag */ uint8_t *wdata; /**< Write data pointer (Host→Slave) */ uint8_t *rdata; /**< Read data buffer pointer (Slave→Host) */ uint32_t data_length; /**< Data transfer length in bytes */ hpm_pmbus_complete_cb_t callback; /**< Transfer completion callback */ } hpm_pmbus_slave_cfg_t;
6.3. API Workflow
6.3.1. PMBus Initialization
6.3.1.1. Master Mode
Use
i2c_init_masterAPI to initialize I2C in master mode (defined inhpm_i2c_drvdriver)API prototype:
hpm_stat_t i2c_init_master(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
Pointer to I2C controller base address
src_clk_in_hz
uint32_t
I2C clock source frequency
config
i2c_config_t*
Pointer to I2C configuration structure
- Return values:
status_success: Initialization successfulstatus_invalid_argument: Invalid parameter
Example: Initialize I2C0 in master mode (100KHz, 7-bit address)
#define TEST_PMBUS HPM_I2C0 #define TEST_PMBUS_CLOCK_NAME clock_i2c0 i2c_config_t config; board_init_i2c_clock(TEST_PMBUS); init_i2c_pins(TEST_PMBUS); config.i2c_mode = i2c_mode_normal; config.is_10bit_addressing = false; uint32_t freq = clock_get_frequency(TEST_PMBUS_CLOCK_NAME); hpm_stat_t stat = i2c_init_master(TEST_PMBUS, freq, &config); if (stat != status_success) { return stat; }
6.3.1.2. Slave Mode
Requires
i2c_init_slavefor basic I2C configuration andhpm_pmbus_slave_initto enable PMBus-specific interruptsInitialize I2C in slave mode using
i2c_init_slave:hpm_stat_t i2c_init_slave(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config);
Parameters identical to master mode API
- Return values:
status_success: Initialization successfulstatus_invalid_argument: Invalid parameter
PMBus slave initialization with
hpm_pmbus_slave_init:hpm_stat_t hpm_pmbus_slave_init(I2C_Type *ptr, uint8_t slave_addr);
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
I2C controller instance
slave_addr
uint8_t
7-bit slave address
- Enables critical interrupts:
Address match
Transfer completion
Interrupt handler prototype:
void hpm_pmbus_isr_handler(I2C_Type *ptr);
Example: Configure I2C0 as PMBus slave (0x16 address, 100KHz)
#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); } void init_slave() { i2c_config_t config; 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; uint32_t freq = clock_get_frequency(TEST_PMBUS_CLOCK_NAME); hpm_stat_t 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. Read/Write Operations
6.3.2.1. Master Mode
6.3.2.1.1. Write Operation
Use
hpm_pmbus_master_writeAPI for write operationsKey features:
- Retrieves predefined command parameters from pmbus_cmd_param_table[command]:
Transaction type (byte/word/block)
Expected data length
Protocol parameters
- Supports 5 write modes:
send_byte: Command byte only (no data)
write_byte: Command + 1 byte data
write_word: Command + 2 bytes data
write_block: Command + length byte + data block
- Block write handling:
0xFFFFFFFF: Dynamic length mode (uses caller’s len parameter)
Other values: Use predefined fixed length
Auto-handles PMBus length byte prefix
- Error codes:
status_pmbus_not_support_cmd: Unsupported command
status_pmbus_not_transaction_type: Invalid transaction type
API prototype:
hpm_stat_t hpm_pmbus_master_write(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t len);
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
I2C controller base address
slave_address
uint8_t
7-bit slave address
command
uint8_t
PMBus command code (e.g. 0x21 for VOUT_COMMAND)
data
uint8_t*
Data buffer (format depends on command type)
len
uint32_t
Data length (effective for block writes only)
Returns:
status_success: Operation successfulstatus_pmbus_not_support_cmd: Unsupported PMBus commandstatus_pmbus_not_transaction_type: Invalid transaction type
Example: Set output voltage to 3.3V (write word 0x0D00):
/* PMBus initialization omitted */ 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. Read Operation
Use
hpm_pmbus_master_readAPI for read operationsKey features:
Supports three read modes:
Byte read: Single byte status registers
Word read: 16-bit measurements (voltage/current)
Block read: Large data chunks (logs etc.)
Length handling:
Byte/word: Fixed 1/2 byte returns
Block read:
0xFFFFFFFF: Dynamic length mode (uses caller’s len parameter)
Other values: Use predefined length
Error codes:
status_pmbus_not_support_cmd: Unsupported command
status_pmbus_not_transaction_type: Invalid transaction type
API prototype:
hpm_stat_t hpm_pmbus_master_read(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t *len);
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
I2C controller base address
slave_address
uint8_t
7-bit slave address
command
uint8_t
PMBus command code
data
uint8_t*
Data receive buffer pointer
len
uint32_t*
Input: buffer capacity / Output: actual data length
- Returns:
status_success: Operation successfulstatus_pmbus_not_support_cmd: Unsupported PMBus commandstatus_pmbus_not_transaction_type: Invalid transaction type
Example: Read output voltage:
/* PMBus initialization omitted */ 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; /* Convert to voltage value */ }
6.3.2.2. Slave Mode
6.3.2.2.1. Slave Command Transaction Management
6.3.2.2.1.1. Command Transaction Installation
Use
hpm_pmbus_slave_command_transaction_installto configure slave command responseKey features:
Pre-bind PMBus commands with data buffers
Register transaction completion callback
Supports standard command codes (0x00-0xFF)
Auto-handles PEC checksum space allocation
API prototype:
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 );
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
Bound I2C controller instance (e.g. HPM_I2C0)
command
uint8_t
PMBus standard command code
wdata
uint8_t*
Host write buffer (slave receive), must reserve PEC space
rdata
uint8_t*
Host read buffer (slave transmit), must reserve PEC space
len
uint32_t
Total buffer length (data + PEC checksum)
callback
hpm_pmbus_complete_cb_t
Transaction completion callback pointer
- Returns:
status_success: Configuration successfulstatus_invalid_argument: Null pointer/insufficient bufferstatus_pmbus_not_support_cmd: Unsupported command type
6.3.2.2.2. Command Transaction Uninstallation
Use
hpm_pmbus_slave_command_transaction_uninstallto remove command configurationKey features:
Release command slot resources
Clear associated callback functions
Disable specified command response
API prototype:
hpm_stat_t hpm_pmbus_slave_command_transaction_uninstall( I2C_Type *ptr, uint8_t command );
Parameters:
Parameter
Type
Description
ptr
I2C_Type*
I2C controller instance (must match installation)
command
uint8_t
PMBus command code to remove
- Returns:
status_success: Uninstallation successfulstatus_invalid_argument: Invalid controller pointer
6.3.2.2.3. Application Example
Slave Voltage Monitoring (Respond to READ_VOUT)
/* Command parameters */
#define VOUT_CMD PMBUS_CMD_READ_VOUT /* 0x8B */
#define DATA_BUF_LEN 3 /* 2 data bytes + 1 PEC */
uint8_t vout_data[DATA_BUF_LEN] = {0}; /* Voltage storage (little-endian) */
/* Voltage read callback */
void vout_callback(I2C_Type *base, hpm_pmbus_complete_cb_cfg_t *cfg)
{
if (cfg->read) {
printf("Host read %d voltage bytes\n", cfg->len);
} else {
printf("Host wrote %d config bytes\n", cfg->len);
}
}
/* System initialization */
void pmbus_slave_init(void)
{
/* Initialize I2C slave mode */
i2c_init_slave(TEST_PMBUS, freq, &config);
hpm_pmbus_slave_init(TEST_PMBUS, 0x16);
/* Install voltage read transaction */
hpm_pmbus_slave_command_transaction_install(
TEST_PMBUS,
VOUT_CMD,
NULL, /* Ignore host write */
vout_data, /* Read data buffer */
DATA_BUF_LEN,
vout_callback
);
/* Set initial voltage (11.5V = 0x47E)
vout_data[0] = 0xE0 | (0x47 & 0x1F); /* Exponent */
vout_data[1] = (0x47 >> 5); /* Mantissa */
}
/* deinit */
void pmbus_slave_deinit(void)
{
hpm_pmbus_slave_command_transaction_uninstall(TEST_PMBUS, VOUT_CMD);
}