metronome/info-explorer.html
Me Here 3192f3debc PM_X-1 0.0.1: Pimoroni Explorer sibling firmware + Kit 0.0.23 device-id reply
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>
2026-05-30 20:43:38 -05:00

169 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VARASYS PM_X-1 Explorer - wiring, parts &amp; firmware (Pimoroni Explorer / RP2350)</title>
<meta name="description" content="PM_X-1 Explorer - the Pimoroni Explorer (PIM744, RP2350) as a 6-button polymeter metronome with live-sync to the web editor. Pinout, parts list, and the precompiled CircuitPython firmware bundle." />
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,@BUILD:favicon@">
<script>
(function(){ try{ var p = localStorage.getItem("metronome.theme");
if (p!=="light" && p!=="dark" && p!=="system") p = "system";
document.documentElement.dataset.theme = p==="system" ? (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p;
} catch(e){ document.documentElement.dataset.theme = "dark"; } })();
</script>
<style>
/*@BUILD:include:src/base.css@*/
:root{ --bg1:#12151c; --bg2:#05070a; --txt:#c7d0db; --muted:#7f8b9a; --link:#6cb6ff;
--panel-bg:#161b22; --panel-bd:#2a313c; --field-bg:#0e1116; --field-bd:#2a313c; --silk:#aab2bc; }
:root[data-theme="light"]{ --bg1:#f5f8fc; --bg2:#dde4ec; --txt:#1e2630; --muted:#5c6776; --link:#1769c4;
--panel-bg:#ffffff; --panel-bd:#d2dae4; --field-bg:#f1f4f8; --field-bd:#d2dae4; }
body{ margin:0; min-height:100vh; padding:22px 16px 56px; color:var(--txt);
background:radial-gradient(circle at 50% -8%, var(--bg1), var(--bg2)); }
a{ color:var(--link); }
main{ width:100%; max-width:980px; margin:0 auto; }
.info-hero{ text-align:center; padding:16px 8px 2px; }
.info-hero h1{ font-size:clamp(24px,5vw,36px); margin:0; letter-spacing:-.01em; }
.info-hero .sub{ margin:9px auto 0; max-width:64ch; font-size:14.5px; }
.steps{ width:100%; max-width:760px; margin:8px auto 0; color:var(--muted); font-size:14px; line-height:1.6; }
.steps li{ margin:5px 0; }
.steps code, .about code, .sub code { background:var(--field-bg); border:1px solid var(--field-bd); border-radius:5px; padding:1px 5px; font-size:12.5px; }
.dl{ display:inline-flex; align-items:center; gap:7px; margin:4px 10px 4px 0; padding:9px 14px; border-radius:10px;
background:linear-gradient(180deg,#34c6ff,var(--cyan)); color:#04121b; font-weight:700; text-decoration:none; font-size:13.5px; }
.dl.alt{ background:var(--field-bg); color:var(--txt); border:1px solid var(--field-bd); font-weight:600; }
</style>
</head>
<body>
/*@BUILD:include:src/header.html@*/
<main>
<section class="info-hero">
<h1>PM_X-1 Explorer</h1>
<p class="sub">The off-the-shelf <b>Pimoroni Explorer Kit</b> (RP2350, 2.8&quot; LCD, 6 buttons, piezo) as a polymeter metronome - sibling to the PM_K-1 Kit, sharing the engine, program-string grammar, and live-sync protocol with the web editor.</p>
</section>
<section class="about">
<h2>What it is</h2>
<div class="ff-tags"><span class="hw">Buildable now</span><span>RP2350 (Pico 2 class)</span><span>Pimoroni Explorer PIM744</span><span>~$60</span></div>
<p>The <a href="https://shop.pimoroni.com/products/explorer" target="_blank" rel="noopener">Pimoroni Explorer Kit (PIM744)</a> is a finished
development board: <b>RP2350B</b> built in, <b>2.8&quot; ST7789V 320x240 IPS LCD</b>, <b>6 user buttons</b> (A/B/C
on the left of the screen, X/Y/Z on the right), a <b>piezo speaker</b>, USB-C, a JST-PH battery
connector, and a mini breadboard with 6 GPIOs / 3 ADCs broken out for sensor projects. No soldering;
you flash CircuitPython and drop the firmware on. <b>No touchscreen, no joystick, no RGB LED</b> -
everything is driven from the 6 buttons.</p>
<p>It runs the same <b>polymeter engine</b> and the same <b>program strings</b> as the web editor.
Beat editing is done in the browser; <b>Live sync</b> mirrors edits to the device in real time
(HELLO/FULL/DELTA over USB-MIDI), and the device mirrors play/stop/tempo/track changes back. The
piezo clicks; a tiny on-screen dot shows run state.</p>
</section>
<details class="spec" open>
<summary>Wiring - the Pimoroni Explorer fixed pinout (no breadboarding required)</summary>
<div class="spec-body">
<p class="sub">Everything is wired on the board; this is what the firmware reads. The display is driven by an 8-bit parallel bus initialised by CircuitPython's official board definition - we use <code>board.DISPLAY</code> directly.</p>
<table class="bom">
<thead><tr><th>Component</th><th>RP2350 pins</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="2">Display - 2.8&quot; ST7789V, 320x240 (8-bit parallel 8080)</td></tr>
<tr><td class="part">BL / CS / DC / WR / RD / D0-D7</td><td>GP26 / GP27 / GP28 / GP30 / GP31 / GP32-GP39 (board.c)</td></tr>
<tr class="grp"><td colspan="2">Buttons (digital, pull-up)</td></tr>
<tr><td class="part">A (play/stop) / B (tap tempo) / C (menu)</td><td>GP16 / GP15 / GP14 (left side, top to bottom)</td></tr>
<tr><td class="part">X (prev track) / Y (-bpm) / Z (next track)</td><td>GP17 / GP18 / GP19 (right side, top to bottom)</td></tr>
<tr class="grp"><td colspan="2">Audio</td></tr>
<tr><td class="part">Piezo PWM</td><td>GP12</td></tr>
<tr><td class="part">Amp enable</td><td>GP13</td></tr>
<tr class="grp"><td colspan="2">I2C (QwSTEMMA - unused by the firmware, free for sensors)</td></tr>
<tr><td class="part">SDA / SCL</td><td>GP20 / GP21</td></tr>
</tbody>
</table>
</div>
</details>
<details class="spec" open>
<summary>Controls</summary>
<div class="spec-body">
<table class="bom">
<thead><tr><th>Button</th><th>Action</th></tr></thead>
<tbody>
<tr><td class="part">A</td><td>play / stop</td></tr>
<tr><td class="part">B</td><td>tap tempo</td></tr>
<tr><td class="part">C</td><td>menu (Settings / Practice log / Help / About)</td></tr>
<tr><td class="part">X</td><td>prev track (hold to repeat)</td></tr>
<tr><td class="part">Z</td><td>next track (hold to repeat)</td></tr>
<tr><td class="part">Y</td><td>tempo -1 (hold = -5 after 1.5 s)</td></tr>
<tr><td class="part">X + Z (chord)</td><td>tempo +1 (same hold rule as Y)</td></tr>
<tr class="grp"><td colspan="2">In a menu</td></tr>
<tr><td class="part">X / Z</td><td>move cursor up / down (Help: prev / next page)</td></tr>
<tr><td class="part">Y</td><td>decrement the focused value</td></tr>
<tr><td class="part">A</td><td>cycle / increment / select</td></tr>
<tr><td class="part">B</td><td>back (cancel)</td></tr>
<tr><td class="part">C</td><td>close the menu</td></tr>
</tbody>
</table>
</div>
</details>
<details class="spec" open>
<summary>Parts</summary>
<div class="spec-body">
<p class="sub">A finished development board, not a custom build - ballpark one-off price (USD).</p>
<table class="bom">
<thead><tr><th>Part</th><th class="q">Qty</th><th class="c">~$</th></tr></thead>
<tbody>
<tr><td class="part">Pimoroni Explorer Kit (PIM744) <span class="spec">- RP2350B, 2.8&quot; ST7789V, 6 buttons, piezo + amp, USB-C</span></td><td class="q">1</td><td class="c">60</td></tr>
<tr><td class="part">USB-C cable <span class="spec">- power + flashing</span></td><td class="q">1</td><td class="c">2</td></tr>
<tr class="total"><td>Total (one-off)</td><td class="q"></td><td class="c">&asymp; $62</td></tr>
</tbody>
</table>
<p class="sub" style="margin-top:10px">Reference: <a href="https://shop.pimoroni.com/products/explorer" target="_blank" rel="noopener">Pimoroni Explorer product page</a>
&middot; <a href="https://github.com/pimoroni/explorer" target="_blank" rel="noopener">vendor code</a>
&middot; <a href="https://circuitpython.org/board/pimoroni_explorer2350/" target="_blank" rel="noopener">CircuitPython for Pimoroni Explorer (RP2350)</a>.</p>
</div>
</details>
<details class="spec" open>
<summary>Firmware - self-contained appliance (USB drive &middot; web-driven editing via Live sync &middot; MIDI audio &middot; practice log)</summary>
<div class="spec-body">
<p class="sub">The firmware turns the Explorer into a self-contained appliance: it mounts as a
<b>USB drive</b> carrying the (precompiled) firmware, your tracks and an offline copy of this editor;
drives a lanes/pads display with <b>web-driven editing</b> via <b>Live sync</b>; <b>logs your practice</b> to
<code>history.json</code>; takes new set lists <b>pushed from the editor over USB-MIDI</b>; and plays
out your <b>computer's speakers over USB-MIDI</b>. By default the firmware owns the drive (read-only to
the computer - so it can log and can't be accidentally erased); hold <b>button A</b> at power-on for
editor mode (drive writable).</p>
<p>
<a class="dl" href="/pm_x1_circuitpy.zip" download>Download CircuitPython bundle &darr;</a>
<a class="dl alt" href="https://codeberg.org/VARASYS/metronome/src/branch/main/pico-explorer" target="_blank" rel="noopener">Source + README &nearr;</a>
</p>
<ol class="steps">
<li>Flash <b>CircuitPython for Pimoroni Explorer (RP2350)</b>
(<a href="https://circuitpython.org/board/pimoroni_explorer2350/" target="_blank" rel="noopener">download</a>)
via BOOTSEL, unzip the bundle onto <code>CIRCUITPY</code>, and power-cycle. It boots into appliance mode.</li>
<li><b>Edit on the web:</b> open the <a href="/editor-beta.html">editor (beta)</a> in Chrome / Edge / Firefox,
click <b>&#x1f517; Live sync</b>, and the Explorer mirrors your edits live (beats, tempo, track changes).</li>
<li><b>Save a set list to the device</b> for offline use: set-list <b>&middot;&middot;&middot;</b> menu &rarr;
<b>&#x1f4DF; Save to device</b>. It's pushed over USB-MIDI; the device persists it to
<code>/programs.json</code>.</li>
<li><b>Play through your computer:</b> click <b>&#x1f3b9; Device audio</b>, then press <b>A</b> on the device -
the full groove sounds through your speakers over USB-MIDI, in sync. A <b>MIDI</b> badge appears in the
header and the piezo auto-mutes.</li>
<li><b>Practice log:</b> press <b>C</b> &rarr; <b>Practice log</b>. Plays over 5 s appear (time &middot; BPM &middot; duration &middot; bars).</li>
<li><b>Firmware updates:</b> &middot;&middot;&middot; menu &rarr; <b>&#x2B06; Update firmware</b> - the editor reads
the device id (X = Explorer), fetches the matching <code>pico-explorer-app.mpy</code>, and pushes it
over USB-MIDI. The device A/B-updates with automatic rollback if a build won't boot.</li>
</ol>
</div>
</details>
<p class="sub" style="max-width:760px;margin:14px auto 0">Pairs with the touch-driven <a href="/info-kit.html">PM_K-1 Kit</a> - same engine, same programs.json, same web editor.</p>
</main>
/*@BUILD:include:src/footer.html@*/
<script>
const APP_VERSION = "v0.0.1-dev";
/*@BUILD:include:src/chrome.js@*/
</script>
</body>
</html>