Go Down

Topic: DUE ADC Read Value Stability (Read 7092 times) previous topic - next topic

Dande80

Hi everyone,

I have a problem with the stability of the read value of the ADCs of my Due. I wanted to check how stable the valuesare  I read using the ADC ports. To do this I used a voltage divider between 3v3 and GND to get a reading somewhere in the middle of the voltage range, a condensator in parallel to it to reduce the noise on the supply voltage and a passive low pass filter  to reduce the noise even further before I connect the signal to an ADC pin. See attached image.

In the sketch I did nothing but setting the analogreadresoultion to 12 bit, and reading the analog value and posting it to the serial port using analogread and serial.print.

Result: The read value varies around 10 units so basically 3 bits of the analog read resoliution are wasted on noise.
As I plan to use at least 11 of the 12 bits of ADC resolution I need to improve this. I tried different ADC ports, varied resistor and capacitor values and implemented some delay (up to 1s) between the analog reads with more or less no change.

The question is what is influencing the read value. I see 3 possible sources.
First of all I wired all of this on a little test board with some wires from and to the Due board. This could simply pick up some noise. I will solder a test board but this will take me some days as I need to get some parts.
Second possibility is that the supply voltage and/or the derived analog reference voltage is not stable enough. Can somebody give me some guidance how to check this? I would prefer not to modify the DUE board itself but at last for the analog reference voltage that would be necessary.
Third possilibilty is that I got a faulty or a clone board of insufficient quality. The board looks quite ok and like the original ones but I didn't buy it in an official store. Therefore it might be an low quality clone. Is there any possiblity to check this without buying another DUE?

Can anybody state some expierence with the DUEs ADCs? Is the performance I measured typicall?

Thanks for your help
Daniel

dlloyd

I'm surprised your readings are actually this stable. The signal connected to the ADC should be buffered or have low impedance, preferably less than 10K. In the datasheet (pg 1419), see Table 46-35 Source impedance values.

Dande80

Hi,

thanks for the reply. As far as I understood it the limit for the impedance comes from the fact that the there is some input capacity for the ADC and you need some current in order to get the voltage to reach the set voltage fast enough. And it is especially necessary if you switch ADC channels, as there is only one ADC that is multiplexed.

As i only use one analog input and I don't see a voltage drift but noise I don't think the impedance is an issue. But I will check if this is an issue by adding an OpAmp as a voltage follower in between my circuit and the ADC input.

Daniel

l-mb

I've found that all inputs that I don't apply a band-stop 45-55 Hz filter to will show very noticable line noise. Even on circuits that are noise filtered before I connect them to the Due (e.g., the Olimex EKG-EMG shields supposedly have a filter circuit built in).

It doesn't seem to matter if it's all running off battery or if I eliminate all power lines on the table - the 50 Hz vibe is literally everywhere.

MarkT

#4
Jan 19, 2015, 01:12 pm Last Edit: Jan 19, 2015, 01:13 pm by MarkT
Yes, the Due analog section is pretty crap.  The DAC is worse, BTW, it seems to have sparkle
codes that deviate 20+ counts IIRC.  And it doesn't do rail-to-rail.  I suspect the poor performance
is partly the chip and partly the layout of the board - the switchmode supply is too close to the sensitive
analog signals perhaps.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

dlloyd

#5
Jan 19, 2015, 03:59 pm Last Edit: Jan 19, 2015, 04:28 pm by dlloyd
Here, "val" should be noise free ...

Code: [Select]
unsigned long total = 0, val = 0;

void setup() {
}

void loop() {
  total = total + analogRead(A0) - val;
  val = total / 32;
}

Microzod

#6
Jan 19, 2015, 05:46 pm Last Edit: Jan 19, 2015, 05:47 pm by Microzod
Another thing you could do is to use a external voltage reference IC, I have soldered a REF2030 to a SO8 adapter board that sits in D13, GND, Vref. So D13 powers the IC, if using a external reference one needs to re-solder a jumper on the board that ties the supply voltage to the Vref pin.
But if the ADC is used to read the supply voltage maybe it won't help much if the noise is still in the supply voltage?

I have made a layout for a tiny little PCB that should be able to be soldered into the due much more closely to the SAM so as to not have such a long way for the reference IC to connect to the chip, its kind of sketchy but it will work if one would want a proper reference voltage.

l-mb

I've tried with an external reference voltage myself (from an LM4040, for testing), and I still observed the 50 Hz noise.

For comparison, I also connected an ADS1115 via I²C, and - even with everything operating on battery! - was able to spot the 50 Hz noise there.

So, yeah, the stuff simply is so sensitive that the 50 Hz noise from the environment is being picked up. I doubt the Due construction is to be blamed for that.

Frankly, I was amazed, I (as a software guy) always thought "electro smog" was somet new-agey hippie crap, until it showed up in my own measurements ;-)

Dande80

Here, "val" should be noise free ...

Code: [Select]
unsigned long total = 0, val = 0;

void setup() {
}

void loop() {
  total = total + analogRead(A0) - val;
  val = total / 32;
}


