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
154
tools/boot_deep_verify.py
Normal file
154
tools/boot_deep_verify.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Deep verification: full register dump + indirect register test.
|
||||
|
||||
Checks whether:
|
||||
1. Direct registers (0xA0-0xBF) are truly all 0x02 or vary
|
||||
2. Indirect registers respond (proves DSP core is running)
|
||||
3. Signal monitoring works after boot
|
||||
4. Boot with vs without FW download produces different indirect reg values
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
sys.path.insert(0, 'tools')
|
||||
from skywalker_lib import SkyWalker1
|
||||
|
||||
CMD_RAW_DEMOD_READ = 0xB1
|
||||
CMD_I2C_RAW_READ = 0xB5
|
||||
BCM4500_ADDR = 0x08
|
||||
|
||||
|
||||
def full_direct_dump(sw, label):
|
||||
"""Read all direct registers 0xA0-0xBF via raw I2C."""
|
||||
print(f'\n --- {label}: Direct Register Dump 0xA0-0xBF ---')
|
||||
values = {}
|
||||
for reg in range(0xA0, 0xC0):
|
||||
try:
|
||||
data = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR,
|
||||
index=reg, length=1)
|
||||
values[reg] = data[0]
|
||||
except Exception:
|
||||
values[reg] = None
|
||||
|
||||
# Print in 2 rows of 16
|
||||
for base in [0xA0, 0xB0]:
|
||||
row = []
|
||||
for reg in range(base, base + 16):
|
||||
v = values.get(reg)
|
||||
row.append(f'{v:02X}' if v is not None else '??')
|
||||
print(f' {base:02X}: {" ".join(row)}')
|
||||
|
||||
unique = set(v for v in values.values() if v is not None)
|
||||
print(f' Unique values: {sorted(f"0x{v:02X}" for v in unique)}')
|
||||
return values
|
||||
|
||||
|
||||
def indirect_reg_test(sw, label):
|
||||
"""Read indirect registers to test DSP core responsiveness.
|
||||
Uses 0xB1 with wIndex=0 (indirect mode): wValue=page."""
|
||||
print(f'\n --- {label}: Indirect Register Test ---')
|
||||
# Key DSP pages: 0x00 (config), 0x06 (acq), 0x07 (AGC),
|
||||
# 0x0A (Viterbi), 0x0F (transport)
|
||||
pages = [0x00, 0x01, 0x06, 0x07, 0x0A, 0x0F, 0x10, 0x20]
|
||||
results = {}
|
||||
for page in pages:
|
||||
try:
|
||||
data = sw._vendor_in(CMD_RAW_DEMOD_READ, value=page,
|
||||
index=0, length=1)
|
||||
val = data[0]
|
||||
results[page] = val
|
||||
marker = ' << DSP alive!' if val != 0 else ''
|
||||
print(f' Page 0x{page:02X}: 0x{val:02X}{marker}')
|
||||
except Exception as e:
|
||||
results[page] = None
|
||||
print(f' Page 0x{page:02X}: FAILED ({e})')
|
||||
|
||||
nonzero = sum(1 for v in results.values() if v and v != 0)
|
||||
print(f' Non-zero pages: {nonzero}/{len(pages)}')
|
||||
return results
|
||||
|
||||
|
||||
def boot_and_test(sw, flags, label):
|
||||
"""Boot with given flags and run full diagnostics."""
|
||||
print(f'\n{"="*60}')
|
||||
print(f'TEST: {label} (wIndex=0x{flags:02X})')
|
||||
print(f'{"="*60}')
|
||||
|
||||
# Shutdown + wait
|
||||
sw._vendor_in(0x89, value=0, index=0, length=3)
|
||||
time.sleep(0.5)
|
||||
|
||||
# Boot
|
||||
result = sw._vendor_in(0x89, value=1, index=flags, length=3)
|
||||
cfg, stage = result[0], result[1]
|
||||
bits = []
|
||||
if cfg & 0x01: bits.append('Started')
|
||||
if cfg & 0x02: bits.append('FW_Loaded')
|
||||
print(f' Config: 0x{cfg:02X} ({" | ".join(bits) if bits else "none"})')
|
||||
print(f' Stage: 0x{stage:02X}' +
|
||||
(' (COMPLETE)' if stage == 0xFF else f' (at {stage})'))
|
||||
|
||||
# Full register dumps
|
||||
direct = full_direct_dump(sw, label)
|
||||
indirect = indirect_reg_test(sw, label)
|
||||
|
||||
# Wait and re-test indirect (DSP may need startup time)
|
||||
time.sleep(0.5)
|
||||
indirect2 = indirect_reg_test(sw, f'{label} +500ms')
|
||||
|
||||
# Signal monitor
|
||||
print(f'\n --- Signal Monitor ---')
|
||||
try:
|
||||
sig = sw.signal_monitor()
|
||||
print(f' {sig}')
|
||||
except Exception as e:
|
||||
print(f' Failed: {e}')
|
||||
|
||||
return direct, indirect, indirect2
|
||||
|
||||
|
||||
def main():
|
||||
sw = SkyWalker1()
|
||||
sw.open()
|
||||
print('=== BCM4500 Deep Boot Verification ===')
|
||||
print(f'Firmware: {sw.get_fw_version()}')
|
||||
|
||||
# Test 1: Init blocks only (no FW download)
|
||||
d1, i1, i1b = boot_and_test(sw, 0x01,
|
||||
'Init blocks only (skip FW download)')
|
||||
|
||||
# Test 2: Full boot (FW download + init blocks)
|
||||
d2, i2, i2b = boot_and_test(sw, 0x00,
|
||||
'Full boot (FW download + init blocks)')
|
||||
|
||||
# Compare indirect registers between the two modes
|
||||
print(f'\n{"="*60}')
|
||||
print('COMPARISON: Indirect Registers (init-only vs full boot)')
|
||||
print('='*60)
|
||||
pages = [0x00, 0x01, 0x06, 0x07, 0x0A, 0x0F, 0x10, 0x20]
|
||||
for page in pages:
|
||||
v1 = i1b.get(page)
|
||||
v2 = i2b.get(page)
|
||||
v1s = f'0x{v1:02X}' if v1 is not None else '??'
|
||||
v2s = f'0x{v2:02X}' if v2 is not None else '??'
|
||||
diff = ' << DIFFERENT!' if v1 != v2 else ''
|
||||
print(f' Page 0x{page:02X}: init-only={v1s} full={v2s}{diff}')
|
||||
|
||||
# Compare direct registers
|
||||
print(f'\nDirect register comparison (0xA0-0xBF):')
|
||||
diffs = []
|
||||
for reg in range(0xA0, 0xC0):
|
||||
v1 = d1.get(reg)
|
||||
v2 = d2.get(reg)
|
||||
if v1 != v2:
|
||||
diffs.append(f' 0x{reg:02X}: init-only=0x{v1:02X} full=0x{v2:02X}')
|
||||
if diffs:
|
||||
print('\n'.join(diffs))
|
||||
else:
|
||||
print(' No differences (all registers identical)')
|
||||
|
||||
sw.close()
|
||||
print('\n=== Done ===')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue