# 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.
