Adds pico-explorer/ as a parallel CircuitPython firmware target alongside the 52Pi
Kit in pico-cp/. Same engine, same program-string grammar, same programs.json, same
live-sync protocol. Read-only on the device (no on-device beat editing); the web
editor's Live sync mirrors all edits in real time and the Explorer emits its own
play/stop/bpm/sel deltas back.
Hardware (Pimoroni Explorer PIM744):
- RP2350B + 2.8" ST7789V 320x240 LCD (8-bit parallel; CircuitPython's official
board definition pre-builds the BusDisplay so we just use board.DISPLAY).
- 6 user buttons - A/B/C on the left of the screen, X/Y/Z on the right.
- Piezo speaker on GP12 (PWM) with amp enable on GP13.
- I2C QwSTEMMA on GP20/21 - reserved, unused by the firmware.
- No touchscreen, no joystick, no RGB LED. Run state shows on a tiny on-screen dot.
Buttons:
- A = play/stop. B = tap tempo. C = menu.
- X = prev track (hold-repeat). Z = next track (hold-repeat).
- Y = tempo -1 (hold-repeat; -5 after 1.5s).
- X+Z chord = tempo +1 (mirrors Y).
- In a menu: X/Z move the row cursor, Y decrements, A cycles/increments/selects,
B = back, C = close.
Files added:
- pico-explorer/{boot.py, code.py, app.py, programs.json, README.md}.
app.py = 1444 lines (~73KB source -> 29.8KB compiled .mpy).
- info-explorer.html.
Files touched:
- pico-cp/app.py: bump to 0.0.23. Version-query (SysEx 0x02 -> 0x03) reply now
includes the device id as "K;<version>" (backward-compat: editor parses
"contains ';'?" - old firmware sent bare version, treated as K).
- editor.html + editor-beta.html: _parseDeviceReply() splits id;version, FW_PATHS
maps id to .py/.mpy URL pair, so Update firmware now pushes the right binary.
- build.sh + deploy.sh: precompile pico-explorer/app.py -> dist/explorer-app.mpy,
zip pm_x1_circuitpy.zip alongside pm_k1_circuitpy.zip, ship
pico-explorer-app.{py,mpy} next to pico-cp-app.{py,mpy}.
- docs/livesync-protocol.md: new section 7 - per-device emit/apply matrix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
3.9 KiB
Markdown
74 lines
3.9 KiB
Markdown
# PM_X-1 "Explorer" — CircuitPython edition (Pimoroni Explorer · RP2350)
|
||
|
||
The **CircuitPython** firmware for the [Pimoroni Explorer Kit (PIM744)](https://shop.pimoroni.com/products/explorer),
|
||
set up as a self-contained appliance. Sibling to the PM_K-1 build in `../pico-cp/` (the 52Pi EP-0172
|
||
kit) — same engine, same program strings, same `programs.json`, same web editor.
|
||
|
||
This board is a **2.8″ ST7789V 320×240 LCD + 6 user buttons (A/B/C on the left, X/Y/Z on the right)
|
||
+ piezo speaker** built around an RP2350B (Pico 2 class chip). **No touchscreen, no joystick, no
|
||
RGB LED.** Editing is done 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.
|
||
|
||
## Controls
|
||
|
||
| Button | Action |
|
||
| ------ | --------------------------------------------------------------------- |
|
||
| **A** | play / stop |
|
||
| **B** | tap tempo |
|
||
| **C** | menu (Settings / Help / About / Practice log) |
|
||
| **X** | prev track (hold to repeat) |
|
||
| **Y** | tempo −1 (hold to repeat; after ~1.5 s the step grows to −5) |
|
||
| **Z** | next track (hold to repeat) |
|
||
| **X + Z** | tempo +1 (chord; same hold-repeat as Y) |
|
||
|
||
In a menu: **X / Z** move the cursor up / down, **Y** decrements the focused value, **A** commits or
|
||
cycles, **B** = back, **C** = close.
|
||
|
||
## Install
|
||
|
||
1. **Flash CircuitPython for Pico 2 / RP2350.** Hold **BOOTSEL** on the Explorer, plug it in over
|
||
USB-C, drop the [Pimoroni Explorer (RP2350) CircuitPython `.uf2`](https://circuitpython.org/board/pimoroni_explorer2350/)
|
||
onto the `RP2350` drive. A `CIRCUITPY` drive appears.
|
||
2. **Copy the bundle onto `CIRCUITPY`** — `boot.py`, `code.py`, **`app.mpy`**, `programs.json`,
|
||
`font_s.bin` / `font_m.bin` / `font_l.bin`, `logo.bin` / `midi.bin` / `usb.bin`, `editor.html`
|
||
(offline editor). If an old `app.py` is on the drive, delete it.
|
||
3. **Power-cycle.** It boots into appliance mode and runs.
|
||
|
||
## Program it from the web
|
||
|
||
Open <https://metronome.varasys.io> in Chrome / Edge / Firefox. The set-list **⋯** menu →
|
||
**📟 Save to device** pushes a `programs.json` over USB-MIDI; the device persists it and reloads.
|
||
Click **🔗 Live sync** to mirror edits in real time.
|
||
|
||
## Pin reference
|
||
|
||
The display, buttons, and audio are wired into the board — no jumpers required. CircuitPython's
|
||
official board definition for `pimoroni_explorer2350` exposes `board.DISPLAY` pre-initialized, so
|
||
the firmware just uses it.
|
||
|
||
| Function | GPIO |
|
||
| ----------------- | -------- |
|
||
| Button A | GP16 |
|
||
| Button B | GP15 |
|
||
| Button C | GP14 |
|
||
| Button X | GP17 |
|
||
| Button Y | GP18 |
|
||
| Button Z | GP19 |
|
||
| Piezo audio (PWM) | GP12 |
|
||
| Piezo amp enable | GP13 |
|
||
| I²C SDA (QwSTEMMA) | GP20 |
|
||
| I²C SCL (QwSTEMMA) | GP21 |
|
||
| Display | `board.DISPLAY` (8080 parallel bus on GP26..GP39, initialized by board.c) |
|
||
|
||
## Calibration (flags at the top of `app.py`)
|
||
|
||
- **Speaker too loud / quiet:** the piezo + amp gain is fixed in hardware. `MUTE_SPEAKER`
|
||
silences the click; `SPEAKER_AUTO_MUTE` auto-mutes when a MIDI host is listening.
|
||
- **Buttons feel inverted:** the polarity is hard-coded to active-low (pull-up). If a button
|
||
fires on release instead of press, check the `BTN_*` pin map at the top of `app.py`.
|
||
- **Display orientation:** the board's CircuitPython init mounts the panel landscape
|
||
(320 × 240). If your screen looks rotated, that's a board.c-level thing — file a CircuitPython
|
||
bug, don't patch the firmware.
|
||
|
||
If `app.py` ever errors, CircuitPython prints the traceback **on the screen and over USB serial** —
|
||
send me that.
|