[Part 5] Multi-Core MP3 Player with RP2350

I now have album artwork and song metadata working off of the SD Card, using a program to index the files.
5 min read

It’s been a little while, but I have been making progress! If you missed parts 1, 2, 3, or 4, you might also find those interesting!

First - I got DMA working with my ST7798 screen. It’s much bigger than the OLED I was using. Second, I have full screen buffering working. I’m likely going to make this optional - so games & screens can directly decide when/where to clear the screen. I’m rewriting much of the UIs to allow things like colors be more configurable at a system level. The images in this post, are the “Hacker” theme.

playing music

PCB Progress

Since I solved my display problem, this gives me much more inside real-estate proportional to the screen. And - the pins for the display no longer get in the way of the micro-controllers. I’m laying out the main motherboard like the following:

On the front side - reverse mount headers so screen can just be pressed in. On the reverse - PI Pico 2 W is soldered directly onto the board. Same goes for the VS1053 board.

I think I’m going to make the ‘UI Buttons’ board as I’m calling it - be entirely separate. It’ll get a block of pins. Enough for an I2C bus, and also some raw pins for interrupts (or raw buttons) if I need.

I’m making good progress on this - I think I’m likely to order a duplicate electronics set (really, just a VS1053, 2nd screen, and power supply/battery), a small test run of PCBs. Then try and assemble a prototype! The wiring on the breadboard is kind of flakey especially with the high frequency transmission of pixel / music data over SPI.

Music Library

I have created a rust program to index my files and copy them to the SD card. It writes them in a special, numbered directory so by knowing a song’s ID, you can play it. I might try and keep the directory structure intact and add a lookup table to alow me to find the correct path, but I’m not sure if I want another layer of indirection around the files. The one nice thing, is that would allow a total library update without touching the music, as we’d just be pointing to the latest files.

playing music

My music library is structured like a flat file on the SD card. I can read and seek this using embedded_sdmmc. The structure (currently), is the following:

  • Metadata:
    • MAGIC: 4 bytes, str - file type name. Currently MLIB
    • VERSION: 2 bytes, u16 - version string for backwards compat usage
    • GENERATED_TIMESTAMP, u64 - unix timestamp in seconds.
    • Tables:
      • Artists:
        • ARTISTS_COUNT - u16
        • ARTISTS_TABLE_OFFSET - u32 - how far from start of file do we need to seek to get to the artists table?
        • ARTISTS_TABLE_ENTRY_SIZE - u16 - size in bytes of an entry in the artists table
      • Albums:
        • ALBUM_COUNT - u16
        • ALBUMS_TABLE_OFFSET - u32
        • ALBUMS_TABLE_ENTRY_SIZE - u16
      • Songs
        • SONG_COUNT - u16
        • SONG_TABLE_OFFSET - u32
        • SONG_TABLE_ENTRY_SIZE - u32
    • STRING_POOL_OFFSET - u32 - stores strings data
    • u32 - RESERVED
  • Tables:
    • ARTIST TABLE (ARTIST_COUNT entries)
      • ARTIST_NAME_OFFSET - u32 - offset into string pool
      • ALBUM_COUNT - u16
      • ALBUMS_LIST_POOL_OFFSET - u32 - offset into lists pool, contains list of album indices for this artist
    • ALBUM TABLE (ALBUM_COUNT entries)
      • ALBUM_TITLE_OFFSET - u32 - offset into string pool
      • ARTIST_INDEX - u16 - index into artist table
      • SONG_COUNT - u16
      • SONGS_LIST_POOL_OFFSET - u32 - offset into lists pool, contains list of song indices for this album
      • ARTWORK_ID - u32 - offset into artwork pool, or 0 if no artwork
    • SONG TABLE (SONG_COUNT entries)
      • SONG_FILE_ID - u16 - file path is stored as music/[id].ext
      • SONG_FILE_TYPE - u8 - enum: 0=mp3, 1=flac, 2=m4a, 3=wav
      • SONG_DURATION_MS - u32
      • SONG_TITLE_OFFSET - u32 - offset into string pool
      • ARTIST_INDEX - u16 - index into artist table
      • ALBUM_INDEX - u16 - index into album table
    • STRING POOL
      • A big blob of null-terminated strings, indexed by offset
      • SIZE - u16
      • STRING_DATA - SIZE bytes
      • Null terminator - 1 byte
  • ARTWORK POOL (separate file)
    • A big flat file containing of raw RGB565 pixel data, indexed by ID
    • Items:
      • SIZE - u32
      • IMAGE_DATA - SIZE bytes - NOTE - all should be the same, to permit random seeking to index i based on first SIZE. We can likely remove the redundant size field, I think.

settings menu with library stats

Sync Program

I’m writing a sync program that scans a directory on your computer, and creates library & artwork databases, and then writes them along with the files to your SD card.

Games

Since I have a nice screen now and fast drawing, I’m going to build several games for it. In no particular order:

  • Snake
  • Minesweeper
  • Block-stacking game (tetris-esque)
  • Shoot-em-up arcade game (think galaga, phoenix, others)
  • Breakout style block breaker

Initially, i’m going to bake these in the firmware, until i determine a good API to expose. Then, I think I’d like to be able to expose a basic API and load programs into memory of SD card.

Simplify!

I originally planned to have much more stuff in this box.

For now, I’m eschewing most of that, to simplify the build process for the first version. I may decide to expose a pogo-pin interface (think 3.3v, SDA, SCL, GND), for external accessories like FM Radio, GPS, etc. Maybe things like that can be external accessories.

Feedback

Found a typo or technical problem? report an issue!

Subscribe to my Newsletter

Like this post? Subscribe to get notified for future posts like this.