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.