speed of analogRead

Magician:
I would look for alternative, for example SPI is supported by PDC, so you can add parallel to serial external register IC, depends on bit's width 8-16-32 etc. SPI driven with 42MHz clock may provide over 5 mega read/sec for 8- bits register

Thank you very much, that helped. In fact, my ADC also is sending out the data as serial data clocked at around 28Mhz, 18 bit and each bit valid at rising clock edge and without any delay between each 18 bit transfers. Clock is generated on the ADC board fixed. So it would be a two wire setup.
Do you think one could abuse the Due as a SPI slave to sample that kind of data or am I missing some obvious restriction? I would also be happy with not sending out the data but logging it to a SD Card using the SD Fat library which supports SPI with DMA on Due but i have the feeling there will be more complications.

Thanks for your time,

Laura

Do you think one could abuse the Due as a SPI slave to sample that kind of data or am I missing some obvious restriction?

AFAIK, DUE doesn't support 18-bits. Section 33.2 in SAM3X datasheet:

• Master or Slave Serial Peripheral Bus Interface
– 8- to 16-bit Programmable Data Length Per Chip Select
– Programmable Phase and Polarity Per Chip Select
– Programmable Transfer Delay Between Consecutive Transfers and Delay Before SPI
Clock per Chip Select
– Programmable Delay Between Chip Selects
– Selectable Mode Fault Detection
• Connection to DMA Channel Capabilities Optimizes Data Transfers
– One channel for the Receiver, One Channel for the Transmitter

if I got it right, by using the code underneath, I'll be using the maximum sampling rate possible (the quickest). Is there a way to define a precise sampling rate? (i need 44,1kHz).

As far as I know, as you have to make a reading every 22,67 us and the only time reference you have is the micros(), that is an integer, the answer is "no".

Regards

Magician:
AFAIK, DUE doesn't support 18-bits. Section 33.2 in SAM3X datasheet:

Thank you, I am aware of that. But as the bitflow is continous, I would just save the bytes one after another and let Matlab figure out which bits belong to which full 18bit ADC read.

The missing piece of information for me is:

Would the SAM3X be fine with continous reads with only two lines - Clock and Data - while the Arduinos outputline would just be pulled to ground and chipselect on a fixed potential too?

Would the SAM3X be fine with continous reads with only two lines - Clock and Data - while the Arduinos outputline would just be pulled to ground and chipselect on a fixed potential too?

No, SPI is 3-wire interface.
Your idea is non-sense, no way to shift in 18-bits on 16-bits interface.
You better to post ADC part name, link to datasheet, explain why not 16 or 24 bits is important, and better in another thread, as it has nothing to do with analogread.

I think this one is very important bugfix for the original code. With the original code I had glitches on my charts. Here is the picture:

In the begining of each 256-samples block there are three samples "from the future", they are supposed to be 4 blocks ahead. There also was zero samples in the beginning of the chart:

I think what happens here is the buffer is being sent while ADC is writing in it.
After I've applied the fix from this comment the problem's gone.

Thank you, @madrang!

madrang:

  ADC->ADC_RPR=(uint32_t)buf[0];   // DMA buffer

ADC->ADC_RCR=256;
ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
ADC->ADC_RNCR=256;
bufn=obufn=1;




I'm not sure, but it look like the Due is using buffer 0 for writing and reserving buffer 1 as the next buffer to be used.
If it is the case there is 2 buffer in use.



while(obufn==bufn); // wait for buffer to be full




This line should be



while((obufn + 1)%4==bufn); // wait for buffer to be full




Also why start at buffer 1 ??


bufn=obufn=1;




Would be better to start at 0.


bufn=1;
obufn=0;




Not sure if i understood the code properly, i hope someone can tell me more about this.

Hello! I'm very new in the Arduino world. I'm trying to adapt Stimmer's code to get data from two channels instead of one, but I'm a little bit confused. Can anyone help me?

#undef HID_ENABLED

// Arduino Due ADC->DMA->USB 1MSPS
// by stimmer
// Input: Analog in A0
// Output: Raw stream of uint16_t in range 0-4095 on Native USB Serial/ACM

// on linux, to stop the OS cooking your data:
// stty -F /dev/ttyACM0 raw -iexten -echo -echoe -echok -echoctl -echoke -onlcr

volatile int bufn,obufn;
uint16_t buf[4][256];   // 4 buffers of 256 readings

void ADC_Handler(){     // move DMA pointers to next buffer
 int f=ADC->ADC_ISR;
 if (f&(1<<27)){
  bufn=(bufn+1)&3;
  ADC->ADC_RNPR=(uint32_t)buf[bufn];
  ADC->ADC_RNCR=256;
 }
}

