A standalone Pomodoro timer written in Ruby, running on a Raspberry Pi Pico 2
(RP2350) with the Waveshare Pico-CapTouch-ePaper-2.9 display, via the
prremote mruby/c runtime.
Work 25 min → short break 5 min, ×4 rounds → long break 15 min. Control it with the capacitive touchscreen or the three physical keys.
┌────────────────┐
│ POMODORO │
│ ────────────── │
│ WORK │
│ RUNNING │
│ │
│ 24:13 │ big countdown (MM:SS)
│ [▓▓▓░░░░░░░] │ progress bar
│ ROUND 1/4 │
│ ■ □ □ □ │ round dots
│ ┌────────────┐ │
│ │ PAUSE │ │ touch button (or KEY0)
│ └────────────┘ │
│ ┌─────┐┌─────┐ │
│ │RESET││SKIP │ │ touch buttons (or KEY1 / KEY2)
│ └─────┘└─────┘ │
└────────────────┘
| Function | Signal | Pico GPIO |
|---|---|---|
| e-paper | SPI1 SCK | GP10 |
| e-paper | SPI1 DIN (MOSI) | GP11 |
| e-paper | DC | GP8 |
| e-paper | CS | GP9 |
| e-paper | RST | GP12 |
| e-paper | BUSY | GP13 |
| touch | I2C1 SDA | GP6 |
| touch | I2C1 SCL | GP7 |
| touch | TRST | GP16 |
| touch | INT | GP17 |
| keys | KEY0 / KEY1 / KEY2 | GP2 / GP3 / GP15 |
- Display: 128×296, SSD1680 controller, black/white.
- Touch: ICNT86 capacitive controller, I2C address
0x48.
| Path | What |
|---|---|
pomodoro.rb |
The timer: e-paper (SSD1680) + touch (ICNT86) drivers, font, UI, state machine. |
probe.rb |
Hardware smoke test (I2C scan, touch version, e-paper reset, keys). |
tools/mrbc/mrbc.exe |
Self-contained mrbc (mruby 4.0.0) host compiler for Windows. |
tools/dtr_patch.rb |
rubyserial fixes required on Windows (see Gotchas). |
firmware/prremote-pico2-runtime-0.2.0.uf2 |
RP2350 runtime firmware (built from the fork). |
The board already has the runtime flashed and pomodoro.rb deployed (auto-runs on
power-up). To iterate from the PC:
# from this directory; adjust COM port if needed
export MRBC="$PWD/tools/mrbc/mrbc.exe"
export RUBYLIB="$PWD/tools"
export RUBYOPT="-rdtr_patch"
prremote version -p COM5 # check the runtime is alive
prremote run -p COM5 probe.rb # hardware smoke test
prremote run -p COM5 pomodoro.rb # run live (Ctrl+C to stop)
prremote deploy -p COM5 pomodoro.rb # store to flash; auto-runs on next power-on
prremote undeploy -p COM5 # remove the stored scriptA deployed script only auto-starts on a clean power-on, not after a soft/Ctrl+C reset (the runtime skips autostart on watchdog reboots). Unplug/replug to see it start by itself.
prremote only ships prebuilt firmware for the RP2040 Pico/Pico W, and needs an
mrbc (mruby 4.x) compiler on the host. Neither exists out-of-the-box for an
RP2350 board on Windows, so:
- RP2350 firmware — forked
lumbermill/prremote, added apico2board target plus a GitHub Actions workflow (.github/workflows/build-pico2.yml) that builds the UF2 with the ARM toolchain + pico-sdk 2.2.0. The only source change needed was patching mrubyc's RP2040 HAL for two RP2350 clock-register renames. The resulting UF2 (firmware/) is copied to the board'sRP2350BOOTSEL drive. mrbc.exe— built mruby 4.0.0 locally with the MSYS2 gcc bundled in RubyInstaller; it links only Windows system DLLs, so it is fully portable.
tools/dtr_patch.rb works around two rubyserial-0.6.0 issues; load it via RUBYOPT
(see above) for every prremote call:
- DTR not asserted — the Pico's TinyUSB CDC only flushes once the host raises
DTR. rubyserial leaves it low →
prremotetimes out (ERROR_SEM_TIMEOUT). The patch asserts DTR+RTS on open. - Truncated writes — rubyserial calls
WriteFileonce, ignores the byte count, and uses a 10 ms write timeout, so larger.mrbuploads are silently cut short and the device blocks forever waiting for the rest. The patch loops until every byte is sent and raises the write timeout.
If a prremote call is killed mid-transfer the COM port can stay locked (a pending
USB write that NAKs forever); just unplug/replug the board to clear it.