Increase sampling rate on MKRVidor4000

Hello everyone,
I have been working on this board for several months now, and regarding the FPGA its all ok! My issue now is with SAMD; I need to sample a signal (2khz) at 4kHz (250us). However when I tried to read an analog pin at this frequency I only get about 530us (1.9kHz).

I need to increase at least twice the sample rate I am getting now.

This is how I implemented the test:

void loop() { 
  uint32_t LARGO_LECTURA_CANAL = 100;
  uint32_t SAMPLING_PERIOD = 250;
  uint32_t tiempoInicial = micros();
  uint16_t lectura;
  
  for (int indiceLectura = 0; indiceLectura<LARGO_LECTURA_CANAL; indiceLectura++)
  { 
    while (micros() - tiempoInicial < SAMPLING_PERIOD);
    tiempoInicial = micros();
    lectura = analogRead(1); 
  } 
}

Is the solution changing Prescaler? Where can I modify this?
Or should I modify timers used in the acquisition?

Pls help. Regards!

Hi mgp_watermelon,

The Arduino SAMD21 core file "wiring.c" sets the sampling time control register (SAMPCTRL) to its maximum 63 (0x3F in hex). This adds 64 (SAMPCTRL + 1) half ADC clock cycles to your conversion. A conversion typically taking 426us at 12-bit resolution.

Provided source resistance seen by your ADC input isn't really high, the SAMPCTRL register can ususally safely be set to 0. However this register is write-protected, therefore it's necessary to first disable the ADC:

ADC->CTRLA.bit.ENABLE = 0;                       // Disable the ADC
while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
ADC->SAMPCTRL.reg = 0x00;                        // Reduce the sample time by (63 + 1) * (512 / 48MHz) / 2
ADC->CTRLA.bit.ENABLE = 1;                       // Enable the ADC
while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization

This reduces your conversion time to around 91us for a default 512 ADC clock prescaler.

The calculations for the SAMPCTRL register can be found on Github here: Arduino Zero ADC Sample Time Too Long · Issue #327 · arduino/ArduinoCore-samd · GitHub.

Thanks MartinL for your reply!

When I implement this configuration you mentioned in my code, the time goes from 500us to 330us, which is very good, but still cant get 250us.

ADC->CTRLA.bit.ENABLE = 0;                       // Disable the ADC
while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
ADC->SAMPCTRL.reg = 0x00;                        // Reduce the sample time by (63 + 1) * (512 / 48MHz) / 2
ADC->CTRLA.bit.ENABLE = 1;                       // Enable the ADC
while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization

Is there something I missed? Or another configuration I should consider?

Did some tests.

uint32_t tiempold;
uint32_t LARGO_LECTURA_CANAL = 100;
uint32_t SAMPLING_PERIOD = 250;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  
  tiempold = 0;
  
  ADC->CTRLA.bit.ENABLE = 0;                       // Disable the ADC
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
  ADC->SAMPCTRL.reg = 0x00;                        // Reduce the sample time by (63 + 1) * (512 / 48MHz) / 2
  ADC->CTRLA.bit.ENABLE = 1;                       // Enable the ADC
  while(ADC->STATUS.bit.SYNCBUSY);                 // Wait for synchronization
  
}

void loop() {

  uint32_t tiempoInicial = micros();
  uint16_t lectura;

  Serial.print("\nLoop start delay: ");
  Serial.print(tiempoInicial - tiempold); 
  
  tiempold = tiempoInicial;
  Serial.print("\nStart time: ");
  Serial.print(tiempoInicial); 
  for (int indiceLectura = 0; indiceLectura<LARGO_LECTURA_CANAL; indiceLectura++)
  {
    while (micros() - tiempoInicial < SAMPLING_PERIOD);
    tiempoInicial = micros();
    lectura = analogRead(1);
  }

  Serial.print("\nEnd time: ");
  Serial.print(tiempoInicial);
  Serial.print("\nDiff: ");
  Serial.print(tiempoInicial - tiempold);
  tiempold = tiempoInicial;
 
}

Original ADC conf
Loop start delay: 565
Start time: 1116260
End time: 1158790
Diff: 42530

With ADC changes
Loop start delay: 248
Start time: 1413439
End time: 1438685
Diff: 25246

with SAMPLING_PERIOD set to 0
Loop start delay: 237
Start time: 1358036
End time: 1367250
Diff: 9214

So it looks like it works OK.