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