Showing results for 
Search instead for 
Did you mean: 

Final Demo of how to play Audio files from External Memory using STM32G0 Part1


How to play Audio files from a W25Qxx SPI External Memory using STM32G0

This article guides you over the firmware implementation for the low-level portion of an audio player, including how to configure the peripherals to play audio files. Considering that the audio files are in the external SPI Flash memory, you’ll learn how to read and play them with the STM32.
This article is an evolution from another series called: “
How to play audio files using STM32?” with extended software implementation to access the external SPI Flash memory, where the audio files are stored. It has the same hardware proposal, where we also need to have an audio amplifier and a microphone / speaker to output the audio(music).

These are the requirements for this article’s implementation:
STM32CubeIDE (version 1.7.0 or higher)
STM3G0 HAL firmware pack – you can install this from within STM32CubeIDE
STSW-STM32022 ADPCM algorithm software pack
NUCLEO-G071RB – our STM32 board
STEVAL-CCA037VI – our audio amplifier board

A small board to prototype the low pass filter (breadboard / perf board)
Note: You’ll need to have your audio files in the *.wav form converted to *.ima files using command line software SOX and then to *.c files using HxD software, both processes are detailed in the article mentioned previously. Make sure to have your SPI flash mapped in the STM32CubeProgrammer and STM32CubeIDE as part of the external loader – more details in this
Before diving into the firmware, a few notes about the hardware construction. We’ll aim to have a 16bit resolution in total when using the PWM. This will be implemented with separate 8-bit MSB using TIM3 channel 1, and 8-bit LSB using TIM3 channel 2. To achieve this, the PWM output pins must pass through combined low pass filters as shown in the image below – note that there is a relationship between the resistor values, where R2 is obtained by dividing R1 by 256:

Alternatively, for a simple experiment, you can use just the MSB portion (TIM3 channel 1) and have a simpler low pass filter, like this:

The actual values used for this demo were: R1 = 8.2KOhm, R2 = 33Ohm C = 10nF, but the demo was also tested using only the PWM1 (no R2 connection), which provided a good output audio overall as well.
The hardware connection should look like this:

Since the goal is to have 16bits resolution divided by 2 PWMs, each portion segmented by 8bit resolution, we must configure the timer resolution to be equivalent to an 8bit variable, this means that the counter value should range from 0 up to 255 – this will be shown later in the STM32CubeIDE/configuration file.
The STM32G0 can run up to 64MHz and this application will use a PWM frequency of 125KHz, which will allows us to output each audio sample 8 times to ensure good audio quality, thus rendering the actual audio output frequency of 15.625KHz – a common sampled audio frequency.

This completes our overview of the hardware settings and audio sampling frequency, so let’s start this particular demonstration by creating a new project for the NUCLEO-G071RB – here it is assumed that you already know how to create a project using a given board as the default, configuration of Clock and TIM3 and the SPI. Here is a quick recap of the steps needed:

  1. Open the STM32CubeIDE
  2. Go to File->New->STM32 Project
  3. Go to the second tab “Board Selector” and type “NUCLEO-G071RB”
  4. Click on the board and then “Next”
  5. 1355.png
  6. Name the project and click Finish
  7. When the pop-up message appears, make sure to accept the peripherals with their defaults
Great, you have a project tailored for the NUCLEO-G071RB and the first thing to do is configure the TIM3 to behave as explained previously.
Start by making sure your clock is set as 64MHz, this can be done by going to the “Clock Configuration” tab and asserting the value if needed:
Back to the Pinout & Configuration Tab, add the TIM3 and configure it like this:
Note that for this demo, the PB4 and PB5 are the pins used for the TIM3_CH1 and TIM3_CH2 respectively:
Enable the TIM3 interrupt:
SPI2 Configuration on Pinout & Configuration Tab, add the SPI2 and configure it like this:

Pins PA0, PC2 and PC3 are used as SPI2 CLK, SPI2 MISO and SPI2 MOSI
respectively. As you might have noticed, the chip select pin configuration (NSS signal) is set to be handled by software, this means we’ll have to manually configure the GPIO pin PC4 as GPIO Output to drive the external Flash’s Chip Select
This implementation also used the Code Generator settings to split the peripheral initialization as a pair of source and header file, this can be achieved by going into the Project Manager tab/ Code Generator as shown below:
Now, you are all set to generate your project, so either use the short cut “Alt+K” or go to Project->Generate Code.
Once the files are created, you need to manually copy the SerialFlash.c and SerialFlash.h the flash driver created in this article
How to play audio files from External Flash memory using STM32?”. Also copy the adpcm.c, adpcm.h files from the STSW-STM32022 pack into your STM32CubeIDE project as mentioned in the previous article, under the Core/Src and Core/Inc folders.


With all these configurations we have covered all the foundation steps needed for the STM32 to play our audio file from the External memory, all that is left is to implement is the transfer of the audio file from the external memory to the peripheral, PWM. To make a more realistic implementation, here we will use the SerialFlash.c file to read the audio file from the external memory
The main.c and stm32g0xx_it.c will have functions responsible to read the given audio and we will have the TIM3 interrupt handler, which resides in the stm32g0xx_it.c, to fetch the content and decode it from the external SPI Flash memory and output it over the PWM.
To prepare the External Flash memory section we need to edit and add this section into the linker file. The linker file is the STM32G071RBTX_FLASH.ld:
Once opened, add the lines below, where the external memory position is mapped on the linker by creating a section called “myAudioFiles” :
/* Memories definition */
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 36K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 128K
  SPI_FLASH (rx)   : ORIGIN = 0x00000000,   LENGTH = 8M

.myAudioFiles : 
    . = ALIGN(4);
       __myAudioFiles_START = .;
       __myAudioFiles_END = .;

We will continue with the Firmware implementation in the next part2.
Version history
Last update:
‎2022-07-01 12:24 AM
Updated by: