PMBus 指令解析:VOUT_MODE (20h) + VOUT_COMMAND (21h) 與 LINEAR16 格式
搞懂 PMBus 輸出電壓怎麼設定:VOUT_MODE (20h) 的模式與指數、VOUT_COMMAND (21h) 的 LINEAR16 換算,附指數解析度速查表、LINEAR11 差異比較與 C 語言整數換算範例。
最後更新:
兩個命令的分工
| 命令 | 代碼 | 長度 | 作用 |
|---|---|---|---|
VOUT_MODE | 20h | 1 Byte | 告訴主控端:輸出電壓相關數值用哪種格式、指數是多少 |
VOUT_COMMAND | 21h | 2 Bytes | 設定目標輸出電壓(數值依 VOUT_MODE 的格式解讀) |
哪些命令使用 VOUT_MODE 的格式
VOUT_MODE 不只影響 VOUT_COMMAND,所有以「伏特」為單位的輸出電壓命令都用同一個格式與指數:
| 類別 | 命令 |
|---|---|
| 電壓設定 | VOUT_COMMAND (21h)、VOUT_TRIM (22h)、VOUT_CAL_OFFSET (23h)、VOUT_MAX (24h)、VOUT_MIN (2Bh) |
| Margin | VOUT_MARGIN_HIGH (25h)、VOUT_MARGIN_LOW (26h) |
| 保護門檻 | VOUT_OV_FAULT_LIMIT (40h)、VOUT_OV_WARN_LIMIT (42h)、VOUT_UV_WARN_LIMIT (43h)、VOUT_UV_FAULT_LIMIT (44h) |
| Power Good | POWER_GOOD_ON (5Eh)、POWER_GOOD_OFF (5Fh) |
| 量測 | READ_VOUT (8Bh) |
VOUT_MODE (20h)
傳輸格式
使用 SMBus Read Byte(部分元件也允許 Write Byte,但多數為唯讀):
讀取:S | Addr+W | A | 20h | A | Sr | Addr+R | A | Data | [PEC] | NA | P
位元結構
| b[7:5] Mode | 格式 | b[4:0] Parameter 的意義 |
|---|---|---|
000 | Linear(LINEAR16) | 指數 N,5 位元二補數(−16 ~ +15) |
001 | VID | VID 碼表的類型(依各家 VR 規範) |
010 | Direct | 不使用;換算係數由 COEFFICIENTS (30h) 或規格書提供 |
011 | IEEE 754 半精度浮點 | 不使用 |
實務上電源模組絕大多數使用 Linear 格式,以下都以 Linear 為主。VID 與 Direct 格式的換算方式,請見 PMBus 數值格式深度解析。
主控端解析流程
flowchart TD
A["讀取 VOUT_MODE (20h)"] --> B{"b[7:5]?"}
B -- "000 Linear" --> C["b[4:0] 轉成 5 位元二補數 → N"]
B -- "001 VID" --> V["依 b[4:0] 指定的 VID 碼表換算"]
B -- "010 Direct" --> D["用 m、b、R 係數換算"]
C --> E["讀 READ_VOUT (8Bh) 等命令<br>得到 16 位元無號數 Y"]
E --> F["V = Y × 2^N"]
VOUT_MODE 在大多數電源上是唯讀的,數值由韌體依內部 ADC / DAC 的解析度預先決定,但仍建議開機時讀一次,不要在程式裡寫死。
指數 N 的解讀
b[4:0] 是 5 位元二補數:
00h~0Fh→ N = 0 ~ +1510h~1Fh→ N = 值 − 32,也就是 −16 ~ −1
例如 VOUT_MODE = 17h:
VOUT_COMMAND (21h)
傳輸格式
使用 SMBus Write Word / Read Word,低位元組先傳(Little-Endian):
寫入:S | Addr+W | A | 21h | A | Data Low | A | Data High | A | [PEC | A] | P
LINEAR16 換算公式
Linear 模式下,VOUT_COMMAND 是 16 位元無號整數的尾數 Y,搭配 VOUT_MODE 的指數 N:
換算範例
範例 1:12 V 輸出,VOUT_MODE = 17h(N = −9)
所以寫入 VOUT_COMMAND = 1800h(線上傳送 00h、18h)。
範例 2:1.05 V 輸出,VOUT_MODE = 14h(N = −12)
實際設定值為 ,誤差來自解析度限制。
指數與解析度速查表
指數越小(越負),解析度越細,但能表示的最大電壓越低:
| VOUT_MODE | N | 解析度(1 LSB) | 最大可表示電壓 | 常見用途 |
|---|---|---|---|---|
18h | −8 | 3.906 mV | 255.99 V | 高壓輸出 |
17h | −9 | 1.953 mV | 127.99 V | 12 V / 48 V 電源 |
16h | −10 | 0.977 mV | 63.99 V | |
15h | −11 | 0.488 mV | 31.99 V | |
14h | −12 | 0.244 mV | 15.99 V | 低壓 POL |
13h | −13 | 0.122 mV | 7.99 V | CPU / FPGA 核心電壓 |
最大電壓 。實際可設定的上限還會受 VOUT_MAX (24h) 限制。
容易搞混:LINEAR16 vs LINEAR11
PMBus 有兩種 Linear 格式。輸出電壓用 LINEAR16,其他大部分數值(電流、輸入電壓、溫度、功率)用 LINEAR11:
| 項目 | LINEAR16 | LINEAR11 |
|---|---|---|
| 用在哪裡 | VOUT_COMMAND、READ_VOUT 等輸出電壓命令 | READ_IOUT、READ_VIN、READ_TEMPERATURE_1 等 |
| 尾數 Y | 16 位元無號數(整個 Word) | b[10:0],11 位元二補數 |
| 指數 N | 在 VOUT_MODE 的 b[4:0] | 在同一個 Word 的 b[15:11] |
| 公式 |
flowchart LR
subgraph L16["LINEAR16(VOUT_COMMAND)"]
direction TB
A1["VOUT_MODE b[4:0] = N"]
A2["Data[15:0] = Y(無號)"]
end
subgraph L11["LINEAR11(READ_IOUT 等)"]
direction TB
B1["Data[15:11] = N"]
B2["Data[10:0] = Y(二補數)"]
end
讀取與設定範例
Linux(i2c-tools)
以 PMBus 位址 0x58、I2C bus 1 為例(請換成你系統上的實際值):
# 讀 VOUT_MODE(1 Byte)
i2cget -y 1 0x58 0x20 b
# 讀 VOUT_COMMAND 與 READ_VOUT(Word,i2cget 會自動組合低/高位元組)
i2cget -y 1 0x58 0x21 w
i2cget -y 1 0x58 0x8b w
# 設定 VOUT_COMMAND = 0x1800(N = -9 時為 12 V)
i2cset -y 1 0x58 0x21 0x1800 w
C 語言:整數換算(不需要浮點運算)
MCU 上常常不想用 float,以下用 mV 整數換算:
#include <stdbool.h>
#include <stdint.h>
/* VOUT_MODE 是否為絕對值 Linear 格式(b[7:5] = 000) */
static bool vout_mode_is_linear(uint8_t vout_mode)
{
return (vout_mode & 0xE0u) == 0;
}
/* 取出 5 位元二補數指數 N */
static int vout_exponent(uint8_t vout_mode)
{
int n = vout_mode & 0x1F;
return (n & 0x10) ? n - 32 : n;
}
/* LINEAR16 → mV(四捨五入) */
uint32_t linear16_to_mv(uint16_t y, uint8_t vout_mode)
{
int n = vout_exponent(vout_mode);
uint64_t uv = (uint64_t)y * 1000u; /* 先放大 1000 倍 */
if (n >= 0)
return (uint32_t)(uv << n);
return (uint32_t)((uv + (1ull << (-n - 1))) >> -n);
}
/* mV → LINEAR16(四捨五入,超出範圍時回傳 0xFFFF) */
uint16_t mv_to_linear16(uint32_t mv, uint8_t vout_mode)
{
int n = vout_exponent(vout_mode);
uint64_t y;
if (n <= 0)
y = (((uint64_t)mv << -n) + 500u) / 1000u;
else
y = ((uint64_t)mv + (500ull << n)) / (1000ull << n);
return (y > 0xFFFFu) ? 0xFFFFu : (uint16_t)y;
}
使用方式:
uint8_t mode = 0x17; /* 從 VOUT_MODE 讀回 */
if (vout_mode_is_linear(mode)) {
uint16_t y = mv_to_linear16(12000, mode); /* → 0x1800 */
uint32_t mv = linear16_to_mv(y, mode); /* → 12000 */
}
工程實務提示
結論
VOUT_MODE (20h)決定格式與指數,VOUT_COMMAND (21h)提供尾數,兩者合起來才是電壓。- Linear 格式:,N 是
VOUT_MODEb[4:0] 的 5 位元二補數。 - 常見
VOUT_MODE = 17h→ N = −9 → 12 V =1800h。 - 電壓輸出相關命令用 LINEAR16,電流、溫度等其他命令用 LINEAR11,不要混用。
- 程式裡要先讀
VOUT_MODE再換算,不要寫死指數。
延伸閱讀:
- PMBus 指令解析:OPERATION (01h) 開關機與 Margin 測試(Margin 電壓
VOUT_MARGIN_HIGH/LOW也是用 LINEAR16) - PMBus 指令解析:ON_OFF_CONFIG (02h) 開機條件與 CONTROL 腳位設定
- 下一篇:PMBus 指令解析:STATUS_WORD (79h) 電源故障除錯的第一步