Ok, it took me some minutes but I think I got it. It is basically a digital low pass filter. The noise is reduced by square root of 32 (as expected for averaging). But it will slow down the measurement as it takes 5 to 10 times 32 to get a stable value. As long as the measurement value is changing very slow this is a good solution. So definitely worth remembering.
Thanks
Daniel

Dande80

Another thing you could do is to use a external voltage reference IC, I have soldered a REF2030 to a SO8 adapter board that sits in D13, GND, Vref. So D13 powers the IC, if using a external reference one needs to re-solder a jumper on the board that ties the supply voltage to the Vref pin.
I was thinking about something like this myself. But as the SAM... is powered by a most probably noise 3v3 voltage I am not sure how much this will help. It might be necessary to add some stabilization to the 3v3 voltage itself. Could you share some experience with this?

But if the ADC is used to read the supply voltage maybe it won't help much if the noise is still in the supply voltage?
I was just using this setup to play around with the ADC and to get some feeling how I can use the ADC. What can I expect and what is the effort to achieve this.

I have made a layout for a tiny little PCB that should be able to be soldered into the due much more closely to the SAM so as to not have such a long way for the reference IC to connect to the chip, its kind of sketchy but it will work if one would want a proper reference voltage.
Could you share the design? I would be interested in that.

Daniel

Dande80

So, yeah, the stuff simply is so sensitive that the 50 Hz noise from the environment is being picked up. I doubt the Due construction is to be blamed for that.

Frankly, I was amazed, I (as a software guy) always thought "electro smog" was somet new-agey hippie crap, until it showed up in my own measurements ;-)
It is really amazing what you can see if your shielding is not sufficient. As I worked on my thesis I could identify which instruments were switched on using a FFT on the oscilloscope but good shielding helps a lot. Averaging is also a good way to get rid of these signals as the averaging is normally not synchronized with the interfering signals.

Daniel

dlloyd

#11
Jan 19, 2015, 10:26 pm Last Edit: Jan 19, 2015, 10:37 pm by dlloyd
The filter code is basically just a moving average of "n" readings where n = 32 in the example. It  attenuates noise similar to a capacitor, except the response is more of a linear response than exponential. For quicker response (and less filtering), just use a value less than 32, i.e. try 8. The range is any divisor value from 2 to "unsigned long", however a practical range would be 2-32.

The reading is essentially stable in "n" (divisor) readings.

The signal can change fast, i.e. using analogRead() at 8,000 reads per second, and averaging 8 reads, "val" would have a response of 1 kHz.

Dande80

The filter code is basically just a moving average of "n" readings where n = 32 in the example. It  attenuates noise similar to a capacitor, except the response is more of a linear response than exponential. For quicker response (and less filtering), just use a value less than 32, i.e. try 8. The range is any divisor value from 2 to "unsigned long", however a practical range would be 2-32.

The reading is essentially stable in "n" (divisor) readings.
Actually it behaves more like a exponential averager. I used your code and a constant analog reading of 1000. Look at the attached diagrams (sorry for the quick and dirty excel work). One digramm ist the actual value of val which approches 1000 in an exponential manner and the other is the difference of 1000-val plotted using a logarithmic scale. As you can see the difference plot looks linear using a logarithmic y-scale therefore the function itself is exponential. I am not sure if it is possible to create a moving average filter without saving all values within the average window.

The signal can change fast, i.e. using analogRead() at 8,000 reads per second, and averaging 8 reads, "val" would have a response of 1 kHz.
True but first of all I am not sure that I will always have the time to do mostly analogreads and I prefer to minimize the necessity of digital averaging if it can be achieved without to much trouble.

Daniel

dlloyd

#13
Jan 20, 2015, 04:40 pm Last Edit: Jan 20, 2015, 06:44 pm by dlloyd
Yes, you're right ... thanks for plotting the results.

Another possible solution: This function takes 5 analog readings, sorts them, then returns the middle value. Very high noise rejection with no averaging.

Code: [Select]
unsigned short middle() {
  int n = 5;
  int array[] = {analogRead(A0), analogRead(A0), analogRead(A0), analogRead(A0), analogRead(A0)};

  for (int x = 0; x < n; x++) // sort readings
  {
    for (int y = 0; y < n - 1; y++)
    {
      if (array[y] > array[y + 1])
      {
        int temp = array[y + 1];
        array[y + 1] = array[y];
        array[y] = temp;
      }
    }
  }
  return array[2]; //return middle value
}

l-mb

Taking the samples in such quick succession on a Due means you're sampling at way more than 1 kHz. You'll still experience the full joy of line noise. You need to average (and returning the median is essentially quite similar) over a longer period of time. Also, the sorting is rather CPU intensive.

I guess it depends on what you want to do. For signal processing, I'm merely using the Due as a means of data acquisition, and doing the filtering (Buttworth low-pass) on the PC, which has plenty of CPU power for that. Though I have some signal smoothing built into my Due code, it's optional - any signal processing I could do there is slower than just throwing the data at the PC, for the most part.

Go Up