STM32F4 Discovery USB host and MP3 player

I have not written any new post for a while, so here is one more project for the stm32f4 discovery. I prepared this post a long time ago, but for some reason I never posted it, so here goes:

STM32F4_MP3

Based on one of the examples provided by ST, I have written a program for the STM32F4 Discovery board that plays MP3 files from an USB memory stick. You can download it here.

If you use a usb-host cable such as this one you can connect an USB memory stick (with fat32 file system) with mp3-files to the micro-usb port of the stm32f4 discovery. The files should then be played one by one. The user button can be used to skip to the next file.

If you follow this tutorial you should be able to build and upload the provided files right away.

The main.c-file has many comments, so hopefully you can figure out how it works. Using a USB-memorystick for logging is quite easy with this program as a basis. Only the two usb-pins, 5V and gnd are required to connect it to any stm32 with USB support, so hw-wise it’s even easier than using an SD-card.

77 thoughts on “STM32F4 Discovery USB host and MP3 player

  1. I’m using Windows 7. I build the previous project successfully, But I can not build this one. So many error 🙁

  2. A big thank you for a very — very,very — great job!
    Run on windoz + CooCo-CoIde+ arm-none-eabi and “little” job for manage files .
    ( STM32F407 and Discovery are magic…)

    Thank you.

    • Hi Daniel,

      I will be very grateful if you could let us know how you arranged the files and maybe make your CooCox project available.
      I also use CooCox, I tried to arrange the many files but get plenty of errors which I am not able to sort out.

      Thanks.

  3. Mp3 with sample rate lower than 44.1k plays really fast like I am fast forwarding it while playing how to rectify this?

    • change this line:

      InitializeAudio(Audio44100HzSettings);

      options are:
      Audio8000HzSettings
      Audio16000HzSettings
      Audio32000HzSettings
      Audio48000HzSettings
      Audio96000HzSettings
      Audio22050HzSettings
      Audio44100HzSettings

      This could also be done in an automatic way based on the settings for each mp3, but this is only a simple example.

    • Hi,
      I got the code to compile under CooCox.
      #define USE_HOST_MODE was commented out in usb_conf.h

      Thanks again for your effort.
      Farren

  4. Hi,

    If got a question, do I need 5V for the usb Support ? Because I’d like to connect only 3,3V to the board. Do you think that would be enough ?

    kind regards

    Danny

    • As far as I know, you need 5V for USB devices to work. If you are lucky your USB-memory might work with 3.3V too, so give it at try.

    • Yes, USB needs 5V bau stm32f4discovery has a charge pump to evelate power from 3.3v to 5v for usb usage

  5. Hi,
    Thanks so much for the CooCox project files.
    But when I comile I get this error:

    C:\CooCox_Proj\stm32_th\stm32_th\lib\USB_Host\Core\src\usbh_hcs.c:104:7: error: ‘USB_OTG_CORE_HANDLE’ has no member named ‘host’

  6. Hi Benjamin,

    I have been busy truing to work through the STM32F4 Discovery example that records and plays back a .wav file on attached USB Thumb Drive.
    The ST examples are like looking at scrambled egg and I have got confused and not progresssed well.
    I would really appreciate it if I could get some help with source code to just create/open a file on a USB thumb drive and then write some text to the file such as “hello USB Drive” and then open/read the same file contents to a buffer.
    The aim is to have a very straight forward example project of file i/o using the stm32F4 USB OTG host functions.
    I dont want any Audio or any other overhead code in the way.
    Ultimately I am hoping to use the STM32F4 on a small data logger that logs ASCII data to USB Thumb Drive.
    At the moment I can log data to SD card using ChanFat but I dont want to use the SD Card.

    I am prepared to pay for the code if this can help me save time.

    Thanks
    Farren

    • Hi Farren,

      Does the MP3 player work for you? In that case it should be no problem to just remove the helix decoder files and some parts of the main program and just do what you intend to. The ST example used here is indeed based in Chan’s FatFS-code, so you should be able to use the functions right away.

      Unfortunately, I’m not able to help you with anything related to CooCox since I only use Linux.

      /Benjamin

  7. Hi Benjamin,
    Faddistr posted a reply with link to the CooCox environment.
    I just managed to get your project to compile 100%, no errors with CooCox a few minutes ago.
    I will load it onto the Discovery board to see if it works and then I will try to take out the unneeded audio parts and work through the example to see if I can get what I need.
    Thank you very much for your website, you are a good man to share your work with the community like this.
    Much appreciated.

    P.S. If I get really stuck can I ask your help, I am willing to pay for your time…
    Farren

    • It is nice that you appreciate my website 🙂

      Sure, you can ask me for help if you get stuck. Other people have actually asked me do add a donate button, so I will try to do that some time. Then you can buy me a pizza if I manage to help you 🙂

  8. Yes , A donate button will be a good addition !

    I have loaded the .hex onto the Discovery board and plugged in a USB Thumb Drive and hit reset button. The LED’s flicker and the LED on the Thumb drive also flickers for a short while then stops. So it is doing something but not playing the MP3’s, pressing the user button does not advance to the next MP3 and the system seems to stop there. This is no big deal for me as I will ultimately not be using the mp3 part of the code.
    I will add some code to printf to a terminal through USART2 so that I can put some printf’s in the code to see what is going on.
    I have a TTL to RS232 module connected to TX and RX (PA2 and PA3) and have this working on another Stm32F4 project so I will cut and paste this into to your code.
    I will work on this for a bit and let you know how I progress.

    Is there a way to contact you ? email address ?

    Regards
    Farren

    • The flickering LEDs are a good sign, so I’m sure you will manage to make it work.

      My email address is on the contact page: benjamin (at) vedder.se

    • Hello Farren,

      I have the the same problem with the generated code as you had (playback stops immediately after 1..2 seconds).

      The .hex file from Benjamin posted on May 17, 2014 at 21:24 works perfectly…

      I would be very happy if you (or somebody else) could give me a clue on this!

      Thanks

      Oliver

  9. Hi,
    It is all working , read and write files to the USB pen drive for data logger application on STM32F4 using CooCox CoIde and gcc arm.
    Thanks to Benjamin and everyone that offered help.
    Farren

    • Hi Benjamin,

      Thank you very much for this tutorial. It is a true class to get USB Host works. Now, I want ask to Farren for share the solution. He did the code works in Coocox, but didn’t show the solution.
      Jorge

  10. Hi,

    Thanks so much for the CooCox project files.
    But when I comile I get the same error:

    C:\CooCox_Proj\stm32_th\stm32_th\lib\USB_Host\Core\src\usbh_hcs.c:104:7: error: ‘USB_OTG_CORE_HANDLE’ has no member named ‘host’

    how can I solve it?

    Thanks
    Raphael

  11. Hi!

    I have the same problem like Farren: the LEDs on the boards and the pendrive are flickering for a while, and after that a silent noise comes out from the headphone.

    Can you give me a tip, what should I do? The project is same than the posted CooCox project. Only one modification in the usb_conf.h: uncomment the “#define USE_HOST_MODE”

    I know you are not using the CooCox, but I guess it is not related to the IDE.

    Thanks,
    yoman

    • I’m sorry, but I can’t help you. The code that I have uploaded is working for me after all. It is not possible for me to test the coocox project since I don’t have any machine that runs windows and I don’t plan to get one ever.

    • Thanks for the quick reply Benjamin!

      Okay, I am trying to be specific. My project (downloaded from here) contains two usb_conf.h files. One in the “inc” folder, and one in the “lib/Conf” folder. There is a little difference between these. In the first there is “#define USE_HOST_MODE” and in the second there is “#define USE_DEVICE_MODE”.
      I guess the compiler is little confused due to the same names. Is it ok, that there are two same files?

      Or which mode should I use?

  12. Okay last wish 😀

    Can somebody upload only the hex file of this project? To test, the program can work with my usb drive and mp3 files.
    Thanx!

  13. Hi Benjamin,

    Can you explain to me why the size of these:

    static int16_t audio_buffer0[4096];
    static int16_t audio_buffer1[4096];

    I have to reduce the RAM, I was trying to halve this buffer, but if you do this it does not play.

    Can you help me?

    best regards
    Raphael Gonçalves

    • Hi Raphael,

      The mp3 frame length for higher sample rates than 32kHz is 1152 and there are two channels, so the length of the buffers has to be at least 2304. Thus, half the size is slightly too small 🙂

      /Benjamin

  14. Hi Benjamin,

    Thank you for reply.
    but I can change the sample rate to reduce the length of the buffer?

    Best regards
    Raphael Gonçalves

    • I haven’t tried different sample rates, but it could work. I’m not an expert on mp3 files…

      Another thing you could do would be do split one mp3 frame into two audio callbacks. For this you need one full size buffer (2304 x int16) to decode the whole frame and one smaller buffer to play from while decoding the frame. Then you have something like this:

      Suppose that the smaller buffer has the size SMALL_BUF_SIZE

      Audio callback 1:
      Decode the next mp3 frame to the large buffer. Provide the decoded buffer with the size of the smaller buffer subtracted:
      ProvideAudioBuffer(large_buffer, mp3FrameInfo.outputSamps – SMALL_BUF_SIZE);

      Audio callback 2:
      Copy the last SMALL_BUF_SIZE samples of the larger buffer to the smaller buffer. Provide it to the audio driver.

      For this approach, the small buffer has to be large enough to last for the time it takes to decode one mp3 frame, otherwise the playback won’t be smooth. You can experiment with that size to see what works.

      Hope this helps.
      /Benjamin

  15. Pingback: STM32F4 Beginner Steps (using free tools) | Tools & Technologies From Hasaranga

  16. how to access left/right samples in audio callback?
    is this correct?
    for(int i = 0; i<mp3FrameInfo.outputSamps;i+=2)
    {
    left= samples[i];
    right=samples[i+1];
    }

  17. I have my STMF4 Discovery also working for USB Audio (as USB Sound Card). Changed to 24bit, 48KHz, works as well.
    And: I use the STMF4 Discovery as USB-to-I2S plus an CmodS6 FPGA for audio DSP and processing.
    More details and project files are here:
    http://www.tjaekel.com

    Now I am thinking to do the same with the STMF4 Disco, with the LCD. But it looks like, almost all ports are used for the LCD. And the same project does not work without proper changes (e.g. different port for USB).

    Has anybody tried to create a Coocox project for STMF4 Disco (new chip, not supported yet) with USB OTG (as CDC or Audio)?

  18. Hi Benjamin,

    I have a problem; error: #136: struct “USB_OTG_handle” has no field “host”
    pdev -> host.Rx_Buffer.
    How can i fix it?

  19. Hi Benjamin!

    Can you include a .hex file for this project? I have had no trouble compiling it and flashing the board but there is no indication the USB stick is being accessed. I am trying to figure out if this is a cable or USB stick problem. Thanks for making this available!

    • Thank you! I suspect I have a problem with the USB drive. The cable works fine with everything else and this rules out a problem with my compiler setup. Has anybody else had any problems with different USB drives? I will try a different one as soon as I get my hands on it (this one is amost ten years old but still works in my laptop). Thanks again.

  20. Thanks for your work on this -and for posting the HEX/BIN files. Once I installed the ST LINK utility and USB driver, the HEX loaded without a problem and MP3 file is playing! Something to use in my car – just need my USB stick.

    • This STM32F407 is clocked at 184 MHz, do you know what processor loading is required for this MP3 player? Is it near peak load of this processor? Could this run on a 84 MHz STM32F401?

      I am considering adding a LCD display to show the ID3 data (artist/title) and maybe a encoder to allow song selection (dial up new song, press pushbutton to switch to this song). Also maybe writing the current filename to flash (on STM, not USB stick) so that on power up, it continues to play the last song, rather than starting from the first.

      -Mike

    • The stm32f407 is actually running at 168 MHz, not 184. 84 MHz should be more than enough.

      There are lots of inexpensive 320×240 rgb displays with touch screen on ebay that are quite easy to use, so using one of those would be nice.

  21. Hi!
    Here you can download the patched version of CooCox project:
    https://drive.google.com/file/d/0B9_oXlDo4_lDQ2NLU29pVDNCMUk/edit?usp=sharing

    Compiled by CooCox CoIDE-1.7.6, GCC-4.8q2 (firmware: “test_host.bin”, “test_host.hex”, “test_host.elf”).
    1) In the file \…CoIDE\workspace\test_host\inc\usb_conf.h changed the lines 176 and 177 (uncommented #define USE_HOST_MODE).

    2) In the file \…CoIDE\workspace\test_host\main.c changed the lines 106-109 (added file extension *.MP3, *.Mp3).

    3) Important notice – set in the CoIDE “View-Configuration” label -O3 instead of -O0 (because of this music in the project by Faddistr Oct-2013 played in spurts).

    • Hi!
      I’m using Coocox version of the code and had the same problem with was mentioned above. After connecting the pendrive the first 0.5sec of the first Mp3 was played and it stopped.

      Sergey.Maximovich on August 3, 2014 at 17:07 said:

      Hi!
      Here you can download the patched version of CooCox project:
      https://drive.google.com/file/d/0B9_oXlDo4_lDQ2NLU29pVDNCMUk/edit?usp=sharing

      Compiled by CooCox CoIDE-1.7.6, GCC-4.8q2 (firmware: “test_host.bin”, “test_host.hex”, “test_host.elf”).
      1) In the file \…CoIDE\workspace\test_host\inc\usb_conf.h changed the lines 176 and 177 (uncommented #define USE_HOST_MODE).

      2) In the file \…CoIDE\workspace\test_host\main.c changed the lines 106-109 (added file extension *.MP3, *.Mp3).

      3) Important notice – set in the CoIDE “View-Configuration” label -O3 instead of -O0 (because of this music in the project by Faddistr Oct-2013 played in spurts).

      So I did those modifications, and I’t works!
      I uploaded the hex file before, so I knew that my Discovery board and the pendrive were OK.

      I think the solution was to activate the Optimizer “-O3” in the View/Configuration/Optimization combobox. It solved the freezing. Don’t ask why 🙂
      Playing sound from my STM opens a whole new world!

      So much thanks guys!
      Good hacking.
      Myke

  22. Hello,
    i’m just trying to have it working.
    I managed to compile it correctly, no warnings or errors and the hex file is created, but when i plug the usb disk, i get the red and green led lit, a brief, subtle whistle into the headphones and nothing else.
    I also tried to use your compiled hex files with the same results.
    I’m using a 32GB usb pendrive. Might be this the problem? Is there any limit in the usb drive size?
    Many thanks.

    • Hi,
      As far as I know, there is no space limit. However, the file system on the drive has to be fat32 and not exfat, nfts, extx, hfs or something else. You could also try a different mp3 file.

    • Hi, thanks for answering.
      The pendrive is fat32 and i tried with many different files with the same result. I’ m seeing that if i put non-mp3 files it works: it correctly detects when the pendrive is plugged and unplugged, while if i put there some mp3s, it get stuck into the audio callback where the mp3 decoder is called. For the moment i cannot be more precise, as i’m trying to trace the program flow.
      The strange thing is that also your compiled hex file is producing the same results.

      I’m VERY new to Arm, so could you please tell how to configure stdio in order to have printf working to trace the program more easily? I think i should use uart6 for it.

      Thanks.

    • Ok…
      I’ve just seen your tutorial on how to setup everything to have stdio working on com2. I’ll try to have it working on this project.

    • Hello Benjamin,
      finally i got it working.
      I succeded in having printf working and i did some trace/debug.

      The program was getting stuck into the audio callback, since no case was set to handle ERR_MP3_INVALID_FRAMEHEADER.
      The mp3 file pointer was never increased so the decoder was not able to find a good frame to start with and everything was stuck there.

      I understood this is a general framework and much work is left to the readers, so i’ll do myself the other error and samplerate handling.

      Anyway many many thanks! It’s the first time i’m getting something playing an mp3 out of a microcontroller.

    • Nice!
      I never experienced that problem myself, but I didn’t spend too much time on testing this either. I will update the example soon.

    • Hello Benjamin,
      added the capability to play wav file also (just parsing the header and sending the data directly to the dac).
      I can tell that maybe there is something wrong with the id3tag parser, because many files were not played at all because f_read was returning 0 bytes read.
      So i tried to read those files directly before parsing the id3tag header and they were read correctly, so i bypassed Mp3ReadId3V2Tag and now all files are playing.

      To solve the samplerate issue i could suggest to use the MP3FindSyncWord and MP3GetNextFrameInfo iteratively until a valid frame is found: MP3FindSyncWord often is fooled by a false sync word but MP3GetNextFrameInfo returns no error only if that frame is good.
      Since it returns also the frame header (samplerate and channels number) i did the samplerate switch before entering the audiocallback loop.

      I’m playing around, i’ll report other news, if any.

    • Hello,
      i can confirm that the id3 parser always fails with id3.2.4 headers.
      In this case, the id3 entries are not scanned correctly and the file pointer is moved beyond the end of file, so that file will not be played once the parser exits.
      Since i see that no artist nor songname are used, i just have read the length of the id3tag and moved the filepointer at its end where mp3 audio data should begin.
      In this way i had all mp3 and wav songs on my usb drive played correctly.

  23. Benjamin, good job!
    1) If you make changes to your MP3-player, then download – where are the three music files (codecs FhG, Gogo, LAME3.98), which can not be played on your device. Furthermore, these files stopped the player, who does not respond to pressing button of the STM32F4Discovery.

    2) Do not play files, that contain a name, other than the Latin alphabet (with UTF-8).

    3) When playing music with a sampling frequency of 48 kHz, the frequency shift is observed. For example, instead of 479 Hz to 440 Hz sounds. In a similar project frequency shift is not.

    4) Add the file extension *.MP3 and *.Mp3, that take place to be.

  24. For 1) //drive.google.com/file/d/0B9_oXlDo4_lDSzBtSTd4NU1Pd3c/edit?usp=sharing
    For 3) //code.google.com/p/walkgeek/

  25. Hi guys.
    I really love this project. Lots of thanks to the aurther.
    But seem like my program gets stuck at play_mp3 where (bytes_left < (FILE_READ_BUFFER_SIZE / 2)) is never true. Any help guys.
    Regards.

    • Hi i had a similar problem.
      Check my posts above, there are two major problems in the code:
      one is that the file pointer is not increased when some errors are encountered during decoding, the other is that the id3tag parser fails with version id3.2.4.
      In the first case you get the board stuck as it enters a vicious loop, in the other the file is skipped and not played at all.

      To make the evalboard to play something, try to encode some files with audacity or with the lame mp3 encoder: this will generate a file which will be accepted by the player.

      Hope this helps.

  26. Great example, one step ahead: do you think is possible to have stream from PC instead USB key, like an audio device recognized by Windows?

  27. Thanks to you guys, finally got it playing properly. I encoded the mp3s with audacity as Tom described. Also it seem like some level of optimization is needed in the build options, so I used “Optimize most(-O3)” & “Optimize size(Os)” and both work.

  28. May I know how can I flash the hex file given by you in the the STM32F4 with the ST-link? Cause my one not working. Thanks

  29. I used make to compile the code and then flashed the hex file.
    It says –
    size: 32768
    size: 32768
    size: 32768
    size: 32768
    size: 32768
    size: 32768
    size: 32768
    size: 32768
    size: 7426
    2015-02-13T11:32:25 INFO src/stlink-common.c: Starting verification of write complete
    2015-02-13T11:32:30 INFO src/stlink-common.c: Flash written and verified! jolly good!

    but there is no sound.

  30. Hello, I have been using your code as basis for a personal project I am working on with the STM32F4discovery board. Thank you for posting, it has been invaluable.

    One question, do you have any example code to use the ITM registers to write to the SWO window in ST-LINK? I have tried many things i’ve seen on the web but nothing prints out, only the “Print Data Number” counter increases when I press the user and reset buttons – but that is all. Please note that I soldered the Sb12 bridge so PB3 and SWD pin6 are connected.

    Any help would be appreciated!

  31. hello, I greatly appreciate this project and I am trying to make a MP3_player using stm32f4-discovery and the plate vs1003b with a sd-card, could play a specific song, but did not understand the piece of code that changes the mp3 file if you can me help I am very grateful, see my code.

    I do not know, use this >> if (FR_OK == f_open(&file, filename, FA_OPEN_EXISTING | FA_READ))

    //Mount drive
    if (f_mount(&FatFs, “”, 1) == FR_OK)
    {
    //Try to open file
    if (f_open(&fil, “file.mp3”, FA_READ) == FR_OK)
    {
    while (f_read(&fil, buf, 512, &bytes_read) == FR_OK)
    {
    for( index = 0; index < bytes_read; index += 32 )
    {
    while( MP3_DREQ ==0 );
    VS1003_WriteData( (void*)( buf + index ) );
    }
    }
    }
    }

  32. Can you help me fix error? thank you
    error: #268: declaration may not appear after executable statement in block BYTE unVersion = id3hd[3];

  33. Can you help me fix error? thank you
    error: #268: declaration may not appear after executable statement in block
    BYTE unVersion = id3hd[3];

  34. Thank you very much for this very nice project.
    Spend a few days to make it works on a STM32F411-DISCOVERY (100 MHz CPU) with Coocox, but now everything is ok. The biggest problem was due to the compilation options : code was not executed quickly enough (HCLK set to 96 MHz), and when I tried to increase I2S PLL speed (because original values resulted in a very slow playback (about 1/15 of normal speed)), execution stopped with an ERR_MP3_INDATA_UNDERFLOW error. After changing setting for fastest code execution, I was able to increase PLL speed without underrun. It seems mp3 decoding function consume about 50% of CPU usage à 96 MHz. Maybe I should execute the code from RAM ? Or maybe I’ve done some mistakes and CPU is not running at 96 MHz ?
    In any case, thanks again for sharing your projects.
    I still need to find the correct values for :
    PLL_N, PLL_R, I2S_DIV and I2S_ODD.

  35. I send the previous message too fast….

    For Fs = 44100 Hz following value provide a quite good playback :

    int _plln=361, _pllr=2, _i2sdiv=1,_i2sodd=1;

    I’m still wondering why they are so different from those from Benjamin’s project. ? As if I2S_PLL_M was not set at the same value ?

    • Hello, Yes, I proportioned this project under Keil but I can’t hear anything. Maybe someone could find errors?

  36. First off, thanks for this code, it has really jump started my project. I modified the project to work in the stm32 HAL libraries now.

    Secondly, has anyone had any success with playing a track with optimization option set lower than -O3 or -Ofast such as -O2? -O3 optimizes so many variables out that it makes it very difficult to debug. But I can’t seem to get audio to play for more than a half second or about 5 loops before it locks up.

    Lastly, I’d like to change the structure a bit so that if audio does lock up, it doesn’t take the whole controller with it. ie, if I’ve got high current outputs being cycled on and off, it doesn’t freeze a high load on. I could use some collaboration on this though. Anyone interested?

  37. Hi
    This is my first time using the STM32F4 board and before running this project I’ve executed fairly good examples to know how to execute the process

    but when running this project I get the following error
    Makefile:2: *** missing separator. Stop.

    How can I rectify it , I tried to check the makefiles regarding the spaces and idendation but no use

Leave a Reply to Kwan Cancel 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.