Skip to content

feat(rp2040): zero-touch deployment to an as-received Pico via ROM UF2 #1040

Description

@zackees

Context

Parent: FastLED/FastLED#3626

fbuild can compile the FastLED AutoResearch firmware for the canonical rp2040 environment (rpipico, Earle Philhower Arduino-Pico), but fbuild 2.4.0 and current main have no Platform::RaspberryPi deploy dispatch. The attached Pico produces firmware.bin and firmware.elf, then fails with:

deploy failed: deployer for RaspberryPi not yet implemented

The attached Amazon-purchased Pico 1 is in its as-received state and presents as a healthy Windows USB mass-storage device:

VID:PID: 2E8A:0003
Volume: RPI-RP2
UF2 Bootloader v3.0
Model: Raspberry Pi RP2
Board-ID: RPI-RP2

It has no COM port, so current fbuild port scan does not report it. Windows can use its mass-storage interface, while the separate RP2 Boot vendor interface currently has a device error. The default stock-board path therefore must not assume a working libusb/vendor driver or require Zadig.

This is not a requirement to put the Pico into a non-default state. RP2040 boot ROM checks the flash second-stage CRC and automatically enters USB device boot after about 0.5 seconds when no valid image is present. A factory-blank or invalid-flash Pico can naturally enumerate as RPI-RP2 without pressing BOOTSEL. See RP2040 datasheet section 2.8.1, page 130:

https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf

Current hardware status (2026-07-15)

The attached board automatically enters ROM USB without a physical BOOTSEL press, so BOOTSEL entry is not the problem. Merged fbuild #1072 loaded a RAM-only UF2 repeatedly through the same stock Windows mass-storage path; the volume ejected/re-enumerated and no Disk 51/153 events occurred. Flash-target UF2 alone stalls during the ROM's external-QSPI erase/program operation. This isolates a board-level QSPI fault on serial E0C9125B0D9B; it supersedes earlier hypotheses involving the hub, Windows host access, synthetic-volume corruption, copy semantics, or fltsrv.

Software implementation and deterministic coverage are complete. A known-good replacement Pico 1 now passes normal flash, application CDC, JSON-RPC, watchdog recovery, and ten consecutive subsequent-deploy cycles. The fbuild-only first deployment from an as-received blank/invalid-flash replacement remains open because the user-requested PlatformIO A/B ran first on that unit.

Proposal

Implement a Raspberry Pi deployer around the proven upstream flows rather than creating a new deploy repository or requiring host-installed tools.

Prior art to reuse

  1. Arduino-Pico 4.5.3 generates UF2 with its managed pqt-picotool, optionally performs a 1200-bps serial reset, finds an RPI-RP2 volume by INFO_UF2.TXT, and copies NEW.UF2:

  2. maxgerhardt/platform-raspberrypi already has an already-in-ROM-USB fast path and a 1200-bps reset/wait path:

  3. Arduino-Pico's normal USB serial firmware supports the 1200-bps/DTR reset even without the optional picotool vendor interface:

Required deployment sequence

  1. Resolve rp2040 to the existing rpipico board definition.
  2. Build a Pico 1 UF2 artifact with the correct RP2040 family ID.
  3. Inventory USB boot targets independently of serial ports.
  4. If an RPI-RP2 target is already present, identify it through INFO_UF2.TXT / Board-ID and deploy without requiring -p.
  5. Otherwise, when a compatible application CDC port exists, perform the standard 1200-bps reset and wait for the matching boot volume.
  6. Copy the UF2 through the driverless mass-storage interface by default.
  7. Wait for the boot volume to eject and the application CDC device to enumerate.
  8. Return the actual post-deploy port identity in DeploymentResult; do not assume the old COM name remains valid.

Picotool may be supported as an optional direct transport after its Windows, Linux, and macOS behavior is validated, but picotool load -f must not be assumed to work identically everywhere. The zero-touch stock Windows acceptance path is standard USB mass storage.

Cross-repository development and release workflow

Use ~/dev/fbuild as the authoritative source checkout and ~/dev/fastled as the hardware consumer. Fix deploy problems in fbuild; do not copy deploy code or add a raw uploader workaround in FastLED, and do not wait for a PyPI release between milestones.

1. Link the fbuild checkout into FastLED

Start from current main in both repositories. Sync FastLED once, then replace its released wheel with an editable build of the sibling checkout:

cd ~/dev/fastled
uv sync
uv pip install --python .venv/Scripts/python.exe --reinstall --no-deps -e ../fbuild

