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