# 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 LCD + 6 user buttons + 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.

**Hold the device in portrait** with the A/B/C buttons along the top and X/Y/Z along the
bottom. The firmware drives the LCD as a **240 × 320 portrait** at `display.rotation = 270` —
same UI shape as the PM_K-1 Kit, just shorter. If the screen comes up upside-down on your
unit, change `DISPLAY_ROTATION` near the top of `app.py` to `90` (or `180` if rotated 180°)
and re-flash.

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