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:
- Download the complete source code and makefiles here.
- Unpack the program and run make from its root directory. The binary file that can be uploaded should appear in the build directory.
- Upload the program to the STM32F4 discovery (again, this post explains how) and plug in headphones or speakers to the audio jack.
- 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 |
Benjamin! Your Blog is awesome, of course example was compiled without any problem with code sourcey lite, and after download to STM music stated!
I compiled with GNU ARM under WinXP. It works perfectly!
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
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?
“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.)
just like you read mp3 files can you suggest a way to read jpeg files from memory stick
The syncobj.c contains:
#include // Win32
Where can I find this windows.h ?
wow, awesome stuff thanks
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.
Awesome!!
Can I ask you where did you get the helix mp3 decoder library?
I want to download the float point version but I don´t know how. I tried to compile this version with FPU but I couldn´t.
I know the version is here:
https://helixcommunity.org/viewcvs/datatype/mp3/codec/fltpt/
But again, I don´t know how to download it.
If you can help me I will be really gratefully.
Best regards!
Done!
http://fossies.org/linux/misc/old/hxplay-11.0.0.tar.gz/
Thanks.
I have a question.
Your code play music repeatedly.
How can I play music just one time?
In the main function, put an endless loop after play_directory(“”, 0);
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!
/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
How can I compile it with Keil ? thanks