Teensy 3.6 double DAC resolution

Skelp

Member
Hello everyone,

I am happy to call myself an owner of a Teensy 3.6 board.
It will be used for a synthesizer project, in which I use a self-coded synth library.
My intention is to write to the DAC outputs directly, or at least as low-level as possible, as my library spits out samples in the form of floats.
I have a question on that, too, but that is for another thread, if I can't find what I'm looking for elsewhere.

Anyway, I was curious about one thing, and I couldn't find a similar thread upon looking for it.
What I've seen being done for audio output is a dual-PWM setup, as seen here:
(about 7:28 into the video)

What I am wondering is whether or not it would be possible to use the two DAC output pins in combination to produce one double-resolution (so 24 bit) mono output, instead of a 12 bit stereo output.
Has anyone actually tried this? I would be really curious to see if that was possible.
A synthesizer can get away with mono output in some cases, so this would be a viable solution if one does not want to use the audio board or other explicit (I²C) DAC boards.
 
What I am wondering is whether or not it would be possible to use the two DAC output pins in combination to produce one double-resolution (so 24 bit) mono output, instead of a 12 bit stereo output.

You can try, but you'll end up with far less than 24 bit performance due to lack of precision and noise in the analog circuitry which combines the 2 signals.

For example, if your analog circuit's result depends on the ratio of 2 resistors and you buy 0.1% accurate parts, that's a possible error of 1/1000th, or about 10 bits resolution. Stepping up to much more expensive 0.01% resistors gives you ratio matching error a little better than 13 bits. But in practice the total impedance also includes some minor things like the output impedance of the signal source. You can add buffers to get low impedance outputs, but more amplifiers means adding more noise. You can use higher value resistors so those things matter less, but higher impedance means more thermal induced noise.

But resistor ratio matching probably isn't the only source of error. If you're using opamps, offset voltage and offset currents may matter, depending on how your circuitry is designed. You can try to compensate for those, but then how they vary with time & temperature can also be a factor.

Achieving full 24 bit resolution (even monotonic at 24 bits) is utterly unrealistic. Even just besting 12 bits can be a challenge.

The same is true for combining PWM signals. But results with PWM also include direct coupling of power supply noise, so you're almost always better off using a DAC where the voltage come from a stable reference.
 
You're probably not getting the full 12 ENOB from a 12 bit converter in the first place, combining two DACs is unlikely
to be any better than one. If they could get more than 12 bits of accuracy in the first place they would have made it
a 14 or 16 bit DAC... Each extra bit requires twice the analog performance from the circuitry.

This is not like the dual PWM method for getting higher precision/accuracy by combining two PWM outputs via a
ratio. PWM's accuracy depends on the quartz crystal's jitter and stability performance, which is normally excellent.
 
Theoretically, there could be tricks that allow improving the combined dual-DAC output resolution (to get some more effective bits, but not even close to the full 12+12), but it would require rather elaborate calibration work, and then applying those calibration results digitally to create the pre-compensated samples, etc. And all that will not reduce noise, so noise will still be the bigger problem. I would only consider this kind of solution if there were some really bad requirements vs. space/component count limitations, like having to fit all the extras within the board area and not stick above existing components, or similar. A very unlikely scenario.

Not really worth the effort in general, considering that a cheap (e.g. I2S interfaced) DAC chip designed for audio output (with the relevant additional external components, of course) will do better. Or simpler, buying a cheap ready made audio "shield"...
 
Hello everyone. Thank you all for your responses.
I see my mistake in assuming a doubled bit-resolution. Rather, it should've been a single bit more, doubling the steps of the signal.

