Add boot self-test and idle indicator; target the Waveshare RP2350-Plus

The board arriving is a Waveshare RP2350-Plus (4MB, USB-C), which is now the
default BOARD. Its pico-sdk header defines neither PICO_DEFAULT_LED_PIN nor
PICO_DEFAULT_WS2812_PIN - it has no onboard indicator at all - so a bare board
gives no sign of life. The status-LED support added for boards that do have one
(zero, one, tiny, usb_a on GPIO16; eth on GPIO25) is kept and compiles out here.

That makes feedback on the strip itself the useful path, and it turns out to be
the better one anyway:

- Boot self-test sweeps one pixel from index 0 to the far end once at startup.
  It answers in a single glance whether the firmware runs, PIO drives the line,
  the strip is the length LED_COUNT claims, the far end holds voltage, and -
  because you see which end it starts from - whether STRIP_REVERSED is right.
  It runs before USB, so the first test needs nothing but 5V.
- Idle indicator holds one dim pixel lit while no host is connected, separating
  "powered and waiting" from "no power" and from "crashed".

Both are platform-independent, so the Circle build gets them too.

Verified: tests pass across seventeen configurations, now including the
self-test and idle paths on and off. Both platforms build clean with no
warnings from project sources.

Note on the previous commit's verification: a filtered build log hid a real
compile error in the Pico target (sleep_ms takes uint32_t, which is unsigned
long here, and did not match the portable void(*)(unsigned) delay callback).
The build script now gets an explicit success check rather than a grep.

Claude-Session: https://claude.ai/code/session_01TVCB25LBsmeteWvaSMz4Ne
This commit is contained in:
prosolis
2026-08-27 23:22:56 -07:00
parent 202adacf7a
commit 59bd3b4cea
10 changed files with 307 additions and 14 deletions
+33 -3
View File
@@ -57,9 +57,20 @@ PICO_SDK_PATH=/path/to/pico-sdk ./pico/build.sh
Produces `pico/build/pianoled.uf2`. Hold BOOTSEL while plugging the board in
and copy the `.uf2` onto the drive that appears.
`BOARD` selects the target (`pico`, `pico2`, `pico_w`, `pico2_w`; default
`pico2`). All four run this firmware unchanged — the radio variants simply
leave their radio unused.
`BOARD` selects the target; the default is `waveshare_rp2350_plus_4mb`
(Waveshare RP2350-Plus, 4MB, USB-C). pico-sdk 2.3.0 also ships definitions for
eleven other Waveshare RP2350 boards and the stock `pico`/`pico2`:
```sh
ls "$PICO_SDK_PATH"/src/boards/include/boards/ | grep rp2350
BOARD=waveshare_rp2350_zero ./pico/build.sh
```
Note the RP2350-Plus has **no onboard LED** — its board header defines neither
`PICO_DEFAULT_LED_PIN` nor `PICO_DEFAULT_WS2812_PIN`, so the status-LED code
compiles out. Boards that do have one (`zero`, `one`, `tiny`, `usb_a` on
GPIO16; `eth` on GPIO25) get it automatically. On boards without, the boot
self-test and idle indicator on the strip itself are the feedback.
The strip data pin is `WS2812_PIN` in `src/config.h`, default GPIO2. PIO can
drive it from any GPIO, so this is a free choice.
@@ -165,6 +176,25 @@ the semitone pitch (~1.7 LEDs) is narrower than `LEDS_PER_KEY`. That is
expected, and the renderer paints only lit keys so a neighbour cannot erase
them.
## First power-up
Two things run before any PC is involved, so a bare board on a bench still
tells you something:
- **Boot self-test** — one pixel sweeps from index 0 to the far end, once, then
clears. Watching it answers, in a single glance: the firmware runs, PIO
drives the data line, the strip is the length `LED_COUNT` claims, the far end
still has voltage, and — because you see which end it starts from — whether
`STRIP_REVERSED` is the right way round.
- **Idle indicator** — while no USB host is connected, one dim pixel stays lit
at the strip's start. This distinguishes "powered and waiting for the PC"
from "no power" and from "crashed".
Both are on by default (`BOOT_SELF_TEST`, `IDLE_INDICATOR` in `src/config.h`).
So the very first test needs nothing but 5V: power the strip and the board, and
watch for the sweep.
## Calibration
This is a headless appliance, so calibration runs over MIDI — the one channel