fix(pdb): Read the bricks on the pages the datasheet actually specifies
Every PDB reading came back NA, and the cause was a base error. The four
ADPM12200 bricks put each measurement on its own PMBus PAGE, written
before the read. The bring-up spreadsheet listed those page numbers in
decimal but with an 0x prefix:
Vin PAGE 9 -> it said 0x00 (0x09)
Iin PAGE 10 -> it said 0x10 (0x0A)
Vout PAGE 2 -> it said 0x02 correct by luck
Iout PAGE 14 -> it said 0x14 (0x0E)
Temp PAGE 18 -> it said 0x18 (0x12)
Only Vout worked, because 2 reads the same in either base. Hence Iin and
Iout answering 0xFFFF, Temp answering 0x0000, and a Vin scale factor
having to be invented to make 50 V appear out of a page-0 register.
pwr_brick.sh reads all five bricks with the right pages and the
datasheet's DIRECT equation, X = (1/m)(Y x 10^-R - b): voltage Y x 8 mV,
current Y x 0.04 A, temperature Y x 0.01 C. Cross-checked rather than
assumed - READ_VOUT 0x05D4 decodes to 11936 mV, exactly what
'show platform voltage' reports for that rail through a separate sensor
path. The datasheet is committed alongside so the numbers are checkable.
Left flagged: Table 3 does not list READ_VIN or READ_IIN. They borrow the
voltage and current coefficients here, which is consistent with a ~50 V
input but is not something the datasheet states.
Each value is re-read until it passes three checks: not 0xFFFF, not
0x0000, and inside a plausibility window. The window is the one that
matters - this bus corrupts the HIGH BYTE only, which turns 11.98 V into
32.00 V. Positive, plausible in magnitude, and invisible to any all-ones
filter. 0x0000 is rejected for the mirror-image reason: on the
temperature register it decodes to a believable 0 C.
Adds comboA/comboB margin profiles per board. comboB is comboA with every
direction flipped, so the pair covers each rail high and low while its
neighbours sit the other way. NC channels stay nominal in both - there is
nothing to margin on an unused rail.
Script C re-enables the BMC USB journalctl dump, which had been commented
out, so that service log now reaches the master log.
Script A -> V1.1.6.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RetWKFZFG1ZHcitQAyhwM
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
; =============================================================================
|
||||
; Script A for Blanton
|
||||
; Version : V1.1.5
|
||||
; Date : 2026-09-01
|
||||
; Version : V1.1.6
|
||||
; Date : 2026-09-02
|
||||
; Author : ETWen
|
||||
; =============================================================================
|
||||
; Version History:
|
||||
@@ -233,6 +233,43 @@
|
||||
; counter totals are not comparable across this
|
||||
; build - the PASS/FAIL cross-check is unaffected
|
||||
; tools/Multiphase_*.txt Bench command references for the new script
|
||||
; V1.1.6 2026-09-02 Blanton_Script/pwr_brick.sh Add PDB / CPB power brick readings
|
||||
; 5 devices, Vin / Iin / Vout / Iout / Temp:
|
||||
; SWB0.PU207 0x62 SWB0.PU13 0x63
|
||||
; SWB1.PU332 0x60 SWB1.PU85 0x61
|
||||
; CPB.PU37 0x26
|
||||
; The four ADPM12200 put each measurement on its own
|
||||
; PMBus PAGE, so a PAGE write has to precede every
|
||||
; read - blanton_pwr_data.sh sends none, which is why
|
||||
; it reports the whole PDB table as NA
|
||||
; Vin PAGE 9 Iin PAGE 10 Vout PAGE 2
|
||||
; Iout PAGE 14 Temp PAGE 18
|
||||
; !! the bring-up spreadsheet wrote those page numbers
|
||||
; in decimal but with an 0x prefix (10 -> 0x10,
|
||||
; 14 -> 0x14, 18 -> 0x18). Only Vout worked,
|
||||
; because 2 reads the same either way
|
||||
; Conversions are the datasheet DIRECT equation
|
||||
; X = (1/m)(Y x 10^-R - b), Table 3: voltage Y x 8mV,
|
||||
; current Y x 0.04A, temperature Y x 0.01C
|
||||
; Checked: READ_VOUT 0x05D4 -> 11936 mV, the same
|
||||
; figure show platform reports for that rail
|
||||
; !! Table 3 does NOT list READ_VIN / READ_IIN; they
|
||||
; borrow the voltage / current coefficients here
|
||||
; Each value is re-read until it passes: not 0xFFFF,
|
||||
; not 0x0000, and inside a plausibility window. This
|
||||
; bus corrupts the HIGH BYTE only, which turns 11.98 V
|
||||
; into 32.00 V - a value no all-ones filter catches
|
||||
; docs/ADPM12200..._Datasheet_2025_12_19.pdf The brick datasheet the pages and coefficients above
|
||||
; came from
|
||||
; ScriptC Re-enable the BMC USB journalctl dump - it had
|
||||
; been commented out, so the service log never
|
||||
; reached the master log
|
||||
; LTC2980_Margin_Script/profiles/ Add comboA / comboB per board (CB + SWB CONN13..16)
|
||||
; Checkerboard pair: comboB is comboA with every
|
||||
; direction flipped, so running both covers each rail
|
||||
; high and low while its neighbours sit the other way
|
||||
; NC channels stay nominal in both (CONN14 CH10/11/13,
|
||||
; CONN15 CH10) - nothing to margin on an unused rail
|
||||
; =============================================================================
|
||||
include "config.ttl"
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ wait prompt_sonic_root
|
||||
sendln "cat ./Blanton_Script/log/bmc_poll.log"
|
||||
|
||||
; ========== BMC USB Test result ==========
|
||||
;wait prompt_sonic_root
|
||||
;sendln "journalctl -u qfx5252-bmc-usb-net-test.service --no-pager"
|
||||
wait prompt_sonic_root
|
||||
sendln "journalctl -u qfx5252-bmc-usb-net-test.service --no-pager"
|
||||
|
||||
|
||||
; ========== CHECK Stress results ==========
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Profile: comboA_CB - checkerboard, the complement of comboB_CB
|
||||
# Board: CB only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboA then comboB to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:low:5"
|
||||
"1:low:5"
|
||||
"2:high:5"
|
||||
"3:low:5"
|
||||
"4:high:5"
|
||||
"5:high:5"
|
||||
"6:high:5"
|
||||
"7:high:5"
|
||||
"8:low:5"
|
||||
"9:high:5"
|
||||
"10:high:5"
|
||||
"11:high:5"
|
||||
"12:low:5"
|
||||
"13:high:5"
|
||||
"14:high:5"
|
||||
"15:low:5"
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Profile: comboA_SWB_CONN13 - checkerboard, the complement of comboB_SWB_CONN13
|
||||
# Board: SWB_CONN13 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboA then comboB to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:high:3"
|
||||
"1:high:3"
|
||||
"2:low:3"
|
||||
"3:low:3"
|
||||
"4:high:5"
|
||||
"5:low:5"
|
||||
"6:high:5"
|
||||
"7:high:5"
|
||||
"8:high:5"
|
||||
"9:high:3"
|
||||
"10:high:3"
|
||||
"11:low:3"
|
||||
"12:low:3"
|
||||
"13:high:3"
|
||||
"14:high:3"
|
||||
"15:low:5"
|
||||
)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Profile: comboA_SWB_CONN14 - checkerboard, the complement of comboB_SWB_CONN14
|
||||
# Board: SWB_CONN14 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboA then comboB to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# CH 10, 11, 13 stay nominal: they are NC on this board, so there is
|
||||
# nothing to margin.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:high:3"
|
||||
"1:low:3"
|
||||
"2:low:3"
|
||||
"3:high:5"
|
||||
"4:high:5"
|
||||
"5:high:5"
|
||||
"6:low:5"
|
||||
"7:low:5"
|
||||
"8:low:3"
|
||||
"9:low:3"
|
||||
"10:nominal:5"
|
||||
"11:nominal:5"
|
||||
"12:high:3"
|
||||
"13:nominal:5"
|
||||
"14:high:5"
|
||||
"15:high:3"
|
||||
)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Profile: comboA_SWB_CONN15 - checkerboard, the complement of comboB_SWB_CONN15
|
||||
# Board: SWB_CONN15 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboA then comboB to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# CH 10 stay nominal: they are NC on this board, so there is
|
||||
# nothing to margin.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:low:3"
|
||||
"1:low:3"
|
||||
"2:high:3"
|
||||
"3:high:3"
|
||||
"4:low:3"
|
||||
"5:low:3"
|
||||
"6:high:5"
|
||||
"7:high:3"
|
||||
"8:high:5"
|
||||
"9:low:5"
|
||||
"10:nominal:5"
|
||||
"11:low:5"
|
||||
"12:low:3"
|
||||
"13:high:3"
|
||||
"14:high:3"
|
||||
"15:high:5"
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Profile: comboA_SWB_CONN16 - checkerboard, the complement of comboB_SWB_CONN16
|
||||
# Board: SWB_CONN16 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboA then comboB to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:high:3"
|
||||
"1:high:5"
|
||||
"2:high:5"
|
||||
"3:low:5"
|
||||
"4:high:5"
|
||||
"5:low:5"
|
||||
"6:high:5"
|
||||
"7:high:3"
|
||||
"8:high:3"
|
||||
"9:high:3"
|
||||
"10:low:3"
|
||||
"11:low:3"
|
||||
"12:low:3"
|
||||
"13:low:3"
|
||||
"14:low:3"
|
||||
"15:high:3"
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
# Profile: comboB_CB - checkerboard, the complement of comboA_CB
|
||||
# Board: CB only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboB then comboA to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:high:5"
|
||||
"1:high:5"
|
||||
"2:low:5"
|
||||
"3:high:5"
|
||||
"4:low:5"
|
||||
"5:low:5"
|
||||
"6:low:5"
|
||||
"7:low:5"
|
||||
"8:high:5"
|
||||
"9:low:5"
|
||||
"10:low:5"
|
||||
"11:low:5"
|
||||
"12:high:5"
|
||||
"13:low:5"
|
||||
"14:low:5"
|
||||
"15:high:5"
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Profile: comboB_SWB_CONN13 - checkerboard, the complement of comboA_SWB_CONN13
|
||||
# Board: SWB_CONN13 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboB then comboA to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:low:3"
|
||||
"1:low:3"
|
||||
"2:high:3"
|
||||
"3:high:3"
|
||||
"4:low:5"
|
||||
"5:high:5"
|
||||
"6:low:5"
|
||||
"7:low:5"
|
||||
"8:low:5"
|
||||
"9:low:3"
|
||||
"10:low:3"
|
||||
"11:high:3"
|
||||
"12:high:3"
|
||||
"13:low:3"
|
||||
"14:low:3"
|
||||
"15:high:5"
|
||||
)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Profile: comboB_SWB_CONN14 - checkerboard, the complement of comboA_SWB_CONN14
|
||||
# Board: SWB_CONN14 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboB then comboA to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# CH 10, 11, 13 stay nominal: they are NC on this board, so there is
|
||||
# nothing to margin.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:low:3"
|
||||
"1:high:3"
|
||||
"2:high:3"
|
||||
"3:low:5"
|
||||
"4:low:5"
|
||||
"5:low:5"
|
||||
"6:high:5"
|
||||
"7:high:5"
|
||||
"8:high:3"
|
||||
"9:high:3"
|
||||
"10:nominal:5"
|
||||
"11:nominal:5"
|
||||
"12:low:3"
|
||||
"13:nominal:5"
|
||||
"14:low:5"
|
||||
"15:low:3"
|
||||
)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Profile: comboB_SWB_CONN15 - checkerboard, the complement of comboA_SWB_CONN15
|
||||
# Board: SWB_CONN15 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboB then comboA to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# CH 10 stay nominal: they are NC on this board, so there is
|
||||
# nothing to margin.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:high:3"
|
||||
"1:high:3"
|
||||
"2:low:3"
|
||||
"3:low:3"
|
||||
"4:high:3"
|
||||
"5:high:3"
|
||||
"6:low:5"
|
||||
"7:low:3"
|
||||
"8:low:5"
|
||||
"9:high:5"
|
||||
"10:nominal:5"
|
||||
"11:high:5"
|
||||
"12:high:3"
|
||||
"13:low:3"
|
||||
"14:low:3"
|
||||
"15:low:5"
|
||||
)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Profile: comboB_SWB_CONN16 - checkerboard, the complement of comboA_SWB_CONN16
|
||||
# Board: SWB_CONN16 only. The channel list is positional, so applying this to a
|
||||
# different board margins the wrong rails and nothing detects it.
|
||||
# Run comboB then comboA to cover every rail in both directions while its
|
||||
# neighbours sit the other way.
|
||||
# Applied to whichever LTC2980 is currently loaded via margin_init
|
||||
# Format: "channel:operation:change_percent"
|
||||
|
||||
PROFILE_CHANNELS=(
|
||||
"0:low:3"
|
||||
"1:low:5"
|
||||
"2:low:5"
|
||||
"3:high:5"
|
||||
"4:low:5"
|
||||
"5:high:5"
|
||||
"6:low:5"
|
||||
"7:low:3"
|
||||
"8:low:3"
|
||||
"9:low:3"
|
||||
"10:high:3"
|
||||
"11:high:3"
|
||||
"12:high:3"
|
||||
"13:high:3"
|
||||
"14:high:3"
|
||||
"15:low:3"
|
||||
)
|
||||
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# pwr_brick.sh -- PDB / CPB power brick Vin / Iin / Vout / Iout / Temp
|
||||
# =============================================================================
|
||||
# Version History:
|
||||
# V1.1.0 2026-09-02 PAGE values and conversions taken from the ADPM12200
|
||||
# datasheet instead of the bring-up spreadsheet.
|
||||
# The spreadsheet wrote every PAGE in decimal but with an
|
||||
# 0x prefix, so four of the five selected the wrong page:
|
||||
# Vin PAGE 9 -> it said 0x00 (should be 0x09)
|
||||
# Iin PAGE 10 -> it said 0x10 (should be 0x0A)
|
||||
# Vout PAGE 2 -> it said 0x02 correct by luck
|
||||
# Iout PAGE 14 -> it said 0x14 (should be 0x0E)
|
||||
# Temp PAGE 18 -> it said 0x18 (should be 0x12)
|
||||
# Only Vout worked, because 2 reads the same either way.
|
||||
# That is why Iin/Iout answered 0xFFFF and Temp 0x0000.
|
||||
# Conversions now use the datasheet DIRECT equation; the
|
||||
# reverse-engineered BRICK_VIN_LSB is gone.
|
||||
# V1.0.0 2026-09-02 First version.
|
||||
# =============================================================================
|
||||
#
|
||||
# Path: CB FPGA F3 VI2C ch4 -> TCA954x mux 0x72 ch0 -> the bricks
|
||||
#
|
||||
# The four ADPM12200 modules put each measurement on its own PMBus PAGE, so a
|
||||
# PAGE write has to precede every read. blanton_pwr_data.sh does not send one
|
||||
# at all (its PDB table has page "-"), which is why it reports them as NA.
|
||||
#
|
||||
# READ_VIN 0x88 PAGE 9
|
||||
# READ_IIN 0x89 PAGE 10
|
||||
# READ_VOUT 0x8B PAGE 2
|
||||
# READ_IOUT 0x8C PAGE 14
|
||||
# READ_TEMPERATURE_1 0x8D PAGE 18
|
||||
#
|
||||
# DIRECT format, datasheet Table 3 ("PMBus Command Code Coefficients"):
|
||||
#
|
||||
# X = (1/m) x (Y x 10^-R - b) Y = the 2-byte two's complement word
|
||||
#
|
||||
# Voltage m=0.125 b=0 R=0 units mV -> X = Y x 8 mV
|
||||
# Current m=0.25 b=0 R=2 units A -> X = Y x 0.04 A
|
||||
# Temperature m=1 b=0 R=2 units degC -> X = Y x 0.01 degC
|
||||
#
|
||||
# Sanity check: READ_VOUT 0x05D4 = 1492 -> 1492 x 8 = 11936 mV, which is exactly
|
||||
# what PDB_IBC_SWB1_A_VOUT reports in 'show platform voltage'.
|
||||
#
|
||||
# ⚠️ Table 3 does not list READ_VIN or READ_IIN. They are decoded here with the
|
||||
# Voltage and Current coefficients respectively - reasonable, and consistent
|
||||
# with a ~50 V input, but not stated by the datasheet. PB_VIN_M / PB_IIN_M
|
||||
# below are where to change that if the part turns out to differ.
|
||||
#
|
||||
# ⚠️ CPB.PU37 (0x26) is a DIFFERENT part: no PAGE writes, and its own scaling
|
||||
# (Vin 0.25 V, Vout 2^-11 V, Iout 0.5 A per count of the mantissa). Those
|
||||
# three were confirmed against words this DUT returns.
|
||||
#
|
||||
# Usage:
|
||||
# ./pwr_brick.sh show # the table
|
||||
# ./pwr_brick.sh show -r # add the raw words
|
||||
# ./pwr_brick.sh help
|
||||
# =============================================================================
|
||||
|
||||
# --- User Configurable Section ----------------------------------------------
|
||||
PB_CH="${PB_CH:-4}" # ICB VI2C channel
|
||||
PB_MUX="${PB_MUX:-0x72}" # TCA954x address
|
||||
PB_MUX_SEL="${PB_MUX_SEL:-0x01}" # control byte: bit0 = channel 0
|
||||
PB_TRIES="${PB_TRIES:-8}" # reads per value before giving up
|
||||
|
||||
# PMBus PAGE per measurement (ADPM12200). Decimal page numbers written in hex.
|
||||
PB_PAGE_VIN="${PB_PAGE_VIN:-0x09}" # 9
|
||||
PB_PAGE_IIN="${PB_PAGE_IIN:-0x0A}" # 10
|
||||
PB_PAGE_VOUT="${PB_PAGE_VOUT:-0x02}" # 2
|
||||
PB_PAGE_IOUT="${PB_PAGE_IOUT:-0x0E}" # 14
|
||||
PB_PAGE_TEMP="${PB_PAGE_TEMP:-0x12}" # 18
|
||||
|
||||
# DIRECT coefficients: m, R, and the divisor that takes the datasheet unit to
|
||||
# the displayed unit (mV -> V is 1000; A and degC are already right).
|
||||
PB_VOUT_M="${PB_VOUT_M:-0.125}"; PB_VOUT_R="${PB_VOUT_R:-0}"; PB_VOUT_DIV="${PB_VOUT_DIV:-1000}"
|
||||
PB_VIN_M="${PB_VIN_M:-0.125}"; PB_VIN_R="${PB_VIN_R:-0}"; PB_VIN_DIV="${PB_VIN_DIV:-1000}"
|
||||
PB_IOUT_M="${PB_IOUT_M:-0.25}"; PB_IOUT_R="${PB_IOUT_R:-2}"; PB_IOUT_DIV="${PB_IOUT_DIV:-1}"
|
||||
PB_IIN_M="${PB_IIN_M:-0.25}"; PB_IIN_R="${PB_IIN_R:-2}"; PB_IIN_DIV="${PB_IIN_DIV:-1}"
|
||||
PB_TEMP_M="${PB_TEMP_M:-1}"; PB_TEMP_R="${PB_TEMP_R:-2}"; PB_TEMP_DIV="${PB_TEMP_DIV:-1}"
|
||||
|
||||
# CPB.PU37 only (different part, no PAGE, mantissa-based)
|
||||
CPB_VIN_LSB="${CPB_VIN_LSB:-0.25}" # V per count of the mantissa
|
||||
CPB_IOUT_LSB="${CPB_IOUT_LSB:-0.5}" # A per count of the mantissa
|
||||
|
||||
# Plausibility windows. A decoded value outside its window is discarded and the
|
||||
# read retried; this is what rejects the corrupted words this bus produces - a
|
||||
# bad high byte turns 11.98 V into 32.00 V, which "reject 0xFFFF" never catches.
|
||||
PB_VIN_LO="${PB_VIN_LO:-30}"; PB_VIN_HI="${PB_VIN_HI:-70}"
|
||||
PB_VOUT_LO="${PB_VOUT_LO:-8}"; PB_VOUT_HI="${PB_VOUT_HI:-14}"
|
||||
PB_IIN_LO="${PB_IIN_LO:-0}"; PB_IIN_HI="${PB_IIN_HI:-100}"
|
||||
PB_IOUT_LO="${PB_IOUT_LO:-0}"; PB_IOUT_HI="${PB_IOUT_HI:-300}"
|
||||
PB_TEMP_LO="${PB_TEMP_LO:-0}"; PB_TEMP_HI="${PB_TEMP_HI:-125}"
|
||||
|
||||
# All-ones and all-zeros are the two ways this bus says "nobody answered", and
|
||||
# both can decode into a value that sits inside its window - 0x0000 on the
|
||||
# temperature register reads as a perfectly plausible 0 C. Rejected as raw
|
||||
# words, before any conversion, so no window has to be bent to catch them.
|
||||
PB_REJECT_FFFF="${PB_REJECT_FFFF:-1}"
|
||||
PB_REJECT_0000="${PB_REJECT_0000:-1}"
|
||||
|
||||
# "location:bricks:slave:netname:kind" kind = adpm (PAGE per read) | cpb
|
||||
PB_DEVS=(
|
||||
"SWB0.PU207:BRICKS1:0x62:P12V_SWB0_L:adpm"
|
||||
"SWB0.PU13:BRICKS2:0x63:P12V_SWB0_L:adpm"
|
||||
"SWB1.PU332:BRICKS1:0x60:P12V_SWB1_R:adpm"
|
||||
"SWB1.PU85:BRICKS2:0x61:P12V_SWB1_R:adpm"
|
||||
"CPB.PU37:BRICK:0x26:P12V_STBY:cpb"
|
||||
)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
PB_NA="NA"
|
||||
PB_RAW=0
|
||||
PB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
|
||||
|
||||
_pb_err() { echo -e "[\033[31mERR \033[0m] $*" >&2; }
|
||||
|
||||
# --- backend -----------------------------------------------------------------
|
||||
if ! declare -F vi2c_read >/dev/null 2>&1; then
|
||||
if [ -r "$PB_DIR/blanton_icb_vi2c.sh" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$PB_DIR/blanton_icb_vi2c.sh" >/dev/null 2>&1
|
||||
else
|
||||
_pb_err "blanton_icb_vi2c.sh not found next to this script"; exit 1
|
||||
fi
|
||||
fi
|
||||
declare -F vi2c_read >/dev/null 2>&1 || { _pb_err "vi2c_read() still undefined"; exit 1; }
|
||||
|
||||
# --- decoders ----------------------------------------------------------------
|
||||
# DIRECT: X = (1/m) x (Y x 10^-R - b), b = 0. Y is two's complement, so a word
|
||||
# above 0x7FFF is negative - that matters for temperature, not for the rails.
|
||||
_pb_direct() {
|
||||
awk -v w=$(( $1 )) -v m="$2" -v r="$3" -v d="$4" 'BEGIN{
|
||||
if (w > 32767) w -= 65536
|
||||
printf "%.3f", ((w * (10 ^ -r)) / m) / d
|
||||
}'
|
||||
}
|
||||
# SLINEAR11 mantissa only (bits[10:0], two's complement) - CPB.PU37 path.
|
||||
_pb_mant() { awk -v w=$(( $1 )) 'BEGIN{ m = w % 2048; if (m > 1023) m -= 2048; print m }'; }
|
||||
_pb_mul() { awk -v a="$1" -v b="$2" 'BEGIN{ printf "%.3f", a * b }'; }
|
||||
_pb_lin11() { awk -v w=$(( $1 )) 'BEGIN{ printf "%.4f", w * (2.0 ^ -11) }'; }
|
||||
_pb_in() { awk -v x="$1" -v lo="$2" -v hi="$3" 'BEGIN{ exit !(x >= lo && x <= hi) }'; }
|
||||
|
||||
# _pb_word <slave> <page|-> <reg> -> "0xWWWW"
|
||||
_pb_word() {
|
||||
local slave="$1" page="$2" reg="$3" out
|
||||
[ "$page" != "-" ] && vi2c_write "$PB_CH" "$slave" 0x00 "$page" >/dev/null 2>&1
|
||||
out=$(vi2c_read "$PB_CH" "$slave" "$reg" 2 2>/dev/null \
|
||||
| sed -n 's/.*\[0x\(..\) 0x\(..\)\].*/0x\2\1/p')
|
||||
[ -n "$out" ] && echo "$out"
|
||||
}
|
||||
|
||||
# _pb_val <slave> <page|-> <reg> <decoder> <a1> <a2> <a3> <lo> <hi>
|
||||
# Retries until the decoded value lands inside the window; echoes "value raw".
|
||||
_pb_val() {
|
||||
local slave="$1" page="$2" reg="$3" dec="$4" a1="$5" a2="$6" a3="$7" lo="$8" hi="$9"
|
||||
local i w v
|
||||
for (( i = 0; i < PB_TRIES; i++ )); do
|
||||
w=$(_pb_word "$slave" "$page" "$reg") || continue
|
||||
[ -z "$w" ] && continue
|
||||
[ "$PB_REJECT_FFFF" = "1" ] && [ "$(( w ))" -eq 65535 ] && continue
|
||||
[ "$PB_REJECT_0000" = "1" ] && [ "$(( w ))" -eq 0 ] && continue
|
||||
case "$dec" in
|
||||
direct) v=$(_pb_direct "$w" "$a1" "$a2" "$a3") ;;
|
||||
mant) v=$(_pb_mul "$(_pb_mant "$w")" "$a1") ;;
|
||||
lin11) v=$(_pb_lin11 "$w") ;;
|
||||
esac
|
||||
_pb_in "$v" "$lo" "$hi" || continue
|
||||
echo "$v $w"; return 0
|
||||
done
|
||||
echo "$PB_NA -"; return 1
|
||||
}
|
||||
|
||||
_pb_mux_open() {
|
||||
# The mux takes a bare control byte and vi2c_write always sends a register
|
||||
# first, so passing 0x01 as both makes the part latch 0x01 either way.
|
||||
vi2c_init "$PB_CH" >/dev/null 2>&1
|
||||
vi2c_write "$PB_CH" "$PB_MUX" "$PB_MUX_SEL" "$PB_MUX_SEL" >/dev/null 2>&1
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- show --------------------------------------------------------------------
|
||||
pwr_brick_show() {
|
||||
_pb_mux_open
|
||||
echo "==== PDB / CPB power bricks (VI2C ch${PB_CH} -> mux ${PB_MUX} ch0) ===="
|
||||
printf '%-3s %-12s %-8s %-7s %-14s %10s %10s %10s %10s %9s\n' \
|
||||
"No." "Location" "Bricks" "SlaveID" "Netname" \
|
||||
"Vin(V)" "Iin(A)" "Vout(V)" "Iout(A)" "Temp(C)"
|
||||
printf '%s\n' "--------------------------------------------------------------------------------------------------------------"
|
||||
|
||||
local n=0 entry loc bk slave net kind vi ii vo io tp
|
||||
for entry in "${PB_DEVS[@]}"; do
|
||||
IFS=':' read -r loc bk slave net kind <<< "$entry"
|
||||
n=$(( n + 1 ))
|
||||
if [ "$kind" = "cpb" ]; then
|
||||
vi=$(_pb_val "$slave" - 0x88 mant "$CPB_VIN_LSB" "" "" "$PB_VIN_LO" "$PB_VIN_HI")
|
||||
ii="$PB_NA -" # no input current on this part
|
||||
vo=$(_pb_val "$slave" - 0x8B lin11 "" "" "" "$PB_VOUT_LO" "$PB_VOUT_HI")
|
||||
io=$(_pb_val "$slave" - 0x8C mant "$CPB_IOUT_LSB" "" "" "$PB_IOUT_LO" "$PB_IOUT_HI")
|
||||
tp=$(_pb_val "$slave" - 0x8D direct 1 2 1 "$PB_TEMP_LO" "$PB_TEMP_HI")
|
||||
else
|
||||
vi=$(_pb_val "$slave" "$PB_PAGE_VIN" 0x88 direct "$PB_VIN_M" "$PB_VIN_R" "$PB_VIN_DIV" "$PB_VIN_LO" "$PB_VIN_HI")
|
||||
ii=$(_pb_val "$slave" "$PB_PAGE_IIN" 0x89 direct "$PB_IIN_M" "$PB_IIN_R" "$PB_IIN_DIV" "$PB_IIN_LO" "$PB_IIN_HI")
|
||||
vo=$(_pb_val "$slave" "$PB_PAGE_VOUT" 0x8B direct "$PB_VOUT_M" "$PB_VOUT_R" "$PB_VOUT_DIV" "$PB_VOUT_LO" "$PB_VOUT_HI")
|
||||
io=$(_pb_val "$slave" "$PB_PAGE_IOUT" 0x8C direct "$PB_IOUT_M" "$PB_IOUT_R" "$PB_IOUT_DIV" "$PB_IOUT_LO" "$PB_IOUT_HI")
|
||||
tp=$(_pb_val "$slave" "$PB_PAGE_TEMP" 0x8D direct "$PB_TEMP_M" "$PB_TEMP_R" "$PB_TEMP_DIV" "$PB_TEMP_LO" "$PB_TEMP_HI")
|
||||
fi
|
||||
printf '%-3s %-12s %-8s %-7s %-14s %10s %10s %10s %10s %9s\n' \
|
||||
"$n" "$loc" "$bk" "$slave" "$net" \
|
||||
"${vi%% *}" "${ii%% *}" "${vo%% *}" "${io%% *}" "${tp%% *}"
|
||||
[ "$PB_RAW" = "1" ] && printf '%-3s %-12s %-8s %-7s %-14s %10s %10s %10s %10s %9s\n' \
|
||||
"" "" "" "" "raw" "${vi##* }" "${ii##* }" "${vo##* }" "${io##* }" "${tp##* }"
|
||||
done
|
||||
# No trailing notes on stdout: this table gets pasted into reports and
|
||||
# captured into the master console log, and a caveat printed every run stops
|
||||
# being read after the second time. The caveats live in the file header -
|
||||
# the one that still matters is that READ_VIN / READ_IIN are not in the
|
||||
# datasheet coefficient table and borrow the Voltage / Current sets.
|
||||
}
|
||||
|
||||
pwr_brick_help() {
|
||||
echo -e "\033[1mpwr_brick.sh - PDB / CPB power brick readings\033[0m"
|
||||
echo ""
|
||||
echo -e " \033[33mshow\033[0m [-r] Vin / Iin / Vout / Iout / Temp for all 5 bricks (-r adds raw)"
|
||||
echo -e " \033[33mhelp\033[0m"
|
||||
echo ""
|
||||
echo -e " Path : VI2C ch$PB_CH -> mux $PB_MUX ch0"
|
||||
echo -e " The four ADPM12200 modules need a PMBus PAGE per measurement:"
|
||||
echo -e " Vin $PB_PAGE_VIN(9) Iin $PB_PAGE_IIN(10) Vout $PB_PAGE_VOUT(2) Iout $PB_PAGE_IOUT(14) Temp $PB_PAGE_TEMP(18)"
|
||||
echo -e " DIRECT format, datasheet Table 3: X = (1/m) x (Y x 10^-R - b)"
|
||||
echo -e " CPB.PU37 (0x26) is a different part - no PAGE, its own scaling."
|
||||
echo -e " \033[33mREAD_VIN / READ_IIN are not in Table 3; they borrow Voltage / Current.\033[0m"
|
||||
}
|
||||
|
||||
case "${1:-help}" in
|
||||
show)
|
||||
shift 2>/dev/null
|
||||
[ "${1:-}" = "-r" ] && PB_RAW=1
|
||||
pwr_brick_show ;;
|
||||
help|-h|--help) pwr_brick_help ;;
|
||||
*) _pb_err "unknown sub-command: $1"; pwr_brick_help; exit 1 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user