1a7f0689ab
Devcontainer now grants libusb access to the FT2232H so iceprog (bitstream) and pyftdi (FT2232H EEPROM) run inside the container: - devcontainer.json: --privileged + /dev/bus/usb bind mount - Dockerfile: sudo (NOPASSWD for vscode; USB nodes are root-owned), libusb-1.0-0, libftdi1-2, pyftdi Add the flash-re-bba-rb skill documenting the procedure (bitstream via best swept seed, optional EEPROM string, troubleshooting, guardrails) and flash_ftdi_eeprom.py (pyftdi, backup-first, dry-run default) + ftdi_eeprom.conf value spec. Bring-up on the repaired V1 unit: bitstream flash VERIFY OK (iceprog build/seed4/top.bin, capture 58.36 MHz). EEPROM product string CANNOT be programmed on V1 — U7 is a 93LC46B (128 B), too small for the FT2232H, which needs a 93LC56B (256 B); the 128 B chip mirrors and the config write fails verify. This overturns the old REVIEW note "93LC46B = correct for FT2232H" (that only checked ORG, not size). Board still works blank -> ROM defaults; iceprog + UART unaffected. Documented in REVIEW.md + TODO.md (swap U7->93LC56B for V2); flash_ftdi_eeprom.py detects the mirroring and refuses the write. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
117 lines
5.7 KiB
Markdown
117 lines
5.7 KiB
Markdown
---
|
|
name: flash-re-bba-rb
|
|
description: Use when flashing the re-bba-rb board (GC BBA FPGA replacement) — programming the iCE40UP5K bitstream with iceprog and/or the FT2232H EEPROM product string ("re-BBA-rb") with pyftdi, from inside the WSL2 devcontainer. Covers USB passthrough prerequisites, best-seed bitstream selection, sudo/libusb access, and backup-first EEPROM programming.
|
|
---
|
|
|
|
# Flashing the re-bba-rb board
|
|
|
|
The board is FT2232H (USB) → iCE40UP5K (FPGA) + W5100S (ethernet). Two flashable
|
|
targets, done **in this order**:
|
|
|
|
1. **FPGA bitstream** via `iceprog` (MPSSE on FT2232H channel A) — the functional
|
|
flash. Do this first; it works with a blank EEPROM.
|
|
2. **FT2232H EEPROM** product string via `pyftdi` — cosmetic ("re-BBA-rb" instead
|
|
of "Dual RS232-HS"). Optional, do it only after the bitstream is proven.
|
|
|
|
Both need USB access to the FT2232H (VID:PID `0403:6010`) from inside the
|
|
container. The `vscode` user reaches the root-owned `/dev/bus/usb` nodes via
|
|
passwordless `sudo`.
|
|
|
|
## Prerequisites (once per session)
|
|
|
|
1. **Container built with USB access.** `.devcontainer/` must have `--privileged`,
|
|
the `/dev/bus/usb` bind mount, `sudo`, `libusb-1.0-0`, `libftdi1-2`, and
|
|
`pyftdi`. If `.devcontainer/` was just edited, the user must **rebuild the
|
|
container** — those changes are baked at build/create time.
|
|
2. **Device attached to WSL2.** On the Windows host, as Administrator:
|
|
`.devcontainer/attach-icebreaker.ps1` (wraps `usbipd attach`). Attach before
|
|
or after container start — the bind mount is live, so a later attach still
|
|
appears.
|
|
3. **Confirm the device is visible from inside the container:**
|
|
```bash
|
|
ls /dev/bus/usb/*/* # nodes must exist
|
|
sudo /opt/venv/bin/python -c "import usb.core,usb.backend.libusb1 as b; \
|
|
print(usb.core.find(idVendor=0x0403, idProduct=0x6010, backend=b.get_backend()))"
|
|
```
|
|
A non-`None` device object means libusb can see it. If `/dev/bus/usb` is empty,
|
|
the device is not attached (fix on the Windows side) — see Troubleshooting.
|
|
|
|
## Step 1 — Flash the FPGA bitstream
|
|
|
|
The design's `capture` domain (54 MHz) closes on only a **minority of seeds** —
|
|
always sweep and flash the **best passing** seed, never the default seed-1 build.
|
|
|
|
```bash
|
|
# Build all 8 seeds (from workspace root). Prints the best passing seed + path.
|
|
python -m exi_bba.synth --seeds 8
|
|
```
|
|
Note the reported best seed, e.g. `Best seed: 4 ... build/seed4/top.bin`. (As of
|
|
the last build: **seed 4, `build/seed4/top.bin`, capture 58.36 MHz**, 4/8 pass.
|
|
`build/` is on the host bind mount, so it survives container rebuilds.)
|
|
|
|
Flash it (SRAM-less part → `iceprog` writes the SPI flash; the FPGA boots from
|
|
it):
|
|
```bash
|
|
sudo iceprog build/seed4/top.bin # substitute the reported best-seed path
|
|
```
|
|
Expect `iceprog` to detect the FTDI, erase, write, and **verify OK**. If it says
|
|
"Can't find iCE FTDI USB device", the USB passthrough is not working — see
|
|
Troubleshooting. After a successful flash, power-cycle / re-plug to boot the new
|
|
image.
|
|
|
|
`ICEPROG=/path/to/iceprog` overrides the binary if needed; the container's is on
|
|
`PATH`.
|
|
|
|
## Step 2 — Program the FT2232H EEPROM (optional, cosmetic)
|
|
|
|
Only after Step 1 verifies. This changes **descriptor strings only** — VID/PID
|
|
`0403:6010` and the dual-channel config are preserved, so `iceprog` and the
|
|
channel-B UART keep working. Values live in `hardware/re-bba-rb/flash_ftdi_eeprom.py`
|
|
(and mirror `hardware/re-bba-rb/ftdi_eeprom.conf`): manufacturer `hashru`,
|
|
product `re-BBA-rb`, serial `RBBARB001`.
|
|
|
|
```bash
|
|
# Dry-run first: dumps a backup (eeprom-backup.bin) + prints the diff, no write.
|
|
sudo /opt/venv/bin/python hardware/re-bba-rb/flash_ftdi_eeprom.py
|
|
|
|
# If the diff looks right, commit:
|
|
sudo /opt/venv/bin/python hardware/re-bba-rb/flash_ftdi_eeprom.py --commit
|
|
```
|
|
The script always writes `hardware/re-bba-rb/eeprom-backup.bin` before staging
|
|
changes. After `--commit`, re-plug / re-attach USB so the host re-reads
|
|
descriptors; the unit then shows as **re-BBA-rb**.
|
|
|
|
To restore the backup later, use `pyftdi`/`ftdi_eeprom` to write
|
|
`eeprom-backup.bin` back (raw image).
|
|
|
|
## Troubleshooting
|
|
|
|
- **`/dev/bus/usb` empty / device object is `None`** → not attached to WSL2. Run
|
|
`.devcontainer/attach-icebreaker.ps1` (admin) on Windows; check
|
|
`usbipd list` shows the FT2232H `Attached`. If the WSL2 kernel lacks usbfs,
|
|
`/dev/bus/usb` won't populate at all — update WSL (`wsl --update`).
|
|
- **`Permission denied` / `LIBUSB_ERROR_ACCESS`** → run the command under `sudo`
|
|
(the nodes are root-owned). Both `iceprog` and the pyftdi script need it.
|
|
- **`iceprog` can't find the device but `pyftdi` sees it (or vice-versa)** → a
|
|
kernel driver (`ftdi_sio`) may hold an interface. `iceprog`/`pyftdi` detach it
|
|
automatically under sudo; if stuck, `sudo modprobe -r ftdi_sio` (or re-attach
|
|
the device) and retry.
|
|
- **`iceprog` verify fails / flakey** → the drilled-out-via repair on this V1
|
|
unit may have damaged a flash/CDONE/CRESET trace; check continuity of the SPI
|
|
flash lines and CRESET_B/CDONE to the FPGA before assuming gateware fault.
|
|
- **FPGA boots but the GC won't enumerate the BBA** → this is a *timing* seed
|
|
issue, not a flash issue. Re-flash the reported **best passing** seed (the
|
|
capture domain fails on ~half of seeds). See CLAUDE.md "Current Implementation
|
|
State".
|
|
|
|
## Guardrails
|
|
|
|
- **Bitstream before EEPROM** — the EEPROM string is cosmetic and never worth
|
|
risking before the board is functionally proven.
|
|
- **Never change VID/PID** in the EEPROM — `iceprog` and D2XX look for
|
|
`0403:6010`. The script/conf keep it; don't override.
|
|
- **Always flash the swept best-seed** `.bin`, never a no-`--seeds` seed-1 build
|
|
(capture timing fails on it).
|
|
- Keep the EEPROM backup (`eeprom-backup.bin`) until the string change is
|
|
confirmed good on the host.
|