PMBus深入解析:电源管理的通信总线
·
PMBus深入解析:电源管理的通信总线
一、PMBus概述与基本概念
1.1 PMBus是什么?
PMBus(Power Management Bus)是一种基于SMBus(System Management Bus,I2C的增强版)的开放标准协议,专门用于电源管理设备的通信和控制。
1.2 主要设计目标
- 电源设备的监控:电压、电流、温度等参数的实时读取
- 电源设备的控制:输出电压调整、开关机控制、故障管理等
- 电源系统的配置:保护阈值、时序参数、工作模式的设置
- 数字电源系统管理:支持现代数字电源转换器
1.3 与I2C/SMBus的关系
I2C(基础层)
↓(增强)
SMBus(系统管理总线)
↓(专门化)
PMBus(电源管理总线)
二、PMBus协议架构详解
2.1 协议层结构
应用层:PMBus命令和参数
↓
协议层:SMBus/I2C数据包格式
↓
物理层:SMBus/I2C电气接口
2.2 物理层特性
引脚定义:
- SCL:串行时钟线
- SDA:串行数据线
- ALERT#:警报中断线(可选)
- CONTROL:控制线(可选,用于硬件控制)
- SMBALERT#:SMBus警报(可选)
电气特性(与SMBus兼容):
- 电压:3.3V(常见),5V容忍
- 速度:
* Standard-mode:100 kHz
* Fast-mode:400 kHz
* Fast-mode Plus:1 MHz(部分支持)
- 总线电容:≤ 400 pF
- 上拉电阻:2-10 kΩ
2.3 PMBus与I2C/SMBus的区别
| 特性 | I2C | SMBus | PMBus |
|---|---|---|---|
| 电压范围 | 宽(1.8V-5V) | 严格(2.7V-5V) | 同SMBus |
| 速度 | 100k/400k/1M/3.4M | 100k/400k | 100k/400k |
| 时钟低电平超时 | 无要求 | 25-35ms | 25-35ms |
| 超时机制 | 可选 | 要求 | 要求 |
| 协议开销 | 小 | 中等 | 较大 |
| 目标应用 | 通用 | 系统管理 | 电源管理 |
三、PMBus命令集详解
3.1 命令编码格式
PMBus命令使用1字节(0x00-0xFF)作为命令码,部分命令支持扩展。
3.2 主要命令分类
A. 基本命令(0x00-0x1F)
// 页面/组选择命令
#define PAGE0x00// 选择逻辑页面
#define OPERATION0x01// 设备操作控制
#define ON_OFF_CONFIG0x02// 开关配置
#define CLEAR_FAULTS0x03// 清除故障标志
#define PHASE0x04// 相位配置
#define PAGE_PLUS_WRITE0x05// 多页写入
#define PAGE_PLUS_READ0x06// 多页读取
// 示例:设置设备工作模式
// 发送:[设备地址 + W] [0x01] [0x80]// 开启设备
// 0x80 = 1000 0000b (bit7=1:开启)
B. 监控命令(0x20-0x3F)
// 读取电压/电流/功率
#define READ_VIN0x88// 输入电压
#define READ_VOUT0x8B// 输出电压
#define READ_IOUT0x8C// 输出电流
#define READ_POUT0x96// 输出功率
#define READ_TEMPERATURE_1 0x8D // 温度传感器1
// 数据格式:LINEAR11(最常用)
// 11位浮点格式:5位指数 + 6位尾数
// 值 = Y × 2^N
// 其中Y:11位有符号整数,N:5位有符号指数
C. 配置命令(0x40-0x7F)
// 电压相关配置
#define VOUT_MODE0x20// 输出模式
#define VOUT_COMMAND0x21// 输出电压命令值
#define VOUT_MAX0x24// 最大输出电压
#define VOUT_MIN0x25// 最小输出电压
// 电流/功率限制
#define IOUT_CAL_GAIN0x38// 电流校准增益
#define IOUT_CAL_OFFSET0x39// 电流校准偏移
#define POUT_MAX0x6A// 最大输出功率
D. 保护命令(0x80-0xBF)
// 过压保护
#define VOUT_OV_FAULT_LIMIT0x40// 过压故障阈值
#define VOUT_OV_WARN_LIMIT0x42// 过压警告阈值
// 过流保护
#define IOUT_OC_FAULT_LIMIT0x46// 过流故障阈值
#define IOUT_OC_WARN_LIMIT0x4A// 过流警告阈值
// 过温保护
#define OT_FAULT_LIMIT0x4F// 过温故障阈值
#define OT_WARN_LIMIT0x51// 过温警告阈值
E. 高级命令(0xC0-0xFF)
// 设备信息
#define MFR_ID0x99// 制造商ID
#define MFR_MODEL0x9A// 型号
#define MFR_REVISION0x9B// 修订版本
#define MFR_LOCATION0x9C// 生产地点
#define MFR_DATE0x9D// 生产日期
#define MFR_SERIAL0x9E// 序列号
3.3 数据传输格式
PMBus支持多种数据格式:
3.3.1 LINEAR11格式(最常用)
用于电压、电流、功率、温度等模拟量
格式:16位,其中:
- 高5位:指数N(二进制补码,范围-16到15)
- 低11位:尾数Y(二进制补码)
实际值 = Y × 2^N
示例代码(解析LINEAR11):
float pmbus_linear11_to_float(uint16_t data)
{
int16_t y = (int16_t)(data & 0x07FF);// 11位尾数
int8_t n = (int8_t)(data >> 11);// 5位指数
// 处理符号扩展
if (y & 0x0400) y |= 0xF800;// 如果第10位是1,扩展符号
if (n & 0x10) n |= 0xE0;// 如果第4位是1,扩展符号
return (float)y * powf(2.0f, (float)n);
}
3.3.2 LINEAR16格式
用于直接模式
格式:16位有符号整数,带有缩放因子
实际值 = 值 × 2^(-N),其中N由VOUT_MODE指定
3.3.3 直接格式
用于简单的开关控制
示例:OPERATION命令
0x80 = 设备开启
0x00 = 设备关闭
四、PMBus通信时序
4.1 基本通信帧结构
起始位 → 从机地址(7bit)+W(1bit) → 命令字节 →
数据字节1 → 数据字节2 → ... → 停止位
4.2 写操作示例(设置输出电压)
1. 主机发送:[START] [0xB0 + W] [0x21(VOUT_COMMAND)] [0x80] [0x00] [STOP]
- 0xB0: 从机地址(假设为0x58左移1位)
- 0x21: VOUT_COMMAND命令
- 0x80 0x00: 输出电压值(LINEAR11格式)
2. 从机响应:每个字节后发送ACK
4.3 读操作示例(读取输入电压)
1. 主机发送:[START] [0xB0 + W] [0x88(READ_VIN)] [START] [0xB0 + R]
2. 从机响应:[数据高位] [数据低位] [NAK]
3. 主机发送:[STOP]
4.4 组合格式(Block Write/Read)
用于传输大量数据
Block Write:
[Addr+W] [Command] [长度N] [字节1] ... [字节N]
Block Read:
[Addr+W] [Command] [START] [Addr+R] [长度N] [字节1] ... [字节N]
五、在FPGA中实现PMBus接口
5.1 PMBus主控制器设计
module pmbus_master #(
parameter CLK_FREQ = 100_000_000,// FPGA时钟频率
parameter I2C_FREQ = 100_000// I2C总线频率
)(
inputwire clk,
inputwire reset_n,
// I2C/PMBus物理接口
inoutwire sda,
output wire scl,
inputwire alert_n,// ALERT#信号
// 用户接口
inputwire [6:0]dev_addr,// 设备地址
inputwire [7:0]command,// PMBus命令
inputwire [15:0] write_data,// 写入数据
output reg[15:0] read_data,// 读取数据
inputwirestart,// 启动传输
output regdone,// 传输完成
output regerror,// 错误标志
output regack_error// ACK错误
);
// 状态定义
localparam STATE_IDLE= 0;
localparam STATE_START= 1;
localparam STATE_ADDR_WR= 2;
localparam STATE_CMD= 3;
localparam STATE_WR_DATA_H = 4;
localparam STATE_WR_DATA_L = 5;
localparam STATE_RESTART= 6;
localparam STATE_ADDR_RD= 7;
localparam STATE_RD_DATA_H = 8;
localparam STATE_RD_DATA_L = 9;
localparam STATE_STOP= 10;
reg [3:0] state;
reg [7:0] bit_counter;
reg scl_enable;
reg sda_out;
reg sda_oe;// SDA输出使能
// 时钟分频器
reg [15:0] clk_divider;
reg scl_phase;// SCL相位(0=低电平,1=高电平)
// I2C位传输状态机
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= STATE_IDLE;
scl_enable <= 1'b0;
sda_out <= 1'b1;
sda_oe <= 1'b0;
clk_divider <= 0;
scl_phase <= 1'b0;
done <= 1'b0;
error <= 1'b0;
ack_error <= 1'b0;
bit_counter <= 8'd0;
read_data <= 16'd0;
end else begin
// I2C时钟生成
if (scl_enable) begin
if (clk_divider >= (CLK_FREQ / (I2C_FREQ * 4) - 1)) begin
clk_divider <= 0;
scl_phase <= ~scl_phase;
end else begin
clk_divider <= clk_divider + 1;
end
end else begin
clk_divider <= 0;
scl_phase <= 1'b0;
end
// 状态机
case (state)
STATE_IDLE: begin
done <= 1'b0;
error <= 1'b0;
ack_error <= 1'b0;
scl_enable <= 1'b0;
sda_out <= 1'b1;
sda_oe <= 1'b0;
if (start) begin
state <= STATE_START;
sda_out <= 1'b0;// 产生START条件
sda_oe <= 1'b1;
end
end
STATE_START: begin
// 等待一段时间后开始发送地址
if (clk_divider == (CLK_FREQ / (I2C_FREQ * 8) - 1)) begin
state <= STATE_ADDR_WR;
bit_counter <= 8'd7;
scl_enable <= 1'b1;
end
end
STATE_ADDR_WR: begin
// 在SCL低电平时改变SDA
if (scl_phase == 1'b0 && clk_divider == 0) begin
if (bit_counter > 0) begin
sda_out <= dev_addr[bit_counter-1];
bit_counter <= bit_counter - 1;
end else begin
// 发送读写位(0=写)
sda_out <= 1'b0;
state <= STATE_CMD;
bit_counter <= 8'd8;
end
end
// 在SCL高电平时检查ACK
if (scl_phase == 1'b1 && clk_divider == (CLK_FREQ / (I2C_FREQ * 4) - 1)) begin
if (bit_counter == 0) begin
// 检查ACK
if (!sda_in) begin// 收到ACK
// 继续
end else begin
ack_error <= 1'b1;
error <= 1'b1;
state <= STATE_STOP;
end
end
end
end
// ... 其他状态类似实现
STATE_STOP: begin
// 产生STOP条件
if (scl_phase == 1'b0 && clk_divider == 0) begin
sda_out <= 1'b0;
end
if (scl_phase == 1'b1 && clk_divider == (CLK_FREQ / (I2C_FREQ * 4) - 1)) begin
scl_enable <= 1'b0;
end
if (!scl_enable) begin
sda_out <= 1'b1;
sda_oe <= 1'b1;
done <= 1'b1;
state <= STATE_IDLE;
end
end
endcase
end
end
// SCL输出(开漏,需要外部上拉)
assign scl = (scl_enable && scl_phase) ? 1'b0 : 1'bz;
// SDA双向控制
wire sda_in = sda;
assign sda = sda_oe ? sda_out : 1'bz;
endmodule
5.2 PMBus设备(从机)实现
module pmbus_slave #(
parameter DEVICE_ADDR = 7'h58,// 设备地址
parameter NUM_PAGES = 1// 支持页面数
)(
inputwire clk,
inputwire reset_n,
// I2C/PMBus接口
inoutwire sda,
inputwire scl,
output regalert_n,
// 电源控制接口
output reg[11:0] vout_setpoint,// 输出电压设定值
inputwire [11:0] vin_measured,// 输入电压测量值
inputwire [11:0] vout_measured,// 输出电压测量值
inputwire [11:0] iout_measured,// 输出电流测量值
inputwire [7:0]temp_measured// 温度测量值
);
// PMBus寄存器定义
reg [15:0] pmbus_reg [0:255];
reg [7:0]current_page;
reg [7:0]current_command;
// 故障状态寄存器
reg vin_ov_fault;// 输入过压故障
reg vout_ov_fault;// 输出过压故障
reg iout_oc_fault;// 输出过流故障
reg ot_fault;// 过温故障
// I2C从机状态机
localparam STATE_IDLE = 0;
localparam STATE_ADDR = 1;
localparam STATE_CMD = 2;
localparam STATE_WRITE = 3;
localparam STATE_READ = 4;
localparam STATE_ACK = 5;
reg [2:0] state;
reg [2:0] bit_count;
reg [7:0] shift_reg;
reg address_match;
reg read_mode;
// SDA输入同步
reg sda_sync1, sda_sync2;
reg scl_sync1, scl_sync2;
always @(posedge clk) begin
sda_sync1 <= sda;
sda_sync2 <= sda_sync1;
scl_sync1 <= scl;
scl_sync2 <= scl_sync1;
end
// 检测START和STOP条件
wire sda_falling = sda_sync2 && !sda_sync1 && scl_sync2;
wire sda_rising = !sda_sync2 && sda_sync1 && scl_sync2;
wire start_cond = sda_falling;
wire stop_cond = sda_rising;
// I2C从机状态机
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= STATE_IDLE;
bit_count <= 3'd0;
address_match <= 1'b0;
read_mode <= 1'b0;
alert_n <= 1'b1;
current_page <= 8'h00;
current_command <= 8'h00;
end else begin
case (state)
STATE_IDLE: begin
if (start_cond) begin
state <= STATE_ADDR;
bit_count <= 3'd7;
shift_reg <= 8'h00;
end
end
STATE_ADDR: begin
if (scl_sync2 && !scl_sync1) begin// SCL上升沿
shift_reg <= {shift_reg[6:0], sda_sync2};
if (bit_count == 0) begin
// 检查地址匹配
address_match = (shift_reg[7:1] == DEVICE_ADDR);
read_mode = shift_reg[0];
if (address_match) begin
// 发送ACK
// ... 实现ACK发送
if (read_mode) begin
state <= STATE_READ;
// 准备要发送的数据
prepare_read_data();
end else begin
state <= STATE_CMD;
end
end else begin
state <= STATE_IDLE;
end
end else begin
bit_count <= bit_count - 1;
end
end
end
STATE_CMD: begin
// 接收命令字节
if (scl_sync2 && !scl_sync1) begin
shift_reg <= {shift_reg[6:0], sda_sync2};
if (bit_count == 0) begin
current_command <= shift_reg;
// 发送ACK
// ... 实现ACK发送
state <= STATE_WRITE;
bit_count <= 3'd7;
end else begin
bit_count <= bit_count - 1;
end
end
end
STATE_WRITE: begin
// 接收数据字节
if (scl_sync2 && !scl_sync1) begin
shift_reg <= {shift_reg[6:0], sda_sync2};
if (bit_count == 0) begin
// 处理接收到的数据
process_write_data(shift_reg);
// 发送ACK
// ... 实现ACK发送
bit_count <= 3'd7;
end else begin
bit_count <= bit_count - 1;
end
end
if (stop_cond) begin
state <= STATE_IDLE;
end
end
STATE_READ: begin
// 发送数据字节
if (!scl_sync2 && scl_sync1) begin// SCL下降沿
if (bit_count == 0) begin
// 检查主机的ACK
// ... 处理ACK/NAK
if (sda_sync2) begin// NAK,读取结束
state <= STATE_IDLE;
end else begin// ACK,继续发送下一个字节
bit_count <= 3'd7;
prepare_next_read_byte();
end
end else begin
// 发送下一位
// ... 设置SDA输出
bit_count <= bit_count - 1;
end
end
end
endcase
end
end
// 处理PMBus命令
task process_write_data;
input [7:0] data;
begin
case (current_command)
8'h00: current_page <= data;// PAGE命令
8'h01: begin// OPERATION命令
if (data[7]) begin
// 开启设备
vout_setpoint <= pmbus_reg[8'h21];// 使用VOUT_COMMAND值
end else begin
// 关闭设备
vout_setpoint <= 12'h000;
end
end
8'h03: begin// CLEAR_FAULTS命令
vin_ov_fault <= 1'b0;
vout_ov_fault <= 1'b0;
iout_oc_fault <= 1'b0;
ot_fault <= 1'b0;
alert_n <= 1'b1;
end
8'h21: begin// VOUT_COMMAND命令
pmbus_reg[8'h21] <= {8'h00, data};// 存储设置值
// 实际硬件控制可能需要更多处理
end
// ... 其他命令处理
default: begin
if (current_command < 8'h80) begin
// 写入寄存器
pmbus_reg[current_command] <= {pmbus_reg[current_command][15:8], data};
end
end
endcase
end
endtask
// 准备读取数据
task prepare_read_data;
begin
case (current_command)
8'h88: begin// READ_VIN
shift_reg <= float_to_linear11(vin_measured);
end
8'h8B: begin// READ_VOUT
shift_reg <= float_to_linear11(vout_measured);
end
8'h8C: begin// READ_IOUT
shift_reg <= float_to_linear11(iout_measured);
end
8'h8D: begin// READ_TEMPERATURE_1
shift_reg <= {8'h00, temp_measured};
end
default: begin
// 从寄存器读取
shift_reg <= pmbus_reg[current_command];
end
endcase
end
endtask
// 浮点数转LINEAR11格式
function [15:0] float_to_linear11;
input [11:0] value;// 假设12位ADC值
reg [15:0] result;
begin
// 简化转换:假设ADC值直接对应电压值
// 实际应用需要根据校准系数计算
result = {5'd0, 11'(value)};// N=0, Y=ADC值
float_to_linear11 = result;
end
endfunction
endmodule
5.3 完整的PMBus系统示例
// PMBus电源管理子系统
module pmbus_power_subsystem (
// 时钟和复位
inputwire clk_100m,
inputwire reset_n,
// PMBus接口
inoutwire pmbus_sda,
output wire pmbus_scl,
inputwire pmbus_alert_n,
// 电源监控输入
inputwire [11:0] vin_adc,
inputwire [11:0] vout_adc,
inputwire [11:0] iout_adc,
inputwire [7:0]temp_adc,
// 电源控制输出
output reg[11:0] vout_setting,
output regpower_enable,
output regpower_good,
// 故障指示
output regfault_vin_ov,
output regfault_vout_ov,
output regfault_iout_oc,
output regfault_ot
);
// PMBus主控制器
wire [15:0] pmbus_read_data;
wirepmbus_done;
wirepmbus_error;
pmbus_master #(
.CLK_FREQ(100_000_000),
.I2C_FREQ(100_000)
) pmbus_master_inst (
.clk(clk_100m),
.reset_n(reset_n),
.sda(pmbus_sda),
.scl(pmbus_scl),
.alert_n(pmbus_alert_n),
.dev_addr(7'h58),// 电源设备地址
.command(8'h00),// 命令(动态设置)
.write_data(16'h0000),
.read_data(pmbus_read_data),
.start(pmbus_start),
.done(pmbus_done),
.error(pmbus_error),
.ack_error(pmbus_ack_error)
);
// 监控状态机
reg [3:0] monitor_state;
reg [31:0] monitor_counter;
localparam MON_IDLE = 0;
localparam MON_READ_VIN = 1;
localparam MON_READ_VOUT = 2;
localparam MON_READ_IOUT = 3;
localparam MON_READ_TEMP = 4;
localparam MON_CHECK_LIMITS = 5;
localparam MON_HANDLE_FAULTS = 6;
always @(posedge clk_100m or negedge reset_n) begin
if (!reset_n) begin
monitor_state <= MON_IDLE;
monitor_counter <= 32'd0;
fault_vin_ov <= 1'b0;
fault_vout_ov <= 1'b0;
fault_iout_oc <= 1'b0;
fault_ot <= 1'b0;
power_good <= 1'b0;
end else begin
// 每100ms读取一次监控数据
monitor_counter <= monitor_counter + 1;
if (monitor_counter >= 32'd10_000_000) begin// 100ms @ 100MHz
monitor_counter <= 32'd0;
case (monitor_state)
MON_IDLE: begin
if (power_enable) begin
monitor_state <= MON_READ_VIN;
end
end
MON_READ_VIN: begin
// 启动读取输入电压
// ... 设置PMBus命令为READ_VIN
if (pmbus_done && !pmbus_error) begin
// 处理读取的数据
if (pmbus_read_data > LINEAR11(13.2)) begin// 超过13.2V
fault_vin_ov <= 1'b1;
end
monitor_state <= MON_READ_VOUT;
end
end
MON_READ_VOUT: begin
// 类似处理输出电压
monitor_state <= MON_READ_IOUT;
end
// ... 其他状态
MON_CHECK_LIMITS: begin
// 检查所有限制
power_good <= !(fault_vin_ov | fault_vout_ov |
fault_iout_oc | fault_ot);
monitor_state <= MON_IDLE;
end
endcase
end
end
end
// 配置状态机(上电时配置电源参数)
reg [3:0] config_state;
reg [4:0] config_step;
localparam CONFIG_START = 0;
localparam CONFIG_SET_VOUT = 1;
localparam CONFIG_SET_LIMITS = 2;
localparam CONFIG_SET_TIMING = 3;
localparam CONFIG_ENABLE = 4;
localparam CONFIG_DONE = 5;
always @(posedge clk_100m or negedge reset_n) begin
if (!reset_n) begin
config_state <= CONFIG_START;
config_step <= 5'd0;
power_enable <= 1'b0;
end else begin
case (config_state)
CONFIG_START: begin
// 等待电源稳定
if (monitor_counter > 32'd50_000_000) begin// 500ms
config_state <= CONFIG_SET_VOUT;
end
end
CONFIG_SET_VOUT: begin
// 设置输出电压为3.3V(使用LINEAR11格式)
// 3.3 = Y × 2^N,选择N=-9, Y=1690
// 1690 = 0x69A, N=-9 = 0x17(二进制补码)
// LINEAR11格式:0x17 << 11 | 0x69A = 0xB9A
// 发送VOUT_COMMAND命令
if (config_step == 0) begin
// 发送命令
// pmbus_master_inst.command <= 8'h21; // VOUT_COMMAND
// pmbus_master_inst.write_data <= 16'h0B9A;
// pmbus_master_inst.start <= 1'b1;
config_step <= config_step + 1;
end else if (pmbus_done) begin
config_step <= 5'd0;
config_state <= CONFIG_SET_LIMITS;
end
end
CONFIG_SET_LIMITS: begin
// 设置保护阈值
case (config_step)
0: begin
// 设置过压保护阈值:3.63V(3.3V + 10%)
// pmbus_master_inst.command <= 8'h40; // VOUT_OV_FAULT_LIMIT
// pmbus_master_inst.write_data <= 16'h0C5A; // 3.63V的LINEAR11
config_step <= config_step + 1;
end
1: begin
// 设置过流保护阈值:10A
// pmbus_master_inst.command <= 8'h46; // IOUT_OC_FAULT_LIMIT
// pmbus_master_inst.write_data <= 16'h1388; // 10A的LINEAR11
config_step <= config_step + 1;
end
// ... 设置其他限制
5: begin
config_step <= 5'd0;
config_state <= CONFIG_SET_TIMING;
end
endcase
end
CONFIG_ENABLE: begin
// 启用电源
// pmbus_master_inst.command <= 8'h01; // OPERATION
// pmbus_master_inst.write_data <= 16'h0080; // 开启设备
power_enable <= 1'b1;
config_state <= CONFIG_DONE;
end
CONFIG_DONE: begin
// 配置完成
end
endcase
end
end
endmodule
六、实际应用考虑
6.1 地址分配策略
// PMBus设备地址通常为7位
// 地址分配示例:
#define PMBUS_ADDR_POL10x58// 第一路POL
#define PMBUS_ADDR_POL20x5A// 第二路POL
#define PMBUS_ADDR_VDD_CORE 0x5C// 核心电压
#define PMBUS_ADDR_VDD_IO0x5E// IO电压
#define PMBUS_ADDR_VDD_DDR0x60// DDR电压
#define PMBUS_ADDR_FAN_CTRL 0x62// 风扇控制器
6.2 故障处理机制
// 故障检测和处理
module pmbus_fault_handler (
inputwire clk,
inputwire reset_n,
// 故障输入
inputwire vin_ov_fault,
inputwire vout_ov_fault,
inputwire iout_oc_fault,
inputwire ot_fault,
inputwire uv_fault,
// PMBus接口
output regalert_n,// ALERT#信号
output reg[15:0] status_word,// STATUS_WORD寄存器
// 系统接口
output regshutdown_req, // 关机请求
output reg[7:0] fault_code
);
// STATUS_WORD位定义
localparam BIT_VIN_OV_FAULT= 15;
localparam BIT_VOUT_OV_FAULT= 14;
localparam BIT_IOUT_OC_FAULT= 12;
localparam BIT_OT_FAULT= 4;
localparam BIT_UV_FAULT= 13;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
alert_n <= 1'b1;
status_word <= 16'h0000;
shutdown_req <= 1'b0;
fault_code <= 8'h00;
end else begin
// 更新状态字
status_word[BIT_VIN_OV_FAULT]<= vin_ov_fault;
status_word[BIT_VOUT_OV_FAULT] <= vout_ov_fault;
status_word[BIT_IOUT_OC_FAULT] <= iout_oc_fault;
status_word[BIT_OT_FAULT]<= ot_fault;
status_word[BIT_UV_FAULT]<= uv_fault;
// 检测新故障
if ((vin_ov_fault && !status_word[BIT_VIN_OV_FAULT]) ||
(vout_ov_fault && !status_word[BIT_VOUT_OV_FAULT]) ||
(iout_oc_fault && !status_word[BIT_IOUT_OC_FAULT]) ||
(ot_fault && !status_word[BIT_OT_FAULT])) begin
// 拉低ALERT#信号
alert_n <= 1'b0;
// 设置故障代码
if (vin_ov_fault) fault_code <= 8'h01;
else if (vout_ov_fault) fault_code <= 8'h02;
else if (iout_oc_fault) fault_code <= 8'h03;
else if (ot_fault) fault_code <= 8'h04;
// 严重故障触发关机
if (vout_ov_fault || ot_fault) begin
shutdown_req <= 1'b1;
end
end
// 如果主机清除了故障
if (pmbus_clear_fault) begin
alert_n <= 1'b1;
shutdown_req <= 1'b0;
end
end
end
endmodule
6.3 热插拔支持
// PMBus热插拔检测
module pmbus_hot_swap (
inputwire clk,
inputwire reset_n,
// 物理检测
inputwire presence_detect,// 存在检测引脚
// PMBus接口
output reg[7:0] mfr_id,
output reg[7:0] mfr_model,
output reg[7:0] mfr_revision,
output reg[31:0] mfr_serial,
// 状态输出
output regdevice_present,
output regdevice_ready
);
// 设备检测状态机
reg [1:0] detect_state;
reg [23:0] detect_counter;
localparam DETECT_IDLE = 0;
localparam DETECT_WAIT = 1;
localparam DETECT_READ_ID = 2;
localparam DETECT_READY = 3;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
detect_state <= DETECT_IDLE;
device_present <= 1'b0;
device_ready <= 1'b0;
detect_counter <= 24'd0;
end else begin
case (detect_state)
DETECT_IDLE: begin
if (presence_detect) begin
// 检测到设备插入
device_present <= 1'b1;
detect_state <= DETECT_WAIT;
detect_counter <= 24'd0;
end else begin
device_present <= 1'b0;
device_ready <= 1'b0;
end
end
DETECT_WAIT: begin
// 等待设备稳定(100ms)
detect_counter <= detect_counter + 1;
if (detect_counter >= 24'd10_000_000) begin// 100ms @ 100MHz
detect_state <= DETECT_READ_ID;
end
end
DETECT_READ_ID: begin
// 通过PMBus读取设备ID
// 发送MFR_ID命令 (0x99)
// 发送MFR_MODEL命令 (0x9A)
// 发送MFR_REVISION命令 (0x9B)
// 发送MFR_SERIAL命令 (0x9E)
// 假设读取成功
mfr_id <= 8'h01;// 示例:TI
mfr_model <= 8'h23;// 示例:TPS546C23
mfr_revision <= 8'hA1; // 示例:Rev A1
mfr_serial <= 32'h12345678;
detect_state <= DETECT_READY;
end
DETECT_READY: begin
device_ready <= 1'b1;
// 检查设备是否被移除
if (!presence_detect) begin
detect_state <= DETECT_IDLE;
end
end
endcase
end
end
endmodule
七、调试与测试
7.1 调试技巧
// PMBus调试模块
module pmbus_debug #(
parameter LOG_DEPTH = 256
)(
inputwire clk,
inputwire reset_n,
// PMBus监控接口
inputwiresda_mon,
inputwirescl_mon,
// 调试输出
output reg[7:0]debug_state,
output reg[31:0] packet_counter,
output regerror_detected,
output reg[7:0]last_error_code,
// 日志接口
output reg[63:0] log_data [0:LOG_DEPTH-1],
output reg[7:0]log_wr_ptr,
output reg[7:0]log_rd_ptr
);
// 状态解码
always @(posedge clk) begin
// 监控SDA和SCL,解码PMBus数据包
// 记录时间戳、地址、命令、数据、ACK/NAK状态
// 检测协议违规:时钟超时、总线冲突等
if (scl_mon) begin
// 在SCL高电平时采样SDA
case (debug_state)
0: begin /* 等待START条件 */ end
1: begin /* 接收地址 */ end
2: begin /* 接收命令 */ end
3: begin /* 接收数据或发送数据 */ end
endcase
end
end
// 错误检测
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
error_detected <= 1'b0;
last_error_code <= 8'h00;
end else begin
// 检测时钟低电平超时(>35ms)
// 检测总线冲突
// 检测非法START/STOP条件
// 检测ACK缺失
end
end
endmodule
7.2 测试向量生成
// PMBus测试模块
module pmbus_testbench;
// 生成测试序列
initial begin
// 1. 读取设备ID
pmbus_read(8'h58, 8'h99, 2);// 读取MFR_ID(2字节)
// 2. 读取状态
pmbus_read(8'h58, 8'h79, 2);// 读取STATUS_WORD
// 3. 配置输出电压
pmbus_write(8'h58, 8'h21, 16'h0B9A);// 设置3.3V
// 4. 使能输出
pmbus_write(8'h58, 8'h01, 16'h0080);// OPERATION = 0x80
// 5. 监控循环
repeat (100) begin
#1000000;// 等待1ms
pmbus_read(8'h58, 8'h8B, 2);// 读取VOUT
pmbus_read(8'h58, 8'h8C, 2);// 读取IOUT
pmbus_read(8'h58, 8'h8D, 2);// 读取温度
end
// 6. 测试故障响应
pmbus_write(8'h58, 8'h40, 16'h0A00);// 设置OV阈值到较低值
// 应该触发过压故障
end
task pmbus_write;
input [6:0] addr;
input [7:0] cmd;
input [15:0] data;
begin
// 生成START条件
// 发送地址+W
// 发送命令
// 发送数据高位
// 发送数据低位
// 生成STOP条件
end
endtask
task pmbus_read;
input [6:0] addr;
input [7:0] cmd;
input [7:0] bytes;
begin
// 生成START条件
// 发送地址+W
// 发送命令
// 生成重复START
// 发送地址+R
// 读取数据
// 发送NAK(最后一个字节)
// 生成STOP条件
end
endtask
endmodule
八、总结与建议
PMBus的优势
- 标准化:统一的电源管理接口
- 灵活:支持多种数据格式和命令
- 可监控:实时监控电源参数
- 可配置:运行时调整电源参数
- 可扩展:支持多设备、多页面
实现建议
- 从简单开始:先实现基本的读写功能
- 逐步增加功能:先支持LINEAR11格式,再增加其他格式
- 充分测试:特别测试边界条件和故障情况
- 考虑容错:添加超时、重试机制
- 性能优化:对于高速应用,考虑使用硬件加速
资源参考
- PMBus规范:PMBus官网(www.pmbus.org)
- 应用笔记:TI、ADI、Maxim等厂商的应用笔记
- 开源实现:Linux内核中的PMBus驱动
- 调试工具:Bus Pirate、Total Phase分析仪
PMBus作为现代电源管理的标准接口,在服务器、通信设备、工业控制等领域有着广泛应用。掌握PMBus协议和实现方法,对于设计复杂的电源系统至关重要。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)