ADC Arduino Due
ADC Arduino Due
Useful links:
ADC_STARTUP_FAST 12
ADC_STARTUP_NORM 40
TRACKING_TIME = 1
ADC_SETTLING_TIME_0 = ADC_MR_SETTLING_AST3,
ADC_SETTLING_TIME_1 = ADC_MR_SETTLING_AST5,
ADC_SETTLING_TIME_2 = ADC_MR_SETTLING_AST9,
ADC_SETTLING_TIME_3 = ADC_MR_SETTLING_AST17 (17 periods ADCClock)
TRANSFER_PERIOD = 1
Each sample is formed from: Transfer Time + Tracking Time + Settling Time
https://github.com/arduino/Arduino/blob/ide-
1.5.x/hardware/arduino/sam/system/libsam/source/adc.c#L84
Due ADC Speed (http://www.djerickson.com/arduino/due_adc.html)
The function analogRead() in a tight loop takes 39uS per loop. Considering that the ADC can
convert in 1uS and the processor can execute dozens of instruction in 1 uS. what's the beef? I dug
into the analogRead() function to find out why. The first observation is that analogRead() does not
initialize the ADC, it just sets the channel, starts a conversion and waits for the result. Initialization
is done elsewhere. So basic code structure isn't the problem. Then I dug into the register settings.
The register ADC_MR (Mode Register) contains a number of settings that affect ADC timing:
TRACKTIM, SETTLING, STARTUP, and PRESCALE in addition to SLEEP. The following code allow you
to display the 32 bit contents of the MR register via the serial port.
REG_ADC_MR = 103C0100
The master clock, MCLK is 84MHz. The ADC prescaler is set to 0x01 which is divide by 4 so the ADC
clock is 84MHz / 4 = 21MHz. That is as fast as it can go, so that's not the problem. The ADC clock
period is 1 / 21MHz = 37.6nS. The 0xC sets STARTUP is 768. 768 / 21MHz = 36.6uS. Bingo! So I set
STARTUP to a smaller number, 2, (value = 16 / 21M = .76uS) with this line of code:
REG_ADC_MR = (REG_ADC_MR & 0xFFF0FFFF) | 0x00020000;
And the ADC loop now takes 4uS. Cool. To make it even faster, I also set the Settling number down
from 3 to 1. The data sheet recommends settling and tracking numbers. It also says that if you
want the ADC to convert faster than 500KHz, set the IBCTL field in ADC_ACR to 01. I checked, and
it was already is set to 01.