skywalker-1/tools/indirect_loopback_test.py

177 lines
6.8 KiB
Python
Raw Normal View History

#!/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 ===')