From ec43c694a101a021def647185c61eeb7ef5fe66e Mon Sep 17 00:00:00 2001 From: Me Here Date: Thu, 28 May 2026 22:07:00 -0500 Subject: [PATCH] PM_K-1 CircuitPython: circle pad grid, small labels, dimmer LED, faster SPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- build.sh | 2 +- pico-cp/README.md | 5 ++++- pico-cp/__pycache__/code.cpython-312.pyc | Bin 35070 -> 35561 bytes pico-cp/code.py | 27 ++++++++++++++--------- pico-cp/font_s.bin | Bin 0 -> 3979 bytes pico/_font_l.b64 | 1 + pico/_font_m.b64 | 1 + pico/gen_font.py | 9 ++++++++ 8 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 pico-cp/font_s.bin create mode 100644 pico/_font_l.b64 create mode 100644 pico/_font_m.b64 diff --git a/build.sh b/build.sh index 41d76b6..fc5461c 100755 --- a/build.sh +++ b/build.sh @@ -39,7 +39,7 @@ pathlib.Path("dist/pico-main.py").write_text(pathlib.Path("pico/main.py").read_t print("copied pico-main.py") import zipfile # PM_K-1 CircuitPython drive bundle (download → unzip onto CIRCUITPY) with zipfile.ZipFile("dist/pm_k1_circuitpy.zip", "w", zipfile.ZIP_DEFLATED) as z: - for f in ("code.py", "programs.json", "font_m.bin", "font_l.bin", "README.md"): + for f in ("code.py", "programs.json", "font_s.bin", "font_m.bin", "font_l.bin", "README.md"): z.write("pico-cp/" + f, f) print("zipped pm_k1_circuitpy.zip") PY diff --git a/pico-cp/README.md b/pico-cp/README.md index c1e5832..c5b21ee 100644 --- a/pico-cp/README.md +++ b/pico-cp/README.md @@ -18,7 +18,7 @@ same program‑string language as . 2. **Copy everything from the bundle** onto `CIRCUITPY` (drag‑and‑drop — it's a normal drive now): - `code.py` (this firmware — runs on boot) - `programs.json` (your grooves) - - `font_m.bin`, `font_l.bin` (the anti‑aliased fonts — kept as files to save RAM) + - `font_s.bin`, `font_m.bin`, `font_l.bin` (the anti‑aliased fonts — kept as files to save RAM) 3. It starts immediately. Editing `programs.json` (or re‑saving it from the editor) makes CircuitPython **auto‑reload** with the new tracks. @@ -45,6 +45,9 @@ Each `prog` is a program string from the web editor. Add/replace entries and sav - **Taps land wrong:** set `TOUCH_DEBUG = True`, watch the serial output, then set `TOUCH_SWAP_XY` / `TOUCH_INVERT_X` / `TOUCH_INVERT_Y`. - **Joystick reversed:** toggle `JOY_INVERT_X` / `JOY_INVERT_Y`. +- **LED too bright / too dim:** change `LED_BRIGHTNESS` (0..1, default 0.15). +- **Screen tearing:** the SPI panel has no tearing-effect sync; `SPI_BAUD` (default 62.5 MHz) is pushed fast + to minimise it — lower it only if the display is unstable. - **Screen blank / garbled:** the panel lot may differ; drop `SPI_BAUD`, and if it's a 240×320 ILI9341 instead of the 320×480 ST7796, the init/size need changing (this targets the 320×480 you have). - **RGB LED** is driven by the core `neopixel_write` module — no library to install. If it stays dark, diff --git a/pico-cp/__pycache__/code.cpython-312.pyc b/pico-cp/__pycache__/code.cpython-312.pyc index 905e9d18f76728723f471ee743fbcf666510e452..6a0ab7cfd180f47cef3190ce3511f7e9275c1c1d 100644 GIT binary patch delta 4953 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 delta 4518 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 %d b64" % (len(blob_m), len(base64.b64encode(blob_m)))) print("FONT_L %d bytes -> %d b64" % (len(blob_l), len(base64.b64encode(blob_l)))) +# binary blobs (read at boot by the CircuitPython firmware, pico-cp/code.py) +CP = HERE.parent / "pico-cp" +(CP / "font_s.bin").write_bytes(blob_s) +(CP / "font_m.bin").write_bytes(blob_m) +(CP / "font_l.bin").write_bytes(blob_l) +print("wrote pico-cp/font_{s,m,l}.bin (%d / %d / %d bytes)" % (len(blob_s), len(blob_m), len(blob_l))) # verification image on a dark bg (565 colours like the firmware) def c565(r, g, b): return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)