sample rate jitter with modified adc_pdb example, Teensy 3.2

Status
Not open for further replies.
I would like to sample a single ADC channel at a constant frequency of about 100 kHz and began with the adc_pdb example.

I've simplified the example code as well as I understand it, and it seems to work reasonably well. Monitoring the LED pin using my old 100 MHz analog scope shows that the adc isr is activated at the correct frequency but with occasional surprisingly large jitter of +/- 2 usec. The jitter gets worse if I print the values in loop (unsurprisingly).

I would appreciate suggestions to remove the jitter, or an explanation! Code follows.

Additional questions:

Are my choices of sample and conversion rates appropriate? The voltage source is low (~100 Ohms) impedance.

In the stock adc_pdb example code, why is the ADC value read in loop(), but read and ignored in the adc isr?

Thanks!

Code:
#include <ADC.h>
// based on adc_pdb example
const int readPin = A9; // ADC0

ADC *adc = new ADC(); // adc object;

void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(readPin, INPUT);

  Serial.begin(115200);
  while (!Serial);
  Serial.println("Begin setup");

  ///// ADC0 ////
  adc->setAveraging(0); // set number of averages
  adc->setResolution(12); // set bits of resolution
  adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED); // change the conversion speed
  adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed

  int freq = 100000;
  Serial.print("Start pdb with frequency ");
  Serial.print(freq);
  Serial.println(" Hz.");
  adc->adc0->stopPDB();
  adc->adc0->startSingleRead(readPin); // call this to setup everything before the pdb starts, differential is also possible
  adc->enableInterrupts(ADC_0);
  adc->adc0->startPDB(freq); //frequency in Hz

  // Print errors, if any.
  adc->printError();
  adc->resetError();
}

volatile uint16_t value;
volatile uint8_t new_val = 0;
volatile uint8_t led_stat = 0;

void loop() {
  if (new_val) {
    new_val = 0;
    //    Serial.println(value);
    //    digitalWriteFast(LED_BUILTIN, (led_stat = !led_stat));
  }
}

// Make sure to call readSingle() to clear the interrupt.
void adc0_isr() {
  value = (uint16_t) adc->adc0->readSingle();
  //adc->adc0->readSingle();
  new_val = 1;
  digitalWriteFast(LED_BUILTIN, (led_stat = !led_stat));
}


// pdb interrupt is enabled in case you need it.
void pdb_isr(void) {
  PDB0_SC &= ~PDB_SC_PDBIF; // clear interrupt
  //  digitalWriteFast(LED_BUILTIN, (led_stat = !led_stat));
}
 
Last edited:
In case anyone is interested, after a number of experiments I decided that 12 bits/VERY_HIGH_SPEED/100 kHz was too noisy, with obvious sampling artifacts, and settled on 10 bits/HIGH_SPEED.

I'm not sure that the observed jitter is detrimental for this particular application, which is peak detection for a gamma ray spectrometer. Overall ADC performance/data collection is quite satisfactory.

For bunch data processing and output, while continuing to sample data, I added the ring buffer (part of the ADC package), after increasing the ring buffer size for 8 to 256.
 
Status
Not open for further replies.
Back
Top