Go Down

Topic: speed of analogRead (Read 68866 times) previous topic - next topic

abonellitoro

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

Grumpy_Mike

Quote
I couldn't find anything that answers my questions.
Why not it is all there.

Quote
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?

direvius

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.

abonellitoro

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

https://gist.github.com/pklaus/5921022

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

pmarin

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

ard_newbie

#50
Jul 13, 2017, 04:11 pm Last Edit: Jul 13, 2017, 04:17 pm by ard_newbie
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:

Code: [Select]

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
}







jlsilicon

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

adrianka

#52
May 25, 2018, 02:30 pm Last Edit: May 25, 2018, 02:31 pm by adrianka
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!

ard_newbie


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

adrianka

#54
Jun 08, 2018, 08:49 pm Last Edit: Jun 08, 2018, 09:04 pm by adrianka
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

Code: [Select]
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):

Code: [Select]
#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:

Code: [Select]
Start inter

and just hangs there forever.

Does anyone have an idea?

ard_newbie


Serial is much too slow compared to the speed of ADC samplings in Free Running mode (~ 1 MHz = 1000000 *  uint16_t per second).

adrianka

Serial is much too slow compared to the speed of ADC samplings in Free Running mode (~ 1 MHz = 1000000 *  uint16_t per second).
This is correct. I'm using serial monitor only for simpler debugging. In debugging speed doesn't matter to me. When the problem is solved I'll go back to SerialUSB.

ard_newbie

...debugging speed doesn't matter to me. When the problem is solved I'll go back to SerialUSB.
Then you don't understand the code snippet you are using.


First off, can you write a python code to receive a SerialUSB flow from the DUE ?

adrianka

Then you don't understand the code snippet you are using.


First off, can you write a python code to receive a SerialUSB flow from the DUE ?
Ok thank you for the reply. Can you tell me, what is wrong with the code?

I'm using stimmer's python code. Which worked fine at the beginning.

ard_newbie


Go Up