2b210dc5e3
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>
131 lines
4.8 KiB
Python
131 lines
4.8 KiB
Python
#!/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()
|