Bring-up: W5100 bus self-test, eFuse OVLO bug, Pi SPI EXI host
From the physical V2 bring-up session (2026-09-20): - exi_bba/w5100_selftest.py (NEW): standalone FPGA<->W5100 bus diagnostic. Clock-independent data-bus walk (direct-mode GAR0 read-back, all 8 lines) + MR software-reset self-clear (needs the 25 MHz crystal). Reports 4 verdicts on D6/D7 LEDs AND over UART (115200): GOOD / data-line-N / clock-dead / no-response. Boot wait is 85 ms (> the W5100S 60.3 ms init). On this board: GOOD -- bus + all 8 data lines + 25 MHz clock all verified (unlike V1's broken D3). - REVIEW.md / TODO.md: eFuse U13 OVLO is tied to GND, which on the TPS25961 selects the internal FIXED ~6 V overvoltage cutoff -- so it blocks the 12 V rail entirely (bench-confirmed: 12V_EXI=0, GC_ON=0, W5100 unpowered). FAB- BLOCKER for V2.1: fix with an OVLO divider (~1.1M/100k -> trip ~15 V). Bench workaround: lift U13 pin 2 (OVLO) off GND. Also closed the eFuse-placement, GND-via/3V3-zone, and CC-ESD TODO items. - hardware/re-bba-rb/exi_devid_spi.py (NEW): Pi hardware-SPI (~25 MHz) EXI device-ID host, companion to the bit-bang exi_devid_rpi.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -308,6 +308,19 @@ datasheet extraction, WebSearch/WebFetch for parts and reference designs.
|
||||
EFUSE_EN : R46, R47, U13.5 EN/UVLO
|
||||
EFUSE_ILIM: R45, U13.3 ILIM
|
||||
GND : U13.2 OVLO, U13.4 GND, R45.2, R47.2, C66.2
|
||||
⚠️ **BUG FOUND AT BRING-UP 2026-09-16 — this OVLO=GND is WRONG for a 12 V
|
||||
rail and the eFuse passes NOTHING.** Per the TPS25961 datasheet, tying OVLO to
|
||||
GND selects the *internal fixed* overvoltage threshold **VOVP(R) = 5.98 V typ
|
||||
(5.55–6.5 V)** — NOT "OVLO disabled". A 12 V input is far above that, so the
|
||||
device sits in overvoltage lockout with the FET off (bench-confirmed: 12V_EXI =
|
||||
0 V, GC_ON = 0 V, W5100 unpowered). The earlier review note ("OVLO tied to GND
|
||||
for the internal fixed threshold, abs max 6.5 V fine") caught the pin abs-max
|
||||
but MISSED that the fixed VIN cutoff is ~6 V. **Fix (V2.1):** drive OVLO from a
|
||||
divider off 12V_RAW so the trip sits ~14–16 V (above 12 V, below the 19 V max /
|
||||
the D3 clamp): e.g. **R_top ≈ 1.1 MΩ (12V_RAW→OVLO) + R_bottom ≈ 100 kΩ
|
||||
(OVLO→GND)** → OVLO pin = 1.24 V at ~15 V VIN, and ~1.0 V at 12 V (stays on).
|
||||
BENCH WORKAROUND to keep bring-up moving: inject 12 V straight onto 12V_EXI
|
||||
(C65+ pad or U3.3 VIN), bypassing the mis-set eFuse.
|
||||
**D3 (SMAJ12A TVS) stays on the INPUT side on purpose** — it clamps
|
||||
GC-side surges before they reach the eFuse's 21 V absolute maximum. **C65
|
||||
is on the OUTPUT side on purpose** — it is the bulk cap whose inrush we are
|
||||
|
||||
+19
-12
@@ -241,6 +241,14 @@ schematic changes.
|
||||
at (148.49, 61.7225) near U11 pin 48. Verified 2026-07-22: nets
|
||||
`/ethernet/ETH_RST` + `/ethernet/ETH_3V3` both present on the footprint,
|
||||
0 unconnected items.
|
||||
- [ ] 🔴 **eFuse U13 OVLO MISCONFIGURED — BLOCKS 12 V (found at bring-up
|
||||
2026-09-16, FAB-BLOCKER for V2.1).** OVLO (pin 2) is tied to GND, which on
|
||||
the TPS25961 selects the internal *fixed* overvoltage cutoff ~5.98 V — so a
|
||||
12 V rail is permanently in overvoltage lockout and the eFuse passes
|
||||
nothing (bench-confirmed: 12V_EXI=0, GC_ON=0, W5100 unpowered). **Fix:**
|
||||
OVLO divider off 12V_RAW, R_top ≈ 1.1 M / R_bottom ≈ 100 k → trip ~15 V.
|
||||
See REVIEW.md eFuse entry. Bench workaround: feed 12 V onto 12V_EXI (C65+ /
|
||||
U3 VIN) to bypass it. This must be fixed before any V2.1 fab order.
|
||||
- [ ] **12 V inrush limiter (U13 TPS25961 eFuse) — SCHEMATIC DONE 2026-07-31**,
|
||||
full design rationale in REVIEW.md §6. J3.5 → 12V_RAW → U13 → 12V_EXI;
|
||||
D3 (TVS) stays upstream, C65 downstream. R45 100 k sets I_LIM ≈ 500 mA
|
||||
@@ -273,16 +281,14 @@ schematic changes.
|
||||
board PCF.
|
||||
- [ ] **Gateware: EXI INT drive style** — prefer open-drain emulation (drive
|
||||
low / release) on J3.3 rather than push-pull high.
|
||||
- [ ] **New 2026-07-22: 2 GND vias short the `/Power/3V3` zone on In2.Cu** —
|
||||
found during the last DRC pass, 4 error-severity violations (2×
|
||||
`clearance` + 2× `hole_clearance`, both 0 mm actual). Two GND vias at
|
||||
(190.78, 58.58) and (190.34, 58.58) — just south of J3's courtyard,
|
||||
likely stitching vias added during the J3 reroute — sit directly on
|
||||
top of the 3V3 pour on In2.Cu. This is a real short risk, not a
|
||||
manufacturability nit: move or delete these two vias (or void the 3V3
|
||||
zone locally) before ordering. Also 1 harmless `track_dangling`: a
|
||||
0.06 mm stub on `/exi/EXI_MOSI_RAW` near (188.39, 57.52) — routing
|
||||
debris, delete when convenient.
|
||||
- [x] **2 GND vias vs `/Power/3V3` zone on In2.Cu — RESOLVED 2026-08-28.**
|
||||
Was 4 error-severity DRC violations (2× `clearance` + 2× `hole_clearance`,
|
||||
0 mm) from GND stitching vias sitting on the 3V3 pour. Cleared by refilling
|
||||
the zones (the pour now voids around the vias); `kicad-cli pcb drc
|
||||
--severity-error` = 0 on the filled board. The `flash`/production skill
|
||||
(kicad-manufacturing-export) now refills zones before export, so this
|
||||
can't silently regress. (Any leftover `track_dangling` stub is
|
||||
warning-level debris, delete when convenient.)
|
||||
|
||||
## Broader items (beyond the wiring review — block fab on the first two)
|
||||
|
||||
@@ -374,8 +380,9 @@ schematic changes.
|
||||
exactly what stock iceprog opens by default, which now matches the
|
||||
rewired pins. Optionally program serial/product string later with
|
||||
FT_PROG (do NOT change VID/PID, or iceprog needs -d vid:pid).
|
||||
- [ ] CC1/CC2 have no ESD protection (USBLC6 covers D+/D− only) — optional,
|
||||
most hobby designs skip; note spare-channel budget if respinning D2 area.
|
||||
- [x] CC1/CC2 ESD protection — **WON'T FIX** (Dennis, 2026-08-28). USBLC6
|
||||
covers D+/D− only; CC lines left unprotected by choice, as most hobby
|
||||
designs do. Closed, not a pending item.
|
||||
- [x] `.history/` (embedded `.git`) — VERIFIED ignored via root
|
||||
`.gitignore:28`, nothing tracked.
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
"""EXI device-ID query over the Pi's HARDWARE SPI (spidev) — a near-full-speed
|
||||
(~25 MHz, close to the GameCube's real ~27 MHz EXI clock) companion to the
|
||||
bit-bang exi_devid_rpi.py.
|
||||
|
||||
Use bit-bang (exi_devid_rpi.py) for a slow logic smoke test; use THIS to prove
|
||||
the FPGA's SPI Mode-3 capture front-end also samples cleanly *at rate* without a
|
||||
GameCube. The Pi 4 SPI SCK is core_clk/even-divisor, so a 27 MHz request lands
|
||||
on ~25 MHz — comfortably inside the design's 54 MHz 2x oversampling (and a hair
|
||||
more margin than the real 27 MHz). Do NOT push past ~27 MHz: the capture domain
|
||||
only closes ~49-58 MHz across seeds, so >~27 MHz input under-samples.
|
||||
|
||||
The FPGA prefetches the reply during a clock-IDLE gap between the header and the
|
||||
data bytes (the GC pauses the clock there), so CS must stay LOW across that gap.
|
||||
spidev toggles CS per call, so we park SPI0's hardware CS on BCM7 (unused) and
|
||||
drive the real CS manually on BCM8. Pi config (then reboot):
|
||||
/boot/firmware/config.txt: dtoverlay=spi0-1cs,cs0_pin=7
|
||||
(That frees BCM8 and puts the unused hw CE0 on BCM7. To go back to the bit-bang
|
||||
script, remove that line + reboot so BCM9/10/11 return to plain GPIO.)
|
||||
|
||||
Wiring (Pi -> FPGA EXI, all 3.3 V, shared GND) — identical to the bit-bang one:
|
||||
SCLK BCM11 (pin 23) -> EXI CLK (FPGA 44)
|
||||
MOSI BCM10 (pin 19) -> EXI MOSI (FPGA 4)
|
||||
MISO BCM9 (pin 21) <- EXI MISO (FPGA 3)
|
||||
CS BCM8 (pin 24) -> EXI CS (FPGA 45) [held low manually across the txn]
|
||||
GND (pin 25) <-> GND
|
||||
Run: sudo python3 exi_devid_spi.py [speed_hz] [gap_us]
|
||||
"""
|
||||
import sys, time
|
||||
import spidev
|
||||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
except ImportError:
|
||||
raise SystemExit("needs RPi.GPIO -> sudo apt install python3-rpi.gpio")
|
||||
|
||||
SPEED = int(sys.argv[1]) if len(sys.argv) > 1 else 27_000_000 # ~25 MHz actual (core/10)
|
||||
GAP_US = int(sys.argv[2]) if len(sys.argv) > 2 else 50 # header->data prefetch gap
|
||||
CS = 8 # BCM8 manual chip-select (hardware CE0 parked on BCM7 by the overlay)
|
||||
|
||||
spi = spidev.SpiDev()
|
||||
spi.open(0, 0)
|
||||
spi.mode = 0b11 # SPI Mode 3: CPOL=1, CPHA=1 (EXI CLK idles high)
|
||||
spi.max_speed_hz = SPEED
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(CS, GPIO.OUT, initial=1) # CS idle high
|
||||
|
||||
GPIO.output(CS, 0) # assert CS (active low) for the whole transaction
|
||||
spi.xfer2([0x00, 0x03]) # header: read, addr[12:0]=0, len-1=3 (4 bytes)
|
||||
time.sleep(GAP_US / 1e6) # clock-idle gap -> FPGA prefetches the reply
|
||||
resp = spi.xfer2([0x00] * 6) # clock read bytes; MISO carries the response
|
||||
GPIO.output(CS, 1) # deassert CS
|
||||
spi.close(); GPIO.cleanup()
|
||||
|
||||
print(f"SPI mode 3, {SPEED/1e6:.1f} MHz requested (actual ~= core/even-divisor, ~25 MHz), "
|
||||
f"header->data gap {GAP_US} us")
|
||||
print("read bytes:", " ".join("%02x" % b for b in resp))
|
||||
want = [0x04, 0x02, 0x02, 0x00]
|
||||
if any(resp[i:i + 4] == want for i in range(len(resp) - 3)):
|
||||
print("EXI device-ID 04 02 02 00 -> FOUND. Capture path works at ~full EXI rate!")
|
||||
else:
|
||||
print("device-ID not found. If the slow bit-bang test (exi_devid_rpi.py) PASSES "
|
||||
"but this fails, the front-end is marginal at rate on the flashed seed -> "
|
||||
"reflash the BEST --seeds bitstream, and/or raise the gap (arg2) or lower "
|
||||
"the speed (arg1). Otherwise check wiring/GND and that the FPGA is running.")
|
||||
Reference in New Issue
Block a user