EXI bring-up: full Swiss init runs on hardware; W5100 TX blocked

The whole GC init sequence now runs over EXI on the real board: device ID,
NCRA reset self-clear, PAR0-5, MAR, ANALOG, NWAYC, IMR, NCRA SR, NWAYS 0x17.

GC->wire TX does not complete.  Not an EXI fault and not tx_bytes depth --
8-byte frames fail too, and the UART shell's own UDP send hangs the same way,
so the W5100 bus master is stuck and TXFrameDrain is waiting on it.

Also records that id_phase is a one-shot cleared by the first NCRA reset, so
a re-run probe reads 00 00 00 00 for the device ID and looks broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 18:42:16 +00:00
parent a082e15c4f
commit 2b210dc5e3
2 changed files with 154 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""Full BBA path test: Swiss init, GC->wire TX, wire->GC RX.
Sends a broadcast ARP request ("who has 10.0.0.50, tell 10.0.0.99"). The PC
should answer, which exercises the RX half in the same shot.
"""
import time, sys
import RPi.GPIO as GPIO
CLK, MOSI, MISO, CS = 11, 10, 9, 8
GPIO.setmode(GPIO.BCM); GPIO.setwarnings(False)
GPIO.setup(CLK, GPIO.OUT, initial=1); GPIO.setup(MOSI, GPIO.OUT, initial=0)
GPIO.setup(CS, GPIO.OUT, initial=1); GPIO.setup(MISO, GPIO.IN)
def xfer(b):
r = 0
for i in range(7, -1, -1):
GPIO.output(MOSI, (b >> i) & 1)
GPIO.output(CLK, 0)
r = (r << 1) | GPIO.input(MISO)
GPIO.output(CLK, 1)
return r
def read(addr, n):
GPIO.output(CS, 0); GPIO.output(CLK, 1); time.sleep(0.0003)
xfer((addr >> 6) & 0x7F); xfer(((addr & 0x3F) << 2) | ((n - 1) & 3))
time.sleep(0.002)
out = [xfer(0) for _ in range(n)] # EXACTLY n
GPIO.output(CS, 1); time.sleep(0.0005)
return out
def write(addr, data):
GPIO.output(CS, 0); GPIO.output(CLK, 1); time.sleep(0.0003)
xfer(0x80 | ((addr >> 6) & 0x7F))
xfer(((addr & 0x3F) << 2) | ((len(data) - 1) & 3))
for b in data: xfer(b)
GPIO.output(CS, 1); time.sleep(0.0005)
def stream(addr, n):
"""SPRAM/DMA read: addr >= 0x100 streams until CS, so clock freely."""
GPIO.output(CS, 0); GPIO.output(CLK, 1); time.sleep(0.0003)
xfer((addr >> 6) & 0x7F); xfer(((addr & 0x3F) << 2) | 3)
time.sleep(0.002)
out = [xfer(0) for _ in range(n)]
GPIO.output(CS, 1); time.sleep(0.0005)
return out
def hx(v): return " ".join("%02x" % x for x in v)
MAC = [0x00, 0x09, 0xBF, 0x00, 0x00, 0x01]
SRC_IP, DST_IP = [10, 0, 0, 99], [10, 0, 0, 50]
print("=" * 62)
print("PHASE 1 Swiss init sequence")
print("=" * 62)
dev = read(0x0000, 4)
print(f" 1. device ID {hx(dev)} {'OK' if dev==[4,2,2,0] else 'FAIL'}")
if dev != [4, 2, 2, 0]:
print(" (ID is a one-shot before the first NCRA reset - continuing)")
write(0x00, [0x01]); print(" 2. NCRA = 0x01 (reset + W5100 init)")
for i in range(40):
v = read(0x00, 1)[0]
if not (v & 1): print(f" 3. NCRA reset self-cleared after {i} polls"); break
time.sleep(0.005)
else:
print(" 3. NCRA reset did NOT clear")
write(0x20, MAC[:4]); write(0x24, MAC[4:])
print(f" 4. PAR0-5 = {hx(read(0x20,4))} {hx(read(0x24,2))}")
write(0x26, [0xFF]*4); write(0x2A, [0xFF]*4); print(" 5. MAR0-7 = FF (promiscuous multicast)")
write(0x2E, [0xD6]); print(" 6. ANALOG = 0xD6")
write(0x30, [0x01]); print(" 7. NWAYC")
write(0x08, [0x86]); print(f" 8. IMR = 0x86, readback {hx(read(0x08,1))}")
write(0x32, [0x02]); print(" 9. GCA")
write(0x00, [0x08]); print(f" 10. NCRA SR=1, readback {hx(read(0x00,1))}")
nw = read(0x31, 1); print(f" 11. NWAYS = {hx(nw)} {'link up' if nw==[0x17] else 'UNEXPECTED'}")
# ---------------- build the ARP frame ----------------
frame = [0xFF]*6 + MAC + [0x08, 0x06]
frame += [0x00,0x01, 0x08,0x00, 0x06, 0x04, 0x00,0x01]
frame += MAC + SRC_IP + [0x00]*6 + DST_IP
frame += [0x00] * (60 - len(frame))
print()
print("=" * 62)
print(f"PHASE 2 GC -> wire: {len(frame)}-byte broadcast ARP")
print("=" * 62)
print(f" who has {'.'.join(map(str,DST_IP))}, tell {'.'.join(map(str,SRC_IP))}")
print(f" src MAC {':'.join('%02x'%b for b in MAC)}")
rwp_before = read(0x16, 2)
write(0x34, [len(frame) & 0xFF]); write(0x35, [(len(frame) >> 8) & 0xFF])
print(f" TWD = {hx(read(0x34,2))} (frame length)")
t0 = time.time()
for b in frame:
write(0x48, [b]) # one byte per transaction: eff_addr increments
print(f" streamed {len(frame)} bytes to TXDATA in {time.time()-t0:.2f}s")
write(0x00, [0x08 | 0x02]) # SR + ST0 -> TX trigger
print(" NCRA ST set -> TX triggered")
for i in range(30):
ir = read(0x09, 1)[0]
if ir & 0x04:
print(f" IR = {ir:02x} TI (transmit complete) SET after {i} polls"); break
time.sleep(0.01)
else:
print(f" IR = {read(0x09,1)[0]:02x} TI never set")
print()
print("=" * 62)
print("PHASE 3 wire -> GC: waiting for the ARP reply")
print("=" * 62)
print(f" RWP before = {hx(rwp_before)}")
got = None
for i in range(60):
rwp = read(0x16, 2)
ir = read(0x09, 1)[0]
if rwp != rwp_before or (ir & 0x02):
got = (rwp, ir); break
time.sleep(0.05)
if got:
rwp, ir = got
print(f" RWP moved to {hx(rwp)}, IR = {ir:02x} (RI {'set' if ir&2 else 'clear'})")
data = stream(0x0100, 80)
print(f" SPRAM @0x100: {hx(data[:16])}")
print(f" {hx(data[16:32])}")
print(f" {hx(data[32:48])}")
if 0x08 in data and 0x06 in data:
print(" -> looks like an ARP frame came back. RX PATH WORKS.")
else:
print(f" no RX after 3s (RWP still {hx(read(0x16,2))}, IR {read(0x09,1)[0]:02x})")
print(" TX may still have worked - check the capture.")
GPIO.cleanup()