void setup(){
 SerialUSB.begin(0);
 while(!SerialUSB);
 pmc_enable_periph_clk(ID_ADC);
 adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
 ADC->ADC_MR |=0x80; // free running

 ADC->ADC_CHER=0x80;

 NVIC_EnableIRQ(ADC_IRQn);
 ADC->ADC_IDR=~(1<<27);
 ADC->ADC_IER=1<<27;
 ADC->ADC_RPR=(uint32_t)buf[0];   // DMA buffer
 ADC->ADC_RCR=256;
 ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
 ADC->ADC_RNCR=256;
 bufn=obufn=1;
 ADC->ADC_PTCR=1;
 ADC->ADC_CR=2;
}

void loop(){
 while(obufn==bufn); // wait for buffer to be full
 SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
 obufn=(obufn+1)&3;    
}

I'm doing a project where I need at least 200 kHz of sample rate for each channel, but 100 kHz would be alright too.

I'm doing a project where I need at least 200 kHz of sample rate for each channel, but 100 kHz would be alright too.

Forget it, you can't go that fast on two channels.

Grumpy_Mike:
Forget it, you can't go that fast on two channels.

What is the maximum sample rate I can achieve using both channels? And where is the bottleneck in the conversion?
Thank you in advance!

See
http://forum.arduino.cc/index.php?topic=326944.msg2860396#new

I couldn't find anything that answers my questions. Can you be more specific?

I couldn't find anything that answers my questions.

Why not it is all there.

Can you be more specific?

OK.
The A/D will not go that fast.
If you could get it to go that fast then what are you going to do with the data, there is not enough memory to store very much and you can't get the SD card to read it at that rate. It is too fast to send it out of the serial port.

Specific enough for you?

You're wrong, DUE can do 1MSPS (http://www.atmel.com/ru/ru/Images/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf)

And you can get the data through USB as demonstrated with the code posted before in this topic.

Hi @direvius, I saw you also look at this code:

And I want to ask you if you know how to get data from two channels instead of one. I want to have the max speed achievable, if it's 100 khz per channel it would be great, but it would be useful too to have this code that connects to the PC and Python for 2 channels :slight_smile:

I find this information quite useful! Thank you!
I tried sampling the input voltages to pins A0 and A8 of my Arduino DUE, and I needed 3 us to get both samples. Which is good enough for my application (> 300 kSa/s on 2 pins).
Now, the next I need to do is to sample 2 pins (A1, A9) just once, and then continuosly sample A0 and A8.

I tried two ways

  1. I use analogRead(A1) , analogRead(A9), however, the sampling rate of A0 and A8 decreases (which I dont fully understand why)
  2. I enable also A1 and A9
    ADC->ADC_MR |= 0x80; //set free running mode on ADC
    ADC->ADC_CHER = 0xcc0; //enable ADC on pins A0,1,8,9
    However, of course also the sampling rate will decrease.

My question: Is there a way to "disable" pins A1 and A9 after reading them once?
Or do you have a better idea to keep above 300 kSa/s when reading both A0,A8?
I thouhg DUE

The simplest way to read only once 2 channels and repeatedly 2 others is to :

First setup ADC controller with 4 channels enable
Enable interrupts at the end of each conversion
Disable 2 channels Inside the interrupt Handler

Try the code below with channels 4 and 5 (A3 and A2) disabled after one conversion, and channels 6 and 7 ( A1 and A0) repeatedly read:

volatile uint32_t Channel, LastConversion;

void setup() {
  adc_setup();
}

void loop() {

  // Do whatever you want in loop with LastConversion value
  Channel = LastConversion >> 12;
  LastConversion = LastConversion & 0xFFF;
}

void adc_setup ()
{
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power ON
  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_FREERUN_ON;                    // ADC in free running mode

  ADC->ADC_EMR = ADC_EMR_TAG;                          // ADC_LCDR contains the last channel number

  ADC->ADC_CHER = ADC_CHER_CH4                          // A3
                  | ADC_CHER_CH5                        // A2
                  | ADC_CHER_CH6                        // A1
                  | ADC_CHER_CH7;                       // Enable Channel 7 = A0

  ADC->ADC_IER = ADC_IER_EOC4                          // Interrupt on End of conversion
                 | ADC_IER_EOC5                        // for channels 4,5,6 and 7
                 | ADC_IER_EOC6
                 | ADC_IER_EOC7;

  NVIC_EnableIRQ(ADC_IRQn);                            // Enable ADC interrupt
}

