From on-board feedback (works well; minor tweaks):
- Pad grid uses circles now: big circle on each beat (division), small on the
subdivisions (vectorio.Circle — native, no extra cost), coloured/lit as before.
- Lane labels use a new small font (font_s.bin, ~12px via gen_font.py) so they're
half-size and show more of the voice name (e.g. 'hatClos').
- LED was blinding -> LED_BRIGHTNESS scale (default 0.15) applied on every write.
- Residual tearing -> SPI back to 62.5 MHz (vendor speed; smaller tear window on a
panel with no tearing-effect pin). Both are CONFIG flags.
Verified by rendering the full scene headless. font_s.bin added to gen_font.py + bundle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| __pycache__ | ||
| _font_l.b64 | ||
| _font_m.b64 | ||
| gen_font.py | ||
| main.py | ||
| README.md | ||
PM_K‑1 "Kit" — VARASYS PolyMeter firmware for the Raspberry Pi Pico
MicroPython firmware that turns a Raspberry Pi Pico on the 52Pi EP‑0172 "Pico
Breadboard Kit Plus" into a touchscreen polymeter metronome. It runs the same program
strings as https://metronome.varasys.io — design a groove in the web editor, copy its
program string, paste it into PROGRAMS in main.py, and it plays here.
Everything is in one file: main.py (ST7796 display driver, GT911 touch, WS2812 RGB,
buzzer, joystick, the polymeter engine — no external libraries).
The board (EP‑0172) — fixed pinout
| Component | Pico pins |
|---|---|
| 3.5″ ST7796 320×480 display | SPI0 — SCK GP2, MOSI GP3, CS GP5, DC GP6, RST GP7 |
| GT911 capacitive touch | I2C0 — SDA GP8, SCL GP9 (addr 0x5D) |
| WS2812 RGB LED | GP12 |
| Buzzer | GP13 |
| Button A / Button B | GP15 / GP14 |
| PSP joystick | X = ADC0/GP26, Y = ADC1/GP27 |
The components are wired on the board — you don't breadboard anything; just seat the Pico.
Flash it — TWO separate steps
⚠️
main.pyis NOT a drag-and-drop file. TheRPI-RP2drive that appears in BOOTSEL mode is the bootloader, and it only accepts a.uf2firmware file — anything else (likemain.py) is silently discarded on the next reboot. You first flash MicroPython with a.uf2(drag-and-drop), and then copymain.pyover the USB serial link with Thonny or mpremote. Two different steps.
Step 1 — install MicroPython (drag-and-drop a .uf2, one time)
- Download the MicroPython firmware
.uf2for your board:- Pico / Pico W → https://micropython.org/download/RPI_PICO/ (or
RPI_PICO_W) - Pico 2 / Pico 2 W → https://micropython.org/download/RPI_PICO2/
- Pico / Pico W → https://micropython.org/download/RPI_PICO/ (or
- Hold BOOTSEL, plug into USB → the
RPI-RP2drive appears. - Drag the
.uf2file onto that drive. It copies, the Pico reboots on its own, and the drive disappears — that's correct and means MicroPython is installed. (Don't use BOOTSEL again unless you're reinstalling the firmware.)
Step 2 — copy main.py (over USB serial, NOT to a drive)
After step 1 the Pico runs MicroPython and no longer shows up as a USB drive — so you can't drag files to it. Use a tool that talks to it over USB serial:
- Thonny (easiest): install Thonny, plug the Pico in normally, then
bottom-right click the interpreter selector → MicroPython (Raspberry Pi Pico) (you should see
a
>>>prompt in the Shell). Openmain.py, then File ▸ Save as… ▸ Raspberry Pi Pico and save it as exactlymain.py. - mpremote (command line):
pip install mpremotethenmpremote cp main.py :main.py
Reset (replug) and it boots straight into the metronome.
Controls
- Touch: on‑screen
<</>||/>>(prev · play/stop · next) and−/TAP/+. - Joystick: up/down = tempo (push far for ±5), left/right = previous/next groove.
- Button A (GP15): play / stop. Button B (GP14): tap tempo.
- RGB LED flashes each beat (amber = accent, cyan = normal, violet = ghost); the buzzer clicks with matching pitch.
Add your own grooves
Edit the PROGRAMS list near the top of main.py — each entry is ("Name", "program string").
Get program strings from the web editor's program box (e.g. v1;t120;kick:4;snare:4=.X.X;hat:4/2).
Supported: tempo t<bpm>, lanes sound:grouping[/sub][=pattern][~][!], pattern chars
X accent · x normal · g ghost · . - _ rest, grouped meters like 3+3+2, polymeter ~.
(Per‑lane dB gain @n is parsed but ignored — the buzzer is mono.)
If something looks off — calibration
All the knobs are flags in the CONFIG block at the top of main.py:
- Colours look negative / washed out: toggle
INVERT_COLORS. - Red and blue swapped: set
SWAP_RB = True. - Taps land in the wrong place: set
TOUCH_DEBUG = True, reset, watch the raw coordinates over the USB serial (Thonny shell) as you tap the corners, then setTOUCH_SWAP_XY/TOUCH_INVERT_X/TOUCH_INVERT_Yto match. - Joystick reversed: toggle
JOY_INVERT_X/JOY_INVERT_Y; widenJOY_DEADZONEif it drifts. - Screen stays black: the backlight is hardwired on, so this usually means the SPI init
didn't take — drop
SPI_BAUDto24_000_000and retry. - Garbled / wrong size image: your panel lot may be a 240×320 ILI9341 instead of the
320×480 ST7796. This firmware targets the ST7796 you have (you said 320×480); if a unit
ever ships ILI9341, set
WIDTH,HEIGHT = 240,320and use an ILI9341 init sequence.
Notes
- Audio is a single passive buzzer, so coincident lane hits play one click at the highest priority (accent > normal > ghost); the RGB + screen still show the combined activity.
- The scheduler is non‑blocking and timed off
time.ticks_us(), so tempo stays steady while the screen and inputs update.
Hardware reference: 52Pi EP‑0172 wiki · vendor code. VARASYS — Simplifying Complexity.