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
176
tools/indirect_loopback_test.py
Normal file
176
tools/indirect_loopback_test.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/env python3
|
||||
"""BCM4500 indirect register loopback test.
|
||||
|
||||
Write a known value via indirect write, then read it back.
|
||||
Tests multiple approaches:
|
||||
1. Multi-byte A6+A7+A8 in one transaction (0xB2 uses bcm_indirect_write)
|
||||
2. Separate writes via 0xB6 diagnostic
|
||||
3. Read via 0xB6 with various delays
|
||||
4. Read using 0xB1 (bcm_indirect_read wrapper)
|
||||
|
||||
If we can write-then-read a value back, the DSP command processor works.
|
||||
If not, we need to look at the I2C transaction structure more carefully.
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
sys.path.insert(0, 'tools')
|
||||
from skywalker_lib import SkyWalker1
|
||||
|
||||
CMD_RAW_DEMOD_READ = 0xB1
|
||||
CMD_RAW_DEMOD_WRITE = 0xB2
|
||||
CMD_I2C_RAW_READ = 0xB5
|
||||
CMD_I2C_DIAG = 0xB6
|
||||
BCM4500_ADDR = 0x08
|
||||
|
||||
sw = SkyWalker1()
|
||||
sw.open()
|
||||
print('=== BCM4500 Indirect Register Loopback 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}')
|
||||
time.sleep(0.1)
|
||||
|
||||
# ============================================================
|
||||
# Test 1: Read default indirect register values
|
||||
# ============================================================
|
||||
print('\n=== Test 1: Default indirect register values (0xB1) ===')
|
||||
for page in [0x00, 0x01, 0x06, 0x07, 0x0A, 0x0F]:
|
||||
try:
|
||||
data = sw._vendor_in(CMD_RAW_DEMOD_READ, value=page, index=0, length=1)
|
||||
print(f' Page 0x{page:02X}: 0x{data[0]:02X}')
|
||||
except Exception as e:
|
||||
print(f' Page 0x{page:02X}: FAILED ({e})')
|
||||
|
||||
# ============================================================
|
||||
# Test 2: Write via 0xB2 (multi-byte A6+A7+A8), then read via 0xB1
|
||||
# ============================================================
|
||||
print('\n=== Test 2: Write 0x42 to page 0x00, read back (0xB2 write, 0xB1 read) ===')
|
||||
try:
|
||||
# 0xB2: bcm_indirect_write(page=0x00, val=0x42)
|
||||
# Writes A6=0x00, A7=0x42, A8=0x03 in one 3-byte I2C transaction
|
||||
sw._vendor_in(CMD_RAW_DEMOD_WRITE, value=0x00, index=0x42, length=0)
|
||||
except Exception:
|
||||
pass # May not return data
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
# Read back via 0xB1 (bcm_indirect_read with 1ms delay)
|
||||
try:
|
||||
data = sw._vendor_in(CMD_RAW_DEMOD_READ, value=0x00, index=0, length=1)
|
||||
print(f' Read back page 0x00: 0x{data[0]:02X}')
|
||||
if data[0] == 0x42:
|
||||
print(' >> LOOPBACK SUCCESS! DSP is processing commands!')
|
||||
elif data[0] == 0x00:
|
||||
print(' >> Got 0x00 — either DSP not running or write/read protocol broken')
|
||||
else:
|
||||
print(f' >> Unexpected: 0x{data[0]:02X}')
|
||||
except Exception as e:
|
||||
print(f' Read failed: {e}')
|
||||
|
||||
# ============================================================
|
||||
# Test 3: Direct register reads before/after indirect write
|
||||
# ============================================================
|
||||
print('\n=== Test 3: Direct register state before/after indirect commands ===')
|
||||
print(' Before indirect write:')
|
||||
for reg in [0xA6, 0xA7, 0xA8]:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
print(f' 0x{reg:02X}: 0x{data[0]:02X}')
|
||||
|
||||
# Write via 0xB2
|
||||
try:
|
||||
sw._vendor_in(CMD_RAW_DEMOD_WRITE, value=0x06, index=0xAB, length=0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
time.sleep(0.01)
|
||||
print(' After indirect write (page=0x06, data=0xAB):')
|
||||
for reg in [0xA6, 0xA7, 0xA8]:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
print(f' 0x{reg:02X}: 0x{data[0]:02X}')
|
||||
|
||||
# ============================================================
|
||||
# Test 4: Manual step-by-step with individual I2C writes
|
||||
# ============================================================
|
||||
print('\n=== Test 4: Manual indirect read using individual raw I2C writes ===')
|
||||
print(' Writing A6=0x06 via direct I2C write...')
|
||||
|
||||
# We don't have a raw I2C write command, but we can use the 0xB6 diagnostic
|
||||
# which does individual writes and reads for us.
|
||||
|
||||
# Test 4a: 0xB6 with READ command (wIndex=0x01)
|
||||
print('\n 4a: 0xB6 diagnostic — READ page 0x06:')
|
||||
diag = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x01, length=8)
|
||||
print(f' A6 write ok: {diag[0]}')
|
||||
print(f' A6 readback: 0x{diag[1]:02X}')
|
||||
print(f' A8 write ok: {diag[2]}')
|
||||
print(f' A8 immediate: 0x{diag[3]:02X}')
|
||||
print(f' A8 after 2ms: 0x{diag[4]:02X}')
|
||||
print(f' A7 data: 0x{diag[5]:02X}')
|
||||
print(f' A6 final: 0x{diag[6]:02X}')
|
||||
|
||||
# ============================================================
|
||||
# Test 5: Try reading A7 with longer delays
|
||||
# ============================================================
|
||||
print('\n=== Test 5: Indirect read with longer delays ===')
|
||||
print(' Maybe the DSP needs more time to process the command...')
|
||||
|
||||
# Use 0xB6 to write A6=0x06 and A8=0x01
|
||||
sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x01, length=8)
|
||||
|
||||
for delay_ms in [10, 50, 100, 500]:
|
||||
time.sleep(delay_ms / 1000.0)
|
||||
# Read A7 via raw I2C
|
||||
try:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=0xA7, length=1)
|
||||
print(f' After {delay_ms:4d}ms: A7=0x{data[0]:02X}')
|
||||
except Exception as e:
|
||||
print(f' After {delay_ms:4d}ms: FAILED ({e})')
|
||||
|
||||
# ============================================================
|
||||
# Test 6: Direct register dump after all tests
|
||||
# ============================================================
|
||||
print('\n=== Test 6: Register state after all tests ===')
|
||||
print(' A0-AF:')
|
||||
for reg in range(0xA0, 0xB0):
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
print(f' 0x{reg:02X}=0x{data[0]:02X}', end='')
|
||||
if (reg % 8) == 7:
|
||||
print()
|
||||
print()
|
||||
|
||||
# ============================================================
|
||||
# Test 7: Power cycle BCM4500 and check pre-command register state
|
||||
# ============================================================
|
||||
print('\n=== Test 7: Reboot and check BEFORE any indirect commands ===')
|
||||
sw._vendor_in(0x89, value=0, index=0, length=3) # shutdown
|
||||
time.sleep(0.5)
|
||||
sw._vendor_in(0x89, value=1, index=0, length=3) # full boot
|
||||
time.sleep(0.1)
|
||||
print(' Fresh boot — direct reg reads (no indirect commands issued):')
|
||||
for reg in [0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB]:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
print(f' 0x{reg:02X}: 0x{data[0]:02X}')
|
||||
|
||||
# Now issue ONE indirect read command and check if registers change
|
||||
print('\n After ONE indirect read (page 0x06):')
|
||||
diag = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x01, length=8)
|
||||
print(f' A7 data: 0x{diag[5]:02X} (this is the indirect read result)')
|
||||
|
||||
# Check if direct registers changed
|
||||
print(' Direct register check after indirect command:')
|
||||
for reg in [0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA8]:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
print(f' 0x{reg:02X}: 0x{data[0]:02X}')
|
||||
|
||||
sw.close()
|
||||
print('\n=== Done ===')
|
||||
Loading…
Add table
Add a link
Reference in a new issue