Files
rebbarb/.claude/skills/flash-re-bba-rb/SKILL.md
T
Roflin 1a7f0689ab Enable in-container USB flashing + flash-re-bba-rb skill; find U7 EEPROM undersized
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>
2026-08-22 14:44:43 +00:00

5.7 KiB

name, description
name description
flash-re-bba-rb 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:
    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.

# 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):

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.

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