ADC - analogRead at high frequency (1 MHz) on Arduino DUE

There are some great posts about using Arduino Due (I have a Freaduino Due) to read an analogue signal at high frequency.

http://frenki.net/2013/10/fast-analogread-with-arduino-due/
http://forum.arduino.cc/index.php?topic=137635.5

But the situation changed a bit after ARDUINO 1.5.5 BETA 2013.11.28, when wrong initialization for ADC timings was changed.
This is discussed on:

While before this change you could get an notorious decrease in the sampling time from some 38 us (micro seconds) to 1 us. After that I couldn´t get less than 1.5 us.

With this code I get 1 us again:

int x;                                           // read value

void setup()
{
  Serial.begin(57600);                           // initialize the serial port:
  REG_ADC_MR = 0x10380180;                       // change from 10380200 to 10380180, 1 is the PREESCALER and 8 means FREERUN
  ADC -> ADC_CHER = 0x80;                        // enable ADC on pin A0
}

void loop() {

  unsigned long t = micros();                    // init time an elapsed time, in micro seconds
  
  for(int i = 0; i < 1000; i++) {
    
    // instrucction to measure
    while((ADC->ADC_ISR & 0x80)==0);             // wait for conversion
    x = ADC->ADC_CDR[7];                         // read value A0
    
  }
  
  t = micros() - t - 2;                          // 2 us is nothing measured time
  
  Serial.print("Time (us) ");
  Serial.println( ( (double) t / 1000 ), 6 );
  
  delay(2000);
}

I´m getting a 1.00 us sample time, That is 1 MHz frequency!.

My small innovation from the links is that I changed the PRESCALAR, from 2 to 1. This is in REG_ADC_MR = 0x10380180. I changed the third digit (right to left) from 2 to 1.
The change from 0 to 8 is to enable FREERUN, that means one sample after the other non stop.


Some comments:

Without any optimization I'm getting an analogRead(0); at 3.32 us (300 KHz)
enabling FREERUN (REG_ADC_MR = 0x10380280;) 1.92 us (520 KHz)
and changing resolution to 12 bits (shouldn´t be the opposite?) (analogReadResolution(12)) 1.80 us (555 KHz)

Then, from Stimmer post (I just coping and pasting his code, I am not sure to understand what he is doing)
ADC -> ADC_MR |= 0x80; // set free running mode on ADC;
ADC -> ADC_CHER = 0x80; // enable ADC on pin A0

while((ADC->ADC_ISR & 0x80)==0); // wait for conversion
x = ADC->ADC_CDR[7]; // read value
I´m getting 1.50 us (667 KHz)

I just check the speed. I didn´t check any measured values so far.


Adios from Buenos Aires
Happy coding
Marcelo

I think you can only get 1MHz using dma.

No no. I´m getting 1 MHz with this.
I am only storing it in memory until the measure ends. It´s a big 24000 int array (I should try a short array).

I tested the light output of a compact fluorescent lamp. I will try to add some picture.

Gericom:
I think you can only get 1MHz using dma.

You can only get reliable 1MHz sampling using DMA or disabling all (other) interrupt
handlers (which otherwise may cause lost samples by delaying the ADC code or ISR).

Its obviously going to be more powerful to use DMA which frees the CPU for other stuff.

Ah. Now I understand what you are saying.
Thanks Gericom and thanks MarkT for pointing me that.

Honestly I don´t know how to implement DMA (direct memory access) right now. But I will try to learn (I love to investigate and learn).

In the meantime, will something like this be an acceptable solution?

noInterrupts();

(fast loop of analogRead)

interrupts():

Here you can find the datasheet of the chip: www.atmel.com/Images/doc11057.pdf