Raspberry Pi Pico
Qwiic MP3 Trigger

The Sparkfun Qwiic MP3 Trigger is a breakout board that plays mp3 files. The 'trigger' part refers to the fact that you can use it with just some pushbuttons (and no microcontroller) and have it play mp3 files on button presses. When used with a microcontroller like the Pico, you communicate with it over i2c and can carry out most operations that you would expect from a basic mp3 player. It costs a little under £20.

Pico Circuit

The photo shows the many connection points on the breakout board. On the far left are the pins for i2c connection. At the top left is a USB-C connector which can be used to power the board. Next to that is a Qwiic connector which, with the right cable, could remove the need for any other headers to be soldered. There is a connection for a speaker and, next to that, a headphone jack. Over on the right hand edge are the trigger pins. On the reverse of the board is a holder for an SD card. You put your tunes on that. You can access the SD card when the board is connected to a PC using the USB C cable.

This is the circuit I used for testing. I have used a JST-SH to Dupont adapter to connect the board via the QWIIC connector. I have connected the VCC and GND to 3V3 and GND on the Pico and connected SDA to GP2, SCL to GP3. I have also wired some tiny 2-pin pushbuttons to pins 18, 19, 20 and 21.

Pico Circuit

I wrote a Pico library based on the information provided in Sparkfun's hookup guide. I saved this to the Pico as mp3.py

class Player:    
    def __init__(self, i2c):
        self.i2c = i2c
    
    def w1(self, c):
        self.i2c.writeto(0x37, bytes([c]))
    
    def w2(self, c, v):
        self.i2c.writeto(0x37,b'\x6e')    
        self.i2c.writeto(0x37,bytes([c,v]))

    def Stop(self):
        self.w1(0)
    
    def Next(self):
        self.w1(4)
    
    def Prev(self):
        self.w1(5)
    
    def Pause(self):
        self.w1(3)
    
    def Get_volume(self):
        self.i2c.writeto(0x37,b'\x6e')
        self.i2c.writeto(0x37,b'\x0e')
        return self.i2c.readfrom(0x37 ,1)[0]
    
    def Vol_up(self):
    v = min(self.Get_volume() + 1,31)
        self.w2(7,v)

    def Vol_down(self):
    v = max(self/Get_volume() - 1,0)
        self.w2(7,v)
        
    def Track(self,t):
        self.w2(1,t)
    
    def File(self,f):
        self.w2(2,f)

Although there are some pins you can use to connect up button 'triggers', I wanted to make sure I could trigger some mp3 playing from some button presses. Here was my code for that,

from machine import Pin, I2C 
from time import sleep 
from mp3 import Player 
  
btns = [Pin(i, Pin.IN, Pin.PULL_UP) for i in [18,19,20,21]] 

i2c = I2C(1,sda=Pin(2), scl = Pin(3)) 

p = Player(i2c) 

while True: 
    btn_states = [b.value() ^ 1 for b in btns] 
    if sum(btn_states)>0: 
        track = btn_states.index(1)+1 
        p.Track(track) 
        sleep(0.5) 
    sleep(0.05) 

To test the remaining functions, I just ran them like this.

from machine import Pin, I2C 
from time import sleep 
from mp3 import Player 

i2c = I2C(1,sda=Pin(2), scl = Pin(3)) 

p = Player(i2c) 

p.Track(1)
sleep(3)
p.Pause()
sleep(3)
p.Pause()
sleep(3)
p.Stop()
sleep(3)
p.Track(1)
sleep(3)
p.Next()
sleep(3)
p.Prev()
sleep(3)
p.Stop()