韌體約 4 分鐘

PMBus 指令解析:STATUS_WORD (79h) 電源故障除錯的第一步

PMBus STATUS_WORD (79h) 16 個狀態位元逐一解析,搭配 STATUS_VOUT、STATUS_IOUT、STATUS_INPUT、STATUS_TEMPERATURE、STATUS_CML 的追查流程,附常見數值解讀、清除方式與 C 語言解碼範例。

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

STATUS_WORD 的角色

PMBus 的狀態回報是兩層式的:

  1. 第一層:STATUS_WORD (79h):每個位元代表一大類問題(輸出電壓、輸入、溫度、通訊……)。
  2. 第二層: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名稱設定時代表往下讀
15VOUT輸出電壓有故障或警告STATUS_VOUT (7Ah)
14IOUT/POUT輸出電流或輸出功率有故障或警告STATUS_IOUT (7Bh)
13INPUT輸入電壓、電流或功率有故障或警告STATUS_INPUT (7Ch)
12MFR_SPECIFIC廠商自訂的故障或警告STATUS_MFR_SPECIFIC (80h)
11POWER_GOOD#Power Good 未成立(注意:1 = 電源不正常)—
10FANS風扇或氣流有故障或警告STATUS_FANS_1_2 (81h)、STATUS_FANS_3_4 (82h)
9OTHERSTATUS_OTHER 中有位元被設定STATUS_OTHER (7Fh)
8UNKNOWN偵測到 b[15:1] 都無法歸類的故障廠商規格書

低位元組(b[7:0],= STATUS_BYTE)

Bit名稱設定時代表往下讀
7BUSY元件忙碌中,暫時無法回應—
6OFF輸出沒有供電(不論原因,包含沒有被致能)—
5VOUT_OV_FAULT輸出過壓故障STATUS_VOUT (7Ah)
4IOUT_OC_FAULT輸出過流故障STATUS_IOUT (7Bh)
3VIN_UV_FAULT輸入欠壓故障STATUS_INPUT (7Ch)
2TEMPERATURE溫度故障或警告STATUS_TEMPERATURE (7Dh)
1CML通訊、記憶體或邏輯故障STATUS_CML (7Eh)
0NONE 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收到無效或不支援的資料
5PEC 檢查失敗
4記憶體故障
3處理器故障
2保留
1其他通訊故障
0其他記憶體或邏輯故障

例如對 CRPS 寫入 OPERATION 的 Margin 值,電源回報不支援時,通常就會看到 STATUS_WORD 的 CML (b1) 被設定,而 STATUS_CML 的 b6(無效資料) 為 1。

常見數值解讀

STATUS_WORD被設定的位元可能情況
0000h無正常運作,沒有任何故障或警告
0840hPOWER_GOOD#、OFF輸出關閉中,例如電源未被開機(PSON# 未致能、OPERATION = Off)
2848hINPUT、POWER_GOOD#、OFF、VIN_UV_FAULT輸入電壓不足導致輸出關閉,例如 AC 斷電
0002hCML通訊問題,讀 STATUS_CML 找原因(無效命令、資料或 PEC 錯誤)
0004hTEMPERATURE溫度警告或故障,讀 STATUS_TEMPERATURE
0400hFANS風扇異常,讀 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# 中斷,就不需要一直輪詢。

延伸閱讀: