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 使用 Direct 格式傳輸數值時,物理量 X(電壓 V、電流 A、溫度 °C)與匯流排上的數值 Y 之間,用以下公式轉換:
一般情況下,工程師要查規格書才知道每個命令的 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
- Host 寫入(Block Write 階段)
- Command Code:
30h - Byte Count:
02h - Target Command Code:要查詢係數的命令,例如
READ_VIN (88h) - Read/Write 旗標:
01h= 查詢讀取時用的係數,00h= 查詢寫入時用的係數
- Command Code:
- 電源回應(Block Read 階段)
- Byte Count:
05h(固定 5 Bytes) - m:2 Bytes,16 位元有號數,低位元組在前
- b:2 Bytes,16 位元有號數,低位元組在前
- R:1 Byte,8 位元有號數(二補數)
- Byte Count:
回應資料結構(5 Bytes)
| Byte | 欄位 | 資料型別 | 說明 |
|---|---|---|---|
| 1 ~ 2 | m | 16 位元有號數 | 斜率(Slope) |
| 3 ~ 4 | b | 16 位元有號數 | 偏移(Offset) |
| 5 | R | 8 位元有號數 | 十進位縮放指數(例如 −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) 查詢係數的範例:
- Host 寫入:
30h(Cmd)+02h(Byte Count)+88h(Target)+01h(Read) - 電源回應:
05h(Byte Count)+2B 01(m)+00 00(b)+00(R)- m =
012Bh= 299(注意2B先傳,是低位元組) - b =
0000h= 0 - R =
00h= 0
- m =
- 讀取
READ_VIN (88h):Y =0E04h= 3588 - 計算實際電壓:
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是選配命令,要準備好退回規格書係數表的方案。- 電流係數要留意檢流電阻的影響。
延伸閱讀: