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
+11 -2
View File
@@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
fpga-icestorm \ fpga-icestorm \
libusb-1.0-0 \ libusb-1.0-0 \
libftdi1-2 \ libftdi1-2 \
tshark \
nodejs npm \ nodejs npm \
graphviz \ graphviz \
poppler-utils \ poppler-utils \
@@ -30,13 +31,21 @@ ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv "$VIRTUAL_ENV" RUN python3 -m venv "$VIRTUAL_ENV"
ENV PATH="$VIRTUAL_ENV/bin:$PATH" ENV PATH="$VIRTUAL_ENV/bin:$PATH"
# ENV PATH alone is not enough: Debian's /etc/profile REsets PATH unconditionally,
# so any *login* shell (VS Code's integrated terminal, `su - vscode`, ssh) drops
# /opt/venv/bin and then `python` does not exist at all (slim has only python3).
# Re-prepend the venv for login shells so the documented `python -m exi_bba.synth`
# works everywhere.
RUN printf 'PATH="%s/bin:$PATH"\nexport PATH\n' "$VIRTUAL_ENV" > /etc/profile.d/10-venv.sh
RUN npm install -g @anthropic-ai/claude-code RUN npm install -g @anthropic-ai/claude-code
COPY requirements.txt /tmp/requirements.txt COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt RUN pip install --no-cache-dir -r /tmp/requirements.txt
# pyftdi: programs the FT2232H EEPROM (product string "re-BBA-rb") over libusb. # pyftdi: programs the FT2232H EEPROM over libusb, and (with pyserial) reads the
RUN pip install --no-cache-dir pyftdi # FT2232H channel-B UART directly over libusb for bring-up diagnostics.
RUN pip install --no-cache-dir pyftdi pyserial
RUN useradd -m -u 1000 -s /bin/bash vscode \ RUN useradd -m -u 1000 -s /bin/bash vscode \
&& echo 'vscode ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/vscode \ && echo 'vscode ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/vscode \
+17
View File
@@ -0,0 +1,17 @@
# The devcontainer build uses context ".." (the repo root) but only ever COPYs
# requirements.txt. Keep the context small so a rebuild doesn't ship the whole
# repo (~333 MB) to the docker daemon.
.git/
.venv/
build/
hardware/
docs/
diagrams/
examples/
*.vcd
*.pcapng
*.bin
*.asc
*.json.gz
__pycache__/
*.pyc
BIN
View File
Binary file not shown.
+70 -19
View File
@@ -59,8 +59,10 @@ from exi_bba.bba_top import BBATop
# LEDs which are active-low. No physical button exists on this board (the # LEDs which are active-low. No physical button exists on this board (the
# iCEbreaker's BTN_N was dev-board-only); panel_btn is tied idle instead. # iCEbreaker's BTN_N was dev-board-only); panel_btn is tied idle instead.
# RGB status LED (D11=red/rx, D12=green/tx, D13=yellow/ready) is on the # RGB status LED (D11=red/rx, D12=green/tx, D13=yellow/ready) is on the
# iCE40UP5K's dedicated SB_RGBA_DRV pins 39/40/41 — fixed by the chip # iCE40UP5K's dedicated SB_RGBA_DRV pads 39/40/41. It IS declared as a
# package on any board, not board-specific, so no resource needed here. # "rgb" resource and requested RAW (dir="-") so SB_RGBA_DRV drives the pads
# directly — leaving o_RGB* dangling (the old code) never bonds them and the
# LEDs stay dark. See the "rgb" Resource + elaborate() below, and BRINGUP.md.
# nextpnr P&R options. The binding constraint is the isolated 54 MHz capture # nextpnr P&R options. The binding constraint is the isolated 54 MHz capture
# domain (the SPI Mode-3 bit engine); the 24 MHz sync domain has wide margin. # domain (the SPI Mode-3 bit engine); the 24 MHz sync domain has wide margin.
@@ -75,6 +77,26 @@ from exi_bba.bba_top import BBATop
# sync domain. Plain --opt-timing is the better baseline. # sync domain. Plain --opt-timing is the better baseline.
_PNR_TIMING_OPTS = "--opt-timing" _PNR_TIMING_OPTS = "--opt-timing"
# UART pin override for bring-up. The re-bba-rb V1 lab unit had its UART_RXD
# trace (FPGA pin 19 → FT2232H pin 39) severed by a via-repair drill hole, and
# the 0.5 mm FT2232H pitch is not hand-reworkable. Set env UART_J4=1 to relocate
# the UART onto the accessible J4 debug header — DBG0 = J4 pin 2 = FPGA pin 9
# (FPGA TX), DBG1 = J4 pin 3 = FPGA pin 10 (FPGA RX), GND = J4 pin 1 — so an
# external USB-UART dongle can drive the shell, bypassing the FT2232H channel B
# completely. Unset (default) keeps the normal FT2232H channel-B pins
# (tx = 19 = UART_RXD net, rx = 18 = UART_TXD net).
_UART_TX, _UART_RX = ("9", "10") if os.environ.get("UART_J4") else ("19", "18")
# ETH_D3 relocation for the damaged V1 lab unit: the W5100 data bit-3 trace
# (FPGA pin 28 → W5100 U11 pin 40, top copper) was nicked by a drill hole, and
# neither the 0.5 mm pin nor the 0.1 mm trace is hand-reworkable. Set
# ETH_D3_PIN=<n> to drive W5100 D3 from a coarse J4 header pad instead, and bodge
# that pad to the W5100 D3 net: DBG0=9 (J4 pin2), DBG1=10 (J4 pin3),
# DBG2=11 (J4 pin4), DBG3=12 (J4 pin5), DBG4=6 (J4 pin6). NOTE pin 9 collides
# with UART_J4 TX — fine for the W5100/eth test builds (no UART), not for the
# full UART_J4 design. Default = 28 (real board). See BRINGUP.md.
_ETH_D3 = os.environ.get("ETH_D3_PIN", "28")
class IceBreakerPlatform(LatticeICE40Platform): class IceBreakerPlatform(LatticeICE40Platform):
device = "iCE40UP5K" device = "iCE40UP5K"
@@ -99,7 +121,7 @@ class IceBreakerPlatform(LatticeICE40Platform):
# W5100 indirect parallel bus # W5100 indirect parallel bus
Resource("w5100", 0, Resource("w5100", 0,
Subsignal("addr", Pins("42 38", dir="o")), Subsignal("addr", Pins("42 38", dir="o")),
Subsignal("data", Pins("34 32 31 28 27 26 25 23", dir="io")), Subsignal("data", Pins(f"34 32 31 {_ETH_D3} 27 26 25 23", dir="io")),
Subsignal("cs_n", Pins("43", dir="o")), Subsignal("cs_n", Pins("43", dir="o")),
Subsignal("rd_n", Pins("37", dir="o")), Subsignal("rd_n", Pins("37", dir="o")),
Subsignal("wr_n", Pins("36", dir="o")), Subsignal("wr_n", Pins("36", dir="o")),
@@ -114,11 +136,23 @@ class IceBreakerPlatform(LatticeICE40Platform):
Resource("ledr", 0, Pins("48", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")), Resource("ledr", 0, Pins("48", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")),
Resource("ledg", 0, Pins("47", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")), Resource("ledg", 0, Pins("47", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")),
# UART debug console → FT2232H Channel B. # RGB status LED on the iCE40UP5K's dedicated SB_RGBA_DRV pads
# On the PC: open the second USB serial port at 115200 8N1. # (39=D11 red, 40=D12 green, 41=D13 yellow). Requested RAW (dir="-") in
# elaborate and wired straight from the SB_RGBA_DRV hard block — a normal
# buffered (dir="o") output fails nextpnr packing:
# "SB_RGB_DRV/SB_RGBA_DRV port connected to more than just package pin!"
# (Bug found at bring-up 2026-08-23: these were previously left dangling,
# so the rx/tx/ready RGB indicators never lit. See BRINGUP.md item 5.)
Resource("rgb", 0,
Subsignal("r", Pins("39", dir="o")),
Subsignal("g", Pins("40", dir="o")),
Subsignal("b", Pins("41", dir="o"))),
# UART debug console → FT2232H Channel B (or J4 header if UART_J4=1).
# On the PC: open the serial port at 115200 8N1.
Resource("uart", 0, Resource("uart", 0,
Subsignal("tx", Pins("19", dir="o")), Subsignal("tx", Pins(_UART_TX, dir="o")),
Subsignal("rx", Pins("18", dir="i")), Subsignal("rx", Pins(_UART_RX, dir="i")),
Attrs(IO_STANDARD="SB_LVCMOS")), Attrs(IO_STANDARD="SB_LVCMOS")),
] ]
@@ -170,20 +204,37 @@ class BBATopSynth(BBATop):
if self._status_panel: if self._status_panel:
ledr = platform.request("ledr", 0) ledr = platform.request("ledr", 0)
ledg = platform.request("ledg", 0) ledg = platform.request("ledg", 0)
rgb = platform.request("rgb", 0, dir="-") # raw pads (no buffer)
led = self.panel_led led = self.panel_led
# Green-LED PWM dimming. Both green emitters are over-bright on
# the re-bba-rb V1 (bring-up 2026-08-23): the discrete LED_G/D6
# heartbeat has a wrong 49.9 Ohm series resistor (R37, should be
# ~330 Ohm), and the RGB green D12 die is very efficient even at
# the SB_RGBA_DRV minimum current code. The current code is
# already the minimum, so time-average both greens down with a
# low-duty PWM. Red (D11/LED_R) and yellow (D13) are fine — left
# solid. Tune _GRN_DUTY (0..15, /16 duty) at bring-up; see
# BRINGUP.md items 1 & 5. PWM freq = 24 MHz/16 = 1.5 MHz (no
# visible flicker).
_GRN_DUTY = 2 # ~1/8 duty
pwm_cnt = Signal(4)
grn_pwm = Signal()
m.d.sync += pwm_cnt.eq(pwm_cnt + 1)
m.d.comb += grn_pwm.eq(pwm_cnt < _GRN_DUTY)
m.d.comb += [ m.d.comb += [
ledg.o.eq(led[0]), # heartbeat (active-high LED) ledg.o.eq(led[0] & grn_pwm), # heartbeat (green) — PWM-dimmed
ledr.o.eq(led[1]), # EXI activity (active-high LED) ledr.o.eq(led[1]), # EXI activity (red) — fine
# all 3 bits idle/released (active-low idle = 1) — no # all 3 bits idle/released (active-low idle = 1) — no
# physical button exists on this board to read # physical button exists on this board to read
self.panel_btn.eq(C(0b111, 3)), self.panel_btn.eq(C(0b111, 3)),
] ]
# iCEbreaker RGB LED has no series resistors — must use # RGB LED has no series resistors — must use SB_RGBA_DRV (raw pad
# SB_RGBA_DRV (raw pad driver with built-in current source). # driver with built-in current source). o_RGB* MUST connect
# RGB0=red→rx_act RGB1=green→tx_act RGB2=blue→ready # directly to the pads (rgb.*.io) — a buffered output fails
# Verify colour-to-element mapping against schematic at bring-up. # packing. RGB0=red→rx RGB1=green→tx RGB2=yellow→ready.
m.submodules.rgb_drv = Instance("SB_RGBA_DRV", m.submodules.rgb_drv = Instance("SB_RGBA_DRV",
p_CURRENT_MODE="0b1", p_CURRENT_MODE="0b1",
p_RGB0_CURRENT="0b000001", p_RGB0_CURRENT="0b000001",
@@ -191,12 +242,12 @@ class BBATopSynth(BBATop):
p_RGB2_CURRENT="0b000001", p_RGB2_CURRENT="0b000001",
i_CURREN=Const(1, 1), i_CURREN=Const(1, 1),
i_RGBLEDEN=Const(1, 1), i_RGBLEDEN=Const(1, 1),
i_RGB0PWM=led[2], i_RGB0PWM=led[2], # rx → red D11 (solid)
i_RGB1PWM=led[3], i_RGB1PWM=led[3] & grn_pwm, # tx → green D12 (PWM-dimmed)
i_RGB2PWM=led[4], i_RGB2PWM=led[4], # ready → yellow D13 (solid)
o_RGB0=Signal(name="rgb_r"), o_RGB0=rgb.r.io,
o_RGB1=Signal(name="rgb_g"), o_RGB1=rgb.g.io,
o_RGB2=Signal(name="rgb_b"), o_RGB2=rgb.b.io,
) )
# ── UART debug console/shell → FT2232H Channel B ─────────────── # ── UART debug console/shell → FT2232H Channel B ───────────────
+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": { "board": {
"active_layer": 2, "active_layer": 0,
"active_layer_preset": "", "active_layer_preset": "",
"auto_track_width": true, "auto_track_width": true,
"hidden_netclasses": [], "hidden_netclasses": [],
+1
View File
@@ -1035,6 +1035,7 @@
"netlist": "", "netlist": "",
"plot": "gerbers/", "plot": "gerbers/",
"specctra_dsn": "", "specctra_dsn": "",
"step": "",
"vrml": "" "vrml": ""
}, },
"page_layout_descr_file": "" "page_layout_descr_file": ""