New form factor: a plain RP2040 Pico + Pico Scroll Pack (PIM545) -- a 17x7 single-colour LED matrix + 4 buttons. The 7x17 matrix maps onto the editor's lane x step pad grid. - pico-scroll/: CircuitPython firmware (DEVICE_ID "G"). Engine/scheduler/SysEx/ live-sync copied verbatim from pico-explorer (engine byte-identical, so it stays on the track-format conformance lineage); vendored bulk-framebuffer IS31FL3731 driver (pins/map verified from pimoroni-pico); three LED views (Grid/Pendulum/BPM); 4-button input. Audio over USB-MIDI (no onboard speaker); optional P_BUZZER. - grid.html + info-grid.html: widget page (canvas mirrors the 3 LED views) + spec page with a ~$29 BOM. - Registered in build.sh (precompile + ASCII assert + pm_g1_circuitpy.zip), deploy.sh, embed.js, embed.html, index.html gallery, and both editors' FW_PATHS (device id G). - docs/rust-port.md: core/driver architecture (pm-core no_std engine+protocol; per-board drivers behind embedded-hal/embedded-graphics traits). CLAUDE.md + livesync-protocol.md note the new edition + device id. Python firmware stays in parallel with Rust (no abandonment yet). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
4 KiB
Markdown
67 lines
4 KiB
Markdown
# PM_G-1 "Grid" — CircuitPython edition (Pimoroni Pico Scroll Pack · RP2040)
|
||
|
||
The **CircuitPython** firmware for the [Pimoroni Pico Scroll Pack (PIM545)](https://shop.pimoroni.com/products/pico-scroll-pack)
|
||
on a plain **Raspberry Pi Pico**, set up as a self-contained appliance. Sibling to the PM_K-1 build
|
||
in `../pico-cp/` and PM_X-1 in `../pico-explorer/` — **same engine, same program strings, same
|
||
`programs.json`, same web editor, same live-sync protocol.**
|
||
|
||
This board is a **17 × 7 single-colour (white) LED matrix** (IS31FL3731 over I²C) **+ 4 buttons
|
||
(A/B/X/Y)** — *no touchscreen, no joystick, no RGB LED, and no onboard speaker.* It's the smallest,
|
||
most minimal form factor: the 7-row × 17-column grid **is** the editor's lane × step pad grid in
|
||
miniature. Editing happens in the web editor with **Live sync** on; the device mirrors changes in
|
||
real time and emits its own play/stop/bpm/sel deltas back.
|
||
|
||
**Audio** is over **USB-MIDI** — turn on the editor's **🎹 Device audio** to hear the clicks through
|
||
your computer's speakers. The Scroll Pack has no buzzer; if you solder a piezo to a free GPIO, set
|
||
`P_BUZZER` near the top of `app.py` to that pin to get an on-device click.
|
||
|
||
## Views (button **B** cycles)
|
||
|
||
| View | What the 17 × 7 matrix shows |
|
||
| ---- | ---------------------------- |
|
||
| **Grid** (default) | Each lane is a **row** (top 7), each step a **column**; brightness = accent (bright) / normal / ghost (dim). A bright **playhead** column tracks the beat. Bars with ≤ 17 steps are centred one-column-per-step; longer bars are scaled to fit (multiple steps may share a column — no steps are dropped). |
|
||
| **Pendulum** | A single column **bounces** left↔right across the bar like a metronome arm, with a full-height flash on each beat (accent = brightest). Glanceable from across a room. |
|
||
| **BPM** | The current tempo as three 3 × 5 digits. |
|
||
|
||
## Controls
|
||
|
||
| Button | Tap | Hold |
|
||
| ------ | --- | ---- |
|
||
| **A** | play / stop | **≥ 0.6 s:** cycle view (Grid → Pendulum → BPM) |
|
||
| **B** | next track | **≥ 0.6 s:** next set list |
|
||
| **X** | tempo − 1 | auto-repeat (after ~1.5 s the step grows to − 5) |
|
||
| **Y** | tempo + 1 | auto-repeat (after ~1.5 s the step grows to + 5) |
|
||
|
||
Tap tempo lives in the web editor; the built-in playlists (Styles / Practice / Song) are baked into
|
||
firmware and your own set lists arrive in `/programs.json` over USB-MIDI. The mapping is deliberately
|
||
simple (this is a UI prototype) — all four buttons and their pins are at the top of `app.py`, easy to
|
||
re-bind.
|
||
|
||
## Pinout (verified against the Pimoroni `pico_scroll` library)
|
||
|
||
| Signal | Pico pin |
|
||
| ------ | -------- |
|
||
| Button A / B / X / Y | GP12 / GP13 / GP14 / GP15 |
|
||
| Matrix I²C SDA / SCL | GP4 / GP5 |
|
||
| IS31FL3731 address | `0x74` |
|
||
| (optional piezo) | any free GPIO → set `P_BUZZER` |
|
||
|
||
## Flashing
|
||
|
||
1. Hold **BOOTSEL**, plug the Pico in, and drag on **CircuitPython for Raspberry Pi Pico** (the same
|
||
10.2.x build the Kit uses). The drive remounts as `CIRCUITPY`.
|
||
2. Download **`/pm_g1_circuitpy.zip`** from <https://metronome.varasys.io> and unzip its contents onto
|
||
`CIRCUITPY` (`code.py`, `boot.py`, `app.mpy`, `programs.json`, fonts/icons, `editor.html`).
|
||
3. Reset. By default the firmware owns the drive (appliance mode); **hold button A while plugging in**
|
||
to make the drive writable again (editor mode).
|
||
|
||
The application is the precompiled **`app.mpy`** (the ~25 KB `app.py` source is too big to compile
|
||
on-device without OOM). Firmware updates are **one click** from the editor (⋯ → Update firmware),
|
||
pushed over USB-MIDI as an A/B update with automatic rollback — the device reports id **`G`** so the
|
||
editor sends the Grid build. Unbrickable: BOOTSEL + drag a `.uf2` always restores it.
|
||
|
||
## Status
|
||
|
||
This is the **CircuitPython prototype** used to nail down the LED-grid UI on real hardware. The
|
||
production firmware target is the native-Rust engine (one `pm-core` + per-board drivers — see
|
||
`docs/rust-port.md`); the Python builds stay as the simple, no-toolchain option in parallel.
|