“How to use a microcontroller to drive a speaker using PWM from audio levels stored in a SPI flash chip
This project uses a microcontroller’s PWM output to drive a speaker and play audio stored in a SPI flash chip. This article combines what was learned in my two previous articles: play audio with a microcontroller and use a FT232H to program a SPI flash chip which go into more detail about the circuitry and code behind each of these major steps. By encoding audio at 8-bit resolution with an 8 kHz sample rate, 32 Mb (4 MB) of memory is sufficient to store approximately 8 minutes of raw audio. In this project I’m using a W25Q32 breakout board available on Amazon for about $2 each. Although many similar projects online demonstrate audio playback using SD cards, I find the strategies demonstrated here favorable for simple projects because it can be achieved with the addition of only a single inexpensive component.
The additional circuitry on the breadboard is for power supply filtering and audio amplification using a LM386 as described in my previous article.
The delay between each cycle of the main loop (88 µs) was determined experimentally to achieve approximately 8 kHz playback. Ideally another timer’s interrupt could manage playback, but the Arduino’s primary timer is occupied with systems tasks (like timing) and the secondary timer is used for PWM (to generate the analog audio output waveform), so this was the simplest option. An alternative approach could probably be to slow down the PWM timer’s period and use its overflow interrupt and a counter to manage frame advancement and flash memory reads outside the main program loop, but this code works well for demonstration purposes.
It’s worth noting that accessing the flash memory at 8 kHz is also excessive. A more sophisticated approach is to use a buffer in memory to store chunks of audio data which can be tactically loaded from the SPI chip without requiring a full transaction on every PWM update. Building large buffers can be slow though, so managing the buffer should be performed carefully so as not to require more time than the 8 kHz interrupt needs to complete its cycle.”