A pocket music library for your PicoCalc.
An iPod-inspired, offline MP3 player for the original Raspberry Pi Pico / Pico H (RP2040) inside a ClockworkPi PicoCalc.
Download firmware · Install · Controls · Artwork · Build
PicoPod on PicoCalc.
Now Playing — light and dark previews.
- Browse Songs, Albums, and Artists, with ID3 title/artist/album metadata.
- Album thumbnails and a larger Now Playing cover, with a built-in vinyl graphic when artwork is missing.
- Play/pause, previous/next, approximate seeking, volume, shuffle, and repeat.
- F3 switches between light and dark themes.
- F2 sleeps the display while music continues; any key wakes it.
- F4 sets a sleep timer: Off → 15 → 30 → 45 → 60 → 90 minutes.
- Screen updates target the changed regions, so moving through menus or changing volume does not repaint the entire interface.
- Up to 512 tracks, with shared text storage to fit the RP2040's RAM.
Experimental alpha. The underlying player has been used on one original Pico H, including a 387-song library. This public package has build and automated-test coverage; it has not been broadly tested across boards, cards, encoders, or BIOS versions. The public build includes release-packaging changes and a regenerated startup font; that exact binary still needs device confirmation.
| Home | Songs | Albums |
|---|---|---|
![]() |
![]() |
![]() |
| Artists | Now Playing | Settings |
![]() |
![]() |
![]() |
The gallery uses the built-in placeholder artwork. Your own prepared cover images replace these graphics. See how the screenshots are generated.
| Part | Support |
|---|---|
| ClockworkPi PicoCalc + original Pico / Pico H | RP2040 target; used during development |
| Pico 2 / Pico 2 W | Not supported by this firmware; do not flash the RP2040 UF2 onto these boards |
| Storage | Existing FAT32 SD card |
| Audio | Built-in PWM audio: GPIO26 left, GPIO27 right |
| Network / account | Neither required |
- Download PicoPod-SDK.uf2. The checksum and build notes are in firmware/.
- Back up an older PicoPod file if present. Copy the new file into
pico1-apps/on the SD card. - Safely eject the card and put it back in PicoCalc.
- Hold Up while powering on to open the firmware menu, then select
PicoPod-SDK.uf2.
Select the actual UF2 file to install an update. A bracketed cached-app entry may resume the previously installed image. Keep your other apps and the loader files intact; no card formatting is needed.
The older stock menu that loads specially linked .bin apps cannot launch an arbitrary .uf2 placed in firmware/. Renaming the file does not convert it. For multiple applications, follow the UF2 Loader project instructions for RP2040/Pico 1.
For standalone use, hold the Pico board's BOOTSEL while connecting its micro-USB port with a data cable, and copy the UF2 onto RPI-RP2. This replaces the current application and may require restoring a multi-app loader later. PicoCalc's USB-C port serves a different controller; it is not the Pico's BOOTSEL drive.
PicoPod reads .mp3 files in the SD root and recursively inside /Music. A simple layout is:
SD card/
├── BOOT2040.UF2
├── pico1-apps/
│ └── PicoPod-SDK.uf2
└── Music/
└── Artist/
└── Album/
├── 01 - Song.mp3
├── 02 - Another Song.mp3
└── cover.bmp
Title, artist and album are read from ID3v2 metadata. Without tags, the player uses the filename, Unknown artist, and Singles. Folders organize files; album/artist browsing follows the tags.
After adding files, restart PicoPod or choose Settings → Rescan. Rescanning stops current playback. Hundreds of files take longer to scan than a small library.
PicoPod reads a same-name BMP next to a track, such as 01 - Song.bmp, or a shared cover.bmp in that track's folder. Use an uncompressed 24-bit or 32-bit BMP; 128×128 is the recommended size. The firmware accepts dimensions up to 1024×1024 and scales for its views.
JPEGs, PNGs, and images embedded in MP3s need preparing first. On macOS, use the included Python helper:
# Prepare art beside music already on your card; MP3s are not copied or modified.
python3 prepare_music.py --in-place "/Volumes/YOUR_CARD/Music"It extracts supported embedded JPEG/PNG art and recognizes common files such as Folder.jpg, cover.jpg, front.jpg, and matching song images, regardless of case. It creates compatible BMPs and preserves existing covers. Tracks without a source image retain the vinyl graphic.
To copy music from your Mac and prepare artwork together:
python3 prepare_music.py "/path/to/your/music" "/Volumes/YOUR_CARD"Or double-click Prepare Music.command and choose the source music folder and SD card. This mode copies into /Music/PicoPod, preserves the source folder structure, and does not overwrite existing tracks. Use a source folder outside the destination. The helper uses Python 3 and macOS's built-in sips; the firmware itself does not depend on macOS.
| Key | Action |
|---|---|
| ↑ / ↓ | Move through lists; adjust volume on Now Playing |
| Enter / → | Open a menu or play the selected song |
| Esc | Return to Home, or from a filtered song list to its album/artist browser |
| ← | Back when browsing; seek backward on Now Playing |
| Space / P | Play/pause the current open track |
| Enter on Now Playing | Play/pause |
| [ / ] | Previous / next track |
| ← / → on Now Playing | Seek approximately 10 seconds backward / forward; paused playback stays paused |
| + / = / − | Volume in 5-point steps |
| S | Toggle shuffle |
| R | Cycle repeat: Off / All / One |
| N | Open Now Playing |
| F2 | Sleep the display |
| Any key while asleep | Wake only; the wake press does not also pause, skip, or select |
| F3 | Switch light/dark theme |
| F4 | Cycle the sleep timer: Off / 15 / 30 / 45 / 60 / 90 minutes |
In Settings, Enter/Right changes the selected option. Playing from an album or artist captures that selection as the playback queue; browsing elsewhere does not replace it.
When the sleep timer expires: playback pauses and the display sleeps. The board remains powered. Press a key to wake, then Space to resume if a track remains open.
- MP3 only; this firmware does not decode AAC/M4A, FLAC, Ogg or WAV.
- 512 tracks maximum, also constrained by a 64 KiB shared text pool. Very long or mostly unique metadata/path strings can reach the text budget first.
- Full paths must fit within 239 bytes; directories are scanned up to 12 levels from the card root. Only the root and
/Musictree are searched; hidden entries are ignored. - Non-ASCII metadata is simplified for the bitmap font. Prefer ASCII filenames for reliable access with the current filesystem configuration.
- Duration and seeking are approximate, particularly for variable-bitrate MP3s.
- Start with ordinary 128 kbps / 44.1 kHz MP3s when troubleshooting playback. High bitrates and slower cards need more real-device testing.
- Display sleep is not guaranteed to extinguish the backlight. Stock keyboard-controller firmware clamps brightness above zero, so a faint glow can remain. This project does not update that controller's BIOS.
- Library scanning, restarting and rescanning do not provide persistent playback-position recovery. Theme, volume, timer and queue settings are currently held in RAM.
- Basic transport has been tested on an original Pico H; prolonged playback, every MP3 encoder and other hardware variants remain areas for community testing.
Install CMake 3.16+, Python 3, a native C/C++ compiler, and an Arm GNU arm-none-eabi toolchain. The development setup uses Pico SDK 2.2.0 and Arm GNU 14.2.Rel1 on macOS Apple Silicon.
git clone https://github.com/yashturkar/picopod.git
cd picopod
git clone --depth 1 --branch 2.2.0 https://github.com/raspberrypi/pico-sdk.git ../pico-sdk
git -C ../pico-sdk submodule update --init lib/tinyusb
export PICO_SDK_PATH="$(cd ../pico-sdk && pwd)"
# Optional when arm-none-eabi-gcc is already in PATH:
export PICO_TOOLCHAIN_PATH="/path/to/arm-gnu-toolchain"
sh BUILD.shThe result is build/PicoPod-RP2040.uf2. Build commands do not flash the device. Hardware drivers and libmad are vendored, so cloning this repository does not require their submodules.
sh tests/run_checks.sh
python3 tests/test_art_helper.py # macOS: exercises real sips conversion
python3 tools/check_firmware.py build/PicoPod-RP2040.uf2Host checks exercise the real input controller, compare partial screen updates pixel-for-pixel with full renders, and cover both themes, artwork paths, rapid inputs, queues, timers, stereo pin routing, clock wrap, deep libraries and text-pool exhaustion. They complement device testing; they do not simulate the physical LCD, SD bus or headphone output.
PicoPod builds on community work, including ClockworkPi's MP3 player, libmad, pelrun's UF2 Loader drivers, PocketPico, FatFs, and the Raspberry Pi Pico SDK. The UI fonts are by Achim Döbler (µGUI).
Distributed under GPL-3.0; vendored components retain their own notices and compatible license terms. See LICENSE, THIRD_PARTY.md, and FONT-LICENSE.txt.
No music, standalone commercial album-art files, ROMs, or private development records are included. The device photo shows artwork on the player screen; that artwork remains the property of its respective owners. PicoPod is an independent community project, not affiliated with Apple, Raspberry Pi, or ClockworkPi.