On Linux/macOS, use .venv/bin/python. Confirm the version, editable project location, and source commit before accepting hardware evidence:

cd ~/dev/fastled
FBUILD_DEV_MODE=1 UV_NO_SYNC=1 uv run fbuild --version
uv pip show fbuild
git -C ../fbuild rev-parse HEAD

Keep UV_NO_SYNC=1 set for bash autoresearch; its nested uv run would otherwise restore FastLED's released pin. FBUILD_DEV_MODE=1 isolates development daemon/cache state. Never commit a local/editable dependency path to FastLED. After fbuild Rust or Python changes, rerun the editable-install command so the native package is rebuilt before retesting.

2. Merge fbuild work at major milestones

Implement and validate these coherent fbuild milestones in order:

  1. UF2 artifact/tooling: generate the correct Pico 1/RP2040 UF2 with managed tooling.
  2. Stock-board discovery/deploy: discover RPI-RP2 without a serial port and deploy to the stock ROM-boot volume without -p.
  3. Reset/CDC handoff: add 1200-bps reset, boot-volume transition, CDC reacquisition, and the actual new port in DeploymentResult.
  4. Portability/hardening: cover Windows/Linux/macOS, typed failures, multi-device safety, and the attached-board soak.

For every milestone:

  1. Add focused fbuild tests and run all fbuild-required lint/test gates.
  2. Reinstall the editable fbuild checkout into FastLED.
  3. Run the relevant attached-Pico AutoResearch command with FBUILD_DEV_MODE=1 UV_NO_SYNC=1.
  4. Record the exact fbuild commit SHA, command, VID:PID/board identity, volume/port transition, and decisive output here.
  5. Push a focused fbuild PR linked to feat(rp2040): zero-touch deployment to an as-received Pico via ROM UF2 #1040 and meta(rp2040): Pico 1 AutoResearch bring-up (superseded by #3648) FastLED#3626, then admin-merge it after tests and hardware evidence pass.
  6. Update ~/dev/fbuild/main, relink the merged commit, and continue.

Do not publish an interim fbuild release for each milestone.

3. Publish once, then restore FastLED to a release pin

Open the release gate only after every fbuild-owned issue/checklist linked from FastLED/FastLED#3626, including this issue, is resolved and the stock-board evidence passes.

  1. In ~/dev/fbuild, bump the Rust workspace and Python project versions together in a release PR.
  2. Run complete release validation, push the PR, and admin-merge it.
  3. Let fbuild's autonomous release workflow create the tag, GitHub release, and PyPI artifacts; do not tag or publish manually.
  4. Verify the published version and platform artifacts.
  5. In FastLED, pin that published version, extend the pin history, and run uv sync without UV_NO_SYNC to remove the editable override and restore the release wheel.
  6. Verify uv run fbuild --version reports the published version, then run:
    bash autoresearch rp2040 --rpc-smoke --timeout 120s
  7. Push the FastLED release-pin PR and admin-merge it after validation.

Final closeout must link all milestone PRs, the fbuild release, the FastLED pin-restoration PR, and the decisive stock-board hardware log.

Acceptance criteria

Stock first deployment

  • Test a newly purchased, as-received genuine Pico 1 connected normally by USB.
  • Do not press BOOTSEL, manually replug it, choose a COM port, install Zadig/vendor drivers, or copy a UF2 manually.
  • fbuild deploy <project> -e rp2040 detects the 2E8A:0003 / RPI-RP2 device and succeeds without -p.
  • The generated artifact is firmware.uf2 for Pico 1/RP2040, not only BIN/ELF. Verified by merged fix(rp2040): match upstream UF2 deploy semantics #1050 and regression coverage.
  • The volume ejects, the program boots, application CDC appears, and DeploymentResult contains the new port.

Subsequent deployment

  • A FastLED/Arduino-Pico application is reset automatically through 1200-bps CDC touch.
  • fbuild waits for ROM USB boot, writes UF2, waits for CDC, and returns the current port.
  • Ten consecutive deploy -> reboot -> CDC cycles pass without a stale port, wrong device, or manual intervention.

State and error matrix

Portability and tests

  • Unit/integration coverage exercises USB-volume discovery, first deployment without a port, 1200-bps transition, volume disappearance, and CDC handoff.
  • Windows, Linux, and macOS mount/discovery behavior is covered.
  • The stock path has no dependency on a host-installed uploader or PATH lookup; managed tools are checksum-pinned.
  • Physical evidence records the board VID:PID, INFO_UF2.TXT, exact fbuild command, volume transition, returned port, and decisive output.

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions