Step 8: How the ADC works

Picture of How the ADC works
The Arduino microcontroller features a single 10-bit successive approximation ADC. Before the ADC there is an analog multiplexer that lets us send, to the ADC, the signals from different pins and sources (but only one at a time).

Successive Approximation ADC means that the ADC takes 13 clock cycles to complete the conversion (and 25 clock cycles for the first conversion). There is a clock signal dedicated to the ADC that is "computed" from the main clock of the Arduino; this is because the ADC is a little slow and can not keep up with the pace of the other parts of the microcontroller. It requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate.

But how much higher rates can we use? There are a couple of good guides about the ADC at the Open Music Labs that I suggest to read: Since my purpose is to get a fast oscilloscope I decided to limit the precision to 8-bits. This has several bonuses:
  1. the data buffer can store more data;
  2. you do not waste 6-bits of RAM per datum;
  3. the ADC can acquire faster.
The prescaler lets us divide the frequency, by some factors, by setting the ADPS0-1-2 bits of the ADCSRA register. Seeing the plot of the precision from the Open Music Labs Article, we can see that for 8-bits precision the frequency could go up to 1.5 MHz, good! But since the ability of changing the prescaler factor lets us change the acquisition rate, we can use it also to change the timescale of the oscilloscope.

There is a good feature about the output registers: we can decide the adjusting of conversion bits, by setting the ADLAR bit in the ADMUX register. If it is 0 they are right adjusted and viceversa (see the image). Since I wanted 8-bits precision I set it to 1 so I could read just the ADCH register and ignore the ADCL.

I decided to have just one input channel to avoid having to switch channel back and forth at every conversion.

One last thing about the ADC, it has different running modes each one with a different trigger source:
  • Free Running mode
  • Analog Comparator
  • External Interrupt Request 0
  • Timer/Counter0 Compare Match A
  • Timer/Counter0 Overflow
  • Timer/Counter1 Compare Match B
  • Timer/Counter1 Overflow
  • Timer/Counter1 Capture Event
I was interested in the free running mode that is a mode in which the ADC continuously converts the input and throws an Interrupt at the end of each conversion (associated vector: ADC_vect).