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>
3.9 KiB
PM_X-1 "Explorer" — CircuitPython edition (Pimoroni Explorer · RP2350)
The CircuitPython firmware for the Pimoroni Explorer Kit (PIM744),
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
- Flash CircuitPython for Pico 2 / RP2350. Hold BOOTSEL on the Explorer, plug it in over
USB-C, drop the Pimoroni Explorer (RP2350) CircuitPython
.uf2onto theRP2350drive. ACIRCUITPYdrive appears. - 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 oldapp.pyis on the drive, delete it. - 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_SPEAKERsilences the click;SPEAKER_AUTO_MUTEauto-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 ofapp.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.