Hacker News new | past | comments | ask | show | jobs | submit login
We don't need a DAC on the ESP32-S3 (atomic14.substack.com)
155 points by iamflimflam1 8 months ago | hide | past | favorite | 71 comments



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.


I did this a while back:

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)


It sounds "fluttering" as if there's periodic pauses in the bitstream being sent.


This is a DAC. The low-pass filter is an integrator in disguise.


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).


It's how every sigma-delta DAC works, basically. Less snappy headline though.


Yes. Sharp had a line of minidisc players back in the day with a 1.8 MHz ”1-bit” technology. https://global.sharp/products/1bit_system/tech_sub.html#:~:t....

Aparently very high quality audio.

https://www.reddit.com/r/minidisc/s/OTHQJwSt92

They used ΔΣ as their logo.


That's how SACD works too: 1-bit 2.8MHz DSD.


"We don't need dedicated hardware that's marketed as a DAC on the ESP-32-S3"?


This was so obvious before even clicking, I couldn't imagine that level of trolling on HN, I had to click in to see what they were actually doing.

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?


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.


> 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.


I have no problem with the article, wouldn't say that it's clickbait either. Just saw a DAC >:)


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.


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.


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.


Hardware is getting more and more esoteric, so the delight and surprise should be expected, and encouraged. :)

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 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 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.

https://www.youtube.com/watch?v=rFqvPWnolfY

https://www.youtube.com/watch?v=G3baH5iTcFM

https://github.com/blakelivingston/DuinoTune


> I had really good success abusing the PWM pins on AVR microcontrollers into acting as 8-bit DACs.

This sounds like tricks demo scene coders use to coax sampled audio out of unlikely things like apple IIs and XT-era hardware.


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!


That's really nice!

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


The RP2040 with its PIO is such a versatile chip, I've had a lot of fun working with it over the past year.


Very compact (if cryptic) code to smoothly blink an LED using PDM here:

https://gist.github.com/phkahler/1ddddb79fc57072c4269fdd6716...

I just drop that in my 20khz isr and point to the GPIO with the LED.


I threw that code in a small program. The output of that code seems too regular for it to be PDM, but then I don't really understand the code.

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


I got ChatGPT to read the data, low pass filter and then downsample it.

  1.0035971164599362
  0.9085335060080786
  0.9035432831636958
  0.7979082616868238
  0.7167128607342428
  0.5957569676023409
  0.49808942875852646
  0.4009797804151446
  0.3308973662512045
  0.1857546947996519
  0.07410762115348818
Here's a plot of the original data and low pass filtered: https://imgur.com/a/kCxA7XK


> 1.0035971164599362

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 ?


And that, friends, is why don’t trust a language model to analyze data.


Nice! I guess I'm just bad at judging what's PDM and what's not. :-)


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).


It's sine-ish. It's (1-x^2)^2 with x from -1 to 1.


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.

All in constant execution time too!


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...


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.


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.


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.


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.


Reading up on the ICs the value they add is in the clever modulation schemes they use to avoid needing filters on the output and EMI.

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.


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.

https://www.researchgate.net/publication/242013327_All_ampli...


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.


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. :)


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.


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.


As a down side they are extremely difficult to design for good quality output. Basically impossible for an amateur.


ladyada made a board design that incorporates a class-D amplifier chip, it's open source: https://www.adafruit.com/product/1752 https://github.com/adafruit/Adafruit-MAX9744-Amplifier-PCB

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.


Well yeah you don't need a DAC but that will eat a lot of CPU cycles


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.


You can't do much lookup with sigma-delta modulation but

> has two cores running at 240MHz

Yeah ok that is manageable.


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).


You feed in the PCM samples, the I2S peripheral handles the PDM in hardware. So no CPU should be used.


Read the comment I'm replying to.


An RC integrator has a ~6dB/octave rolloff.

So you can get 100 (bad) analog outputs out of an FPGA. There has to be an application for that. :D


10x10 phased audio array speaker comes to mind...


Didn’t “Mean Streets” for DOS use a similar technique to output digitized speech through the PC speaker?


Apple 2 speaker can be made to work like that too...


brings back memories of playing Castle Wolfenstein on my Apple ][


Schweinhundt!

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.


Is that how for instance the old Technics MASH DACs worked?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: