View All Posts
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi

So, there’s no DAC on the ESP32-S3.

You would think this would be a bit of a downer if if you want to get audio out and use an analog amplifier.

But it’s actually surprisingly easy to output Pulse Density Modulated audio using Sigma Delta Modulation on the ESP32 and you can recover the audio signal by low pass filtering it - an RC filter can be sufficient for this. And that’s what I’m using in the video.

Though the Espressif docs do suggest a much better active filter.

It’s pretty interesting to look at a PDM signal and view it in the frequency domain. Here’s a piece of audio along with it’s spectrogram:

And here’s a simulated PDM version of the original audio. The sample rate of the PDM data is just over 1MHz and I’m showing the spectrogram from 0 to 500KHz

The PDM data just goes from -1 to 1 and changes density depending on the value of the original signal.

If we just look at the lower 8KHz of the spectrum then we can see what looks like our original signal.

So to recover the original audio we just apply a low pass filter - and hey presto, we have our original audio signal back!

So how to do we do this on the ESP32?

There’s a couple of options available to us.

The example code from Espressif suggests using a timer to output each sample using the sigmadelta_set_duty (you could also just use plain old PWM as well). This does work for audio data, and I’ve got some simple sample code that will do it, but it’s not very efficient - we’re constantly interrupted by a timer to send out the next sample. There’s also quite a lot of code required if you want to stream samples out from some other source.

A much better way is to use the I2S peripheral which can also output PDM data. There are two annoying things with this which are highlighted in the timing diagram from the docs.

The first issue is that it always wants to output a left and right channel. This is a bit awkward if we just want to feed the PDM signal straight into an analog audio amplifier or headphones. But we can get around this by just outputting the same value for both the left and right channels.

The second issue is that it always wants to output a clock signal - we don’t really need this. My workaround for this was to just assign the clock to IO45 or IO46 - on the S3 you can’t really use these pins for much as they are strapping pins and it’s best to just leave them alone. But you can use them for outputs once the ESP32 has started up.

There are “proper” PDM amplifier ICs that will take this signal - for example the MAX98358 or the SSM2537.

This all works surprisingly well, you can drive headphones directly from the PDM signal and most analog amplifiers will take the combined stereo PDM signal and will have a low enough bandwidth that they’ll just work.

You can even just drive a speaker with a really simple half or full bridge and get reasonable audio out (though it may be quite noisy).

Have a watch of the video and let me know what you think.


Related Posts

ESP32 Audio Input - MAX4466, MAX9814, SPH0645LM4H, INMP441 - In this blog post, I've delved deep into the world of audio input for ESP32, exploring all the different options for getting analogue audio data into the device. After discussing the use of the built-in Analogue to Digital Converts (ADCs), I2S to read ADCs with DMA, and using I2S to read directly from compatible peripherals, I go on to present hands-on experiments with four different microphones (MAX4466, MAX9814, SPH0645, INPM441). This comprehensive look at getting audio into the ESP32 should be a valuable resource for anyone hungry for a deep-dive into ESP32's audio capabilities, complete with YouTube videos for an even more detailed look!
Minimalist Microcontroller: Building a Bare-Bones Dev Board - In a thrilling DIY endeavour, I attempted to build the most minimalist ESP32 dev board possible. Diving deep into the schematic of the ESP32 S3 WROOM module, I chopped out the non-essentials and whittled our needs down to bare bones. The experiment saw me juggling USB data lines and voltage regulators, waving goodbye to an array of capacitors and connectors and boldly embracing the simplicity of direct connections. Despite a few hitches, the miniature Frankenboard came alive, proving that sometimes less is least in the world of microcontrollers.
ESP32-S3: Which Pins Should I Use? - As an enthusiast of the ESP32-S3's versatility, I recognized the importance of understanding which pins are best to avoid. Inspired by the Random Nerds page for the classic ESP32, I've created a comprehensive pinout for the ESP32-S3 available on GitHub. The community's input is highly valued – suggestions and corrections are welcome to refine this resource into a dynamic guide for developers.
Decoding AVI Files for Fun and... - After some quality time with my ESP32 microcontroller, I've developed a version of the TinyTV and learned a lot about video and audio streaming along the way. Using Python and Wi-Fi technology, I was able to set up the streaming server with audio data, video frames, and metadata. I've can also explored the picture quality challenges of uncompressed image data and learned about MJPEG frames. Together with JPEGDEC for depth decoding, I've managed to effectively use ESP32's dual cores to achieve an inspiring 28 frames per second. Discussing audio sync, storage options and the intricacies of container file formats for video storage led me to the AVI format. The process of reading and processing AVI file headers and the listing subtype 'movi' allowed me to make significant headway in my project. All in all, I'm pretty chuffed with my portable battery powered video player. You can check out my code over on Github!
ESP32 I2S DMA Settings - dma_buf_len and dma_buf_count Explained - In this blog post, we delve deep into the intriguing concepts of I2S audio and DMA, particularly focusing on parameters like dma_buf_count and dma_buf_len. We explore their roles, ideal values, and the impacts they have on aspects such as CPU load and latency. We also discuss the limitations that come hand in hand with these parameters. This post aims to provide you some insights on trading-off between latency, CPU load, memory usage and the overall buffer space allocation. However, the primary takeaway remains that the optimal configurations largely depend on individual context and application needs.