void ADC_Handler() {

  uint32_t status;
  LastConversion = ADC->ADC_LCDR;
  
  status = ADC->ADC_ISR;                            // Read and clear status register
  // Stop reading channels 4 then 5
  if (status && ADC_ISR_EOC4) ADC->ADC_CHDR = ADC_CHDR_CH4;  // Disable channel 4
  if (status && ADC_ISR_EOC5) ADC->ADC_CHDR = ADC_CHDR_CH5;  // Disable channel 5

  // Else keep enabled channels 6 and 7 
}

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 !)

Hello,

I'm an Arduino beginner and I would need your help with the code.
Could you please tell me how to get timestamps to the voltage values and send them over to the python script? as a bundle?

like
1ms , 0V
2ms, 0.1V
...

also I'm getting a sample rate of 660kHz only. Do you know how to speed it up?

Thank you in advance!

Post the sketch you have already done (between code tags).

Thank you for your reply.

Before that, I have a different problem. With stimmer's original code, I am only receiving zeros on python with a frequency generator. And that problem hasn't been there before. First it was all fine.

The line

ADC->ADC_PTCR=1

seems to let the Arduino crash. (I know that because when it is commented then the loop runs.)

The problem is, I don't receive any data from the frequency generator that I have connected to pin A0 of the due.
I have the following slightly altered code (for debugging purposes):

#undef HID_ENABLED

// Arduino Due ADC->DMA->USB 1MSPS
// by stimmer
// from http://forum.arduino.cc/index.php?topic=137635.msg1136315#msg1136315
// Input: Analog in A0
// Output: Raw stream of uint16_t in range 0-4095 on Native USB Serial/ACM


//fast@fast:~/Documents/IP$ nautilus ~/.arduino15/packages/arduino/hardware/sam/1.6.11/cores/arduino


// on linux, to stop the OS cooking your data: 
// stty -F /dev/ttyACM0 raw -iexten -echo -echoe -echok -echoctl -echoke -onlcr
// screen /dev/ttyACM0^C

// changes and prints terminal line settings 
volatile int bufn,obufn;
uint16_t buf[4][256];     // 4 buffers of 256 readings


void ADC_Handler(){       // move DMA pointers to next buffer
  Serial.println("Start interrupt handler");
  int f=ADC->ADC_ISR;     // read the interrupt status register
  if (f&(1<<27)){         // check the bit "endrx" in the status register, if endrx bit == 1 then execute body
                          // 1 = the receive counter register has reached 0 since the last write in ADC_RCR or ADC_RNCR
  /// set up the "next pointer register"
   bufn=(bufn+1)&3;       // wht does this line do?
   ADC->ADC_RNPR=(uint32_t)buf[bufn]; // RPNR = Receive Next Pointer Register points to  
   ADC->ADC_RNCR=256;      // next count register is set to 256
  } 
}

void setup(){
  pinMode(52, OUTPUT);
  digitalWrite(52,HIGH);
  Serial.begin(115200);     // open a serialUSB connection
  //Serial.begin(115200);
  Serial.println("wait for SerialUSB");
  while(!Serial);      // wait for serialUSB, works only when connected to the native port

  pmc_enable_periph_clk(ID_ADC);  
  adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);

  ADC->ADC_MR |=0x80; // free running, set bit 8 to 1 in mode register

  ADC->ADC_CHER=0x80; //channel enable register, set bit 8 to 1, rest 0, meaning enable pin A0
  
  NVIC_EnableIRQ(ADC_IRQn);         // interrupt controller set to enable adc.
  ADC->ADC_IDR=~(1<<27);            // interrupt disable register, disables all interrupts but ENDRX
  ADC->ADC_IER=1<<27;               // interrupt enable register, enables only ENDRX
  ADC->ADC_RPR=(uint32_t)buf[0];    // DMA buffer
  ADC->ADC_RCR=256;
  ADC->ADC_RNPR=(uint32_t)buf[1];   // next DMA buffer
  ADC->ADC_RNCR=256;                // and next counter is set to 256
  bufn=obufn=1;
  ADC->ADC_PTCR=1;  // transfer control register for the DMA is set to enable receiver channel requests
  // now that all things are set up, it is safe to start the ADC.....
  
  ADC->ADC_CR=2;
  
}

void loop(){ 
  
  
  while(obufn==bufn)
  {
    Serial.println("wait for buffer to be full");// wait for buffer to be full
  }
  Serial.println("buffer full");   
  for(int i=0; i<256;i++)
  {
    Serial.println(buf[obufn][i]);
  }
  //SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
  Serial.println("buffer sent");
  //Serial.write((uint8_t *)buf[obufn],512);
  //obufn=(obufn+1)&3;  
}

I wanted to check if the buffer contains no values or if the serialusb interface is failing.
When I checked the Serial Monitor it only showed:

Start inter

and just hangs there forever.

Does anyone have an idea?