PMBus 指令解析:STATUS_WORD (79h) 電源故障除錯的第一步
PMBus STATUS_WORD (79h) 16 個狀態位元逐一解析,搭配 STATUS_VOUT、STATUS_IOUT、STATUS_INPUT、STATUS_TEMPERATURE、STATUS_CML 的追查流程,附常見數值解讀、清除方式與 C 語言解碼範例。
STATUS_WORD 的角色
PMBus 的狀態回報是兩層式的:
- 第一層:
STATUS_WORD (79h):每個位元代表一大類問題(輸出電壓、輸入、溫度、通訊……)。 - 第二層:
STATUS_VOUT (7Ah)、STATUS_IOUT (7Bh)等:說明這一類問題的具體原因(過壓還是欠壓?是警告還是故障?)。
所以除錯的標準流程是:先讀 STATUS_WORD,再依照被設定的位元往下讀。
傳輸格式
使用 SMBus Read Word,低位元組先傳(Little-Endian):
讀取:S | Addr+W | A | 79h | A | Sr | Addr+R | A | Low Byte | A | High Byte | [A | PEC] | NA | P
位元結構
高位元組(b[15:8])
| Bit | 名稱 | 設定時代表 | 往下讀 |
|---|---|---|---|
| 15 | VOUT | 輸出電壓有故障或警告 | STATUS_VOUT (7Ah) |
| 14 | IOUT/POUT | 輸出電流或輸出功率有故障或警告 | STATUS_IOUT (7Bh) |
| 13 | INPUT | 輸入電壓、電流或功率有故障或警告 | STATUS_INPUT (7Ch) |
| 12 | MFR_SPECIFIC | 廠商自訂的故障或警告 | STATUS_MFR_SPECIFIC (80h) |
| 11 | POWER_GOOD# | Power Good 未成立(注意:1 = 電源不正常) | — |
| 10 | FANS | 風扇或氣流有故障或警告 | STATUS_FANS_1_2 (81h)、STATUS_FANS_3_4 (82h) |
| 9 | OTHER | STATUS_OTHER 中有位元被設定 | STATUS_OTHER (7Fh) |
| 8 | UNKNOWN | 偵測到 b[15:1] 都無法歸類的故障 | 廠商規格書 |
低位元組(b[7:0],= STATUS_BYTE)
| Bit | 名稱 | 設定時代表 | 往下讀 |
|---|---|---|---|
| 7 | BUSY | 元件忙碌中,暫時無法回應 | — |
| 6 | OFF | 輸出沒有供電(不論原因,包含沒有被致能) | — |
| 5 | VOUT_OV_FAULT | 輸出過壓故障 | STATUS_VOUT (7Ah) |
| 4 | IOUT_OC_FAULT | 輸出過流故障 | STATUS_IOUT (7Bh) |
| 3 | VIN_UV_FAULT | 輸入欠壓故障 | STATUS_INPUT (7Ch) |
| 2 | TEMPERATURE | 溫度故障或警告 | STATUS_TEMPERATURE (7Dh) |
| 1 | CML | 通訊、記憶體或邏輯故障 | STATUS_CML (7Eh) |
| 0 | NONE OF THE ABOVE | 有 b[7:1] 以外的故障或警告 | 看高位元組 |
除錯追查流程
flowchart TD
A["讀 STATUS_WORD (79h)"] --> Z{"= 0000h?"}
Z -- "是" --> OK["沒有故障或警告"]
Z -- "否" --> V{"b15 VOUT / b5?"}
V -- "是" --> V1["讀 STATUS_VOUT (7Ah)"]
V -- "否" --> I{"b14 IOUT / b4?"}
I -- "是" --> I1["讀 STATUS_IOUT (7Bh)"]
I -- "否" --> N{"b13 INPUT / b3?"}
N -- "是" --> N1["讀 STATUS_INPUT (7Ch)"]
N -- "否" --> T{"b2 TEMPERATURE?"}
T -- "是" --> T1["讀 STATUS_TEMPERATURE (7Dh)"]
T -- "否" --> C{"b1 CML?"}
C -- "是" --> C1["讀 STATUS_CML (7Eh)"]
C -- "否" --> O["檢查 b12 MFR / b10 FANS / b9 OTHER"]
實際上可能同時有好幾個位元被設定,每個被設定的類別都要往下讀,不能只看第一個。
第二層範例:STATUS_CML (7Eh)
通訊相關的問題最常在開發階段遇到,例如寫入不支援的命令或錯誤的數值:
| Bit | 意義 |
|---|---|
| 7 | 收到無效或不支援的命令 |
| 6 | 收到無效或不支援的資料 |
| 5 | PEC 檢查失敗 |
| 4 | 記憶體故障 |
| 3 | 處理器故障 |
| 2 | 保留 |
| 1 | 其他通訊故障 |
| 0 | 其他記憶體或邏輯故障 |
例如對 CRPS 寫入 OPERATION 的 Margin 值,電源回報不支援時,通常就會看到 STATUS_WORD 的 CML (b1) 被設定,而 STATUS_CML 的 b6(無效資料) 為 1。
常見數值解讀
| STATUS_WORD | 被設定的位元 | 可能情況 |
|---|---|---|
0000h | 無 | 正常運作,沒有任何故障或警告 |
0840h | POWER_GOOD#、OFF | 輸出關閉中,例如電源未被開機(PSON# 未致能、OPERATION = Off) |
2848h | INPUT、POWER_GOOD#、OFF、VIN_UV_FAULT | 輸入電壓不足導致輸出關閉,例如 AC 斷電 |
0002h | CML | 通訊問題,讀 STATUS_CML 找原因(無效命令、資料或 PEC 錯誤) |
0004h | TEMPERATURE | 溫度警告或故障,讀 STATUS_TEMPERATURE |
0400h | FANS | 風扇異常,讀 STATUS_FANS_1_2 |
逐位元拆解 2848h 的方式:
2848h = 0010 1000 0100 1000
│ │ │ └─ b3 VIN_UV_FAULT
│ │ └───── b6 OFF
│ └─────────── b11 POWER_GOOD#
└────────────── b13 INPUT
清除狀態
狀態位元通常是鎖存(Latched)的:問題消失後位元不會自己清掉,這樣主控端才不會漏掉短暫發生的故障。常見的清除方式:
| 方式 | 說明 |
|---|---|
CLEAR_FAULTS (03h) | Send Byte 命令,清除所有狀態位元 |
| 重新開關輸出 | 透過 CONTROL 腳位或 OPERATION 關閉再開啟輸出 |
| 斷電重啟 | 移除輸入電源後重新上電 |
SMBALERT#:不用一直輪詢
狀態位元被設定時,元件通常會拉低 SMBALERT# 腳位通知主控端。主控端收到中斷後,可以透過 SMBus 的 Alert Response Address(0x0C) 找出是哪個元件發出警報,再去讀它的 STATUS_WORD。
不想被某些狀態觸發警報時,可以用 SMBALERT_MASK (1Bh) 遮蔽(不是每個元件都支援)。
讀取與解碼範例
Linux(i2c-tools)
以 PMBus 位址 0x58、I2C bus 1 為例(請換成你系統上的實際值):
# 讀 STATUS_WORD(i2cget 會自動組合低/高位元組)
i2cget -y 1 0x58 0x79 w
# 讀第二層狀態,例如 STATUS_CML
i2cget -y 1 0x58 0x7e b
# 清除所有狀態(CLEAR_FAULTS 是 Send Byte,沒有資料)
i2cset -y 1 0x58 0x03
C 語言:列出被設定的位元
#include <stdint.h>
#include <stdio.h>
static const char *const status_word_bits[16] = {
"NONE_OF_THE_ABOVE", "CML", "TEMPERATURE", "VIN_UV_FAULT",
"IOUT_OC_FAULT", "VOUT_OV_FAULT", "OFF", "BUSY",
"UNKNOWN", "OTHER", "FANS", "POWER_GOOD#",
"MFR_SPECIFIC", "INPUT", "IOUT/POUT", "VOUT",
};
/* 每個位元要往下讀的第二層命令(0 = 沒有對應命令) */
static const uint8_t status_word_detail_cmd[16] = {
0x00, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x00, 0x00,
0x00, 0x7F, 0x81, 0x00, 0x80, 0x7C, 0x7B, 0x7A,
};
void decode_status_word(uint16_t sw)
{
printf("STATUS_WORD = 0x%04X\n", sw);
if (sw == 0) {
printf(" 正常,沒有故障或警告\n");
return;
}
for (int bit = 15; bit >= 0; bit--) {
if (!(sw & (1u << bit)))
continue;
printf(" b%-2d %-18s", bit, status_word_bits[bit]);
if (status_word_detail_cmd[bit])
printf(" -> 讀 0x%02X", status_word_detail_cmd[bit]);
printf("\n");
}
}
decode_status_word(0x2848) 的輸出:
STATUS_WORD = 0x2848
b13 INPUT -> 讀 0x7C
b11 POWER_GOOD#
b6 OFF
b3 VIN_UV_FAULT -> 讀 0x7C
結論
STATUS_WORD (79h)是故障總覽,電源出問題時第一個讀它。- 高位元組指向第二層
STATUS_xxx命令,低位元組等於STATUS_BYTE。 - POWER_GOOD# 是負邏輯(1 = 不正常);OFF 不一定是故障。
- 狀態位元會鎖存,用
CLEAR_FAULTS (03h)清除;清掉又出現代表問題還在。 - 搭配
SMBALERT#中斷,就不需要一直輪詢。
延伸閱讀: