I think there are all sorts of modulation schemes that can be used to generate a PDM like signal. The good ones do a lot of clever things to do noise shaping and make sure it's all up the high frequencies so gets filtered out.
Maybe I'm abnormal but I could look at the bitstream above and pretty much see that it was a falling line, although I couldn't tell it was roughly straight (I assumed it was a sine).
What happened here? I know that low-pass filters can "ring" and therefore have some gains in some cases. But any simple FIR digital filter won't ring like this and end up with a value above 1.00
What filter did you (erm, ChatGPT) decide to use that (1 1 1 1 1 1 1 1 0 1 1 1 1) or so averaged out to a value above 1.00 ?
X simply increments with time as a 16 bit signed value so it wraps. Consider it signed value q15 so range is +/-1. Y is then (1-x^2)^2 which approximates a sine wave for brightness (0 to 1). The accumulator "a" gets this added on, but it's as 12 bit accumulator and the overflow/carry bit goes to the led. The carry is cleared on the following iteration. By the mask just before adding in y again. The rate of overflows determines the brightness.
For something that looks to a human like smooth blinking, you really need to have a sine wave, and it needs to be gamma corrected... There might be some easy way to do that, but I always just use a linearly interpolated 8 stage lookup table...
Here's a blog post[1] showing how to do something very similar with the Raspberry Pi Pico, which also doesn't have a DAC. I wrote a very simple 4-channel MOD player[2] for the Pico using his sound output code.
Nice! If I remember correctly, PDM output was uncharted territory on the original ESP32 for several years, despite there even being a low-pass filter suggestion in the docs.
> Low-effort clickbait? Or an innocent misunderstanding by someone who thinks DACs have to be expensive?
Probably the latter. Things like Arduino and cheap ESP modules from china have made electronics vastly more accessible than they were previously. Given that, it makes sense that somebody wouldn't really understand _how_ a DAC works but would understand what one does, what it's used for and that the datasheet for $currentModule says there is none present.
The ready availability of Arduinos and similar technology has brought a lot of people into that scene who are not aware of what all is available to them, what all the bits and bobs are, and what you can bash together with a few resistors and capacitors hooked up correctly.
People like me. I think I can call myself tolerably good at programming, but I can easily tell I'm much more newb at EE and I can really only operate with things that have clearly defined outputs that match up to some other input. Where you may see trivial conversions you could bash together in your sleep, I see an output that doesn't match the input and don't immediately know where to go with that.
In my case, I'm able to follow the post just fine, but if I had to put that circuit together from scratch from first principles I'd be looking at weeks of learning more about EE. And as a result, as I am blundering about an unfamiliar landscape in some personal projects I've got going on, I appreciate posts like this.
That’d be some mighty selective baiting leading to a disappointingly feeble number of clicks. Unless the population of Arduino+audio nerds is secretly massive, which I’m pretty sure is not the case.
In think they just mean "on-chip/integrated DAC peripheral" when they say DAC (which is what a lot of hobbyists/non EE folk think of from the term). The article's just trying to say you don't need one for an audio use case and can use a discreet RC.
I think a 1st order RC filter is simple enough that you could argue that "you don't need a DAC" and is what I expected.
But when I opened up the post and saw a 2nd order (probably) Sallen-key (or is this a MFB? I always get my topologies confused...) with a full-bore OpAmp and capacitors up the wazoo... erm... yeah, they're basically hand-building a DAC at this point.
---------------
A lot of stuff is wishy-washy definitions anyway. What's the difference from an analog-comparator and a ADC anyway? An analog-comparator is just a 1-bit ADC after all.
So a lot of "what is a DAC" exactly is up to opinion around the edges. But if you've got op-amps and signal conditioning, you're getting pretty darn close to "proper DAC" except you know, not as good (ie: cheap, fast, or simple) as a proper professional solution.
-------
EDIT: Reread blogpost. It looks like the RC-filter is in fact, being used. The Espressif docs __suggest__ the OpAmp based 2nd-order filter, but the blogpost is strictly with the simple 1st order RC-filter.
So yeah, I'd say that RC-filter is "not a DAC", due to being too simple. (It functions as a DAC in this case, but we got to draw the line somewhere).
Stupid question: why did espressif leave out the DAC for the S3? I thought it was the new "default" base esp32. I know they had issues with the analog converters in general but this is surprising to me!
The rumour is that the DAC took up a lot of die space and there wasn’t enough room.
For most use cases PWM or PDM is sufficient. For more complex cases you are probably looking for some very specific performance characteristics and an external IC probably makes more sense.
I'd love to have a dac built in, but it strikes me as being a bit like the old tv-vcr combos.
If the built in vcr stinks or doesn't quite meet expectations you're either stuck with its subpar performance, or with the sunk cost of an unused or unusable feature.
Many people might want an audio quality dac.. but 8 bit? 16? 24? Or maybe 4 bit is fine but you need 12 of them... Best to just have good peripheral support.
Interesting! On STM32 etc, the DAC is considered a hacky way of doing audio compared to the SAI peripheral; here without even a DAC, they are making it work.
They've directly implemented a classic design of a DAC by using an external component. You can buy DACs that are exactly this. You can also implement a DAC with digital IO and some resistors. But, having things integrated is nice, and often cheaper. :)
Just for fun, I tried turning a CP2102 USB UART adapter into a PDM DAC, using the raw output of the serial bitstream. It sounds "not good", but honestly not that bad either. Here's a sample from it: https://retr0.id/media/5c4c16ac-bc6d-4bf0-9159-73bbe4fcfb02/...
The only external components were a simple passive RC filter.
Usually there are plenty of free unused CPU cycles. External hardware, on the other hand, is expensive. So why not save some money and use the CPU?
Besides, I don't think it actually uses substantially more CPU than an external DAC. You'd be feeding a DMA buffer into the I2S peripheral either way. If you precompute the PDM waveform from the audio sample it's essentially free. Using a LUT or even computing it realtime should only take a dozen or so cycles per sample, at 44.1kHz.
Considering that the ESP32-S3 has two cores running at 240MHz, even taking an excessive 500 cycles per sample would only be a 5% CPU load.
To me the value of the ESP32 has always been the peripherals that substitute for pure CPU usage (although, it's certainly nice that it has the CPU cycles to do interesting things).
Isn't Delta-Sigma and PDM exactly how DSD works? In fact, I think Sony originally came up with DSD as an intermediate representation of PCM in one of their DACs and then Sony & Phillips got the harebrained idea to use it in SACD. That is to say, a simple DAC for DSD is just a capacitor functioning as a low-pass filter, without any other components.
> I would claim that 70% of software engineers would love taking an electronics course. It's like programing, with electrons.
I very much think all software engineers should take an electronics course. At least an introductory one. Knowing how things work will improve your code, and will give you an alternate way of thinking about programming problems.
But I'll admit my bias: I came to programming by way of a digital electronics course as a child. Since I was a child of a poor family, I couldn't afford to actually do electronics projects at home, though (this was well before everything got so inexpensive), and shifted to programming because you could do that for free if you had access to a computer.
I’m curious : how would knowing more about electronics improve code ? To me, the basic properties of electricity are hidden behind the higher level hardware components code can interact with
Probably the same way exposure to different paradigms of writing software helps one become a better programmer - more abstract tools in your toolkit, more ways to think about how to solve a problem.
If you're ever dipping down into firmware level stuffs, it makes reasoning about things much easier. I can intuit whole systems, where my software only friends really struggle. Some firmware bugs are immediately debugged with a o-scope.
I spent an entire summer circa 2010 trying to rip the decrypted DSD signal off an SACD player via an FPGA. I figured the simple on/off levels would be easy to grab but I had not much success beyond being able to visualize it on a scope. Was trying to get at the high resolution, multichannel tracks for a Lord of the Rings soundtrack.
I spent somewhat inordinate amount of time around 2010 by designing a Class D PA amplifier that used DSD-like bitstream internally. The idea was to convert analog input signal into this bitstream by what amounted to somewhat convoluted sigma-delta ADC, process that with FIR filter in digital hardware and drive MOSFET H-bridge with that. The thing ended up ridiculously complicated (with somewhat impressive amount of SRAMs) and totally non-practical (through hole 74HCT and GALs, which worked out to something like 15 3U eurocards). I never got to complete the board layouts, much less building it, which is probably a good thing.
As I understand it, the really nice modern class D amplifiers use feedback internally, which more or less eliminates using a pre-computed DSD-like bitstream as a good option.
On the other hand, FPGAs and really fast microcontrollers are a thing now, so you could probably get a chip with a nice internal ADC, digitize the output voltage, and use an actual computer program to drive the H bridges, thus making an extremely non-cost-effective class D amplifier :)
The “high-end” PA Class D amplifiers (the kind of thing that is used in clubs on Ibiza and such things) have feedback loop and the feedback loop is closed in purely analog domain around the whole Class D amplifier, alternatively one can look at that as an giant SMPS with large slew rate, which is what that is (there is a bunch of anecdotal evidence around the losses in the output reconstruction/low-pass filters that apparently can reach temperatures that the solder melts, which is kind of problematic when in the chassis the board is mounted components down).
Issue with doing what I tried to do and FPGAs is that the overall architecture of this kind of DSP is perfect example of a thing that does not match the FPGA architecture. It boils down to ridiculously long shift register, few bits per tap of parameter data and reducing tree for the result, ie. most of that is ridiculous amount of 1bit SRAM cells.
And well, in the end I realized that idea, in not-even-that-fast-for-the-time ARM11TDMI and software and 24b samples at 96kSps (both of which is realistically a total overkill for this application), but without the DSD input (in theory the code that produced the output can be inverted and used to convert DSD to some sane representation, but well, I did not really care)
I did not read the article in-depth but class D audio amplifiers use variable pulse widths and then filter it before the speaker. Aside from very good efficiency you also remove the need for a transformer using this method hence why its used.
I'm not sure which is the hard part you're referring to- implementing the amplifier itself, or the board around it. I don't think an amateur would want to build their own class-D from raw components except for pedagogical purposes.
(i've been pretty happy with the results, I used the board to drive a couple speakers and the amplifier is not the first thing I'd fix to improve the audio quality.
I looked at the schematics of the PDM amplifier chips linke and I am puzzled why they put a DAC in front of a class d amp. Can you just digitally amplify the PDM out and then do the low pass trick. I thought that was all the class-d amps are doing.
Highly recommend reading the various interviews and papers by Bruno Putzeyes. He’s been pushing the state of the art in PDM / PWM / Class-D amplification for the last 20 years or so.
Here’s a white paper of his specifically about direct PWM amplification.
I had really good success abusing the PWM pins on AVR microcontrollers into acting as 8-bit DACs. Hooking up earbud headphones or a tiny powered speaker was all that was needed for decent (for 8 bit) fidelity. No low pass necessary since the PWM artifacts were at the upper edge of audibility.
Those micros were much weaker than the ESP, so the audio was all synthesized with a roughly nintendo-parity waveform selection rather than samples. In fact the earliest version was on an attiny85 which had no hardware multiplication, so.. lots of fixed point arithmetic and lookup tables were involved.
My pet project was DuinoTune, which would convert tracker-music into ready-to-compile code.
It's not very far off to digital audio over PC speaker I'm sure!
The AtTiny85 had a great setup for it though, a high speed PWM clock which gives you a 250khz carrier, so just use another hardware timer interrupt every 20khz or so to calculate the waveform and change the PWM duty cycle and boom - music on a pin!
I've done such things when using microcontrollers that lacked a DAC. In my projects, I try hard to use the smallest/wimpiest microcontrollers that can do the job I need done, and for some applications, making do without a DAC is a good tradeoff for me.
However, having an actual on-board DAC is best in general. You get better results and a lower parts count.
My question is, why is every integrated adc/dac in almost every commercial microcontroller stagnant at 12 bit resolution? It's been that way for decades now. Is 16 bit that difficult?
IIRC, switching EM noise from the microcontroller itself (at the MHz range) starts to affect the ADC/DAC. Your "16”-bit converter gives 12 useful bits and 4 bits of junk.
For an ADC, you can get back useful bits via Oversampling & Decimation, at the expense of bandwidth.
Lots of people in this thread reporting “success” with filtered PWM/PDM. Are we ignoring that it sounds terrible? It’s a recognizable audio signal but that’s about it.
In theory, correctly filtered PWM or PDM at a correct modulation rate is identical to the original audio (nyquist-shannon). In practice the square waves produced have so much harmonic content that you need a good filter (like the active opamp filter in the article), and the simple RC filter that a lot of these projects use will sound terrible due to their long cutoff slope.
Very high fidelity sigma delta DACs are filtered PDM, they just use high modulation rate and good filters.
79 comments
[ 3.3 ms ] story [ 146 ms ] threadhttps://gist.github.com/phkahler/1ddddb79fc57072c4269fdd6716...
I just drop that in my 20khz isr and point to the GPIO with the LED.
1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
Ummmm...
What happened here? I know that low-pass filters can "ring" and therefore have some gains in some cases. But any simple FIR digital filter won't ring like this and end up with a value above 1.00
What filter did you (erm, ChatGPT) decide to use that (1 1 1 1 1 1 1 1 0 1 1 1 1) or so averaged out to a value above 1.00 ?
All in constant execution time too!
Here's a blog post[1] showing how to do something very similar with the Raspberry Pi Pico, which also doesn't have a DAC. I wrote a very simple 4-channel MOD player[2] for the Pico using his sound output code.
[1] https://gregchadwick.co.uk/blog/playing-with-the-pico-pt3/
[2] https://github.com/moefh/pico-mod-player
Aparently very high quality audio.
https://www.reddit.com/r/minidisc/s/OTHQJwSt92
They used ΔΣ as their logo.
Nope, that's what they're actually doing. Congrats, you've built a very simple external DAC.
Low-effort clickbait? Or an innocent misunderstanding by someone who thinks DACs have to be expensive?
Probably the latter. Things like Arduino and cheap ESP modules from china have made electronics vastly more accessible than they were previously. Given that, it makes sense that somebody wouldn't really understand _how_ a DAC works but would understand what one does, what it's used for and that the datasheet for $currentModule says there is none present.
People like me. I think I can call myself tolerably good at programming, but I can easily tell I'm much more newb at EE and I can really only operate with things that have clearly defined outputs that match up to some other input. Where you may see trivial conversions you could bash together in your sleep, I see an output that doesn't match the input and don't immediately know where to go with that.
In my case, I'm able to follow the post just fine, but if I had to put that circuit together from scratch from first principles I'd be looking at weeks of learning more about EE. And as a result, as I am blundering about an unfamiliar landscape in some personal projects I've got going on, I appreciate posts like this.
But when I opened up the post and saw a 2nd order (probably) Sallen-key (or is this a MFB? I always get my topologies confused...) with a full-bore OpAmp and capacitors up the wazoo... erm... yeah, they're basically hand-building a DAC at this point.
---------------
A lot of stuff is wishy-washy definitions anyway. What's the difference from an analog-comparator and a ADC anyway? An analog-comparator is just a 1-bit ADC after all.
So a lot of "what is a DAC" exactly is up to opinion around the edges. But if you've got op-amps and signal conditioning, you're getting pretty darn close to "proper DAC" except you know, not as good (ie: cheap, fast, or simple) as a proper professional solution.
-------
EDIT: Reread blogpost. It looks like the RC-filter is in fact, being used. The Espressif docs __suggest__ the OpAmp based 2nd-order filter, but the blogpost is strictly with the simple 1st order RC-filter.
So yeah, I'd say that RC-filter is "not a DAC", due to being too simple. (It functions as a DAC in this case, but we got to draw the line somewhere).
For most use cases PWM or PDM is sufficient. For more complex cases you are probably looking for some very specific performance characteristics and an external IC probably makes more sense.
If the built in vcr stinks or doesn't quite meet expectations you're either stuck with its subpar performance, or with the sunk cost of an unused or unusable feature.
Many people might want an audio quality dac.. but 8 bit? 16? 24? Or maybe 4 bit is fine but you need 12 of them... Best to just have good peripheral support.
The only external components were a simple passive RC filter.
https://hackaday.com/2005/10/25/audio-output-from-a-serial-p...
(Looks like somebody mirrored it to github at https://github.com/koniu/ttyplay)
Besides, I don't think it actually uses substantially more CPU than an external DAC. You'd be feeding a DMA buffer into the I2S peripheral either way. If you precompute the PDM waveform from the audio sample it's essentially free. Using a LUT or even computing it realtime should only take a dozen or so cycles per sample, at 44.1kHz.
Considering that the ESP32-S3 has two cores running at 240MHz, even taking an excessive 500 cycles per sample would only be a 5% CPU load.
> has two cores running at 240MHz
Yeah ok that is manageable.
I would claim that 70% of software engineers would love taking an electronics course. It's like programing, with electrons.
I suspect the next link in the cycle will be how you can make music on an old AM radio, if you attach a length of unterminated wire instead of a cap!
I very much think all software engineers should take an electronics course. At least an introductory one. Knowing how things work will improve your code, and will give you an alternate way of thinking about programming problems.
But I'll admit my bias: I came to programming by way of a digital electronics course as a child. Since I was a child of a poor family, I couldn't afford to actually do electronics projects at home, though (this was well before everything got so inexpensive), and shifted to programming because you could do that for free if you had access to a computer.
On the other hand, FPGAs and really fast microcontrollers are a thing now, so you could probably get a chip with a nice internal ADC, digitize the output voltage, and use an actual computer program to drive the H bridges, thus making an extremely non-cost-effective class D amplifier :)
Issue with doing what I tried to do and FPGAs is that the overall architecture of this kind of DSP is perfect example of a thing that does not match the FPGA architecture. It boils down to ridiculously long shift register, few bits per tap of parameter data and reducing tree for the result, ie. most of that is ridiculous amount of 1bit SRAM cells.
And well, in the end I realized that idea, in not-even-that-fast-for-the-time ARM11TDMI and software and 24b samples at 96kSps (both of which is realistically a total overkill for this application), but without the DSD input (in theory the code that produced the output can be inverted and used to convert DSD to some sane representation, but well, I did not really care)
I'm not sure which is the hard part you're referring to- implementing the amplifier itself, or the board around it. I don't think an amateur would want to build their own class-D from raw components except for pedagogical purposes.
(i've been pretty happy with the results, I used the board to drive a couple speakers and the amplifier is not the first thing I'd fix to improve the audio quality.
I guess you can't really trust the raw PDM output from an MCU which might not be very well designed or shaped.
Maybe better to convert back to analog and then apply whatever secret sauce you have to make the class D amplifier work really well.
Here’s a white paper of his specifically about direct PWM amplification.
https://www.researchgate.net/publication/242013327_All_ampli...
I went back and played it on my Apple //e, it holds up pretty well. The source code for the sequel was released by the authors widow, around 2004. https://archive.org/details/BeyondCastleWolfenstein_source
Oh, now I see it's just decompiled, not the original source. But you'd still be able to find the data and code for the audio.
Those micros were much weaker than the ESP, so the audio was all synthesized with a roughly nintendo-parity waveform selection rather than samples. In fact the earliest version was on an attiny85 which had no hardware multiplication, so.. lots of fixed point arithmetic and lookup tables were involved.
My pet project was DuinoTune, which would convert tracker-music into ready-to-compile code.
https://www.youtube.com/watch?v=rFqvPWnolfY
https://www.youtube.com/watch?v=G3baH5iTcFM
https://github.com/blakelivingston/DuinoTune
This sounds like tricks demo scene coders use to coax sampled audio out of unlikely things like apple IIs and XT-era hardware.
However, having an actual on-board DAC is best in general. You get better results and a lower parts count.
For an ADC, you can get back useful bits via Oversampling & Decimation, at the expense of bandwidth.
So you can get 100 (bad) analog outputs out of an FPGA. There has to be an application for that. :D
Very high fidelity sigma delta DACs are filtered PDM, they just use high modulation rate and good filters.