Moved all components to F.Cu

This commit is contained in:
2026-08-28 10:29:41 +02:00
parent 6ba3447e58
commit 009a643698
9 changed files with 22476 additions and 22501 deletions
+150
View File
@@ -0,0 +1,150 @@
# re-bba-rb — bring-up TODO / findings (first physical unit)
Findings from bringing up the first assembled V1 board (repaired: 7 shorted
vias drilled out, some collateral trace damage). Started 2026-08-23. This is a
running list — items are **not** being worked yet, just recorded.
## Established good so far (context)
- Bitstream flashes + verifies (`iceprog`, channel A); FPGA configures (heartbeat).
- FT2232H healthy (channel-A MPSSE + channel-B internal loopback both pass).
- **W5100 clock confirmed GOOD** (Y2 25 MHz crystal oscillating): the on-board
diagnostic (`scratchpad/w5100_check.py`) shows solid green — MR software-reset
self-clears, which only happens on the internal clock.
- W5100 register write/read-back works on 7 of 8 data lines.
## Known damage on THIS unit (self-inflicted, from the via repair — not design bugs)
- **UART_RXD trace broken** (FPGA pin 19 → FT2232H pin 39). Workaround built:
`UART_J4=1` synth build relocates the UART to the J4 header (DBG0=pin9=TX,
DBG1=pin10=RX, GND=J4 pin1) for an external USB-UART/Pi dongle.
- **ETH_D3 trace broken** (W5100 data bit 3): net `ETH_D3` = FPGA **U9 pin 28**
↔ W5100 **U11 pin 40**. Confirmed by the diagnostic's red blink-code (4 blinks
= D3). One bodge needed; bridge the drilled break (scrape to trace copper / a
via — no need to touch the 0.5 mm chip pads). Optional: remap the FPGA D3 bit
to a spare J4 pad (DBG2=pin11=J4 pin4) to make one end a coarse header pad.
---
## TODO
### 1. LED brightness — LED_G and the two transistor-driven LEDs are blindingly bright
**Observation:** `LED_G` (D6, green) and the two transistor-driven LEDs are far
too bright; `LED_R` (D7, red) is fine.
**Root cause (from netlist):** the series resistors are wrong.
- `LED_R` (D7, red): **R38 = 330 Ω** → correct brightness (the reference).
- `LED_G` (D6, green): **R37 = 49.9 Ω** → ~25 mA, blinding.
- Transistor-driven: **D8** (green, via Q1 S8050) and **D9** (green, via Q2
S8550, collector → **R42 = 49.9 Ω** → D9) → same over-drive. (Confirm D8's
own series resistor value too.)
**Fix direction:** raise the 49.9 Ω LED series resistors (**R37**, **R42**, and
D8's) to ~**330 Ω–1 kΩ** to match D7. (The 49.9 Ω value looks copy-pasted from
the impedance-matching resistors — wrong part for an LED.) The RGB LED
(D11/D12/D13 via `SB_RGBA_DRV`, `RGB*_CURRENT=0b000001`) is separate and not
part of this complaint. BOM/PCB change for V2; a rework could tack larger
resistors on this unit if the brightness is a bench nuisance.
### 2. GC_ON is not the clean on/off the gateware assumed (sits at 2.3 V; both handover LEDs on)
**Observation:** `GC_ON` measures **2.3 V** (not a clean rail). With **both USB
and GC connected**, both transistor-driven LEDs (D8, D9) are lit — the intent
was a power-handover indicator with only ever one active (USB vs GC).
**Analysis (from netlist):** `GC_ON` = TPS2116 status (net: U2.8 = mux ST,
U12.3, FPGA **U9 pin 21**, pulled up by R5 10 k to 3V3; drives Q1 base via R39
10 k and Q2 base via R40 10 k). The two indicator transistors are complementary
(Q1 = S8050 NPN, Q2 = S8550 PNP) expecting GC_ON to swing rail-to-rail:
- At **GC_ON ≈ 2.3 V**, the NPN (Q1, on when base ≳0.7 V) **and** the PNP (Q2, on
when base ≲2.6 V) **both conduct** → both D8 and D9 light. There is no clean
one-or-the-other point at this intermediate voltage.
**Two things to resolve:**
- **Hardware:** the complementary-transistor indicator doesn't give a clean
handover display at the actual GC_ON level. Re-think for V2 (e.g., a comparator
/ proper level, or drive the two indicators from a real one-hot power-source
signal). First confirm what GC_ON's ST pin actually does across the USB-only /
GC-only / both states (TPS2116 ST semantics — see REVIEW.md).
- **Gateware:** GC_ON is wired to FPGA pin 21 but **not yet used**. The planned
"gate all outputs on GC_ON" (see TODO.md) assumed GC_ON is a clean logic level.
2.3 V is above the iCE40 3.3 V-LVCMOS V_IH (~2.0 V) so pin 21 would read HIGH,
but it's marginal and the semantics aren't the assumed on/off. Verify the real
signal before relying on it for output gating.
### 3. Functional W5100 test — send a packet capturable in Wireshark (works around broken D3?)
**Goal:** a test bitstream that makes the W5100 transmit a frame on the wire,
captured with Wireshark on the laptop (magjack J2 → laptop).
**Feasible:** reuse `W5100ParallelMaster` (MACRAW socket 0, or the UDP socket
path) with a small periodic trigger + a canned frame. Init runs on NCRA/startup.
**Caveat — the broken ETH_D3:** every byte written to the W5100 has data bit 3
corrupted, so a frame sent *now* would have wrong MAC/ethertype/payload bytes —
Wireshark might see a malformed frame (or the W5100 may reject a bad length).
- A garbled frame appearing at all would still prove **TX path + PHY + magnetics**
work on the wire.
- For a **clean, valid** packet capture, do the **ETH_D3 bodge first** (item in
"Known damage"). Recommended order: bodge D3 → re-run `w5100_check` (red should
go dark) → then this packet test.
### 4. Bit-bang EXI from a Raspberry Pi to test the FPGA's EXI capture
**Goal:** validate the EXI Mode-3 capture front-end without a GameCube, by having
a Pi emulate the GC EXI master.
**Approach:** Pi SPI **master, Mode 3 (CPOL=1, CPHA=1)**, 3.3 V (both sides
3.3 V — no shifting). Drive the EXI **device-ID query** and check the response:
write `0x0000` (2 bytes) then read 4 bytes → must be **`0x04 0x02 0x02 0x00`**.
In SPI terms: assert CS, clock out `00 00 xx xx xx xx`, the last 4 MISO bytes are
the device ID. A match proves ExiCapture → register file → MISO end-to-end.
**Connections (FPGA EXI pins):** CLK=44, MOSI=4, MISO=3, CS=45 (INT=46) — reach
them at the SP1 edge connector J3 or the damper resistors (R21/R25). Map to Pi:
Pi SCLK→CLK, Pi MOSI→MOSI(FPGA in), Pi MISO←MISO(FPGA out), Pi CE→CS, GND↔GND.
**Notes:** run the Pi SPI **slow** (e.g., 1 MHz) — the capture domain oversamples
the EXI clock, so a slow clock is *easier* than the real 27 MHz and fully
exercises the Mode-3 logic + register file. Good first EXI smoke test before
trusting it against a real console.
### 5. RGB LEDs (D11 red / D12 green / D13 yellow) — drive bug + brightness
Two findings, from lighting them for the first time at bring-up:
**(a) DRIVE BUG — they don't light in the current gateware (functional, not cosmetic).**
`SB_RGBA_DRV`'s `o_RGB0/1/2` outputs are left as dangling internal signals in
`synth.py` (and were in the first test builds). nextpnr never bonds them to the
dedicated RGB pads (pins 39/40/41 — confirmed absent from the PCF), so the driver
outputs float and **the LEDs never light**. This means the **rx / tx / ready RGB
indicators are non-functional in the default build.**
- **Fix (confirmed on the bench):** request the RGB pins *raw* (no SB_IO buffer)
and connect the driver outputs directly to the pads:
```python
rgb = platform.request("rgbpad", 0, dir="-") # Resource: r=39 g=40 b=41
Instance("SB_RGBA_DRV", ...,
o_RGB0=rgb.r.io, o_RGB1=rgb.g.io, o_RGB2=rgb.b.io)
```
Connecting through a normal `dir="o"` request fails packing:
`ERROR: SB_RGB_DRV/SB_RGBA_DRV port connected to more than just package pin!`
- **APPLIED 2026-08-23** in `synth.py`: added a raw `rgb` Resource (39/40/41) and
wired `o_RGB0/1/2 = rgb.{r,g,b}.io`; the RGB indicators now light.
**(b) BRIGHTNESS — only GREEN (D12) is too bright; red (D11) and yellow (D13)
are fine.** Measured with the corrected drive at the driver's *minimum* current
(`CURRENT_MODE` half, `RGBx_CURRENT=0b000001`). The green die is much more
efficient per mA, so at the same minimum current it's blinding while red/yellow
look right. Since the current code is already at minimum, the fix is **PWM
dimming on green only** — feed a low-duty PWM into `RGB1PWM` (green) instead of a
static `1`, and leave red/yellow (`RGB0PWM`/`RGB2PWM`) driven solid.
- **APPLIED 2026-08-23** in `synth.py`: a `_GRN_DUTY` (default 2/16 ≈ 1/8) PWM now
gates **both** green emitters — `RGB1PWM` (D12) and `LED_G`/D6 (the discrete
heartbeat, over-bright from R37 — item 1). Red/yellow/LED_R stay solid. Tune
`_GRN_DUTY` (0..15) at the bench. Gateware mitigation; the proper V2 hardware
fix for D6 is still R37 → ~330 Ω (item 1).
### 6. (reserved — Dennis to add)
_Placeholder for the item Dennis was trying to recall._
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""EXI device-ID query for re-bba-rb bring-up — run on a Raspberry Pi wired to
the FPGA's EXI pins, to validate the GameCube-facing capture path with NO W5100
involved (so it works even on a unit whose W5100/ethernet side is dead).
It bit-bangs the EXI SPI the way the GameCube does: CLK idles HIGH; the FPGA
samples MOSI on the falling edge and drives MISO on the rising edge. It sends
the device-ID read header (read 4 bytes @ addr 0 = 0x00 0x03), then pauses (the
GC pauses the clock between the header and the data so the FPGA can prefetch the
response), then clocks read bytes and looks for the reply 04 02 02 00.
Wiring (Pi BCM GPIO -> FPGA EXI, all 3.3 V, shared GND):
CLK -> EXI CLK (FPGA pin 44)
MOSI -> EXI MOSI (FPGA pin 4, an FPGA *input*)
MISO <- EXI MISO (FPGA pin 3, an FPGA *output*)
CS -> EXI CS (FPGA pin 45)
GND <-> GND
Reach these at the SP1 edge connector (J3) or on the series damper resistors.
Edit the BCM pin numbers below to match your wiring. Run: sudo python3 exi_devid_rpi.py
Requires the FPGA to be running the full BBA design (e.g. build/seed3/top.bin)
and its 12 MHz clock (X1) alive — both independent of the W5100.
"""
import time
try:
import RPi.GPIO as GPIO
except ImportError:
raise SystemExit("needs RPi.GPIO -> sudo apt install python3-rpi.gpio")
# ---- set these to your actual Pi BCM pin numbers ----
CLK, MOSI, MISO, CS = 11, 10, 9, 8
GPIO.setmode(GPIO.BCM)
GPIO.setup(CLK, GPIO.OUT, initial=1) # CPOL=1: clock idles HIGH
GPIO.setup(MOSI, GPIO.OUT, initial=0)
GPIO.setup(CS, GPIO.OUT, initial=1) # inactive HIGH
GPIO.setup(MISO, GPIO.IN)
def xfer(b):
"""Clock one byte MSB-first; FPGA samples MOSI on falling, drives MISO on rising."""
r = 0
for i in range(7, -1, -1):
GPIO.output(MOSI, (b >> i) & 1) # MOSI stable while CLK is high
GPIO.output(CLK, 0) # falling edge -> FPGA samples MOSI
GPIO.output(CLK, 1) # rising edge -> FPGA drives MISO
r = (r << 1) | GPIO.input(MISO)
return r
GPIO.output(CS, 0) # assert CS (active low)
xfer(0x00) # header byte 0: read, addr[12:6]=0
xfer(0x03) # header byte 1: addr[5:0]=0, len-1=3 (4 B)
time.sleep(0.001) # gap so the FPGA can prefetch the reply
resp = [xfer(0x00) for _ in range(6)] # clock a few read bytes
GPIO.output(CS, 1) # deassert CS
GPIO.cleanup()
print("read bytes:", " ".join("%02x" % x for x in resp))
want = [0x04, 0x02, 0x02, 0x00]
found = any(resp[i:i + 4] == want for i in range(len(resp) - 3))
if found:
print("EXI device-ID 04 02 02 00 -> FOUND. EXI capture path works!")
else:
print("device-ID not found. Try: swap to mode-2 edges (move the MISO sample "
"to just before the falling edge), check wiring/GND, confirm the FPGA "
"is running the BBA design and its 12 MHz clock is alive.")
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"board": {
"active_layer": 2,
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
+1
View File
@@ -1035,6 +1035,7 @@
"netlist": "",
"plot": "gerbers/",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""