DUE adc oscillating at a constant voltage read

I'm testing a reading from ADC over a constant voltage.

The test is very simple I tested the 3.3v pin and I get 4095 as expected over a 12bit adc, then I tested using a voltage divider (to divide by 2) straight on the pins (see photo) and I get the result of the graphic.

I did the test over the pins because the result get worst over wires using a protoboard.

The resulted shows that the value is not constant, it's oscillating in a +- 1 over 2043.

As I only have this device I don't know if this is expected behavior for a due.

What can I do to improve this if possible? I already try to power it over USB and a power source the result is the same.

Anyone that has another due and can do a similar test can tell me the result, is constant? or is like my?
Because I don't think this due is good at least it's adc is not.

I really need the adc to be stable, for the use I'll make of it.

This behavior is due to the noise captured by the ADC pin. Anything connected to this 12-bit ADC pin is like a small antenna and you would have the same waveform with no voltage applied to A0.

There are several workarounds:

  • Add an RC filter to A0 with an RC constant greater than 100 times the period of the analog input in case this is a periodic analog input,

  • Read A0 with an input voltage and (e.g.) A1 without any input voltage in the same conditions (add the same resistor between A1 and Gnd), subtract A1 to A0 before any use of your A0 conversion. It's important to read A1 the faster you can after A0.

  • Read A0 much faster than you need (oversampling), then average (averaging).

An extension of the last method is used to extend the precision from 12-bit to 16-bit ADC conversions whenever your noise is a white noise (at first glance your noise should be in this category...), see this Application Note:

For better ADC conversions, power the board with a battery pack thru the jack (I gusess you already do that according to the picture posted) because the power line of the USB cable is very unstable.

ard_newbie:
This behavior is due to the noise captured by the ADC pin. Anything connected to this 12-bit ADC pin is like a small antenna and you would have the same waveform with no voltage applied to A0.

There are several workarounds:

  • Add an RC filter to A0 with an RC constant greater than 100 times the period of the analog input in case this is a periodic analog input,

  • Read A0 with an input voltage and (e.g.) A1 without any input voltage in the same conditions (add the same resistor between A1 and Gnd), subtract A1 to A0 before any use of your A0 conversion. It's important to read A1 the faster you can after A0.

  • Read A0 much faster than you need (oversampling), then average (averaging).

An extension of the last method is used to extend the precision from 12-bit to 16-bit ADC conversions whenever your noise is a white noise (at first glance your noise should be in this category...), see this Application Note:

https://www.silabs.com/documents/public/application-notes/an118.pdf

For better ADC conversions, power the board with a battery pack thru the jack (I gusess you already do that according to the picture posted) because the power line of the USB cable is very unstable.

Thanks, this really help as I wasn't aware of methods to improve the precision.

But one thing I did't understand about reading the A1 connected to GND with a resistor, the process I think I understudy but the result I did not get it, as A1 is always in a perfect 0 (zero) in this case, maybe I did understood wrong.

What I did was only add a 1k resistor from A1 to GND, and measure it to see if there is something, and there ins't.

I was already trying the RC and average methods to get some improve, but I think the precision can give me a better result overall.

This is the test I did:

As due has 12 available ADC inputs, and I only need to use 3, I put 4 ports to read one input what gives me a precision of 13 bits, not much but is theoretically half the error.

basic reading code to convert 12 to 13bits

values = (ADC->ADC_CDR[7] + ADC->ADC_CDR[6] + ADC->ADC_CDR[5] + ADC->ADC_CDR[4]) >> 1;

were all ADC_CDR are connected to the same input.

reading 3.3v with a divider of 2

And once I finish the PCB I will probably get a better result as I plan to optimize spacing and positioning to get the lowest noise possible.

...

Off topic but valid, one thing I discover was that one can read the ADC at faster speed in one very odd case...

For example I enable all available ADC input

ADC->ADC_CHER = 0x3CFF;

and only reading one by for example reading A0

    while ((ADC->ADC_ISR & 0x80) == 0);// wait for conversion of A0
    value = (ADC->ADC_CDR[7];//read it and only it

Gives me a average reading of 0.3 us.

Technically what happens here is that the ADC is only updating the value of A0 and keeping the value of all others to what it first read, by connecting all empty ADC ports to GND will eliminate the noise of floating ports and give a better performance in the case only one port is needed to be sampled at maximum speed estimated 3.3Mhz.

AFAIK, ADC samplings for n channels should follow this rule : (n * Sampling_rate ) can't be much faster than 1 MHz (See page 1403, Sam3x datasheet) with a PDC DMA.

Here are some ADC example sketches with and without DMA:

https://forum.arduino.cc/index.php?topic=547194.0
reply 3

https://forum.arduino.cc/index.php?topic=224672.0
reply 10

https://forum.arduino.cc/index.php?topic=487989.0
reply 1

ard_newbie:
AFAIK, ADC samplings for n channels should follow this rule : (n * Sampling_rate ) can't be much faster than 1 MHz (See page 1403, Sam3x datasheet) with a PDC DMA.

Here are some ADC example sketches with and without DMA:

how to get the 1Msps in Due - Arduino Due - Arduino Forum
reply 3

Sinewave 100k generator, DAC + PDC + Timer. - Arduino Due - Arduino Forum
reply 10

Direct Accessing of ADC Registers - Arduino Due - Arduino Forum
reply 1

Yes but that is the ADC Sampling Frequency 1MHz to evaluated all Available channels?

Because I'm not changing clocks, I just enable all available channel (12), use ADC->ADC_ISR to check if ready, and read the value for it channel and my final result is that I can do that 1000 times in 1500us so 666.666KHz.

With is bellow the 1MHz max Sampling Frequency.

I'm wrong here? should then be !MHz for one channel and to read all 12 I need to set a maximum frequency of 83.33KHz or something close to it?

because I don't get way my test works without any adicional changes to clock reference I just using the default options and enabling FREERUN.

(number_of_Enabled_channels * Sampling_rate ) <= 1 MHz.