After considering all your points, I was thinking of splitting the values into two 12-bit-values, distributing the original value equally across both values.
That way, I can feed both DACs with said signal and have double the precision, provided both DACs are perfectly equal.
Even if they differ a small amount, it would at least decrease the voltage difference between each step in the signal.
Using a simple RC filter to remove the DC offset and then a voltage divider to bring down the signal a bit would probably suffice to give it a try at least.
It checks out in theory, but I am uncertain of how it would behave in reality. Are there any obvious oversights in this plan? If not, I would give it a try once I got some components on my hand.
 
Hello everyone. Thank you all for your responses.
I see my mistake in assuming a doubled bit-resolution. Rather, it should've been a single bit more, doubling the steps of the signal.

It depends; as mentioned by MarkT, PWM-based DACs can be very precise (as their output is mostly based on counting very precise ticks of time), which allows getting more resolution out of combining two. But Teensy's SoC's internal DACs can be safely assumed to be of mediocre quality (or worse, depending on one's expectations). For example, max +/-8 LSBs of integral non-linearity. Adding more resolution by adding attenuated info from the other DAC will certainly give smaller steps, but the quality of the combined signal will still be about as bad, at least considering the intended use of audio.

After considering all your points, I was thinking of splitting the values into two 12-bit-values, distributing the original value equally across both values.
That way, I can feed both DACs with said signal and have double the precision, provided both DACs are perfectly equal.

Not really double the precision, and definitely not perfectly equal. Driving two ideal equal DACs with the same input values would produce the exact same output as driving one DAC, just a bit more potential output power and certain elements of noise reduced by a little bit. With certain way to splitting the input value (not exactly equally, per se), one could get that extra bit of resolution, with perfect DACs. But these are not the perfect DACs you're looking for.

Even if they differ a small amount, it would at least decrease the voltage difference between each step in the signal.

They can differ by quite a large amount; check the datasheets, INL and DNL, noise levels (if/when given). (See https://www.pjrc.com/teensy/K66P144M180SF5V2.pdf page 52). The average error might reduce a bit, but those built-in DACs can have some weird surprises; e.g. using both DACs simultaneously could perhaps increase the noise in both outputs, end result being then actually worse. (I've read corresponding issues with built-in ADCs so far, but I wouldn't be surprised if such won't affect DACs, too). For this case there is a mention like this: "Be aware that if the DAC and ADC use the VREF_OUT reference simultaneously, some degradation of ADC accuracy is to be expected due to DAC switching." I wonder, if both DACs use that same vref, would that caveat apply also between DACs?

Using a simple RC filter to remove the DC offset and then a voltage divider to bring down the signal a bit would probably suffice to give it a try at least.
It checks out in theory, but I am uncertain of how it would behave in reality. Are there any obvious oversights in this plan? If not, I would give it a try once I got some components on my hand.

Note, the typical "RC filter" concept in relation to DACs (i.e. low pass filter) doesn't remove DC offset. "DC blocking capacitor" arrangement does. But that, in turn, doesn't not do any low pass filtering which would be nice to have; it will do high pass filtering instead (with the voltage divider resistors you were planning for) :p

No harm done in learning by trying. Especially when the needed components are cheap and simple. And energies are low.
 
Not really double the precision, and definitely not perfectly equal. Driving two ideal equal DACs with the same input values would produce the exact same output as driving one DAC, just a bit more potential output power and certain elements of noise reduced by a little bit. With certain way to splitting the input value (not exactly equally, per se), one could get that extra bit of resolution, with perfect DACs. But these are not the perfect DACs you're looking for.

I should have probably clarified what I meant with that.
Assuming I have floats, I would first convert the value to an integer in the range between 0 and 8190.
Using floor() and ceiling() (have to look up the C++ equivalent from the Math library, you got me :cool:) on the division of the converted value by two I can have the original precision, but split into two values instead of one.
So, my thinking was that I can now drive both DACs with the resulting values, which both should add up to the doubled precision of 0 to 8190. With roughly double the voltage.

But I guess values to play around with explain the idea better: https://www.desmos.com/calculator/tqrulg5ejf

Note, the typical "RC filter" concept in relation to DACs (i.e. low pass filter) doesn't remove DC offset. "DC blocking capacitor" arrangement does. But that, in turn, doesn't not do any low pass filtering which would be nice to have; it will do high pass filtering instead (with the voltage divider resistors you were planning for) :p

I have done goofed! Of course you're right, I meant a CR filter to essentially create a passive high pass filter.
Suppose a high pass RC filter wouldn't hurt, it just won't remove DC offset as you correctly said. :rolleyes:

And I failed to mention this before: A proper, dedicated DAC would definitely be the better option, I'm agreeing with you all on this.
The reason I'm going for this rather crude implementation of an audio output is to see how far the onboard capabilities can be pushed.
Also, the teensy is my first physical board I can program.

Learning how to control an external DAC is not an issue, but I would also like to get better with analog circuitry and its components.
also, a couple of resistors and capacitors fit easily next to the teensy on the same, thin perfboard, so the small package is an added bonus. :)

No harm done in learning by trying. Especially when the needed components are cheap and simple. And energies are low.
That is my current mantra to be honest - I just want to get into how the board works, and also get my circuit skills up to beginner understanding at least.
 
...
Using floor() and ceiling() (have to look up the C++ equivalent from the Math library, you got me :cool:) on the division of the converted value by two I can have the original precision, but split into two values instead of one.

Yes, that is a way to get an extra bit. Theoretically.

The reason I'm going for this rather crude implementation of an audio output is to see how far the onboard capabilities can be pushed.

Hmm.. Considering that the DACs seem to be of the type with long series of resistors, its errors are mostly constant per input value (ignoring various temperature etc. effects here for now), the calibration-and-compensate -way would be something for "how far .. can be pushed". The calibration is certainly not something easy to do, but there really aren't many methods that can give any effective help in practice, let alone easy ones.

Just thinking aloud here: The SoC has decent enough PWM features, and good enough built-in clock. Create heavily filtered PWM output (basically a very slow, but well defined DAC; note, careful with the filter capacitor(s) choice(s)). Use external opamp to get amplified difference between that PWM output and the corresponding normal DAC's output. Sweep through all values. Slowly, one by one, average lots of samples to reduce noise. Do the sweeps a few times. Since the PWM version should be much more linear (smaller errors from some linear), that opamp output will be half-decent estimation of the DAC's error from that "some linear output". Feed that amplified difference to SoC's ADC. They are also crappy as ADCs, but they only need to get like 4-6 MSB's right. The collected ADC results will need some math; finding out a "best fit" with linear through those results, then applying that as gain and offset adjustment for the PWM input-to-count control (for a better match with the DAC). Then repeat the measurements with that better fit. The new results will give errors for the individual steps. Apply those as compensation for the input data before feeding to DAC.

Then repeat all that for the other DAC.

Then repeat all all that at multiple chip temperatures (I hope that SoC had temperature sensor). If the results are good enough at all relevant temperatures, one can stop here and be happy. Otherwise linear interpolation of compensation values between different measured temperature points.

Then recheck in a week or two. Maybe also in few months. Just in case the resistors keep drifting over time. If they do... I'd give up. Someone else might continue checking if the drift is slow and/or predictable enough...

May need a bit of memory for the compensation lookup tables. May be possible to store just some of them, giving a coarser correction table.

Once done, the difference amp and path back to ADC can be removed. Or left there for possible recalibration once the DAC resistors and output buffer drift over time in all possible ways. Or kept just for the looks.

I left purposefully several details out. Left as an exercise to the reader. No guarantees of any actual improvements. Does not reduce noises. Good bits below noise are irrelevant in the intended use case (audio), could be of some use in other cases. But in some of those other cases using the PWM-method might be a better choice.

(Edit: there is also a way to get some improvement with using just the DAC itself to external components to ADC, but it would need some more external components than the above and is a bit trickier with the math...)
 
If your DAC is faster than you need, you can dither it to get extra bits. Eg, 25% of the time at 1000 and 75% at 1001 yields 1000.75.
 
Hey again, thanks for all your responses.
I have done some research and thinking after reading your replies and have opted to go with single channel DAC for now, as the potentially higher bit resolution doesn't outweigh the trouble for me.
I will definitely give it a try at a later time though, just not for my current project.
For now though, I am choosing to use a 10pF cap to remove the DC offset and an RC Filter to filter out inaudible high-frequency content using a 4.7k resistor and a 1uF cap.
 
It has been quite a few years since I last time did something with audio-frequency DC-blocking caps, but... that 10pF sounds small... very small.
 
You may be right about that, actually. I know that Paul recommends a 10uF cap, but I don't see why I should use such a high value for filtering just DC.
According to the calculator here http://sim.okawa-denshi.jp/en/CRtool.php it should be totally fine.
I am not using a resistor in parallel, so it is an implied infinite-ohm resistor. Using a fictional 10000M Ohm resistor shows a frequency response that is pretty much what I need - filtering out only close to 0 Hz. Is my thinking wrong in this regard?

/edit: I should probably mention that I am highly uneducated in this field - electrical engineering is pretty new to me, so my reply should be read more like a question than anything. If anyone could tell me why 10uF is more applicable than 10nF for this case, I would like to know. That would help me in the future a lot, thanks!
 
For the DC-blocking cap, the correct calculator is http://sim.okawa-denshi.jp/en/CRhikeisan.htm, but even that will not directly fit your case, since you have the RC-filter after the blocking cap, not just the resistive load. Note that the RC-filter will get its output after the resistor (i.e. for signal, the R is in series with the load, not the load itself).

As a thought exercise, think what happens if you replace that 4.7k resistor with, say, 0.1ohms; the circuit becomes basically capacitive voltage divider with 10pF and 1uF; it will attenuate any relevant frequency a lot. With 4.7k, it is more like divider with 10pF and 4.7kohm at the upper side, and 1uF on the lower side...

For DC-blocking uses, the series capacitor should be as high as possible compared to the load capacitance (which the RC-filter's capacitor is, for the blocking capacitor's point of view). Or, blocking capacitor's impedance should be as low as possible compared to load impedance (except for DC, of course).

If I remember right, I used to just slap 100nF capacitors (I don't remember the voltage rating, high enough), because I happened to have bought a bunch of such with suitable qualities from the bargain bin.. But the load was also minimal so that 100nF was way more than enough. Note, the DC-blocking capacitor should be bi-polar or of type that is naturally such.
 
Last edited:
Oops - my bad, apparently I sent the URL to the low-pass filter from a different tab. :rolleyes:
Double oops: I originally meant to use a 1nF cap for the low pass filter, not a 1uF cap.
So even with just the low-pass filter alone, it would've filtered out anything above 33 Hz using a 1uF cap... yeah, not my best typo.

Playing around with the 2nd order CR band-pass filter tool (http://sim.okawa-denshi.jp/en/CRCRtool.php) visualized what you said above.
The lower the capacitance of the series cap, the more it attenuates the entire frequency spectrum, not just the DC offset.
Gradually increasing its capacity to the 100nF you mentioned makes it attenuate the spectrum way less indeed.
That visualized what you have said quite well, and it also sort of makes sense from a low-level component point of view.

This is probably where some decent amount of basic electrical engineering would be helpful.
From what I can tell, the parallel resistor in the high-pass is pretty much only every used if one wants to cut-off more than 0 Hz.

To put it all together:
A better alternative to my previous selected values would thus be a 100nF or above series cap (hence Pauls suggestion of a 10uF cap I assume) and my previously mentioned 4.7k series resistor and 1nF parallel cap.
Does that sound about right?

/ edit: oh and yes, I am using ceramic caps to avoid polarity issues. They can't dry out either, which is a plus.
 
Last edited:
I know that Paul recommends a 10uF cap, but I don't see why I should use such a high value for filtering just DC.

10uF is generic advice given without knowledge of the input impedance of whatever will receive the signal.

10uF is also a very widely used and inexpensive capacitor.


If anyone could tell me why 10uF is more applicable than 10nF for this case, I would like to know.

A simple approximation is to think of the DC blocking capacitor and the input impedance of the receiving circuitry as a single pole high pass filter. You probably want the corner frequency to be no higher than 20 Hz, or maybe much lower if you're an audiophile concerned about perfectly flat response and phase shifts.

So for 10uF, you need the input impedance to be 800 ohms or higher to get 20 Hz passed (with -3dB attenuation... what I'm assuming is the minimum acceptable performance). Most good quality consumer stereo amplifiers have input impedance in the 10K to 100K range. Some cheap computer speakers have 1K to 10K. Most headphones are 32 ohms. Long ago 600 ohms used to be used.

If you use 10nF, then you only pass the full audio spectrum (again with -3dB attenuation on the low end at 20 Hz) if the receiving equipment has an input impedance of 800K or higher. Almost no commercially made audio gear has input impedance that high. While there may be some exceptions, generally 100K is the highest input impedance commonly used. In practical applications, too high input impedance risks electromagnetic coupling from AC power, radio waves and other interference. Nobody wants to buy an amplifier or stereo receiver or computer speaker that makes buzzing or squealing sounds when powered but not connected. Most consumers would consider such gear defective and quickly return it. Manufacturers want customers to be satisfied and they don't want to risk returned products.


Using a fictional 10000M Ohm resistor shows a frequency response that is pretty much what I need - filtering out only close to 0 Hz. Is my thinking wrong in this regard?

I'm guessing you're running computer simulation? That's probably the only place you could investigate a 10000M impedance!

Most types of resistors aren't even sold with values higher than 1M or 10M.

I wouldn't necessarily use the word "wrong", but perhaps I would call this "impractical". Aside from the common practice of consumer & professional audio equipment, it's hard to imagine many compelling reasons to use such a low value capacitor. They're not significantly different in price (all these sorts of parts are so cheap that SMT assembly cost usually overwhelms the component cost). In these modern times you can get the lower values in extremely small packages, so maybe it makes sense to use less capacitance for a project with intense miniaturization requirements. But going to such a low value would only make sense in so few cases that it's hard to imagine it being very useful.
 
To put it all together:
A better alternative to my previous selected values would thus be a 100nF or above series cap (hence Pauls suggestion of a 10uF cap I assume) and my previously mentioned 4.7k series resistor and 1nF parallel cap.
Does that sound about right?

Again, I suspect you're not anticipating the load (input impedance) of whatever other audio gear will receive your signal.

This sort of simple all-passive (no additional opamps, transistors, etc) filter is sensitive to the load you connect. Its performance does change. The higher the resistor and lower the capacitors you use, the more it changes in response to whatever you connect across the output.

If your signal is to be hard-wired to a specific circuit with known input impedance, you can optimize your design for that 1 case. But if you're making a general audio output which could possibly be connected to a wide range of audio equipment, the general approach most people take involves much higher DC blocking capacitance and lower series resistance (and corresponding capacitor at the output) than you've chosen, so the performance is less variable when different loads are connected.
 
Thanks again for your thorough reply, Paul.

10uF is generic advice given without knowledge of the input impedance of whatever will receive the signal.

10uF is also a very widely used and inexpensive capacitor.

Again, I suspect you're not anticipating the load (input impedance) of whatever other audio gear will receive your signal.

Now that you mention it, I kept the input impedance completely out of the circuit thus far - good thing you mentioned it.
Indeed, I have not thought of the receiving side at all!


A simple approximation is to think of the DC blocking capacitor and the input impedance of the receiving circuitry as a single pole high pass filter. You probably want the corner frequency to be no higher than 20 Hz, or maybe much lower if you're an audiophile concerned about perfectly flat response and phase shifts.

Yes, assuming I want the cut-off to be as close to the lower audible range as possible, I can see why a low capacitor would cause issues. Especially when thinking about the input impedance now.
With the project I'm working on, I only want to cut-off the DC offset and leave everything above 0 Hz alone. Or at least as much as possible. For one because of phase shifting as you've mentioned, but also because I want to keep the output as close to the original DAC output as possible. Only DC offset and the inaudible high-frequency content from the DAC needs to be filtered out.

I'm guessing you're running computer simulation? That's probably the only place you could investigate a 10000M impedance!

That's correct, I have used the RC calculator from my replies above.
I used an unrealistically high impedance to approximate having no resistor in parallel at all and seeing how the frequency response changes.

But going to such a low value would only make sense in so few cases that it's hard to imagine it being very useful.

Well, before finding out through trial and error using the RC filter calculator that too low of a capacitance causes heavy attenuation across the board, I would have argued that I want to go as low as possible to filter out only the lowest of the low near 0 Hz.
But I guess that thought goes out the window now.

If your signal is to be hard-wired to a specific circuit with known input impedance, you can optimize your design for that 1 case.

Unfortunate for me then that I am not always certain which input impedance the gear I'll be connecting to will have.

This sort of simple all-passive (no additional opamps, transistors, etc) filter is sensitive to the load you connect. Its performance does change.

Well, I suppose there had to be a trade-off for having a relatively simple filter design. The simplicity in comparison to active filters should've rang a bell for me.

I think I'm understanding this a lot better than before.
What this tells me is that DC blocking might not be too big of an issue with varying input impedance (so long as I only want to remove DC offset and nothing much else), but passive low-pass filters are nearly impossible to calibrate under the enormous range of varying input impedance.

If I want to ensure that the cut-off of said filter is between 20-40kHz then I'm likely forced to employ an active filtering system, is that correct?
 
Last edited:
If I want to ensure that the cut-off of said filter is between 20-40kHz then I'm likely forced to employ an active filtering system, is that correct?
And/or a buffer between filter output and device output to make the filter not affected by the input impedance of the next device. (Or could call it "driver", or even amplifier if it at the same time boosts the amplitude/power capability to a desired level.) An active filter section could in some cases also work as the output driver.
 
And/or a buffer between filter output and device output to make the filter not affected by the input impedance of the next device.

After getting to know what a buffer is and how it operates, I'm pretty sure that your suggestion is the best next thing for me, if I want to keep the previous filter design.
I'll need to do some more research and figure out what component I should use.

The Teensy 3.3V pin allows for 250mA max, assuming a minimal resistance of 32 ohm of the device using the DAC signal, that should be good enough.
I suppose a safety 32 ohm resistor in series with the output can't hurt?

In any case, I'll have some digging to do. Especially which component would suit this use case best. Of course, if any if you guys have a suggestion based on your experiences, please let me know.
Thanks a lot everyone!

/edit: Yeah, nevermind that 32 ohm thing. I don't expect the teensy to drive headphones, not that an op-amp like the LM741 could without another amp anyway.
The LM741 outputs at most 25mA, so that answered that question.
 
Last edited:
I am looking for a DC control voltage for driving a VCO smoothly in a musical range. By smoothly I mean I'm not looking for 5+ octaves of equally-tempered notes over a 12 bit DAC. I'm looking for a way of doing theremin-like portamento over a wide range: Sweeping pitches without digital steps.
I know I can do that with floating point math on a Teensy DCO, and it sounds great. But in this case I need to control an analog VCO and VCF.
So I considered this possibility of using 2 12-bit DAC outputs where one scales the other.
I don't know where I can go with this. It seems like implementing analog portamento is more likely to produce a good result.
 
Back
Top