PMBus 指令解析:LINEAR11 格式與 READ_VIN / IOUT / TEMPERATURE / POUT 量測讀取
PMBus LINEAR11 資料格式完整解析:5 位元指數 + 11 位元尾數的換算、負數處理與常見錯誤,搭配 READ_VIN (88h)、READ_IOUT (8Ch)、READ_TEMPERATURE_1 (8Dh)、READ_POUT (96h) 等量測命令速查表與 C 語言整數編解碼範例。
READ_* 量測命令速查表
所有量測命令都使用 SMBus Read Word,低位元組先傳:
| 命令 | 代碼 | 單位 | 資料格式 |
|---|---|---|---|
READ_VIN | 88h | V | LINEAR11 |
READ_IIN | 89h | A | LINEAR11 |
READ_VOUT | 8Bh | V | ⚠️ LINEAR16(依 VOUT_MODE) |
READ_IOUT | 8Ch | A | LINEAR11 |
READ_TEMPERATURE_1 | 8Dh | °C | LINEAR11 |
READ_TEMPERATURE_2 | 8Eh | °C | LINEAR11 |
READ_TEMPERATURE_3 | 8Fh | °C | LINEAR11 |
READ_FAN_SPEED_1 | 90h | RPM | LINEAR11 |
READ_FAN_SPEED_2 | 91h | RPM | LINEAR11 |
READ_DUTY_CYCLE | 94h | % | LINEAR11 |
READ_FREQUENCY | 95h | kHz | LINEAR11 |
READ_POUT | 96h | W | LINEAR11 |
READ_PIN | 97h | W | LINEAR11 |
溫度感測器的位置(TEMPERATURE_1 是散熱片?還是進風口?)每家電源不同,要看產品規格書。各量測值的故障與警告狀態,則在 STATUS_WORD (79h) 與它往下的 STATUS_IOUT、STATUS_TEMPERATURE 中回報。
LINEAR11 格式
15 11 10 0
┌────────────┬───────────────────────────┐
│ N (5 bit) │ Y (11 bit) │
│ signed │ signed │
└────────────┴───────────────────────────┘
解碼步驟
- 取高 5 位元:
N = raw >> 11,若 ≥ 16 則N -= 32 - 取低 11 位元:
Y = raw & 0x7FF,若 ≥ 1024 則Y -= 2048 - 計算
換算範例
範例 1:READ_IOUT = F0A6h
F0A6h = 1111 0000 1010 0110
└─N──┘└───Y──────┘
N = 11110b = 30 → 30 − 32 = −2
Y = 000 1010 0110b = 166
範例 2:READ_VIN = F9CCh
N = 11111b → −1,Y = 1CCh = 460:
範例 3:READ_POUT = 08F9h(正指數)
N = 00001b → +1,Y = 0F9h = 249:
範例 4:READ_TEMPERATURE_1 = 07FBh(負數)
N = 00000b → 0,Y = 7FBh = 2043,因為 ≥ 1024,所以 Y = 2043 − 2048 = −5:
常見錯誤
| 錯誤 | 後果 |
|---|---|
| N 沒有做二補數轉換 | F0A6h 的 N 變成 +30,數值大到離譜 |
| Y 沒有做二補數轉換 | 負值變成接近 2048 × 2N 的大數 |
用 LINEAR11 解 READ_VOUT | 電壓完全錯誤(應該用 LINEAR16) |
| 把上次讀到的 N 存起來重複使用 | 元件可能每次回傳不同的 N,數值會跳動 |
精度與指數的取捨
Y 只有 11 位元(約 3 位有效數字),N 越小解析度越細,但能表示的最大值越小:
| N | 解析度(1 LSB) | 可表示範圍 |
|---|---|---|
| −4 | 0.0625 | −64 ~ 63.94 |
| −2 | 0.25 | −256 ~ 255.75 |
| −1 | 0.5 | −512 ~ 511.5 |
| 0 | 1 | −1024 ~ 1023 |
| +1 | 2 | −2048 ~ 2046 |
元件通常會依照量測範圍選擇合適的 N,例如 0 ~ 50 A 的電流用 N = −4,數百瓦的功率用 N = 0 或 +1。
讀取範例
Linux(i2c-tools)
以 PMBus 位址 0x58、I2C bus 1 為例(請換成你系統上的實際值):
i2cget -y 1 0x58 0x88 w # READ_VIN
i2cget -y 1 0x58 0x8c w # READ_IOUT
i2cget -y 1 0x58 0x8d w # READ_TEMPERATURE_1
i2cget -y 1 0x58 0x96 w # READ_POUT
i2cget 的 w 模式會自動把低/高位元組組合好,直接拿來解碼即可。
C 語言:整數編解碼(不需要浮點運算)
以「千分之一單位」(mV、mA、m°C、mW)表示,方便在 MCU 上使用:
#include <stdint.h>
/* 有號整數除法,四捨五入(遠離 0) */
static int64_t div_round(int64_t num, int64_t den)
{
return (num >= 0 ? num + den / 2 : num - den / 2) / den;
}
static int linear11_exponent(uint16_t raw)
{
int n = raw >> 11;
return (n & 0x10) ? n - 32 : n;
}
static int linear11_mantissa(uint16_t raw)
{
int y = raw & 0x7FF;
return (y & 0x400) ? y - 2048 : y;
}
/* LINEAR11 → 千分之一單位 */
int64_t linear11_to_milli(uint16_t raw)
{
int n = linear11_exponent(raw);
int64_t v = (int64_t)linear11_mantissa(raw) * 1000;
if (n >= 0)
return v * ((int64_t)1 << n);
return div_round(v, (int64_t)1 << -n);
}
/* 千分之一單位 → LINEAR11,自動選擇解析度最細的指數 */
uint16_t milli_to_linear11(int64_t milli)
{
for (int n = -16; n <= 15; n++) {
int64_t y = (n <= 0) ? div_round(milli * ((int64_t)1 << -n), 1000)
: div_round(milli, (int64_t)1000 << n);
if (y >= -1024 && y <= 1023)
return (uint16_t)(((unsigned)n & 0x1Fu) << 11 | ((unsigned)y & 0x7FFu));
}
return milli < 0 ? 0x7C00 : 0x7BFF; /* 超出範圍:回傳最小 / 最大值 */
}
測試結果:
| 呼叫 | 結果 |
|---|---|
linear11_to_milli(0xF0A6) | 41500(41.5 A) |
linear11_to_milli(0xF9CC) | 230000(230 V) |
linear11_to_milli(0x08F9) | 498000(498 W) |
linear11_to_milli(0x07FB) | -5000(−5 °C) |
milli_to_linear11(41500) | 0xE298(N = −4, Y = 664) |
milli_to_linear11(-5000) | 0xCD80(N = −7, Y = −640) |
編碼函式會用在寫入 LINEAR11 格式的設定值,例如過流保護門檻 IOUT_OC_FAULT_LIMIT (46h)、過溫保護門檻 OT_FAULT_LIMIT (4Fh) 等。
結論
- LINEAR11:,N 在 b[15:11]、Y 在 b[10:0],兩者都是二補數。
- 電流、輸入電壓、溫度、功率、風扇轉速等量測都用 LINEAR11;
READ_VOUT例外,用 LINEAR16。 - 每筆讀值都要用自己的 N 解碼,不要快取指數。
- MCU 上可以用整數運算換算成千分之一單位,避免浮點運算。
延伸閱讀: