Files

10 KiB
Raw Permalink Blame History

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.

V2 schematic changes already applied (2026-08-25)

  • U7 EEPROM → 93LC56B (LCSC C6164, MPN 93LC56BT-I/SN, same SOIC-8). Fixes the soft-brick (256 B is the FT2232H's full EEPROM size). [TODO/REVIEW updated]
  • All 7 LEDs → Everlight 24-21 reverse-mount 1206 (bottom-viewed, top-populated single-side assembly): red D7/D11 = C2892757 (24-21SURC), green D6/D8/D9/D12 = C2980185 (24-21/G6C), amber D13 = C424133 (24-21UYC). All Vf ≈ 2.0 V (3.3 V-rail + SB_RGBA_DRV safe), moderate mcd. New footprint hardware/LED_1206_ReverseMount_Everlight_24-21.kicad_mod (pad1=cathode, ø1.7 mm Edge.Cuts light-window — datasheet-confirmed 2026-08-28, spec 1.7 mm ±0.1). Refdes text is 1.0 mm (JLC silk floor).
  • LED series resistors R37/R41/R42: 49.9 Ω → 330 Ω (reused existing part C25104; R38 already 330). ~3.9 mA vs the blinding ~26 mA — closes item 1's resistor half. Green PWM (_GRN_DUTY) in gateware still applies to D6/D12; the new green is only 1845 mcd so it can likely be relaxed.
  • Gateware (synth.py): RGB drive bug fixed (raw-pad o_RGB*) + green PWM dimming — see items 1 & 5.

Still open below: GC_ON handover redesign (#2), the datasheet-aperture verify, EXI/W5100 functional validation (needs a working board), plus the ground-plane fill for fab.

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 was not a clean on/off (sat at 2.3 V; both handover LEDs on) — FIXED in schematic 2026-08-28

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.

Root cause (identified 2026-08-28): the intermediate ~2.3 V is base-loading of the open-drain ST node. When GC is the source, ST is Hi-Z and should sit at 3V3 (R5 pull-up), but Q1's base (through R39 10 k) drags it down — R5‖R39 divide 3V3 to ~2.0 V — which is low enough that the PNP Q2's V_EB ≈ 1.3 V and it conducts too. So both LEDs light, and the FPGA/EN see a soggy 2 V instead of 3V3. TPS2116 ST is only characterised to sink 1 mA (DS: V_OL @ I_ST = 1 mA, t_ST @ R_ST = 10 k), so simply strengthening R5 is not allowed.

Hardware fix — APPLIED 2026-08-28 (schematic): raise the base resistors and modestly lower the pull-up so GC_ON swings clean while ST stays ≤1 mA:

  • R5 10 k → 5.1 k (C25905, reuses R6/R7 part)
  • R39 / R40 10 k → 33 k (C25779, reuses R1 part) Result: GC active → GC_ON ≈ 2.95 V → Q1 saturates (D8/GC lit), Q2 V_EB ≈ 0.35 V → OFF (D9/USB dark); USB active → ST low (sinks ~0.73 mA < 1 mA) → D9 lit, D8 dark. Clean one-hot. No new BOM lines, no PCB layout change (resistor value swaps only — run "Update PCB from Schematic" so the F.Fab values match). This also resolves the gateware concern below: GC_ON now reads a solid ~2.95 V (well above the iCE40 V_IH) instead of a marginal 2.3 V. D8/D9 = GC/USB is the confirmed assignment (TPS2116 ST "low when VIN1 not used", VIN1 = GC priority — see REVIEW.md); the B.SilkS labels are correct.
  • Gateware: GC_ON marginal at 2.3 V for the FPGA pin-21 read — addressed by the fix above (now ~2.95 V). The "gate all outputs on GC_ON" work (TODO) can now assume a clean level; still verify on the reworked bench unit.

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:
    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.