Add experimental I2C debugging and EEPROM analysis tools
One-off diagnostic scripts from experiments 0xD7-0xDB investigating the I2C BERR deadlock. Documents the systematic elimination of software-only recovery approaches: - i2c_host_test.py: Proved 0xA0 register writes cannot drive I2C bus - i2c_register_test.py: Tested I2C register writability from host - i2c_recovery_boot.py: Attempted I2C state machine recovery via boot - eeprom_flash_a0.py: Host-side EEPROM flash attempt (failed) - boot_ab_test.py / boot_test.py: EEPROM boot reliability testing - a8_autoclear_test.py: BCM4500 command register auto-clear behavior - addr_gateway_test.py: BCM3440 gateway address routing analysis - stock_fw_compare.py / stock_fw_test.py: Stock vs custom fw analysis
This commit is contained in:
parent
97c1000d8b
commit
0d6facb321
16 changed files with 3279 additions and 0 deletions
95
tools/a8_autoclear_test.py
Normal file
95
tools/a8_autoclear_test.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Test whether BCM4500 register A8 auto-clears after write commands.
|
||||
|
||||
If A8 auto-clears to 0x00 (or 0x02) after writing 0x03, then
|
||||
bcm_poll_ready() would always return TRUE, masking the fact that
|
||||
the DSP isn't processing commands.
|
||||
|
||||
Uses enhanced 0xB6 diagnostic:
|
||||
wValue = page, wIndex = A8 command (0 = default READ)
|
||||
Returns 8 bytes:
|
||||
[0] write_A6_ok
|
||||
[1] A6 readback
|
||||
[2] write_A8_ok
|
||||
[3] A8 IMMEDIATE readback (no delay)
|
||||
[4] A8 after 2ms delay
|
||||
[5] A7 data result
|
||||
[6] A6 final state
|
||||
[7] echo: command sent
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
sys.path.insert(0, 'tools')
|
||||
from skywalker_lib import SkyWalker1
|
||||
|
||||
CMD_I2C_DIAG = 0xB6
|
||||
CMD_I2C_RAW_READ = 0xB5
|
||||
BCM4500_ADDR = 0x08
|
||||
|
||||
sw = SkyWalker1()
|
||||
sw.open()
|
||||
print('=== A8 Auto-Clear Test ===')
|
||||
print(f'Firmware: {sw.get_fw_version()}')
|
||||
|
||||
# Boot with full sequence
|
||||
print('\n--- Booting BCM4500 (full boot) ---')
|
||||
result = sw._vendor_in(0x89, value=1, index=0, length=3)
|
||||
cfg, stage = result[0], result[1]
|
||||
print(f' Config: 0x{cfg:02X}, Stage: 0x{stage:02X}')
|
||||
|
||||
# Read A8 default state before any commands
|
||||
print('\n--- A8 default state (after boot, before diagnostic) ---')
|
||||
a8_default = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=0xA8, length=1)
|
||||
print(f' A8 default: 0x{a8_default[0]:02X} (bit0={a8_default[0] & 0x01})')
|
||||
|
||||
# Test 1: READ command (0x01) — this was the previous behavior
|
||||
print('\n=== Test 1: A8 with READ command (0x01) ===')
|
||||
diag1 = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x01, length=8)
|
||||
print(f' A6 write ok: {diag1[0]}')
|
||||
print(f' A6 readback: 0x{diag1[1]:02X}')
|
||||
print(f' A8 write ok: {diag1[2]}')
|
||||
print(f' A8 IMMEDIATE: 0x{diag1[3]:02X} (bit0={diag1[3] & 0x01})')
|
||||
print(f' A8 after 2ms: 0x{diag1[4]:02X} (bit0={diag1[4] & 0x01})')
|
||||
print(f' A7 data: 0x{diag1[5]:02X}')
|
||||
print(f' A6 final: 0x{diag1[6]:02X}')
|
||||
print(f' Command sent: 0x{diag1[7]:02X}')
|
||||
|
||||
# Reset A8 back to default by reading
|
||||
time.sleep(0.01)
|
||||
|
||||
# Test 2: WRITE command (0x03) — the one used by init blocks
|
||||
print('\n=== Test 2: A8 with WRITE command (0x03) ===')
|
||||
diag2 = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x03, length=8)
|
||||
print(f' A6 write ok: {diag2[0]}')
|
||||
print(f' A6 readback: 0x{diag2[1]:02X}')
|
||||
print(f' A8 write ok: {diag2[2]}')
|
||||
print(f' A8 IMMEDIATE: 0x{diag2[3]:02X} (bit0={diag2[3] & 0x01})')
|
||||
print(f' A8 after 2ms: 0x{diag2[4]:02X} (bit0={diag2[4] & 0x01})')
|
||||
print(f' A7 data: 0x{diag2[5]:02X}')
|
||||
print(f' A6 final: 0x{diag2[6]:02X}')
|
||||
print(f' Command sent: 0x{diag2[7]:02X}')
|
||||
|
||||
# Test 3: Try other A8 values
|
||||
print('\n=== Test 3: Various A8 values ===')
|
||||
for cmd in [0x00, 0x02, 0x04, 0xFF]:
|
||||
time.sleep(0.01)
|
||||
diag = sw._vendor_in(CMD_I2C_DIAG, value=0x00, index=cmd, length=8)
|
||||
print(f' CMD=0x{cmd:02X}: A8_imm=0x{diag[3]:02X} A8_2ms=0x{diag[4]:02X} '
|
||||
f'A7=0x{diag[5]:02X}')
|
||||
|
||||
# Analysis
|
||||
print('\n=== Analysis ===')
|
||||
if diag2[3] != 0x03 or diag2[4] != 0x03:
|
||||
print(f' !! A8 AUTO-CLEARS after WRITE command!')
|
||||
print(f' Wrote 0x03, immediate={diag2[3]:02X}, after_2ms={diag2[4]:02X}')
|
||||
if (diag2[3] & 0x01) == 0 or (diag2[4] & 0x01) == 0:
|
||||
print(f' bcm_poll_ready() sees bit0=0 → always returns TRUE')
|
||||
print(f' Init blocks appear to succeed but DSP never processes them!')
|
||||
else:
|
||||
print(f' A8 retains WRITE command (0x03). No auto-clear.')
|
||||
if (diag1[3] == 0x01) and (diag2[3] == 0x03):
|
||||
print(f' Both READ and WRITE commands stick. DSP is genuinely not processing.')
|
||||
|
||||
sw.close()
|
||||
print('\n=== Done ===')
|
||||
Loading…
Add table
Add a link
Reference in a new issue