Play MP3 on the STM32F4 Discovery

Update: I also have a project that plays mp3 from an USB memory stick with a fat32 file system here.

About

I have written a simple program for the STM32F4 Discovery board that plays a short mp3 file from flash memory. For the decoding, the fixed point version of the Helix mp3 decoder is used. The audio output driver is the one used for the Peridiummmm demo, modified to use the peripheral library provided by ST.

The audio driver has two DMA buffers and a callback function that asks a user-provided function to fill one buffer with audio data when it runs out, while the other DMA buffer is streamed to the audio CODEC. This user function decodes one MP3 frame and forwards the raw audio samples to the audio driver. As this is interrupt driven, the main function can still be used for other things.

How to build and use it

If you don’t have the necessary toolchain to build and upload programs to the STM32F4, you can have a look at this post. Otherwise, the following steps should be enough to test it:

  1. Download the complete source code and makefiles here.
  2. Unpack the program and run make from its root directory. The binary file that can be uploaded should appear in the build directory.
  3. Upload the program to the STM32F4 discovery (again, this post explains how) and plug in headphones or speakers to the audio jack.
  4. You should hear some music! You can change the volume between two discrete steps by pressing the user button on the discovery board.

That’s it! It should be quite easy to modify the code to play mp3s from, for instance, an external SD card.

Use your own MP3 file

The the mp3_data[] in src/mp3_data.c is just the raw data of a normal mp3 file. I used this perl script to convert the mp3 file to a c array. After you unzip the perl script, you can use it like this:

chmod +x bin2hex
./bin2hex MP3FILE.mp3 1 > mp3_data.c

Where MP3FILE.mp3 should be replaced with the mp3 file you want to convert.

Remember that the mp3 file has to be small enough to fit on flash memory of the STM32F4. You can use Audacity to trim/re-encode mp3 files. You should also clear the ID3 tag if possible, as this saves space. As it is now, stereo files with 44.1 KHz sample rate (and any bitrate, even VBR) can be played. When the number of channels or the sample rate differs, the playback speed will become incorrect. This can of course be fixed easily, but I wanted to keep this example as simple as possible.

On Ubuntu, you can install audacity with:

sudo apt-get install audacity

18 thoughts on “Play MP3 on the STM32F4 Discovery

  1. Benjamin! Your Blog is awesome, of course example was compiled without any problem with code sourcey lite, and after download to STM music stated!

  2. Hello Benjamin, my name is Bruno and I´m from ARgentina.

    I was looking you excelent proyect but I can´t understand what did you do to configure the static void AudioCallback(void *context, int buffer) routine, which is “called by the audio driver when it is time to provide data to one of the audio buffers (while the other buffer is sent to the CODEC using DMA). One mp3 frame is decoded at a time and
    provided to the audio driver.”

    As you can see, I’m a little newbie with stm32, lol. Please, if you can, help me 🙂

    Best regards,

    Bruno

    PD: sorry if my english is not good!

    • Hi,

      The audio driver is set up with

      PlayAudioWithCallback(AudioCallback, 0);

      where the address of the AudioCallback function is passed. This function pointer is then used by the audio driver to call that function.

      Hope this helps
      /Benjamin

  3. Excelent! I can figure it out. Another question, when you do:

    err = MP3Decode(hMP3Decoder, (unsigned char**)&read_ptr, &bytes_left, samples, 0);

    if (err) {
    /* error occurred */
    switch (err) {
    case ERR_MP3_INDATA_UNDERFLOW:
    outOfData = 1;
    break;
    case ERR_MP3_MAINDATA_UNDERFLOW:
    /* do nothing – next call to decode will provide more mainData */
    break;
    case ERR_MP3_FREE_BITRATE_SYNC:
    default:
    outOfData = 1;
    break;
    }
    } else {
    /* no error */
    MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo);
    }

    if (!outOfData) {
    ProvideAudioBuffer(samples, mp3FrameInfo.outputSamps);
    }

    I understand you call ProvideAudioBuffer when the audio_buffer0 or 1 are full, or I´m wrong? And in that case, what happend with the PCM samples that don´t fix in the buffer?

    Again, thank you very very much for your help!

    Best regards,

    Bruno

    • Sorry, I meant: *And in that case, what happened with the PCM samples that didn’t fit in the buffer?

  4. “It should be quite easy to modify the code to play mp3s from, for instance, an external SD card.”

    Unfortunately, SDIO and the CS43L22 have an overlap at PC10 and PC12. I wonder if the DMAs are fast enough to switch the pin functions back and forth when streaming off an SD card? Or you could forego SDIO and use SPI mode, I suppose..

    (Disclaimer: I probably have no idea what I’m talking about.)

  5. Thanks for this post, I used it to make a gear warning alert for a glider. The old system with reed contacts was never reliable, I now added two Cherry MP1014 Hall sensors to an ST board running “Warning” from memory.

  6. Wow!

    That (more or less 😉 immediatelly worked after compiling on my Windows system using Yagarto. I had to doublecheck, if my headphones were really connected to the STM32F4-Discovery 😉

    Best regards from Germany!

  7. /bin/sh: /Users/abc/sat/bin/arm-none-eabi-gcc: No such file or directory
    make[2]: *** [misc.o] Error 127
    make[1]: *** [all] Error 2
    make: *** [lib] Error 2
    172-16-28-222:STM32F4_USB_MP3 3 abc$

    I am getting this error, can you please help me out

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.