Learn how to use the MAX98357A breakout board with an ESP32 to output audio, create a digital audio path, configure the I2S interface, and read WAVE files from SPIFFS in this engaging tutorial.
[0:00] Music Playing…
[0:20] Hey Everyone, we’ve spent a couple of videos getting audio into the ESP32
[0:26] We’re now going to switch it up a bit and get audio out of the ESP32!
[0:32] I’m going using the MAX98357A breakout board from Adafruit.
[0:40] This is a class D amplifier with an I2S interface.
[0:45] You need to wire up the LRC, BCLK and DIN lines.
[0:51] Be careful not to confuse the pin labelled SD with the Serial Data pin
[0:55] this pin is actually the Shutdown and channel select pin.
[1:00] Use the DIN pin for the serial data.
[1:03] The amplifier needs to connect directly to a speaker
[1:06] you cannot use this board as a pre-amp.
[1:10] The amount of power you can get out of the board depends on the impedance of the speaker
[1:15] and the voltage you supply to the board.
[1:17] The maximum output you can achieve is 3 watts with a 5V supply and 4ohm speaker
[1:24] but this does come at the price of some audio distortion.
[1:28] If you want to run at this power you will need a power supply that can deliver at least 1.25 Amps.
[1:35] You can control the amount of amplification the board provides by configuring the gain pin.
[1:40] In my tests I have found that leaving the pin floating seems to cause some random noise on the output
[1:45] so it may be worth experimenting in your own setup or tying the pin high or low with or without a resistor.
[1:53] In the video I had the gain pin pulled down with a 100K resistor for maximum gain.
[2:00] The SD pin is a bit more complicated to configure and is confusingly named
[2:05] a lot of other boards use SD to stand for Serial Data
[2:09] but in this case it’s the Shutdown and mode pin.
[2:13] If you are planning on playing mono audio then you can leave it floating
[2:18] and simply send data on both the left and right channels simultaneously.
[2:23] If you tie it to ground then the amplifier will shut down
[2:27] if you tie it to Vin then the amplifier will play the left channel.
[2:31] And to play the right channel you need to use a pull-up resistor.
[2:34] The value for this resistor is slightly complicated by the fact that the board
[2:39] already has an internal voltage divider on this pin.
[2:42] I’ve calculated an appropriate value for the resistor for you in this table of 39Kohm
[2:49] which should work for both 3.3V and 5V
[2:52] but you may want to use 47Kohm resistor if using a 5V supply to be safe and allow for
[2:59] resister tolerance.
[3:01] That’s the basic wiring of the board, but what actually is a class D amplifier?
[3:08] Class D amplifiers are also known as switching amplifiers.
[3:13] They output a modulated signal that switches between the positive and negative power rails.
[3:20] This signal is passed into a low pass filter or directly to the loudspeaker to recover
[3:25] the audio signal.
[3:27] This makes the amplifier very efficient as the transistors are only dissipating power
[3:32] when they are switching from high to low and low to high.
[3:37] This animation demonstrates this process - we have an input sine wave coming into the system.
[3:42] This input signal is then converted to the PWM signal
[3:47] and then we reconstruct the output by low pass filtering the PWM signal.
[3:52] In this animation I am using a very low frequency for the PWM signal.
[3:58] So our reconstructed signal is very noisy.
[4:01] This next animation shows how you can create a PWM signal.
[4:06] Once again we have an input sine wave.
[4:10] To generate the PWM signal we compare the input signal with a high-frequency triangle wave.
[4:16] Where the signal is higher we output high and when it is lower we output low.
[4:22] I’ve captured the output from the amplifier when it is being fed with a 10KHz sin wave.
[4:30] To simulate the speaker acting as a low pass filter I’ve added a simple LC filter to
[4:35] the output and captured the filtered signal.
[4:39] As you can see we can recover the 10KHz input sine wave from the amplifier’s PWM signal.
[4:47] One of the nice things about this board is that it has an I2S interface.
[4:53] This means that we can feed it a digital signal straight from the ESP32.
[4:58] Our entire audio path is digital up until the speaker output.
[5:03] Let’s have a look at how the I2S interface is wired up.
[5:07] There are at least three required lines:
[5:10] We have a serial clock - this is used to clock data to or from the peripheral.
[5:16] We have a word select (also called the left-right clock or LRCLK)
[5:22] this selects the channel that you want to send or receive data for.
[5:26] And finally, we have the data line.
[5:29] When the Word Select is low data for the right channel is sent,
[5:33] and when it is high data for the left channel is sent
[5:36] I’ve captured these three lines from the ESP32 on my oscilloscope
[5:43] Here we see the left-right clock line going high and low for each channel.
[5:48] And here is the serial clock.
[5:51] I’m sending 16-bit data so we see 16 clock cycles for each left-right clock phase.
[5:58] And here is the serial signal carrying the audio data encoded as 16-bit words.
[6:05] That’s all the wiring up taken care of.
[6:08] Let’s have a look at the code.
[6:11] Here we have the I2S configuration
[6:14] We will be running in master mode and transmitting data
[6:19] We’ll take our sample rate from whatever is being used to generate our samples - either
[6:25] directly from a WAV file or from a generated signal.
[6:30] We’ll output 16 bits for each sample
[6:34] And we’ll be outputting both left and right channels - this lets us support both mono
[6:40] and stereo sources.
[6:42] The stereo source will be mixed by the amplifier board into mono.
[6:47] If you have two amplifier boards then you could configure one to be the left channel and one
[6:52] to be the right channel and connect them to the same I2S pins.
[6:58] Sending data is pretty straightforward
[7:01] We wait for the I2S peripheral to reach the end of one of its DMA buffers
[7:07] And then we pull some samples from our sample generator
[7:10] And then we write those samples out to the I2S peripheral
[7:15] We need some audio data to play - the simplest format for us to use are WAVE files.
[7:22] The header for a WAVE file contains all the information we need to understand the contents
[7:26] of the file.
[7:27] We’ll only try and support very basic WAVE files.
[7:31] We need the number of channels - we can support either mono or stereo files in our code.
[7:37] And we need the sample rate to configure the I2S peripheral.
[7:43] We also need to know the bit depth - in our code we can only support 16-bit samples
[7:48] but the code could be extended to support other bit depths.
[7:53] Here’s some very basic code for reading the WAVE file header.
[7:57] We can read directly into our C structure
[8:01] And pull out the details we are interested in.
[8:07] Here’s the basic code for reading samples from a WAVE file
[8:12] We seek past the header data which we know is 44 bytes
[8:15] And then read a sample from the file
[8:19] If we only have mono data then we copy across the left channel to the right channel
[8:24] Otherwise we read in the next sample from the file for the right channel
[8:29] All we need to do now is wire up the sample generator to the I2S output and we should
[8:34] get audio coming out of the speaker.
[8:39] We store our audio files on SPIFFS - to do this in platform.io you put them in the data folder.
[8:45] To upload the filesystem, click on the platform.io icon and then find the env section in the
[8:52] project tasks.
[8:53] Scroll down and you’ll find the upload file system command.
[8:58] So, that’s it for this video, I found the MAX 98357 very easy to use and a nice simple
[9:05] way to get audio data out of the ESP32.
[9:08] It’s a class D amplifier so it’s very efficient.
[9:12] The I2S interface means that we are pretty much digital all the way to the speaker output
[9:19] We’ve also seen that reading basic WAV files from the SPIFFS is pretty straightforward.
[9:24] Thanks for watching, all the source code is on GitHub - the link is in the description.
[9:30] If you found the video useful then please hit the subscribe - there’s more videos
[9:34] in the pipeline
[9:35] and I’m still working on my next big project which is getting pretty interesting!
[9:40] Thanks again and I’ll see you in the next video.
[9:43] Music Playing