metronome/info-kit.html
Me Here e8945ee1d1 PM_K-1: one-click A/B firmware updates over USB-MIDI (+ version check)
Split the CircuitPython firmware into a tiny stable loader (code.py) + the application (app.py,
carries APP_VERSION). The editor's ⋯ → "⬆ Update firmware" queries the device version (SysEx 0x02
-> 0x03 reply), fetches the latest app from the site (/pico-cp-app.py), shows device-vs-latest, and
pushes the new app.py over USB-MIDI (SysEx 0x20). The device installs it to a trial slot (old build
kept as app.bak), reboots, and the loader AUTO-ROLLS-BACK to app.bak if the new build fails to start;
a build that runs cleanly ~5s is confirmed (clears /trial). No BOOTSEL, no dragging; Chromium/Firefox.
app.py forced to pure ASCII so it pushes raw (no base64); SysEx buffer raised to 60KB.

build.sh/deploy.sh: bundle code.py+app.py and serve /pico-cp-app.py. Docs updated.

Verified in CPython: version reply, update install+reboot+ACK, rollback file dance; editor loads clean
with the updater wired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 06:55:58 -05:00

173 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VARASYS PM_K1 Kit — wiring, parts &amp; firmware (Raspberry Pi Pico build)</title>
<meta name="description" content="PM_K1 Kit — build a touchscreen polymeter metronome from a Raspberry Pi Pico on the 52Pi EP0172 breadboard kit (3.5in ST7796 captouch, joystick, RGB, buzzer). Pinout, parts list, and the MicroPython firmware to flash." />
<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_K1 Kit</h1>
<p class="sub">Build it yourself: a Raspberry Pi Pico on the 52Pi breadboard kit becomes a touchscreen polymeter metronome — same engine, same program strings, with MicroPython firmware you flash in two minutes.</p>
</section>
/*@BUILD:include:src/infoembed.html@*/
<section class="about">
<h2>What it is</h2>
<div class="ff-tags"><span class="hw">Buildable now</span><span>Raspberry Pi Pico</span><span>52Pi EP0172 kit</span><span>~$45 incl. Pico</span></div>
<p>This is the first member of the family you can actually build today from offtheshelf parts: a
<b>Raspberry Pi Pico</b> seated on the <b>52Pi EP0172 "Pico Breadboard Kit Plus"</b>, which carries a
3.5″ <b>ST7796</b> 320×480 capacitivetouch screen (<b>GT911</b>), a PSP <b>joystick</b>, a <b>WS2812 RGB</b>
LED, a <b>buzzer</b> and two buttons — all prewired, so you don't solder anything; you just seat the Pico
and copy one file onto it.</p>
<p>It runs the same <b>polymeter engine</b> and the same <b>program strings</b> as the web editor: design a
groove on the site, copy its program string into the firmware's <code>PROGRAMS</code> list, and it plays on
the device. Tap the screen, nudge tempo with the joystick; the RGB flashes each beat (amber accent / cyan
normal / violet ghost) and the buzzer clicks. Powered over the Pico's USB.</p>
</section>
<details class="spec" open>
<summary>Wiring — the EP0172 fixed pinout (Raspberry Pi Pico)</summary>
<div class="spec-body">
<p class="sub">Everything is wired on the board; this is just what the firmware drives. No breadboarding required.</p>
<table class="bom">
<thead><tr><th>Component</th><th>Raspberry Pi Pico pins</th></tr></thead>
<tbody>
<tr class="grp"><td colspan="2">Display — 3.5″ ST7796, 320×480 (SPI0)</td></tr>
<tr><td class="part">SCK / MOSI</td><td>GP2 / GP3</td></tr>
<tr><td class="part">CS / DC / RST</td><td>GP5 / GP6 / GP7</td></tr>
<tr class="grp"><td colspan="2">Touch — GT911 capacitive (I2C0)</td></tr>
<tr><td class="part">SDA / SCL <span class="spec">— addr 0x5D</span></td><td>GP8 / GP9</td></tr>
<tr class="grp"><td colspan="2">Controls &amp; feedback</td></tr>
<tr><td class="part">PSP joystick X / Y</td><td>ADC0 (GP26) / ADC1 (GP27)</td></tr>
<tr><td class="part">Button A (play/stop) / Button B (tap)</td><td>GP15 / GP14</td></tr>
<tr><td class="part">WS2812 RGB LED</td><td>GP12</td></tr>
<tr><td class="part">Buzzer</td><td>GP13</td></tr>
</tbody>
</table>
</div>
</details>
<details class="spec" open>
<summary>Parts</summary>
<div class="spec-body">
<p class="sub">An offtheshelf kit, not a custom board — ballpark oneoff prices (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">Raspberry Pi Pico (or Pico W / Pico 2) <span class="spec">— the brain</span></td><td class="q">1</td><td class="c">5</td></tr>
<tr><td class="part">52Pi EP0172 "Pico Breadboard Kit Plus" <span class="spec">— 3.5″ ST7796 captouch, GT911, PSP joystick, WS2812 RGB, buzzer, 2 buttons, breadboard, acrylic panel</span></td><td class="q">1</td><td class="c">38</td></tr>
<tr><td class="part">USB cable <span class="spec">— power + flashing</span></td><td class="q">1</td><td class="c">2</td></tr>
<tr class="total"><td>Total (oneoff)</td><td class="q"></td><td class="c">≈ $45</td></tr>
</tbody>
</table>
<p class="sub" style="margin-top:10px">Reference: <a href="https://wiki.52pi.com/index.php?title=EP-0172" target="_blank" rel="noopener">52Pi EP0172 wiki</a>
· <a href="https://github.com/geeekpi/pico_breakboard_kit" target="_blank" rel="noopener">vendor code</a>. Lots may ship the screen as ST7796 (320×480) — this build targets that.</p>
</div>
</details>
<details class="spec" open>
<summary>Firmware — flash it in two minutes</summary>
<div class="spec-body">
<p>
<a class="dl" href="/pico-main.py" download="main.py">Download main.py ↓</a>
<a class="dl alt" href="https://codeberg.org/VARASYS/metronome/src/branch/main/pico" target="_blank" rel="noopener">Source + README ↗</a>
</p>
<p class="sub"><b>Two separate steps</b> — and <b><code>main.py</code> is not a draganddrop file.</b> The
<code>RPIRP2</code> drive only accepts a <code>.uf2</code> firmware file; a <code>.py</code> copied there is
discarded on reboot. You draganddrop the firmware once, then copy <code>main.py</code> over USB serial.</p>
<ol class="steps">
<li><b>Install MicroPython</b> (draganddrop, one time): hold <b>BOOTSEL</b>, plug the Pico into USB, and drop
the MicroPython <code>.uf2</code> onto the <code>RPIRP2</code> drive
(<a href="https://micropython.org/download/RPI_PICO/" target="_blank" rel="noopener">Pico</a> /
<a href="https://micropython.org/download/RPI_PICO2/" target="_blank" rel="noopener">Pico 2</a>). It reboots
on its own and the drive disappears — that's correct.</li>
<li><b>Copy <code>main.py</code></b> (the Pico is no longer a USB drive, so use a serial tool):
in <a href="https://thonny.org" target="_blank" rel="noopener">Thonny</a> pick the interpreter
<i>MicroPython (Raspberry Pi Pico)</i>, then <i>File ▸ Save as ▸ Raspberry Pi Pico</i> as <code>main.py</code>;
or <code>mpremote cp main.py :main.py</code>.</li>
<li>Reset — it boots straight into the metronome.</li>
<li>Add your own grooves by pasting program strings from the editor into the <code>PROGRAMS</code> list at the
top of <code>main.py</code>. If colours, touch, or the joystick look off, flip a flag in the
<code>CONFIG</code> block (see the README's calibration notes).</li>
</ol>
<p class="sub">It's one selfcontained file — the ST7796 driver, GT911 touch, WS2812 RGB, buzzer and the
polymeter engine, no external libraries.</p>
</div>
</details>
<details class="spec">
<summary>CircuitPython edition — selfcontained appliance (USB drive · push programming · MIDI audio · practice log)</summary>
<div class="spec-body">
<p class="sub">An alternative firmware that turns the Pico into a selfcontained appliance: it mounts as a
<b>USB drive</b> carrying the firmware, your tracks and an offline copy of this editor; drives a full
lanes/pads touchscreen; <b>logs your practice</b> to <code>history.json</code> on the device; takes new
set lists <b>pushed from the editor over USBMIDI</b>; and plays out your <b>computer's speakers over
USBMIDI</b>. By default the firmware owns the drive (readonly to the computer — so it can log and
can't be accidentally erased); hold <b>button A</b> at poweron for editor mode (drive writable). The
MicroPython firmware above stays the simple, rocksolid option.</p>
<p>
<a class="dl" href="/pm_k1_circuitpy.zip" download>Download CircuitPython bundle ↓</a>
<a class="dl alt" href="https://codeberg.org/VARASYS/metronome/src/branch/main/pico-cp" target="_blank" rel="noopener">Source + README ↗</a>
</p>
<ol class="steps">
<li>Flash <b>CircuitPython</b> (<a href="https://circuitpython.org/board/raspberry_pi_pico/" target="_blank" rel="noopener">raspberry_pi_pico</a>)
via BOOTSEL, unzip the bundle onto <code>CIRCUITPY</code>, and powercycle. It boots into appliance mode.</li>
<li><b>Program it from the web:</b> build a set list in the <a href="/editor.html">editor</a> (Chrome/Edge/Firefox),
then the setlist <b></b> menu → <b>📟 Save to device</b>. It's pushed over USBMIDI and the device shows
<b>Saved ✓</b>. (Fallback for any browser: it downloads <code>programs.json</code> — boot holding A and drag it on.)</li>
<li><b>Play through your computer:</b> click <b>🎹 Device audio</b>, then press play on the device — the full
groove sounds through your speakers over USBMIDI, in sync; the screen shows a <b>MIDI</b> badge and the buzzer mutes.</li>
<li><b>Practice log:</b> plays over 5 s appear at the bottom of the screen (time · BPM · duration · track); tap a row twice to delete.</li>
<li><b>Firmware updates:</b> ⋯ menu → <b>⬆ Update firmware</b> — it checks your version, pushes the latest over USBMIDI, and the device A/Bupdates with automatic rollback if a build won't boot.</li>
</ol>
</div>
</details>
<p class="sub" style="max-width:760px;margin:14px auto 0">Embed this widget elsewhere with one <code>&lt;div&gt;</code> + a script —
see <a href="/embed.html">the embed docs</a>.</p>
</main>
/*@BUILD:include:src/footer.html@*/
<script>
const APP_VERSION = "v0.0.1-dev";
window.INFO_DEVICE = { file:"/kit.html", name:"PM_K1 Kit" };
/*@BUILD:include:src/infoembed.js@*/
/*@BUILD:include:src/chrome.js@*/
</script>
</body>
</html>