Arduino Mega based MP3 Player

What do you get if you cross an Arduino Mega, an MP3 decoder, an SD card, and a nokia LCD?

If you throw in several hundred hours of programming, and a few thousand lines of code, you get an MP3 player.

For an Embedded systems module at Uni, I decided to be over the top and try to push what an 8 bit microcontroller can do to the absolute maximum (There are large parts of the program where all the RAM is used and the atmega is running flat out). I thought I would share the project with you all at Sparkfun as a number of the parts are from you:

  • LiPo battery

  • LiPo boost converter/charger breakout

  • Blackberry Trackerball breakout

  • Nokia LCD Arduino Sheild

Picture Time:

Prototype

http://www.railways-in-miniature.co.uk/ … totype.png

Final Project on custom PCB (hand soldered :D)

http://www.railways-in-miniature.co.uk/ … loseup.png

I will post some pictures of it running, and which show how it works soon - got to download them off my camera.

In the mean time, for those interested in the LCD, I wrote my own library for it, which can be found at:

https://github.com/TCWORLD/gLCD-Library

I will also post the code some time soon too.

Walkthrough

When it is turned on, first it checks all the hardware is working, then updates the song library. There is a text file in which the user simply enters the filename of any songs they want to add (less extension) on a new line at the top, with a + in front of each if it is a song file, or an @ in front if it is Album Art.

The software then checks that each song exists, and then using TAG data from the song, it adds the song to the library under the correct Artist and Album (Each artist has a text file containing a list of Albums - each line contains the name of an album, and the filename of its index). In the Album index file is a list of the name of each song, and its filename. If an album or artist exists, then the song is placed in the correct file, else a new artist or album file is created. The files are used later to display data onscreen.

If any new Album art is added (a standard 24bit BMP file, or any size greater than or equal to 128px square), then the image is checked to be a valid bitmap and then converted into a file containing 12bit pixel colour data for use by the screen. If the image is larger than 128px square, it is rather nicely scaled down to the correct size with my own image scaling method. Images can then be assigned to album(s) to which is belongs.

If an album doesn’t have any Art assigned, it uses a default image, which is just a picture of a music note.

After that is all done, it moves to the song selector. This allows the user to pick a song or album to play, or alternatively, allows the creation/naming/renaming/deletion/editing of custom playlists.

There is also a page which shows a list of settings - screen brightness, contrast, dimmed brightness. These settings can be changed.

When a song/album/playlist is selected to be played, it moves on to the Media Player portion of the code. This displays the album art for any given song, buffers the song into some onboard flash memory (enough for one song - this is needed as reading from the SD card directly is far too slow), and then sends the data to an MP3 decoder IC (STMicroelectronics STA013S) for playback.

The media Player also scrolls through the Tag information - showing album name, artist name, track name, year, track number, and also the Genre (decoded with a lookup table).

There are options for play, pause, stop, skip, mute, volume control, repeat, and random shuffle (doesn’t repeat any song until all have been played). There is also an option to turn the MP3 player off.

Volume is shown on a bar graph. To save space onscreen, every few seconds, the bar graph is replaced by a symbol showing battery level, and whether it is charging.

The screen is automatically dimmed after 4 minutes of no user activity (it continues to play the song though). Any activity on the trackball will brighten the screen again. Also when the battery starts to run low, the screen is permanently dimmed to save power.

If you unplug the headphones, playback is automatically paused until they are reconnected, at which point it resumes.

Everything is controlled through the trackerball.

I think that just about covers all the features.

Screenshots

Song Selector

List of Artists:

http://www.railways-in-miniature.co.uk/ … 20(13).png

Scrolling to the left there is a list of playlists:

http://www.railways-in-miniature.co.uk/ … 20(12).png

To delete or rename, you click on rename or remove, and then the next playlist you click will have that action performed on it. To create a playlist, just click create, or to edit one, click on that playlist. This will then allow you to move through the list of songs selecting songs or whole albums you want in the playlist. Anything in the playlist is highlighed blue. Clicking on a blue item removes it from the playlist, clicking again readds it.

Scrolling Left from a playlist shows you songs in the playlist:

http://www.railways-in-miniature.co.uk/ … 20(11).png

and allows you to start playback by clicking on a song in this list - it will then play all songs in the list starting with the one you clicked.

Settings:

http://www.railways-in-miniature.co.uk/ … 20(10).png

