Normally, if you want to play music or other audio on a microcontroller, you need to get yourself a DAC. Or at least, that’s the easiest way to go about it and the one most likely to get you good, intelligible audio. You don’t have to go that way, though, as [antirez] demonstrates.
[antirez] decided to do this with a Pi Pico, but it’s applicable to other microcontrollers too. It’s all done with a single pin and a PWM output. The PWM output is set to a very high frequency beyond human hearing. In this case, it was 100 KHz. Then, the duty cycle of the PWM is changed to essentially output various average voltage levels at the pin. Vary the output voltage as per your desired sound file by using each sample to vary the duty cycle of the PWM. Voila! You can output whatever sound you want on that pin! [antirez] steps through the basics of doing this, including processing simple WAV files into a raw format that can be dumped into MicroPython code.
There’s no sound sample on the project page, and we’d have to assume it sounds pretty crunchy when hooked up to a speaker. And yet, it could prove a useful technique if you’re designing your own audio greeting cards or something, so keep that in mind!
For those interested in doing this on the rp2040 in C++, the pico-extras repo has library support for pwm audio (along with spdif and i2s): https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_audio_pwm. It uses the PIO with DMA and handles sample conversion and buffering. I’ve only used it a bit but it seems pretty serviceable.
It is called “Delta-Sigma Modulation” and is a very common trick to get a Analog signal out of a digital device. All you need is to plop a RC/LC afterwards and you get a proper voltage signal out of it. I use it all the time when dealing with current controlled devices.
Generally the idea is to crank up the switching frequency as high as you can. The higher the frequency, the easier it is for a filter to get rid of the switching noise. With commercial Delta-sigma DACs for audio reaching into the multiple megahertz.
Filter and buffer with an active opamp and you will likely find this giving an ok, albeit probably hissy signal.
The DAC technique here appears to be simple PWM. Delta-sigma is a much more complex technique which involves digital domain filtering.
a first order delta-sigma is basically just an adder, not really complex
@fonz said: “a first order delta-sigma is basically just an adder, not really complex”
It’s a lot more than “just an adder”. For a delta-sigma DAC block diagram look at the bottom half of Figure-1 on this page:
https://en.wikipedia.org/wiki/Delta-sigma_modulation
no it is not a lot more, https://www.beis.de/Elektronik/DeltaSigma/DeltaSigmaDBlockDiagram.GIF
so it is basically add three numbers one of them inverted
Less complex is pulse density modulation, which is similar to DSM in that a low pass filter is all that’s needed for decoding. Maybe that’s what they mean?
I interpret a first order 1-bit delta-sigma as being a pulse density modulation. One state means +1 and another state means -1. If you have digital (PCM) samples in your software, then you keep a running error of how you’re doing, and add +1 or -1 for each sample depending on if you’re below or above that error. The output is a binary stream that you can feed into an analog low-pass filter to recover the intended stream. so a circuit consisting of a few op-amps is sufficient to do the job of filtering and scaling your digital output into a useful analog output.
yeah and for pushing up into the MHz i can’t shake the feeling that the rp2040’s weird little “PIO” coprocessor is just the ticket.
Antirez? That’s the Redis guy!
This existed back on the esp8366, really nothing new. I used it in a project. I seem to recall you had to do some pre processing on the sound file, but it was so long ago I really do not recall the fine points, outside of it worked well enough to warrant not getting a dedicated sound player.
I’m sure similar was done close to 40 years ago with the pc speaker
Absolutely. I’ve used almost the same techniques from the 80s and 90s with microcontrollers without DACs. Old PCs are actually a great salvage source for speakers and transistors ideal for this method with Arduino.
Update by making the CPU vibrate.
Yes. I did the same on my Apple //e in the early eighties. The best I could do was, I believe, an 80 microsecond inner loop, so the sampling frequency was in the audible range, 12.5 kHz. Not great. But now I’m an old man and I bet I couldn’t hear it anyway!
Isn’t this how the OG Raspberry Pi outputs sound over the headphone jack?
I thought this was the basis for a class d amplifier, and also how brushless DC motor controllers generate the require signals? Me electronics noob though.
Lame, the audio doesn’t stream from redis streams. Maker clearly knows nothing about high-bandwidth architectures and datastructures.
:D :p
In case my joke is too dumb, antirez is Salvatore Sanfilippo, the author of redis. I had to double check, but were there really going to be two antirez’s? ;) He’s a true engineering hero, to me.
What the hack is the KHz? I knew the kHz but Kelvin Hertz?
It is when temperature changes very quickly.
hahaha fun fact! fourier invented his transform because he had come up with a formula for how the temperature would equalize along a rod if the temperature gradient started out as a single sine wave, and he wanted to prove that therefore he’d solved the whole problem for any arbitrary temperature distribution. imo one of the crazier stories in physics.
Wouldn’t PDM be better here? It’s a low easier to low pass filter.
I did the same thing with an Arduino 15 years ago. SDCard ->Arduino Nano -> PWM pin -> low pass filter -> 741 -> audio amp -> Speaker. I was running the PWM at 44khz which twice the sample rate of the wave files I used for input. I stuffed all that in to a jewelry/music box for my wife. She loves it and it still works to this day…
The Arduino-framework of the PiPico allows this since a long time:
https://github.com/tierneytim/Pico-USB-audio