DAC/ADC reference inconsistency

While the code the reference can generically be set as "internal" or "external", only the ADC follows this setting; the DAC (as a result) will be use either the internal reference, either the 3.3V LDO (which may be an external "reference" - not really as it is an LDO - but it is not THE external reference - AREF). Obviously, this is a bug and needs to be addressed. Of course, it would be even better having the ability to set the references independently (ADC and DAC).

1. Any plans to fix this error?
2. What is the work around this issue?

Thanks!
 
While the code the reference can generically be set as "internal" or "external", only the ADC follows this setting; the DAC (as a result) will be use either the internal reference, either the 3.3V LDO (which may be an external "reference" - not really as it is an LDO - but it is not THE external reference - AREF). Obviously, this is a bug and needs to be addressed. Of course, it would be even better having the ability to set the references independently (ADC and DAC).

1. Any plans to fix this error?
2. What is the work around this issue?

Thanks!

Not sure I'd call that an error, VDDA *is* a "supply" input; but yeah, that's somewhat confusing. AFAICS, that's the expected behaviour:

The DAC reference can be selected to be VDDA or the voltage output of the VREF module (VREF_OUT)
... but not VREFH ("AREF").

Looking at the schematic, there's no neat workaround. I suppose you could desolder the ferrite and 470R resistor and supply VDDA from some separate / clean(er) supply; possibly via the AREF pin if you put a 0 ohm resistor instead of the 470R.
 
Not sure I'd call that an error, VDDA *is* a "supply" input; but yeah, that's somewhat confusing. AFAICS, that's the expected behaviour:

... but not VREFH ("AREF").

Looking at the schematic, there's no neat workaround. I suppose you could desolder the ferrite and 470R resistor and supply VDDA from some separate / clean(er) supply; possibly via the AREF pin if you put a 0 ohm resistor instead of the 470R.

Thanks mxxx...

That is still an error because the chip uses a non-documented reference when it is configured as "external". The references are still toggled but not to the same rails.

Regardless if it can be considered an implementation error (as I would) or not, I am waiting for Paul's feedback; he replied to me earlier:

"Yes. The workaround is to write to the hardware registers which control these things."

and

"I write detailed tech answers on the forum, so the info becomes a searchable public knowledge base."...

Thanks in advance, Paul !
 
Why, I'm pretty sure Paul knows more about it than I do. That said, the quote above is taken from the MK20 datasheet * ; on that basis it's not clear to me what the "non-documented reference" might be? when set to external, the DAC uses VDDA, as documented in the datasheet, which happens to be 3v3.

The somewhat confusing thing is that the same variable ("analog_reference_internal") is used in analog.c for both analogWriteDAC0() and analogReference(), though "external" (analog_reference_internal = 0) means two different things (VDDA resp. VREFH). that's fixable no problem, but it won't make the DAC track AREF.

note that's re MK20. teensy LS is different (in which case "The DAC reference can be selected to be VDDA or VREFH.")

* more verbose (from the MK20 reference manual):
3.7.3.3.
For this device VREF_OUT and VDDA are selectable as the DAC reference.
VREF_OUT is connected to the DACREF_1 input and VDDA is connected to the
DACREF_2 input. Use DACx_C0[DACRFS] control bit to select between these two
options.
 
ps. reading more closely, I realize you weren't all that much concerned about the DAC not tracking AREF. (sorry)

to make things work independently, the workaround i suppose would be to edit analogWriteDAC() (so it ignores any reference stuff) and set the reference manually. for example
 
Thanks, mxxx!

Your code is way above my current level - when I grow up I want to be like you :)...

Actually I do care about the ADC and DAC following the same reference - namely the AREF - for better accuracy. I was expecting by setting the reference external to connect the DAC to the same external reference but - as it happens - the DAC reference is either internal, either the 3.3V rail.

Thus, it would be OK if both DAC and ADC could be set by the same switch to use the same references (INT or EXT) or (better because of the increased flexibility) to have separate switches so the references can be set independently for DAC and ADC. Either way works for me... but the current one.

In my case, I set the external reference at 2.5V and I was quite surprised to see the DAC voltage hitting 3.3V.
 
Thanks, mxxx!

Your code is way above my current level - when I grow up I want to be like you :)...

it's Paul's code ...


Actually I do care about the ADC and DAC following the same reference - namely the AREF - for better accuracy. I was expecting by setting the reference external to connect the DAC to the same external reference but - as it happens - the DAC reference is either internal, either the 3.3V rail.

Thus, it would be OK if both DAC and ADC could be set by the same switch to use the same references (INT or EXT) or (better because of the increased flexibility) to have separate switches so the references can be set independently for DAC and ADC. Either way works for me... but the current one.

In my case, I set the external reference at 2.5V and I was quite surprised to see the DAC voltage hitting 3.3V.