If the cursor was hovering over create,delete, or rename, then instead of showing songs in the list, it moves to the settings page, where clicking on a setting and scrolling left/right changes it. Click again to save.

Scrolling right moves back a page until you reach the Artist page.

From there scrolling right displays a list of albums by the highlighed artist:

http://www.railways-in-miniature.co.uk/ … %20(9).png

Clicking on an album plays all songs in that album.

Scrolling right from an album shows songs in the album:

http://www.railways-in-miniature.co.uk/ … %20(8).png

clicking on one plays just that song.

You can scroll left to move back a page until you reach the Artist page again.

Media Player

Firstly, it loads the album art of the song, and then buffers the song into the onboard flash:

http://www.railways-in-miniature.co.uk/ … %20(7).png

Then starts playback, showing song information at the bottom. The media player buttons are shown at the top, as is how much of the song has been played, and how long is left. There is a portion of the media player that toggles between showing battery level, and volume level:

Battery:

http://www.railways-in-miniature.co.uk/ … %20(5).png

Volume:

http://www.railways-in-miniature.co.uk/ … %20(4).png

If the headphones are unplugged, the song is paused, and the speaker symbol is replaced by an x. A message at the bottom informs you to reconnect the headphones:

http://www.railways-in-miniature.co.uk/ … %20(6).png

Left an right scrolls move which button is highlighed. Clicking informs the button to do its funtion. In the case of the speaker being highlighted, clicking mutes, while scroll up and scroll down change the volume level.

In this case the volume button is highlighed, and I scrolled up to increase the volume. The volume graph increased as can be seen by comparing it to one of the previous screenshots:

http://www.railways-in-miniature.co.uk/ … %20(2).png

Non active funtions are shown in red, for example the shuffle and repeat buttons on the left. When one of these is clicked, it is activated and turns blue, e.g. here shuffle is clicked to activate:

http://www.railways-in-miniature.co.uk/ … %20(3).png

Thats about it :D. Any questions?

TCWORLD:
Thats about it :D. Any questions?

Built one myself awhile back (1998 :) ) and have updated it a number of times over the years. Started out with a PIC16F877, progressing up thru 18F4620, 18F4685, finally to 18F47J53. Started out with parallel port transfers, up thru USB ("special firmware", not bulk file transfers), ended up with a USB mass storage device type thing. Started out with a power pack, progressed from that to NiCad, NiMH, ended up with LiPo's which as you know. Didn't have a dedicated charging chip. Controlled the charging with the main PIC. Kinda playing with fire (literally), but it always worked for me. Started out with a 16x1 green LCD, ended up with a 320x240 RGB LCD. Started out with a 3.5" power hungry 4GB desktop drive (which killed the batteries and made the power supply huge), ended up with a microSD slot. Used a STA013 for MP3 decoding. In the end, it was a mess, a LOT bigger than yours, but it worked, and it was mine.

I didn’t have an album art option. That would’ve been nice. Also didn’t use the tags, just the filename itself.

You say reading from the SD card is far too slow. I didn’t have a problem with it, even at a PIC speed of 8Mhz (max SPI speed of 2Mhz), although I spent most of the time running the PIC at 32Mhz to keep the screen scrolling smooth. Eye candy ya know. Pausing play when the headphones are disconnected is a neat option. Didn’t think of that. I also had a function that kinda rated my songs. In the random mode, it would give “preference” to songs that rated higher than others, but wouldn’t totally discount low rated songs.

In short…cool. When your friends show you their iPod, you show them this, and chuckle a bit…

Yeah, basically, if i read directly from the SD card, either byte by byte, or block by block. It plays but stutters an awful lot. The main SPI bus runs at 8MHz, but even then something is wierd.

Its possible that it is due to both elements being on the same bus, but I doubt that as I was disabling the data input while reading from the SD card. But anyway, it works this way, it just annoyingly takes around 30 seconds to buffer a song (depending on how big the song is).

I had thought to use the filename, but the Arduino SD library only allows 8.3 filenames. The SD card is the only bit of code that I didn’t write for this as I really didn’t feel like working out how to decode the FAT filesystem.

But still, it was a fun project - alot more than I thought one of the set projects we could have chosen from would be (slightly simpler things like an alarm clock). Plus it is always nice to come up with you own ideas - even if people beat you to it 13 years ago! :smiley:

If your SD and LCD are on the “same bus”, then ya, you’ll have some problems.

