Last December I wrote about generating fast PWM on the Arduino Leonardo board.
This time I will follow my ideas of going beyond stock vanilla Arduino talking about the ADC.
You can use the Arduino analogRead function to read an analog value on one of the analog enabled pins. On the Arduino Leonardo there are 12 analog inputs. The typical A0 to A5 six standard Arduino inputs and the additional six lines A6 to A11 that correspond to D4, D6, D8, D9, D10 and D12.
The ADCs contained in the Atmega MCUs used in Arduino boards are 10 bit converters. To do one conversion the analogRead function takes 100us. It is supposed that the MCU needs that much time to give a 10 bit precision conversion. But 100us, for some applications, can be too much time. It limits, in fact, the maximum analog sample frequency to 10kHz and this doesn't take into account the time needed to process the read data.
You can do better. You can do faster. But, as is normal in life, there must be some trade offs. So, if you want to do faster conversions you need to know what are you trading for them.
The ATmega 32u4 ADC
I suspect that other ATmega based Arduinos include a similar ADC, but I don't know for sure. The ADC uses an internal clock that is obtained from the system clock (16MHz on Arduino Leonardo) which is divided by factor between 2 and 128 using an special register setting.
On the Arduino Leonardo, the divider is set to the maximum 128 value so, at 16MHz master clock frequency we get a 125kHz ADC clock frequency.
To obtain the time needed to do a conversion from the ADC clock frequency we can refer to one table in the ATmega 42u4 datasheet.
|Number of cycles to do a conversion|
There are three kinds of conversion: First Conversion, Normal Conversions and Auto Triggered Conversion. The ones that apply to analogRead are the two first ones, but the first only applies to the first conversion so we can use the central column (Normal Conversion) as the typical case.
The ADC needs to do two things to provide a conversion: Sample and Hold and SAR Conversion. In the table we find that those needs 1.5 and 13 cycles for a total of 14.4 cycles. As the ADC frequency is 125kHz, the total ADC time is 14.5/125kHz = 116 us. That's where the about 100us analogRead time comes from.
The MCU datasheet states that we need an ADC frequency between 50kHz and 200kHz to get the maximum 10 bit resolution. With a 200kHz frequency we could shorten the total ADC time to 72,5us. Unfortunately the clock divider option next to 128 is 64 so, we cannot select 200kHz. We can only select 125kHz, 250kHz... Any option beyond 125kHz, using a 16MHz master clock, goes beyond the Atmel recommendations for the MCU.
Separating the two things the ADC does we get 12us Sample and Hold time and 104us SAR Conversion time. If we increase the ADC frequency we could shorten those times but. We know that we won't get maximum resolution but, ¿What are exactly the side effecs?
Sample and Hold
To understand the Sample and Hold we can use one of the figures in the ATmega 32u4 datasheet:
The Sample and Hold (S&H) circuit is composed on a switch, a resistor and a capacitor. At the start of the conversion the switch is closed during the sample time (1.5 ADC clock cycles). After that, the switch is open and the ADC SAR circuit does the real conversion. The S&H circuit is important because the signal should not change during the SAR conversion. That is guaranteed by the fact that the switch is open during the conversion.
One fundamental point about S&H circuits is that the capacitor need to be charged to the input voltage, during the sample time, before the conversion starts. As this is an RC circuit, in theory, the capacitor voltage will never reach the input one. In practice we only need to get as close to the input voltage as is needed for the converter resolution. For a 10 bit ADC, in order to get a negligible error we need to get to 1/2^11 of the ADC reference value that is normally 5V for Arduino boards.
The RC charging, assuming the worst case of capacitor at zero will be modelled by:
In the worst case, the input voltage will be 5V and to meet the required 10 bit precision the input value capacitor value should get to 1/2^11 of the input value.
That will get:
At 125kHz ADC clock operation we know that the sample time is 12us, so the time constant should be 1,57us or less. As the capacitance is 14pF, the total resistance should be below 112 kOhm. As the ADC internal resistance can go up to 100k, that limits the external resistance to about 12kOhm. That is consistent with the fact that the MCU datasheet recommends external resistances to the ADC of 10 kOhm or less.
The above formula is quite important. When using the ADC. At a 16MHz master frequency the sample time cannot be bigger than 12us so you should not use a total external resistance to the ADC greater than 12 kOhm. Using a greater resistance could limit the ADC resolution lowering the effective number of bits you get from the ADC.
If, for instance, you only need 8 bits because you are discarding the 4 lower bits resulting from the conversion, you only need to have a 5,4 us time constant (sampling time divided by ln(9) ) so, with the same 14pF ADC capacitance you will only need a total resistance below 386k Ohm. Considering the maximum 100k internal ADC resistance you only need to guarantee a maximum of 286k Ohm external resistance.
The ATmega 32u4 MCU uses a Succesive Approximation Register (SAR) to do the conversion. This is the most usual kind of converter that can be found on MCUs. These converters get one bit at a time at each clock cycle. So, in order to get a 10bit value, we need 10 clock cycles. From the table found on the datasheet we know that the actual conversion takes 13 cycles. The extra 3 cycles are probably for synchronization tasks.
Increasing the clock frequency during the conversion operation will affect the ADC resolution but the effect is not easy to model although it can be measured. Fortunately someone has done this measurements.
On the Open Music Labs website you can find this two articles:
They are a quite interesting read and they explain more details on the Sample and Hold operation. The links apply to the ATmega 328p but I don't think that the ATmega 32u4 ADC should be much different.
The result is that increasing the ADC frequency reduces the equivalent number of bits (ENOB) of the conversion. Observe that at the minimum stock 125 kHz frequency the ENOB is not 10 bits but something above 9. Also, at 250 and 500 kHz the ENOB is also over 9 but decaying. At 1MHz the ENOB is over 8. For frequencies greater than that the ENOB falls below 8 bits.
Finally we can find the trade offs of using a bigger ADC frequency:
- The resolution (number of bits) could be limited by the S&H
- The resolution (number of bits) will be limited during the conversion
The number of bits of an ADC is an integer number, but the Equivalent Number of Bits (ENOB) is not. At 125kHz, if the S&H is not the limiting factor, you will get about 9,5 bits worth of data. That is, the ratio between the maximum value you can convert and the conversion noise will be limited to a 2^9,5 ratio. If you don't need more than 9 bits of real resolution, you can increase the ADC clock frequency up to 500kHz but you must verify that the S&H is also capable to keep with that speed for your ADC external resistance values. For 8 bit operation you could go to 1MHz. That is eight times the original conversion speed.
In order to change the ADC speed clock you need to change the ADC Control and Status Register A (ADCSRA).
The 3 lower bits of this register determine the divider used to obtain the ADC clock from the MCU master frequency.
For 111 we get a 128 prescaler that corresponds to the 125 kHz stock Arduino frequency.
For 110 we get a 64 divider that gets a 250kHz clock. For 101 we get 500kHz and for 100 we get 1MHz.
The following example program just does 4 conversions in a row. The first at the stock 125kHz, the second at 250kHz, the third at 500kHz and the last one at 1MHz.
The program also toggles the Arduino pin 3 before and after each call to analogRead so that the total time associated to this function can be measured.
|Output at pin 3|
From the mesurement we can see how the analogRead function time halves on each call as the ADCSRA register is changed to obtain greater ADC frequencies.
Fortunately the analogRead function itself doesn't modify the ADCSRA register. If that was the case we could not hack the ADC speed without creating a new analogRead function.
Code on Github (11/02/2018)The code is now on Github: