From be24eebff25176bd37ce84f9a4110ae7dbfa5802 Mon Sep 17 00:00:00 2001 From: ETWen Date: Thu, 12 Nov 2026 20:35:58 +0800 Subject: [PATCH] feat(pwr): Add blanton_multiphase_read.sh to read back the SWB VRMs Reads the controllers blanton_multiphase_margin.sh writes (native i2c, SWB0 = i2c-13/15, SWB1 = i2c-14/16) and prints one row per chip in the pu_show.sh layout - VOUT/VOUT2, IOUT/IOUT2, POUT (V x I), TEMP - with the raw PMBus word in hex after every voltage and current, plus the total power per board. PAGE is read back after each page and the page is re-read if something else moved it. Not run on the bench yet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0131orciRKrejchsuDk6UpXk --- .../Blanton_Script/blanton_multiphase_read.sh | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/Script_ABC_Blanton/Blanton_Script/blanton_multiphase_read.sh diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_multiphase_read.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_multiphase_read.sh new file mode 100644 index 0000000..eef9bb4 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_multiphase_read.sh @@ -0,0 +1,202 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_multiphase_read.sh -- read back the SWB multiphase VRMs (V / I / P / T) +# ============================================================================= +# Version History: +# V1.0.0 2026-11-04 First version. Reads the same controllers that +# blanton_multiphase_margin.sh writes (native i2c, +# SWB0 = i2c-13/15, SWB1 = i2c-14/16) and prints one row +# per chip in the pu_show.sh layout, with the raw PMBus +# word in hex after every voltage and current. +# ============================================================================= +# +# Per chip, per PAGE (page 0 -> VOUT/IOUT, page 1 -> VOUT2/IOUT2): +# PAGE 0x00 i2cset +# READ_VOUT 0x8B MP29816 : bits[11:0] x LSB from MFR_VOUT_SCALE_LOOP +# (0x29) bits[12:10], read from the chip +# MP2985B : bits[11:0] x 1 mV +# READ_IOUT 0x8C SLINEAR11 +# READ_TEMP1 0x8D page 0 only. MP29816 SLINEAR11, MP2985B bits[10:0] +# two's complement degC +# POUT computed V x I (not READ_POUT) -- same as pu_show.sh +# Conversions are the ones verified in blanton_pwr_data.sh V1.0.0. +# +# The kernel / platform daemons may talk to the same chips and move PAGE +# between our page select and our read. After every page's reads the PAGE +# register is read back; if it moved, that page is re-read (MP_RETRY times) +# and printed NA if it never holds still. 0xFFFF is also treated as NA. +# +# Read only -- nothing but PAGE is written. PAGE is put back to 0 afterwards. +# ⚠️ Do not run while blanton_multiphase_margin.sh is writing: both select +# PAGE on the same chips and neither one knows about the other. +# +# Usage: +# ./blanton_multiphase_read.sh # both boards +# ./blanton_multiphase_read.sh -u 0 # SWB0 only +# ./blanton_multiphase_read.sh -n # print the i2c commands only +# +# Options: +# -u|--unit <0|1|all> which switch board (default: both) +# -d|--debug print every i2c command and the word it returned +# -n|--dry-run print the commands only, do not touch the DUT +# -h|--help help +# ============================================================================= + +MP_UNITS="${MP_UNITS:-0 1}" +MP_RETRY="${MP_RETRY:-3}" +MP_DRY_RUN=${MP_DRY_RUN:-0} +DEBUG_MODE=${DEBUG_MODE:-0} +MP_NA="NA" + +# --- Chip map ---------------------------------------------------------------- +# "name:part:bus_swb0:addr:pages" SWB1 = same addr on bus + 1 (13->14, 15->16) +# PU numbers are from PWR_Data.xlsx (blanton_pwr_data.sh PWR_RAILS). +MP_CHIPS=( + "PU2:MP29816:13:0x20:0" + "PU105:MP2985B:13:0x21:0 1" + "PU102:MP2985B:13:0x22:0 1" + "PU114:MP2985B:13:0x25:0 1" + "PU122:MP2985B:13:0x27:0 1" + "PU142:MP2985B:13:0x29:0 1" + "PU108:MP2985B:15:0x23:0 1" + "PU111:MP2985B:15:0x24:0 1" + "PU118:MP2985B:15:0x26:0 1" + "PU127:MP2985B:15:0x28:0 1" +) + +_mp_err() { echo -e "[\033[31mERR \033[0m] $*" >&2; } +_mp_dbg() { [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] $*\033[0m" >&2; return 0; } + +# --- i2c --------------------------------------------------------------------- +_mp_setpage() { # + if [ "$MP_DRY_RUN" = "1" ]; then echo "i2cset -f -y $1 $2 0x00 $3"; return 0; fi + _mp_dbg "i2cset -f -y $1 $2 0x00 $3" + i2cset -f -y "$1" "$2" 0x00 "$3" 2>/dev/null +} + +_mp_rd() { # -> decimal on stdout + local out + if [ "$MP_DRY_RUN" = "1" ]; then echo "i2cget -f -y $1 $2 $3 $4" >&2; echo 0; return 0; fi + out=$(i2cget -f -y "$1" "$2" "$3" "$4" 2>/dev/null) || { _mp_dbg "i2cget -f -y $1 $2 $3 $4 -> fail"; return 1; } + _mp_dbg "i2cget -f -y $1 $2 $3 $4 -> $out" + case "$out" in 0x[0-9a-fA-F]*) echo $(( out )) ;; *) return 1 ;; esac +} + +# --- decoders ---------------------------------------------------------------- +_mp_l11() { # SLINEAR11 word -> value + local w=$(( $1 & 0xFFFF )) e m + e=$(( (w >> 11) & 0x1F )); (( e > 15 )) && e=$(( e - 32 )) + m=$(( w & 0x7FF )); (( m > 1023 )) && m=$(( m - 2048 )) + awk -v m="$m" -v e="$e" 'BEGIN { printf "%.3f", m * (2.0 ^ e) }' +} + +_mp_res() { # MP29816 Vout LSB (V) from MFR_VOUT_SCALE_LOOP bits[12:10] + case $(( ($1 >> 10) & 0x7 )) in + 0) echo 0.00625 ;; 1) echo 0.005 ;; 2) echo 0.0025 ;; 3) echo 0.002 ;; + 4) echo 0.001 ;; 5) echo 0.00390625 ;; 6) echo 0.001953125 ;; 7) echo 0.0009765625 ;; + esac +} + +# --- one page: sets V_STR / I_STR / V_VAL / I_VAL ---------------------------- +_mp_read_page() { # + local part="$1" bus="$2" addr="$3" pg="$4" res="$5" try wv wi wp + V_STR="$MP_NA"; I_STR="$MP_NA"; V_VAL=""; I_VAL="" + for (( try=0; try/dev/null; return 0; } + wp=$(_mp_rd "$bus" "$addr" 0x00 b) || continue + (( wp == pg )) || { _mp_dbg "$bus/$addr: PAGE moved to $wp, re-reading page $pg"; continue; } + break + done + (( try == MP_RETRY )) && return 1 + if [ -n "$wv" ] && (( wv != 0xFFFF )); then + if [ "$part" = "MP29816" ]; then + V_VAL=$(awk -v c=$(( wv & 0xFFF )) -v r="$res" 'BEGIN { printf "%.3f", c * r }') + else + V_VAL=$(awk -v c=$(( wv & 0xFFF )) 'BEGIN { printf "%.3f", c / 1000 }') + fi + V_STR=$(printf '%s(0x%04X)' "$V_VAL" "$wv") + fi + if [ -n "$wi" ] && (( wi != 0xFFFF )); then + I_VAL=$(_mp_l11 "$wi") + I_STR=$(printf '%s(0x%04X)' "$I_VAL" "$wi") + fi + return 0 +} + +_mp_pout() { [ -n "$1" ] && [ -n "$2" ] && awk -v v="$1" -v i="$2" 'BEGIN { printf "%.3f", v * i }' || echo "$MP_NA"; } + +# --- main -------------------------------------------------------------------- +blanton_multiphase_read() { + while [ $# -gt 0 ]; do + case "$1" in + -u|--unit) + case "$2" in + all|ALL) MP_UNITS="0 1" ;; + 0|1) MP_UNITS="$2" ;; + *) _mp_err "invalid unit '$2' (use 0, 1 or all)"; return 2 ;; + esac + shift 2 ;; + -d|--debug) DEBUG_MODE=1; shift ;; + -n|--dry-run) MP_DRY_RUN=1; shift ;; + -h|--help) sed -n '/^# Usage:/,/^# =====/p' "${BASH_SOURCE[0]}" | sed '$d; s/^# \{0,1\}//'; return 0 ;; + *) _mp_err "unknown option '$1'"; return 2 ;; + esac + done + command -v i2cget >/dev/null 2>&1 || [ "$MP_DRY_RUN" = "1" ] || { _mp_err "i2cget not found"; return 1; } + + local fmt='%-16s| %-17s| %-17s| %-18s| %-18s| %-9s| %-9s| %s\n' + local rule='--------------------------------------------------------------------------------------------------------------------------' + local u e name part bus0 addr pages bus res w temp tot sums="" + local V1 I1 V1v I1v V2 I2 V2v I2v P1 P2 m + + printf "$fmt" NAME "VOUT" "VOUT2" "IOUT" "IOUT2" "POUT" "POUT2" "TEMP" + echo "$rule" + for u in $MP_UNITS; do + tot=0 + for e in "${MP_CHIPS[@]}"; do + IFS=: read -r name part bus0 addr pages <<< "$e" + bus=$(( bus0 + u )) + res=""; temp="$MP_NA" + V1="$MP_NA"; I1="$MP_NA"; V1v=""; I1v="" + V2="$MP_NA"; I2="$MP_NA"; V2v=""; I2v="" + + # page 0: scale (MP29816), temperature, VOUT/IOUT + _mp_setpage "$bus" "$addr" 0 + if [ "$part" = "MP29816" ]; then + w=$(_mp_rd "$bus" "$addr" 0x29 w) && res=$(_mp_res "$w") + [ -n "$res" ] || res=0.0025 + fi + if w=$(_mp_rd "$bus" "$addr" 0x8D w) && (( w != 0xFFFF )); then + if [ "$part" = "MP29816" ]; then temp=$(printf '%.2f' "$(_mp_l11 "$w")") + else m=$(( w & 0x7FF )); (( m > 1023 )) && m=$(( m - 2048 )); temp=$(printf '%.2f' "$m"); fi + fi + if _mp_read_page "$part" "$bus" "$addr" 0 "$res"; then + V1="$V_STR"; I1="$I_STR"; V1v="$V_VAL"; I1v="$I_VAL" + fi + if [[ " $pages " == *" 1 "* ]] && _mp_read_page "$part" "$bus" "$addr" 1 "$res"; then + V2="$V_STR"; I2="$I_STR"; V2v="$V_VAL"; I2v="$I_VAL" + fi + _mp_setpage "$bus" "$addr" 0 >/dev/null + + P1=$(_mp_pout "$V1v" "$I1v") + if [[ " $pages " == *" 1 "* ]]; then P2=$(_mp_pout "$V2v" "$I2v"); else P2="$MP_NA"; fi + [ "$P1" != "$MP_NA" ] && tot=$(awk -v a="$tot" -v b="$P1" 'BEGIN { printf "%.3f", a + b }') + [ "$P2" != "$MP_NA" ] && tot=$(awk -v a="$tot" -v b="$P2" 'BEGIN { printf "%.3f", a + b }') + + [ "$MP_DRY_RUN" = "1" ] && continue + printf "$fmt" "SWB${u}-MP_${name}" "$V1" "$V2" "$I1" "$I2" "$P1" "$P2" "$temp" + done + sums="${sums}SWB${u} Total Power: ${tot} W"$'\n' + done + [ "$MP_DRY_RUN" = "1" ] && return 0 + echo "$rule" + printf '%s' "$sums" + echo "(hex = raw PMBus word; POUT = VOUT x IOUT; an NA row means the chip did not answer or PAGE kept moving)" +} + +if [ "${BASH_SOURCE[0]}" = "$0" ]; then + blanton_multiphase_read "$@" +fi