EXI bring-up: device enumerates on hardware over the J4 header
First silicon proof of the EXI capture path. A Pi bit-banging EXI into J4 reads the device ID 04 02 02 00 21/21, NWAYS 0x17, HIPR 0x01, writes and reads back PAR0-3, writes IMR, and sees NCRA's reset bit self-clear. Fixes two host-side bugs found getting there: - exi_devid_rpi.py sampled MISO just after the rising edge, racing the slave's own update and landing one bit early (04 came back as 08). Sample in the CLK-low phase, as the simulation does. - pi-exi-wirecheck.py's bridge scan drove HIGH against pull-downs, but the FPGA's SB_IO pull-up out-pulls the Pi's internal pull-down, so every pin reported as bridged. The aggressor now drives LOW against pull-ups. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Clock EXACTLY the requested byte count, the way the GC driver does."""
|
||||
import time, collections
|
||||
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, gap=0.005, idle=0.010):
|
||||
GPIO.output(CS, 0); GPIO.output(CLK, 1); time.sleep(0.0005)
|
||||
xfer((addr >> 6) & 0x7F); xfer(((addr & 0x3F) << 2) | ((n - 1) & 3))
|
||||
time.sleep(gap)
|
||||
out = [xfer(0x00) for _ in range(n)] # EXACTLY n bytes, no more
|
||||
GPIO.output(CS, 1); time.sleep(idle)
|
||||
return out
|
||||
|
||||
def trial(tag, addr, n, want, reps=21, idle=0.010):
|
||||
hits = collections.Counter(); ok = 0
|
||||
seq = []
|
||||
for _ in range(reps):
|
||||
r = read(addr, n, idle=idle)
|
||||
hits[" ".join("%02x" % x for x in r)] += 1
|
||||
good = r == want
|
||||
ok += good
|
||||
seq.append("." if good else "x")
|
||||
print(f" {tag:<34} {ok:>2}/{reps} {''.join(seq)}")
|
||||
for pat, cnt in hits.most_common(3):
|
||||
print(f" {cnt:>3}x {pat}")
|
||||
|
||||
print("=== exact-length reads, 10ms idle between transactions ===")
|
||||
trial("device ID @0x0000 (4B)", 0x0000, 4, [0x04, 0x02, 0x02, 0x00])
|
||||
trial("NWAYS @0x31 (1B)", 0x31, 1, [0x17])
|
||||
trial("HIPR @0x3A (1B)", 0x3A, 1, [0x01])
|
||||
print()
|
||||
print("=== same, but 200ms idle (does state decay?) ===")
|
||||
trial("device ID @0x0000 (4B)", 0x0000, 4, [0x04, 0x02, 0x02, 0x00], reps=9, idle=0.200)
|
||||
GPIO.cleanup()
|
||||
Reference in New Issue
Block a user