I have problems with instability in the ADC conversion value at high conversion rates. I need an ADC conversion time of 5 µs, or less with 12-bit resolution. The 350 ksample/s ADC of the M0 PRO should seems to suggest a conversion time of ~2.8 µs should be achievable. I discovered the conversion value is unstable at high conversion rates.
First, I timed the standard analogue readout code from a single pin (A1) using the code in Sketch 1 and a 100 MHz bandwidth oscilloscope. The conversion time was ~220 µs, which surprisingly, is actually worse than for an Arduino Uno (~120 µs). This is far from my requirement – so I dug into the ADC configuration.
I connected the A1 input pin to the nearest GND pin by a 1.5 cm wire. (I checked and a 50 Ohm source will give about 112 ns settling time according to the manual. [http://www.atmel.com/images/atmel-42181-sam-d21_datasheet.pdf p. 962.) So this should be a very good 0 V input.
So I set up a sketch for testing purposes based on the code on the GitHub site:
- Without any modifications of the registers. (see http://www.atmel.com/images/atmel-42181-sam-d21_datasheet.pdf, pages: 846- 885 for description.) I obtained the following hex values for the register contents.
INTFLAG: 8 //Synch read interrupt set
INTENSETs: 0
INTENCLR: 0
EVCTRL: 0 // No events set-up
SAMPLEN: 3F // Max sample length
CTRLB: 520 // Prescale factor 128, 10-bit single-conversion, single ended
AVGCTRL: 11 // Average two successive conversions
SWTRIG: 0
INPUTCTRL: 1802 // ADC1 input pos and internal negative input.
REFCTL: 1 //2.2297 V internal reference
Conversion value: 7 // This is varies by ±1-2 LSB. Just noise- which is OK.
Under these conditions the conversion time is ~210 µs. The slight improvement over Sketch 1 is because intitialisation code is moved so it is only executed in setup().
-
Changing to remove the averaging over two conversions (AVGCTRL = 0x00) reduces the conversion time to ~53 µs with no noticeable degradation in conversion value.
-
Increasing the resolution to 12 bits (CTRLB= 0x500) increased the conversion value to ~34 with ± few LSB scatter with no change in conversion time. (53 µs).
-
Reducing the number of half-cycles to 1 (SAMPLEN=0x01) gave no change in conversion values, ~34±few LSB, but reduced conversion time to 27 µs.
-
Decreasing the prescale factor to 64X (CTRLB= 0x400) leads to instability that appears as large changes in successive conversion values. (e.g. 1651->0->176…). Conversion time ~15 µs.
-
Increasing the sampling time to 10 half clock-cycles restored stability in conversion values to ~34±few LSB. This is OK for my purpose. Conversion time 20.2 µs.
-
Decreasing the prescale factor to 32X (CTRLB= 0x300) and increasing the sample time to the maximum (1 (SAMPLEN=0x3F) ) leads to instability in the conversion values gave larger conversion values ~298. And a longer conversion time 31 µs.
My conclusion from all this is that ADC conversion becomes unstable if the sample time and clock time becomes too short. The best result so far is in Sketch 2.
QUESTIONS
Q1. Has anybody found a solution to this instability problem?
Q2. Presumably, the solution is to optimise the ADC clock, prescale and samples time. With the prescale the ADC clock can only be adjusted in steps of two. I presume this ADC clock can be modified by the Generic clock generator. Does anybody have an experience of this? Or example code?
Q3. Of course, decreasing the conversion time makes the whole ADC more susceptible to spikes on the supply lines. I don't see any visible spikes on the different GND lines. Which one is best to use as analogue ground? (I might suggest for future Arduino designs that one of the three GND pins on the standard pin-out is dedicated to the GNDANA pin on the chip. This should reduce pick-up.)
Many thanks in advance for any advice and help!
Harry J. Whitlow
Sketch_1.ino (321 Bytes)
Sketch_2.ino (4.9 KB)