# pm-daisy — PolyMeter click engine on the Daisy Pod A time-boxed spike (see [`docs/daisy-spike.md`](../../docs/daisy-spike.md)): play the PolyMeter groove engine on real Cortex-M7 hardware to judge whether the [Electrosmith Daisy Pod](https://electro-smith.com/products/pod) (STM32H750, onboard audio codec) is a credible home for the audio engine if PolyMeter ever grows into a real-time audio workstation. It boots playing a hardcoded 124-BPM 909 pattern (`pm_synth::SPIKE_PROGRAM`) out the Pod's audio jack, flashing the Daisy Seed's USER LED on each click. ## What runs here - **Shared engine, verified on host.** The audio is produced by `pm_synth::Player` — the *exact* same code the host `synthrender` renders to `pm-daisy-preview.wav`. Listen to that WAV to hear what the hardware should play before you flash anything. - **Transport only is new.** This crate is a thin board-support binary: heap + board bring-up + the SAI audio-DMA interrupt feeding `Player::next_sample()` into stereo frames. Structure follows the `daisy` crate's `examples/audio.rs`. ## ⚠️ Set the board revision (or you get silence) The Daisy Seed comes in revisions with different audio codecs. Pick the one on **your** Seed (check the sticker / silkscreen) — it's a Cargo feature: | Your Seed | Codec | Build with | |---|---|---| | Daisy Seed (original) | AK4556 | `./build.sh seed` | | **Daisy Seed 1.1** (default) | WM8731 | `./build.sh` (or `seed_1_1`) | | Daisy Seed 1.2 / Seed2 DFM | PCM3060 | `./build.sh seed_1_2` | ## Build ```sh ./build.sh [revision] # containerized (pm-rust:2); produces pm-daisy.bin + pm-daisy.elf ``` ## Flash — two options **A. Debug probe (recommended — gives you defmt logs over RTT):** A probe wired to the Seed's SWD pins (e.g. the Raspberry Pi Debug Probe you already use for pm-grid/pm-kit — see [`rust/probe-flash.md`](../probe-flash.md)). ```sh probe-rs run --chip STM32H750VBTx pm-daisy.elf # or `cargo run --release` from this dir ``` **B. USB DFU (no probe needed):** Hold the Daisy's **BOOT** button, tap **RESET**, release BOOT — the Seed enumerates as STM32 system DFU. Then: ```sh dfu-util -a 0 -s 0x08000000:leave -D pm-daisy.bin -d ,0483:df11 ``` ## Too big for 128 KB? The STM32H750 has only **128 KB internal flash**. If the linker reports a `FLASH` overflow, flash via the **Daisy Bootloader** to the 8 MB QSPI instead: 1. Install the bootloader once at (Bootloader tab, v6.x). 2. In [`memory.x`](memory.x), set `FLASH : ORIGIN = 0x90040000, LENGTH = 8M - 0x40000` (commented there). 3. Rebuild, then enter the bootloader (tap BOOT within 2 s of reset; LED pulses) and: ```sh dfu-util -a 0 -s 0x90040000:leave -D pm-daisy.bin -d ,0483:df11 ``` ## Pod controls The Pod's buttons, encoder, knobs, and RGB LEDs are wired up (in `src/controls.rs` + `src/leds.rs`). Boot still plays the spike groove (program index 0), so the original spike criteria stay observable. | Control | Action | |---|---| | Encoder turn | tempo ±1 BPM per detent (clamped 5–300) | | Encoder push | play / pause (ignored if you turned while holding it) | | Button 1 / Button 2 | previous / next program (`src/programs.rs`, wraps) | | Knob 1 | master volume (read at boot — no startup jump) | | Knob 2 | reserved (read but unused) | | RGB LED 1 | beat flash, colored by dynamic: accent = yellow, normal = cyan, ghost = magenta | | RGB LED 2 | transport: green = playing, red = paused | | Seed USER LED | unchanged spike beat flash | At boot both RGB LEDs cycle R → G → B (a ~0.45 s self-test) so a miswired or dead leg is obvious before audio starts. A live tempo or program change rebuilds the engine in the main loop (not the audio IRQ) and swaps it in under a short critical section, preserving loop phase on tempo changes. **Pin map** (verified against libDaisy `daisy_pod.cpp`, cross-checked with the `daisy` crate's `pins.rs`): buttons D27/D28 (PG9/PA2), encoder A/B/click D26/D25/D13 (PD11/PA0/PB6), knobs D21/D15 (PC4/PC0 → ADC1), LED 1 D20/D19/D18 (PC1/PA6/PA7), LED 2 D17/D24/D23 (PB1/PA1/PA4). The RGB LEDs are common-anode (active-low). If the encoder feels reversed or double-steps, adjust the decode in `Pod::poll` (detents-per-quadrature-cycle varies by encoder).