The PageMac SerialMP3 module is an embedded MP3 and WAV player designed for robotics, home automation, and other hobbyist projects. Powered by an Atemega328P microcontroller, a VS1003B MP3 decoder and a 1.5W audio amp, the module only requires 5V power and a serial connection. You tell it what file to play over serial, and the module plays the file from an onboard microSD card. The module is 5cm x 5cm, so it's easy to include on a robot. The total cost of the serialMP3 module is about $20.
I had wanted a small module that could play sound files easily for quite some time. I wanted it to be simple - just provide track numbers over serial, play common file formats (OGG or MP3) with no crazy converfsions required, and an integrated audio amplifier. The last part proved to be difficult - I was unable to find any modules that met all of these requirements. There were plenty of MP3 modules, but I didn't want a headphone jack output - I wanted to connect it directly to a speaker. So I decided to build my own!
Most MP3 modules out there use the VLSI VS1053B. But this IC is expensive - $20 each! Ideally, I wanted my entire module to cost less than this. But while browsing SparkFun, I found the VS100D breakout board. The VS100D is a System-On-Chip, so it does more than just encoding and decoding. I bought the module with the hope that I could write my own software for the chip to play tracks and load files from an on-board flash memory chip. Unfortunately, after spending several weeks trying to get the damn thing to work, I gave up. Although I was able to get the module to play OGG files, and even load an example firmware that plays tracks over serial, I wasn't able to write my own code and get that to compile and load on the chip.
Frustrated, I searched the internet more for some more IC's to do that job for me, but I just kept coming back to the VS1053B. But eventually I found the VS1003. The VS1003 is an older MP3 decoding chip with less features than the VS1053, but all I needed it to do was decode MP3! Maybe this could work?
I bought the MP3 Player Shield and mono audio amp breakout. I was able to connect both of these to my Arduino Uno fairly easily, and since someone else has already writen a library to interface with the shield, I didn't have to write much code at all. The prototype worked!
But, the combined cost of all these breakout boards was about $70. I needed to make my own PCB to make it cheaper!
I thought about using a PIC (my go-to microcontroller) to tie all this together, but then I'd have to spend hours implementing SD card and VS1053 code. So I opted to instead to just use a bare Atemega328p, put the Arduino bootloader on it and use all the libraries that have already been written.
Below is a block diagram of the SerialMP3 module:
The hardware design is basically a combination of an Arduino Pro, the SparkFun MP3 Player Shield and the mono audio amp. But I wasn't quite sure about a few things:
I probably should have made another prototype to verify that my design would work, but since it costs me about $15 for a batch of PCBs, I just went for it. Although I have thought of a few things I'd like to change on the board (such as putting 5V power on the serial control header so you can just use 1 cable), it is fully functional and there are no mistakes.
I got the board fabricated at http://www.elecrow.com:Elecrow. It's $10 + shipping for 10 boards.
Since the PCB has mostly surface mount components, I used solder paste with a microscope to assemble the board. You can read more about how I assemble PCB's here.
The firmware is relatively straight-forward. It listens for basic serial commands such as Play, Stop, Loop, Enqueue, Volume. The Enqueue command is for basic playlist functionality - you can queue up several tracks, and the module will play them sequentially. If you try to play a file when another file is currently being played, it will stop the current file.
This project uses two libraries: the Sparkfun MP3 Shield Arduino Library and sdfatlib. Both libraries were slightly modified to make this module work correctly. On the sdfatlib library, I increased the SPI speed since I was using an 8 MHz clock on the Atmega chip. (not really sure if this was required actually). On the SFEMP3 shield library, I had to make several changes to adapt it to work with the VS1003 chip instead of the VS1053. I also added functions to loop sound files.
Additionally, I changed the way it plays “tracks”. The existing code in the library can play a track, for example you call the function to play track 1, and it will load track001.mp3. I wanted to be able to retain more of the file name, so my code actually looks for a file called 001_whatever.mp3. This way I can look at all of the files on the SD card and still know what the files are.
The code doesn't currently play tracks by file name (you just tell it a track number instead), but it would be very easy to modify the code so that it played full tracks. The library already supports this.
I bought my ATmega328P IC's from DigiKey since it's more expensive to buy them pre-loaded with the Arduino bootloader. So before loading the firmware, the ATemega328p must be programmed with the bootloader.
I use the Pocket AVR Programmer. The easiest way to load the firmware is to just use the Arduino IDE.
I used to use avrdude to program new boards, but the Arduino IDE method described above is a little easier.
The bootloader hex is located here:
\arduino-1.0.3\hardware\arduino\bootloaders\optiboot\optiboot_atmega328-Mini.hex
Open a command window in the same directory and use the following commands to set the fuses then program the hex file:
avrdude -b 19200 -c usbtiny -p m328p -v -e -U efuse:w:0x05:m -U hfuse:w:0xD6:m -U lfuse:w:0xFF:m avrdude -b 19200 -c usbtiny -p m328p -v -e -U flash:w:optiboot_atmega328-Mini.hex -U lock:w:0x0F:m
When I made this board, I had two usages in mind: my home security system and robots. In both cases, I would be controlling the SerialMP3 module from another microcontroller, and I only wanted to provide track numbers to play instead of a full file name. So, the current serial protocol reflects that. Commands are as follows:
PXX\r - Play track, where XX is the 2 hexit number of the track in hexadecimal. pXXX\r - Play track, where XXX is the 3 digit number of the track in decimal. LXX\r - Loop track, where XX is the 2 hexit number of the track in hexadecimal. EXX\r - Enqueue track, where XX is the 2 hexit number of the track in hexadecimal. VXX\r - Set volume of track, where XX is the 2 hexit number of the volume. (loudest is 00, quietest is FF) S\r - Stop all tracks
I love this board. I have successfully integrated it with my home security system. The audio is loud and clear, and I'm even able to loop WAV files without gaps! This was a huge bonus for me, as I have several alarm files that sound much better with gapless playback.