韌體約 3 分鐘

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 語言整數編解碼範例。

📘 參考規格書PMBus · PMBus Power System Management Protocol Specification Part II原廠文件 ↗

READ_* 量測命令速查表

所有量測命令都使用 SMBus Read Word,低位元組先傳:

命令代碼單位資料格式
READ_VIN88hVLINEAR11
READ_IIN89hALINEAR11
READ_VOUT8BhV⚠️ LINEAR16(依 VOUT_MODE)
READ_IOUT8ChALINEAR11
READ_TEMPERATURE_18Dh°CLINEAR11
READ_TEMPERATURE_28Eh°CLINEAR11
READ_TEMPERATURE_38Fh°CLINEAR11
READ_FAN_SPEED_190hRPMLINEAR11
READ_FAN_SPEED_291hRPMLINEAR11
READ_DUTY_CYCLE94h%LINEAR11
READ_FREQUENCY95hkHzLINEAR11
READ_POUT96hWLINEAR11
READ_PIN97hWLINEAR11

溫度感測器的位置(TEMPERATURE_1 是散熱片?還是進風口?)每家電源不同,要看產品規格書。各量測值的故障與警告狀態,則在 STATUS_WORD (79h) 與它往下的 STATUS_IOUT、STATUS_TEMPERATURE 中回報。

LINEAR11 格式

 15        11 10                        0
┌────────────┬───────────────────────────┐
│  N (5 bit) │        Y (11 bit)         │
│   signed   │          signed           │
└────────────┴───────────────────────────┘

解碼步驟

  1. 取高 5 位元:N = raw >> 11,若 ≥ 16 則 N -= 32
  2. 取低 11 位元:Y = raw & 0x7FF,若 ≥ 1024 則 Y -= 2048
  3. 計算 X=Y×2NX = Y \times 2^{N}

換算範例

範例 1:READ_IOUT = F0A6h

F0A6h = 1111 0000 1010 0110
        └─N──┘└───Y──────┘
N = 11110b = 30 → 30 − 32 = −2
Y = 000 1010 0110b = 166
IOUT=166×2−2=41.5 AI_{\text{OUT}} = 166 \times 2^{-2} = 41.5\ \text{A}

範例 2:READ_VIN = F9CCh

N = 11111b → −1,Y = 1CCh = 460:

VIN=460×2−1=230 VV_{\text{IN}} = 460 \times 2^{-1} = 230\ \text{V}

範例 3:READ_POUT = 08F9h(正指數)

N = 00001b → +1,Y = 0F9h = 249:

POUT=249×21=498 WP_{\text{OUT}} = 249 \times 2^{1} = 498\ \text{W}

範例 4:READ_TEMPERATURE_1 = 07FBh(負數)

N = 00000b → 0,Y = 7FBh = 2043,因為 ≥ 1024,所以 Y = 2043 − 2048 = −5:

T=−5×20=−5 ∘CT = -5 \times 2^{0} = -5\ ^{\circ}\text{C}

常見錯誤

錯誤後果
N 沒有做二補數轉換F0A6h 的 N 變成 +30,數值大到離譜
Y 沒有做二補數轉換負值變成接近 2048 × 2N 的大數
用 LINEAR11 解 READ_VOUT電壓完全錯誤(應該用 LINEAR16)
把上次讀到的 N 存起來重複使用元件可能每次回傳不同的 N,數值會跳動

精度與指數的取捨

Y 只有 11 位元(約 3 位有效數字),N 越小解析度越細,但能表示的最大值越小:

N解析度(1 LSB)可表示範圍
−40.0625−64 ~ 63.94
−20.25−256 ~ 255.75
−10.5−512 ~ 511.5
01−1024 ~ 1023
+12−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:X=Y×2NX = Y \times 2^{N},N 在 b[15:11]、Y 在 b[10:0],兩者都是二補數。
  • 電流、輸入電壓、溫度、功率、風扇轉速等量測都用 LINEAR11;READ_VOUT 例外,用 LINEAR16。
  • 每筆讀值都要用自己的 N 解碼,不要快取指數。
  • MCU 上可以用整數運算換算成千分之一單位,避免浮點運算。

延伸閱讀: