Analog I/O Pins and ADC Sampling Frequency

Hello,

I am completely new to arduino programming. I picked up the Arduino Due with the intention of sampling an analog signal (60Hz) at specific frequencies. I am trying to sample from one of the analog pins at integer multiples of 60Hz, such as 3.84kHz, 6kHz or 21.6kHz. I have found little documentation for the Due online.

The datasheet states that the clock governing the analog pins is set to the MCK (asuming the master clock, 84MHz) divided by a prescaler value. The formula given is MCK / ((Prescaler value +1) * 2), with prescaler value ranging from 0 to 512. If the max prescaler value is 512 does this mean that I must slow down the MCK to attain the desired sampling frequency? If so, I cannot find anything in the data sheet that states how to alter the MCK. How do I set the sampling frequency to a specific value?

I am also questioning the method I am using to detect how many samples a second I am recording. I reading from an analog pin for 1 second (with various baud rates) and detecting how many values are sent to my computer through the microUSB port (using Putty). Any advice or direction you can give me would be greatly apreciated. Thanks.

I also just received the Due and have found myself facing similar problems. Check out the following link:

Apparently it's the startup time that screws us up. Another way I went about fixing that is using:
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
Where I simply multiplied the max frequency by 2 (less advised as its probably set at max for a reason). I hear what you're saying about the prescaler, but I have yet to find a way to edit it directly. In the above link he states that its set to its maximum value, so there's that too. Anyway best of luck with this mysterious chip :stuck_out_tongue:

Hello!

I am also interested in knowing more about this, I found some information about how to increase other Arduino boards sampling frequency, but there is very little about the DUE.

Jason504, thanks for this information, I was able to double the default ADC samplerate adding that to the setup() function ( but I would still need at least 100Khz ).

I bought the DUE because it had better processing capabilities, looking forward to see further developments in this part.

Ok, here's some testings I made, I really don't know what I'm doing, but if someone assures me there's no danger of frying my board with this, I'll be happy... see my comments:

#define MAX_ADC_RESOLUTION 10 //changing resolution doesn't seem to affect sampling rate speed in this test

void setup() {

//I tested this with a hall sensor, not sure if results will vary according to the sensor used, but please be gentle with me, I just started learning this 3 days ago, I'm just an amateur programmer. :slight_smile:

Serial.begin(9600);

//check adc.h in the /sam folder

analogReadResolution(MAX_ADC_RESOLUTION); //

//by default, I get around 25000 samples per second, readings around 570 ( 10bit ) with a hall sensor plugged in

//adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX2, 1); //~313000 samples per second, A/D readings kaput
//adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX
2, 2); //~288 000 samples per second, A/D readings now have about 10% deviation
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX2, 3); //~267000 samples per second, A/D readings OK, the best compromise I got
//adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX
2, 4); //~220000 samples per second, A/D readings OK
//adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX2, ADC_STARTUP_NORM ); //~65000 samples per second,A/D readings OK
//adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX
2, ADC_STARTUP_FAST ); //~47000 samples per second, from the name, I was tempted to think this would perform better. But I know nothing.

edit: correction, I missed that 4 bit part from Dave's documentation. :-/

pinMode(ADC0,INPUT);
}

void loop() {

int start = millis();
int num_samples = 0;

//just to evaluate any possible accurancy degradation while messing around with this
int value = 0;
int max_value = 0;
int min_value = 2^MAX_ADC_RESOLUTION;

//let's see how many samples we can read in 1 second
while( millis() - start < 1000 )
{
value = analogRead(ADC0);

if(value > max_value )
max_value = value;

if(value < min_value )
min_value = value;

num_samples++;
}

// print out the control results
Serial.println("\nsamples read: ");
Serial.print(num_samples);

Serial.println("\nMax value: ");
Serial.print( max_value );

Serial.println("\nMin value: ");
Serial.print( max_value );

delay(1000);
}

Any thoughts?

I'm a bit lost inbetween the arduino standard calls and what the DUE is or does,
but I learned that that MCK/2 and prescaler determine the speed of the ADC processing.
given that (clock) speed, taking a sample takes a few clock cycles.

but what determines the sampling timing is what the datasheet calls a trigger.
the trigger can be an external signal or e.g. a timer.

I have not yet gotten that to work yet, however.
If / when I do, I'll report. but I'm following the datasheet, not the arduino calls, so the code is extensive.

I am also interested in knowing how to increase the speed of digitalRead() and digitalWrite().

I know there's a library with faster calls for that operation, but I don't know if it supports the Arduino DUE.

The values I have currently are enough for a simple input / output measurement, but I am concerned with accuracy loss the more pins are used.

no answer to the digital read/write question, but going back to OP:
the link that BuckM provided (Evaluating Arduino and Due ADCs) is a real gem if you want fast ADC (analogRead). This djerikckson did a fantastic job in evaluating the ADC speed, resolution, accuracy etc of the Arduino DUE.
What is most interesting is that he hints at a possible programming mistake in the Arduino 1.5 codebase; a quote from the ADC speed section of djerickson's evaluation:
"This may be a bug. STARTUP is a four bit field so 12 (0xC) works, but 40 (0x28) won't work. And 12 sets the value to 768 which is why the ADC is so slow. So I suspect that the programmer confused the value with the hardware settings. "

I tried the hack and it works as claimed:

    REG_ADC_MR = (REG_ADC_MR & 0xFFF0FFFF) | 0x00020000;

this gives a 4usec analogRead, instead of the 39usec that the standard settings give you.

tip of the hat and big thanks to djerickson.com

1 Like

I saw this post also. Does anyone know the proper protocol to bring this to the attention of the Due analogread code maintainers? 10x performance improvement in analogread seems like a big deal to me.

The electrical characteristics of the SAM3X datasheet specifies:

ADCClock - max 20Mhz
Conversion Time - 20 ADCClock

So the old prescaler is correct (ADC_FREQ_MAX == 20000000) while ADC_FREQ_MAX*2 is out of specification.
The conversion time was wrong, I've set it to 24 ADCClocks (that is "3", instead "2" is 16 and is under the minimum required).

Thank you!

Hi,

can the ADC from arduino working with 1MHz (1 µs) or not.
I try this code from internet site :
http://frenki.net/2013/10/fast-analogread-with-arduino-due/

but i receive just 1,4 µs.

I will sampling an rectangle signal of 250 KHz.

Thanks

You cannot get that speed from analogRead, you have to set up continuously triggered
reads to DMA if I remember rightly, that speed involves pipelining the ADC to its limit.

You could probably speed the ADC beyond 1MHz by :

analogReadResolution(10); // Set the AD to 10 bits of resolution instead of 12

adc_configure_timing (ADC, 1, ADC_SETTLING_TIME_3, 0); // Not (1) - 3 cycles instead of 5 (you have the choice !)