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
This commit is contained in:
@@ -149,12 +149,68 @@ make -C firmware EXTRADEFINE=-DSTRIP_REVERSED=1 # Circle
|
||||
cmake -B pico/build -S pico -DCMAKE_CXX_FLAGS=-DSTRIP_REVERSED=1 # Pico
|
||||
```
|
||||
|
||||
> **Known limitation:** the note-to-LED mapping is linear in semitone index,
|
||||
> but a real keybed is not — 52 white keys span the same 1222mm, so one white
|
||||
> key is ~3.38 LEDs rather than 2. This drifts within each octave, worst at F,
|
||||
> by up to ~0.87 LEDs (~6mm) even after an optimal offset and scale. A
|
||||
> geometric map derived from white-key positions would remove it. Not yet
|
||||
> implemented.
|
||||
### Note-to-LED mapping
|
||||
|
||||
`NOTE_MAP_GEOMETRIC` (default 1) derives each key's position from white-key
|
||||
geometry: 52 white keys span the strip, so a white key is `LED_COUNT / 52`
|
||||
pixels — **~3.38 at 176 LEDs, not 2** — with black keys on the boundaries.
|
||||
|
||||
Setting it to 0 restores the plan's original `(note - 21) * 2`. That map is
|
||||
linear in semitone index, but a keybed is not: it drifts within each octave,
|
||||
worst at F, by up to ~0.87 LEDs (~6mm) even after an optimal offset and scale.
|
||||
Keep it only to reproduce the original behaviour.
|
||||
|
||||
One consequence of the geometric map: adjacent key spans **overlap**, because
|
||||
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.
|
||||
|
||||
## Calibration
|
||||
|
||||
This is a headless appliance, so calibration runs over MIDI — the one channel
|
||||
that already exists. `tools/calibrate.sh` drives it from the PC:
|
||||
|
||||
```sh
|
||||
tools/calibrate.sh list # find the port
|
||||
tools/calibrate.sh ends # pixel 0 (red), last pixel (green)
|
||||
tools/calibrate.sh octaves # every C, middle C in red
|
||||
tools/calibrate.sh keys # every key: white green, black blue
|
||||
tools/calibrate.sh walk 37 # one pixel only
|
||||
tools/calibrate.sh sweep # walk every pixel in turn
|
||||
tools/calibrate.sh all # every pixel — voltage droop test
|
||||
tools/calibrate.sh off # back to normal
|
||||
```
|
||||
|
||||
A pattern replaces the note display entirely while it is active; `off`
|
||||
restores it.
|
||||
|
||||
### Procedure
|
||||
|
||||
Work in this order — each step depends on the one before.
|
||||
|
||||
1. **`ends`** — one pixel lights at each end of the strip. If red is at the
|
||||
treble end, set `STRIP_REVERSED 1` and rebuild. If either end is dark, the
|
||||
strip is not the length `LED_COUNT` assumes.
|
||||
2. **`all`** — every pixel white. Watch the far end: if it drifts dim or warm,
|
||||
the strip needs 5V injected at that end too. This draws roughly
|
||||
`LED_COUNT × 3 × GLOBAL_BRIGHTNESS/255 × 20mA` — about 4A at the defaults,
|
||||
inside a 6A supply but well beyond normal play, which caps at
|
||||
`MAX_LIT_KEYS`.
|
||||
3. **`keys`** — every key lit, whites and blacks in different colours. Check
|
||||
the colours line up with the actual keys across the whole span. This is the
|
||||
fastest way to see a mapping or length error.
|
||||
4. **`octaves`** — every C, middle C in red. Drift shows up as the marks
|
||||
walking off the keys as you move up the keyboard. With the geometric map
|
||||
they should stay put.
|
||||
5. **`sweep`** or **`walk <n>`** — step one pixel at a time until you find the
|
||||
pixel sitting over A0. If that is not the pixel the firmware expects, the
|
||||
difference is your `LED_OFFSET`. Set it and rebuild.
|
||||
6. **`chromatic`** — plays every key in turn. Watch for the lit span leading
|
||||
or lagging the key as it climbs.
|
||||
|
||||
Then decide the product questions the firmware cannot: colours *through the
|
||||
diffuser* (not bare), brightness, and whether velocity should modulate
|
||||
anything. All of them live in `src/config.h`.
|
||||
|
||||
## MIDI behaviour
|
||||
|
||||
@@ -165,6 +221,8 @@ cmake -B pico/build -S pico -DCMAKE_CXX_FLAGS=-DSTRIP_REVERSED=1 # Pico
|
||||
for the plan's Phase 3 "light the next key to play". A key actually being
|
||||
played takes precedence over a hint on the same key.
|
||||
- Notes held when the USB host suspends are cleared, so nothing stays lit.
|
||||
- CC 20 selects a calibration pattern; CC 21/22 set the pixel for the walk
|
||||
pattern. See **Calibration** above.
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user