PMBus 系列約 3 分鐘

PMBus 指令解析:COEFFICIENTS (30h) 動態讀取 Direct 格式的 m、b、R 係數

PMBus COEFFICIENTS (30h) 完整解析:Block Write-Block Read Process Call 封包格式、讀取 / 寫入方向旗標、5 Bytes 回應的 m、b、R 解包方式,附 READ_VIN 實際解碼範例、檢流電阻陷阱與 C 語言解包程式。

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

綱要介紹

PMBus 使用 Direct 格式傳輸數值時,物理量 X(電壓 V、電流 A、溫度 °C)與匯流排上的數值 Y 之間,用以下公式轉換:

Y=(m×X+b)×10R⟺X=1m(Y×10−R−b)Y = (m \times X + b) \times 10^{R} \qquad\Longleftrightarrow\qquad X = \frac{1}{m}\left(Y \times 10^{-R} - b\right)

一般情況下,工程師要查規格書才知道每個命令的 m、b、R。如果電源模組支援 COEFFICIENTS (30h),Host 就可以在執行期間動態讀取這些係數,自動完成解碼。

通訊協定格式

S | Addr+W | A | 30h | A | 02h | A | Target Command | A | R/W | A
  | Sr | Addr+R | A | 05h | A | m_L | A | m_H | A | b_L | A | b_H | A | R | [A | PEC] | NA | P
  1. Host 寫入(Block Write 階段)
    • Command Code:30h
    • Byte Count:02h
    • Target Command Code:要查詢係數的命令,例如 READ_VIN (88h)
    • Read/Write 旗標:01h = 查詢讀取時用的係數,00h = 查詢寫入時用的係數
  2. 電源回應(Block Read 階段)
    • Byte Count:05h(固定 5 Bytes)
    • m:2 Bytes,16 位元有號數,低位元組在前
    • b:2 Bytes,16 位元有號數,低位元組在前
    • R:1 Byte,8 位元有號數(二補數)

回應資料結構(5 Bytes)

Byte欄位資料型別說明
1 ~ 2m16 位元有號數斜率(Slope)
3 ~ 4b16 位元有號數偏移(Offset)
5R8 位元有號數十進位縮放指數(例如 −1、−2、0)

運作流程

flowchart TD
    A["Host 送出 COEFFICIENTS (30h)<br>Target = 88h,R/W = 01h"] --> B["電源模組查詢內部係數表"]
    B --> C["回傳 5 Bytes<br>m_L, m_H, b_L, b_H, R"]
    C --> D["Host 組合 m、b(Little-Endian)<br>R 轉成有號數"]
    D --> E["讀取 READ_VIN (88h) 得到 Y"]
    E --> F["X = (Y × 10^-R − b) / m"]

實務解碼範例

以下是對 READ_VIN (88h) 查詢係數的範例:

  1. Host 寫入:30h(Cmd)+ 02h(Byte Count)+ 88h(Target)+ 01h(Read)
  2. 電源回應:05h(Byte Count)+ 2B 01(m)+ 00 00(b)+ 00(R)
    • m = 012Bh = 299(注意 2B 先傳,是低位元組)
    • b = 0000h = 0
    • R = 00h = 0
  3. 讀取 READ_VIN (88h):Y = 0E04h = 3588
  4. 計算實際電壓:
VIN=1299(3588×100−0)=3588299=12.0 VV_{\text{IN}} = \frac{1}{299}\left(3588 \times 10^{0} - 0\right) = \frac{3588}{299} = 12.0\ \text{V}

Linux(i2c-tools)

以 PMBus 位址 0x58、I2C bus 1 為例(請換成你系統上的實際值):

# 查詢 READ_VIN (88h) 的讀取係數:寫 4 Bytes,Repeated Start 後讀 6 Bytes
i2ctransfer -y 1 w4@0x58 0x30 0x02 0x88 0x01 r6
# 回應範例:0x05 0x2b 0x01 0x00 0x00 0x00

C 語言:解包回應

#include <stdbool.h>
#include <stdint.h>

typedef struct {
    int16_t m;
    int16_t b;
    int8_t  r;
} pmbus_coeff_t;

/* resp 是 Process Call 讀回的 6 Bytes:Byte Count + 5 Bytes 資料 */
bool parse_coefficients(const uint8_t resp[6], pmbus_coeff_t *c)
{
    if (resp[0] != 5)
        return false;                                   /* Byte Count 不對 */

    c->m = (int16_t)(uint16_t)(resp[1] | (resp[2] << 8));   /* Little-Endian */
    c->b = (int16_t)(uint16_t)(resp[3] | (resp[4] << 8));
    c->r = (int8_t)resp[5];
    return c->m != 0;                                   /* m = 0 無法換算 */
}

解包後的 m、b、R,搭配 數值格式總覽文章中的 direct_to_milli() 就能換算成千分之一單位:

uint8_t resp[6] = { 0x05, 0x2B, 0x01, 0x00, 0x00, 0x00 };
pmbus_coeff_t c;

if (parse_coefficients(resp, &c)) {
    int64_t mv = direct_to_milli(3588, c.m, c.b, c.r);   /* → 12000 mV */
}

工程實務提示

結論

  • COEFFICIENTS (30h) 用來動態讀取 Direct 格式的 m、b、R 係數。
  • 使用 Process Call:寫入目標命令碼 + 讀寫方向旗標,讀回 5 Bytes。
  • m、b 是 16 位元有號數、Little-Endian;R 是 8 位元有號數。
  • 30h 是選配命令,要準備好退回規格書係數表的方案。
  • 電流係數要留意檢流電阻的影響。

延伸閱讀: