main
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
59bd3b4cea |
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 |
||
|
|
202adacf7a |
Add calibration patterns and a geometric note-to-LED map
Hardware arrives tomorrow, which makes this the blocking work: the appliance has no console, so without it there is no way to answer "is pixel 0 at the end I think it is" except by guessing. Geometric mapping. NOTE_MAP_GEOMETRIC (default on) derives each key from white-key geometry rather than semitone index: 52 white keys span the strip, so a white key is LED_COUNT/52 pixels - about 3.38 at 176 LEDs, not 2 - with black keys on the boundaries. The old linear map drifts within each octave, worst at F, by up to ~0.87 LEDs (~6mm) even after an optimal offset and scale. Set NOTE_MAP_GEOMETRIC=0 to restore it. This exposed a real bug. Under the geometric map adjacent key spans overlap, because the semitone pitch (~1.7 LEDs) is narrower than LEDS_PER_KEY. The renderer painted unlit keys black, so a key erased its lit neighbour's pixels. It now clears once and paints only lit keys. The linear map never overlapped, so this could not have been found without the geometry change. LED_OFFSET shifts every key, absorbing where the strip was actually cut and where the profile ended up. Off-strip pixels are clipped, never wrapped. Calibration patterns, selected by CC 20, with CC 21/22 setting the pixel for the walk: ends (orientation and length), octaves (mapping drift), keys (whole mapping at once), walk (finding LED_OFFSET), all (voltage droop at the far end). Patterns run at the same brightness ceiling as normal operation, so none can exceed the current budget the design already allows. tools/calibrate.sh drives all of it from the PC over ALSA MIDI, and README carries the six-step procedure in dependency order. Verified: tests pass across fourteen configurations, now including both mapping modes and positive, negative and reversed offsets. Both platforms build clean - pianoled.uf2 for RP2350 and both Circle kernel images - with no warnings from project sources. Claude-Session: https://claude.ai/code/session_01TVCB25LBsmeteWvaSMz4Ne |
||
|
|
469b321a40 |
Port to RP2040/RP2350, extract the shared logic
Raspberry Pi supply is unreliable, and Circle is Broadcom-only - there is no Allwinner or Rockchip support anywhere in its tree, so an Orange Pi is not a board swap but a restart on an unproven base. RP2040/RP2350 is the better answer: available, ~$4, and a better fit for this job than the Zero ever was. Structure. All the visualizer logic moves to src/ and is now platform-independent, depending only on ILEDStrip (four methods) with MIDI pushed in via OnMIDIPacket(). Each platform supplies a backend and a main loop. The Circle build is unchanged in behaviour and still produces both kernel images. Pico backend: - WS2812B from a PIO state machine, which clocks the 1.25us bit cell directly rather than faking it with 8 SPI bytes per data bit as the Circle build must. - TinyUSB MIDI 1.0 device. Enumerates as an ordinary ALSA port, as the Circle gadget does. Packet framing comes from the USB MIDI Code Index Number rather than being re-derived. - Mount, unmount, suspend and resume all clear held notes, so a chord held when the host goes away cannot stay lit. - Latch spacing is enforced against a timestamp, so a caller cannot start a frame inside the WS2812B reset window. Verified: builds clean for both pico (RP2040, 30052 bytes) and pico2 (RP2350, 28284 bytes), no warnings from project sources, and the Circle build still produces kernel.img and kernel7.img. Tests pass across nine configurations. Incidental findings. PIO frees both hardware SPI blocks; on a Pi Zero Circle exposes only one SPI master (DEVICES=1 for RASPPI<4) and the WS2812B driver monopolises it, so a display and the strip could not coexist there. RP2040/ RP2350 also support USB host and, on the W variants, BLE via btstack - both of which section 3a records as impossible on Circle. Also documents a known limitation found while looking at calibration: the note-to-LED map is linear in semitone index, but a keybed is not. 52 white keys span the same 1222mm, making one white key ~3.38 LEDs rather than 2. The error drifts within each octave, worst at F, by up to ~0.87 LEDs (~6mm) even after an optimal offset and scale. A geometric map would remove it. Not yet implemented. Claude-Session: https://claude.ai/code/session_01TVCB25LBsmeteWvaSMz4Ne |
||
|
|
3904703de1 |
Add Phase 1 Circle firmware
Greenfield bare-metal firmware for a Pi Zero that lights a WS2812B strip above an 88-key keybed. The Pi is a USB MIDI gadget; the PC is the host and owns the piano connection and everything else. No network stack, no filesystem, no shell. Circle is a submodule pinned to Step51. Builds kernel.img (RASPPI=1, Zero / Zero W) and kernel7.img (RASPPI=2, Zero 2 / Zero 2 W); both coexist on one card, so either model runs from the same SD. Resolves two open assumptions from the plan against the Circle sources rather than by guessing: - CWS28XXStripe clocks the waveform out over SPI at a fixed 6.4MHz, one SPI byte per LED bit. On device 0 that puts data on MOSI = GPIO10 = physical pin 19. The implied 5.28ms frame time matches the plan's arithmetic. - The USB gadget lifecycle follows sample/29-miniorgan, which already carries a USB_GADGET_MODE path. Three details the hardware forces: - The gadget destroys and recreates its CUSBMIDIDevice across a USB suspend, so the kernel re-fetches it and clears notes held at that moment. Otherwise a chord would stay lit forever when the PC sleeps. - Rendering blocks for ~5.3ms of SPI traffic, so the MIDI packet handler only records state and the main loop draws. - MAX_LIT_KEYS complements the global brightness ceiling. 176 LEDs at full white would draw ~10.5A against a 6A supply; together the two clamps make that unreachable rather than merely unlikely. Every Phase 0 product decision has a named slot in firmware/config.h, all overridable at build time via EXTRADEFINE. tests/run.sh compiles the real pianoleds.cpp against stubbed Circle headers and checks the mapping, note-off paths, range clamping and both power clamps across nine configuration variants. It verifies arithmetic, not wiring, and does not replace bench-testing on real hardware. Claude-Session: https://claude.ai/code/session_01TVCB25LBsmeteWvaSMz4Ne |