Related Videos

We don't need a DAC - ESP32 PDM Audio - In this video, I've made some fascinating explorations with the ESP32 S3 chips and TinyS3 boards from Unexpected Maker. Intriguingly, even without a DAC converter, S3 chips can produce an audio waveform. I've played around with a basic RC filter to reconstruct the analogue audio signal from a PDM signal. The result was quite impressive for a board without a native DAC! I also discussed the possibility of creating a simple amplifier using just a MOSFET as a switch. Finally, I gave a peek into some of my new boards from PCBWay and looked at how Delta Sigma modulation can be played with to recover original data. It's all quite a fun foray into the world of circuitry and audio signals!
ESP32 Audio: I2S & Built-In DACs Explained - Learn how to utilize ESP32's built-in Digital to Analog Converters (DACs) for outputting audio and arbitrary signals at high frequencies, along with a step-by-step guide on configuring the I2S peripheral for using DAC channels.
ESP32 Audio Input Using I2S and Internal ADC - Learn how to effectively capture audio data using an ESP32 device and analog-to-digital converters in this detailed tutorial. Discover the power of I2S peripheral with DMA controller and optimize your system's audio performance with the MAX 4466 and MAX 9814 microphone breakout boards.
Play MP3 Files on ESP32 Without Codec Chip: Easy Guide - Learn how to decode and play MP3 audio files on the ESP32 with both headphone support and I2S digital amplifiers. Discover techniques to enhance audio quality and reduce power interference for clearer sound.
Sound and (almost 😉) Vision - We're getting closer to our own Tiny 📺 - In this exciting video, we're making progress on our miniature television project, having perfected sound and making strides with vision. We delve into the audio aspect, utilizing Mini esp32 S3 boards with 3-watt class D amplifiers based on the versatile max 98357ic. Fascinating features like class D amplifiers' efficiency and the easy PWM signal creation process are explored. We also play around with speakers of varying sizes, check out the temperature of the amplifier, and fiddle with animated gifs on our square display. Lots to come in future videos, including Version 2 of our boards and potential video playing methods!
HELP SUPPORT MY WORK: If you're feeling flush then please stop by Patreon Or you can make a one off donation via ko-fi
Want to keep up to date with the latest posts and videos? Subscribe to the newsletter
Blog Logo

Chris Greening


> Image


A collection of slightly mad projects, instructive/educational videos, and generally interesting stuff. Building projects around the Arduino and ESP32 platforms - we'll be exploring AI, Computer Vision, Audio, 3D Printing - it may get a bit eclectic...

View All Posts