Mainly, depends on your “OS”. Interrupts are the way to go. Use that DATA_REQ pin to signal for more data, stop everything else and refill the STA013 input buffer. Buffering to onboard flash will work, but you’ll quite possibly wear out that flash fairly quick. If you want some fast “flash”, check out Ramtron’s “FRAM” chips. Kinda spendy, but they’re fast like SRAM, operate like serial flash, and come in 256KB types. Start the song by grabbing a block or two into the on-MCU ram, grab another couple of blocks, put them into the FRAM, start playing from on-MCU ram, keep pulling data into the FRAM, all while using interrupts to push data from the FRAM to the STA013. Wire it up right and you could push data straight from the FRAM to the STA013 without having to go thru the MCU.

At the moment, i am using SPI flash, so data is output directly from the memory to the STA013 timed by the dataReq (The arduino sends dummy bytes onto the bus to creates clock cycles to pull data from the memory directly to the decoder). Dummy bytes are sent until the data buffer is full. At which point it goes back to controlling the user interface.

I had tried having the SD card on seperate software SPI, and buffering into the memory during playback, but this was too slow.

I chose Flash as it was the only SPI memory that had enough capacity for a whole song (the one I have is 128Mbit). I used this in my test to buffer during playback as I had already bought it. I think i will create a prototype which uses FRAM to do this and see if it works better.

Oh, the LCD is on a completely seperate bitbanged software SPI, by both elements I mean the Decoder and SD card (along with the Arduino)

Like I said, you might want to rethink your whole flow of how everything works.

Eye candy is good, and instant user control response is ok, but ya gotta figure, you want the thing to do what you primarily designed it to do…play music. Absolutely everything else is secondary.

On the FRAM, I’ve been able to run them as fast as my PICs SPI can run, at least 16Mhz at the chip itself…and ZERO waits when writing to it.

Again, learn those interrupts, timers, etc.

The data transfer is entirely Interrupt based, and has priority over anything else, it was just too slow. I have an plan to replace one of the flash modules with an SRAM module and used that to buffer during playback. Hopefully it will be fast enough.

The SRAM should be pretty much as fast as the FRAM, but doesn’t cost anywhere near as much. Will see how it goes.

Oh ok…maybe swap out the crystal and get some more speed behind the whole thing?

And yes, the FRAM speed would be the same as the SRAM speed, but as you know, FRAM’s cost a lot more than SRAMs. On the upside, if you look at Ramtron’s web site, you can send off for free samples, no strings attached. How do you think I got all my FRAM chips? :slight_smile: (with a little help from my friends…that’s how! :slight_smile: )

Do you recon that would work? I thought the Mega was limited to 16MHz at 5v. I dont really want to try changing the crystal unless I know it would work ([de]soldering SMD crystals is a nightmare), plus if it does any damage to the atMega I’d be screwed - it was hard enough soldering it with nothing else on the board, but it is now surrounded by other components.

What sort of frequency were you thinking?

No idea what freq would work for you. Double what you’ve got now is an easy number to work with, but I don’t know how close to max you are as it is. I’d be willing to think that if you had it playing with a bit of stuttering, then you might not be too far off. I don’t play with Arduino’s, so I can’t speak directly to it. A PIC at 8Mhz is more like a 'duino at 2Mhz (4 clocks per cycle for a PIC vs. one clock per cycle with the Mega chips I think). I guess what I’m getting at in the end is that it’s probably easiest to rethink the software side of things. Find your biggest time-waster and work on that.

Hi, this is great. You’ve done an awesome job.

Any chance you can share the code? I’m doing simple mp3 player project with an mp3 shield + arduino and cannot find any library that lets me read files with long filename from the SD card, all the libraries I found only allow the 8.3 format. If you dont want to share the code can you throw me some suggestion on reading files with long filenames from the SD card?

Thanks!

Thanks :slight_smile:

Unfortunately I don’t use long filenames, so I can’t help you there. My way around that issue was to use 8.3 names, but also have a series of index files which contain the title of the song extracted from the ID3 TAG data, and on the same line, the filename of the song. There is then code to let the user select the title, and the filename is deciphered and opened.

I also don’t use the MP3 Shield, so can’t be much help with that either.

I plan to post my code (well maybe a stripped down version as there is a lot) at some point in the next couple of weeks, but at the moment I am away from home for christmas so don’t currently have access to the code.