i see. well, as noted above, my understanding is that's not the way it (MK20) works. you can set them independently by bypassing the code in analog.c, but "EXTERNAL" means AREF for the ADC, and VDDA for the DAC; with VDDA tied to VOUT33 (in this case). if you search the forum, you'll find a couple of threads with people wondering about the same thing (why won't the DAC track AREF?)

what is it that you want to do? if you want/need better accuracy, i'd suggest using an external DAC, reference and so on?
 
Well, I need to scale the DAC to an accurate 2.5V, without sacrificing the resolution. I already built my PCB and I am unwilling to change it to add components. Besides, it doesn't even make sense; for what I need (speed-wise) a plain Arduino would do but I selected Teensy mostly because it embeds a real DAC... well - faster IOs too.

Of course, I suppose I can live with fewer steps (about 3.1k, which is not so bad), it is just that it bugs me - "does not compute"; If I could fix it, I would.
 
Well, I need to scale the DAC to an accurate 2.5V, without sacrificing the resolution. I already built my PCB and I am unwilling to change it to add components. Besides, it doesn't even make sense; for what I need (speed-wise) a plain Arduino would do but I selected Teensy mostly because it embeds a real DAC... well - faster IOs too.

i see. can't you try with a teensy LC ? i've never tried this but, as mentioned, in that case it should work: "The DAC reference can be selected to be VDDA or VREFH."
 
Hi Paul,

I am having the same problem...we connected external reference 2.5V to AREF, and this works for the ADC, but not the DAC...The DAC is still using 3.3V.
Please let me know if we are doing something wrong or how can we setuup the ADC and DAC to use the same value that is connected at AREF?
Thanks...Ness

Sample code below:

int ledPin = 13; // select the pin for the LED
// Pin 13: Arduino has an LED connected on pin 13
// Pin 11: Teensy 2.0 has the LED on pin 11
// Pin 6: Teensy++ 2.0 has the LED on pin 6
// Pin 13: Teensy 3.0 has the LED on pin 13
int ADC_Pin = A0; // select the A0 input pin 14 for Voltage Measurement
int DAC_Pin = A14; //use A14 as Analog Out (DAC)
int i=0; //global loop counter
void setup()
{

Serial.begin(9600);
pinMode(ledPin, OUTPUT); //Pin 13 Led On/Off
pinMode(ADC_Pin, INPUT); //Pin 14 = A0 used for Voltage Input
analogReadResolution(16); //set resolution to 13 bits usable
analogReference(EXTERNAL); // use AREF for reference voltage (2.5V reference is used)
analogWriteResolution(12); //set resolution to 12 bit resolution - max for DAC
analogWrite(DAC_Pin, 0); //default DAC (Iset) = 0

}

void loop()
{

int DAC_ValueBits = 0;
float ADC_Measurement = 0.0;
float ValueInVolts = 0.0;
Serial.print ("Iteration = ");
Serial.println (i);

ADC_Measurement = analogRead(ADC_Pin); // read the value from the AD0 Pin
ValueInVolts = ADC_Measurement * (2.5/65535); // BitsRead * (VmeasMax/BitsMax) 16 bits = FFFF 65535 and Vmax = external Vref = 2.5V
Serial.print ("Measure and Display Value in Bits = ");
Serial.println (ADC_Measurement);
Serial.print ("Measure and Display Value in Volts = ");
Serial.println (ValueInVolts);

DAC_ValueBits = (int)(1.0 * (4096/2.5)); //convert desired volts to bist per 4096 bits (12bit) for 2.5V max (external reference is 2.5V)
analogWrite(DAC_Pin, DAC_ValueBits); //set DAC
Serial.println ("Setting DAC output to 1V with 2.5V external reference");
Serial.print ("\n\tDAC Value in Bits = ");
Serial.println (DAC_ValueBits);
analogWrite(DAC_Pin, DAC_ValueBits);


}
 
Serial.println ("Setting DAC output to 1V with 2.5V external reference");

Unfortunately, the DAC can not use the AREF voltage. This is a hardware limitation inside the chip, so there is no workaround.

All the hardware details are in the reference manual. Here's the DAC's block diagram, from page 730:

mk20dx256_figure33-1.png
(click for full size)

As you can see, the DAC has only 2 options, DACREF_2 and DACREF_1. The connection of these 2 internal signals is documented on page 107:

3.7.3.3 12-bit DAC Reference

For this device VREF_OUT and VDDA are selectable as the DAC reference.
VREF_OUT is connected to the DACREF_1 input and VDDA is connected to the
DACREF_2 input. Use DACx_C0[DACRFS] control bit to select between these two
options.

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.

The chip simply can't use the AREF pin which connects to VREFH. See the schematic for details.

Your only options are 3.3V VDDA or 1.2V internal reference, which are selected by analogReference(EXTERNAL) and analogReference(INTERNAL).

For the ADC, analogReference(EXTERNAL) uses VREFH, which "defaults" to 3.3V due to the 470 ohm resistor. If you apply a reference voltage to AREF, it is used by the ADC, but not by the DAC. Unfortunately, this is simply the way Freescale made the chip, so there's nothing the Teensyduino software can do to give you DAC output based on your 2.5V reference.
 
Unfortunately, the DAC can not use the AREF voltage. This is a hardware limitation inside the chip, so there is no workaround.

All the hardware details are in the reference manual. Here's the DAC's block diagram, from page 730:

View attachment 7259
(click for full size)

As you can see, the DAC has only 2 options, DACREF_2 and DACREF_1. The connection of these 2 internal signals is documented on page 107:



The chip simply can't use the AREF pin which connects to VREFH. See the schematic for details.

Your only options are 3.3V VDDA or 1.2V internal reference, which are selected by analogReference(EXTERNAL) and analogReference(INTERNAL).

For the ADC, analogReference(EXTERNAL) uses VREFH, which "defaults" to 3.3V due to the 470 ohm resistor. If you apply a reference voltage to AREF, it is used by the ADC, but not by the DAC. Unfortunately, this is simply the way Freescale made the chip, so there's nothing the Teensyduino software can do to give you DAC output based on your 2.5V reference.

Hi Paul,

I came across this issue with my Teensy 3.5, I was pretty shocked when I realized that I cant use my external 2.048V reference for the DAC. Absolutely didn't expect that.

However, I'm not giving up (yet). I was digging in the datasheet and the reference manual of the MCU and according to my understanding it should be possible to tie the VREF_OUT pin which seems to be the internal bandgap reference to any desired level (below VCC of course).

This is the block diagram of the 1,2V reference which is at VREF_OUT, if I'm correct:

vref.PNG

In https://www.nxp.com/docs/en/reference-manual/K64P144M120SF5RM.pdf on page 942 it says:

"The reference voltage signal is output on a dedicated output pin when the VREF is enabled."

and:

38.1.3 Modes of Operation

...

NOTE on page 943:
When the VREF output buffer is disabled, the status of the
VREF_OUT signal is high-impedence.

So wouldn't be it possible to just connect the 2.048V reference to the VREF_OUT pin, when the buffer is turned off and therefore high impedance?

Anyway, it really was a bummer when I realized that out of the box the AREF is only usable for the ADC, you really might want to make a note on your website regarding this.
Yes it was my fault to not try it on a breadboard first before making a PCB but I just really didn't expect that at all (I mean, WHY did they do it this way...).

Thanks!
 
And why not simply use the internal bandgap reference and add a rail-to-rail op amp at the output to scale the voltage by 2048/1200? With that, you'd even save by dropping your external reference.
 
And why not simply use the internal bandgap reference and add a rail-to-rail op amp at the output to scale the voltage by 2048/1200? With that, you'd even save by dropping your external reference.

because that would make an even higher gain of the opamp necessary, which is quite high with 2.048V VREF already.
That raises the minimum output of the DAC you could get to about 50-80mV which is not good for a Lab PSU where you want to regulate your output all the way down zero or at least near zero.

Calculate the current of 80mV @ 100mOhm (short). Poor series pass transistor...
 
Have a look at the MAX44267. It can even output negative voltages with only an unipolar positive power supply. I used it in synth projects to generate negative control voltages without the need of a bipolar supply.
 
Have a look at the MAX44267. It can even output negative voltages with only an unipolar positive power supply. I used it in synth projects to generate negative control voltages without the need of a bipolar supply.

Thanks, good looking device, but the opamp is not the issue if I'm not misleaded.
I use the OPA2197 which can go all the way down to a few mV with single supply voltage, which is good enough.

The problem is the DAC, which outputs at least around 5mV or so, which get amplified by the opamp by a gain of 10-20, depending on the VREF (which is very low on the Teensy DAC) so I get at least 50-100mV output.

I guess I'd have to create an offset at the opamp to shift the voltage down about 50mV but I haven't done this yet, no idea how this is accomplished, while keeping high precision.
 
Hello, not sure if this question related,

I see DAC could be used as a comparator source from datasheet.

though DAC cannot use AREF as a reference,
can DAC work as an analog reference, externally, with some extra wiring from DAC to AREF?
 
I see DAC could be used as a comparator source from datasheet.

Maybe you could be more specific, about which datasheet you're and which part, which pages? There any many different files, some have thousands of pages, and some chips have both 12 bit DACs and little 6 bit DACs built into the comparator section.
 
@Paul
Thanks I didn't notice the 6-bit / 12-bit DAC were different modules.
I first see the comparator used as wake up source in snooze library, and can use some DAC reference voltage to compare.

At teensy LC datasheet 2.2.6 or Table 2.7, at 46 page /876, I see LC have both 6/12bit DAC modules
It says 6 bit DAC is internally used and not accessable. :\ so probably not for 6 bit since there's no external pinout.

I don't undertstand much of the schematic picture at DAC so I can't tell if 12 bit DAC could use as a ADC voltage reference, or will they interfere each other.
 
The 6bit DACs are not accessible from outside. They are kind of hardwired to the comparators.
The 12bit DAC should theoretically be able to deliver a voltage which the ADCs could use as a reference by adding an external wire from DACout (A14) to AREF. Just try it out, i.e. by setting the DAC output to let’s say 2.5V and let the ADC do some conversions to see if the reference is correctly applied...
 
Back
Top