How can I achieve the highest sampling rate using ADC on Teensy?

Roni

Member
Hello everyone, I am still new to Teesy. I am working on an acoustic project on Teensy 4.1, this project requires two piezo sensors and a very high sampling rate.
I want to continuously monitor the piezo sensors and write the values to the serial.

What I want to do, is to have a uniform synchronous sampling, with preferably the highest rate possible (so in the range of 100 KHz to 400 KHz ). I tried several codes that I found on the internet though I am not achieving this rate. I know that writing to the serial is quite slow (or that's what I think), so I can use the compare function on the ADC to only convert values that are higher than a threshold, though I don't know if it impacts the sampling speed or not.

Also, if I want to use the synchronized reading, should I attach both sensors to the same ADC or to different ADC, like one of them to ADC 0 and one to ADC 1?
Thank you all in advance for your help, it is much appreciated.


My code:
#include <ADC.h>

const int readpin1 = A14; // First analog input pin

const int readpin2 = A16; // Second analog input pin



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



#define SAMPRATE 200000 // Sampling rate 200 000 Hz

#define AVERAGING 1

#define RESOLUTION 12



#define ADCSAMPLES 10000 // Number of samples to collect

uint16_t adcbuffer1[ADCSAMPLES]; // Buffer for first analog input

uint16_t adcbuffer2[ADCSAMPLES]; // Buffer for second analog input

volatile uint32_t adcidx = 0; // Must be volatile as it is changed in interrupt handler

const char compileTime[] = "ADC Timer test Compiled on " __DATE__ " " __TIME__;



void setup() {

delay(500);

Serial.begin(200000);

delay(1000);

pinMode(readpin1, INPUT_DISABLE);

pinMode(readpin2, INPUT_DISABLE);

delay(1500);

Serial.print("\n\n");

Serial.println(compileTime);

Serial.println("Press <n> to collect and display data");



adc->adc0->setAveraging(AVERAGING); // Set number of averages

adc->adc0->setResolution(RESOLUTION); // Set bits of resolution

adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed

adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed



adc->adc1->setAveraging(AVERAGING); // Set number of averages

adc->adc1->setResolution(RESOLUTION); // Set bits of resolution

adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed

adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed

}



void loop() {

char ch;

if (Serial.available()) {

ch = Serial.read();

if (ch == 'n') GetADCData();

}

}



// This ISR reads both ADCs

void adc0_isr() {

uint16_t adc_val1, adc_val2;



// Read analog values from both ADCs

// Read analog values from both ADCs

adc->adc0->startSingleRead(readpin1);

adc_val1 = adc->adc0->readSingle();

adc->adc1->startSingleRead(readpin2);

adc_val2 = adc->adc1->readSingle();







if (adcidx < ADCSAMPLES) { // Storage stops when enough samples collected

adcbuffer1[adcidx] = adc_val1;

adcbuffer2[adcidx] = adc_val2;

adcidx++;

}

}



void GetADCData(void) {

delay(100); // Wait for USB serial to finish

adc->adc0->stopTimer();

adc->adc0->startSingleRead(readpin1); // Setup everything before the Timer starts, differential is also possible

adc->adc1->startSingleRead(readpin2);

delay(1);

adc->adc0->readSingle();

adc->adc1->readSingle();

adcidx = 0;

// Now start the ADC collection timer

adc->adc0->startTimer(SAMPRATE); // Frequency in Hz

adc->adc0->enableInterrupts(adc0_isr);



// do {

// // You could process a sample here with multiple buffers or copying to a new buffer

// // for processing while collection is in progress

// } while (adcidx < ADCSAMPLES);



adc->adc0->stopTimer();

Serial.println("Collection complete.");

// The data is in the global adcbuffer arrays.

ShowADC();

}



// Display the start of data in counts. Send 10 values per line

// Data is in the global variables adcbuffer1 and adcbuffer2.

void ShowADC(void) {

uint32_t i;

Serial.println("ADC Data in Counts");

for (i = 0; i < ADCSAMPLES; i++) {

if ((i % 10) == 0) {

Serial.printf("\n% 3d: ", i);

}

Serial.printf("% 5d, % 5d", adcbuffer1, adcbuffer2);

if ((i + 1) % 10 == 0) {

Serial.println();

}

}

Serial.println();

}
 
Can you repost that code in code tags (the </> button), so its formatted properly please?
 
Can you repost that code in code tags (the </> button), so its formatted properly please?
MY bad,
C++:
#include <ADC.h>

const int readpin1 = A14; // First analog input pin

const int readpin2 = A16; // Second analog input pin



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



#define SAMPRATE 200000 // Sampling rate 200 000 Hz

#define AVERAGING 1

#define RESOLUTION 12



#define ADCSAMPLES 10000 // Number of samples to collect

uint16_t adcbuffer1[ADCSAMPLES]; // Buffer for first analog input

uint16_t adcbuffer2[ADCSAMPLES]; // Buffer for second analog input

volatile uint32_t adcidx = 0; // Must be volatile as it is changed in interrupt handler

const char compileTime[] = "ADC Timer test Compiled on " __DATE__ " " __TIME__;



void setup() {

delay(500);

Serial.begin(200000);

delay(1000);

pinMode(readpin1, INPUT_DISABLE);

pinMode(readpin2, INPUT_DISABLE);

delay(1500);

Serial.print("\n\n");

Serial.println(compileTime);

Serial.println("Press <n> to collect and display data");



adc->adc0->setAveraging(AVERAGING); // Set number of averages

adc->adc0->setResolution(RESOLUTION); // Set bits of resolution

adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed

adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed



adc->adc1->setAveraging(AVERAGING); // Set number of averages

adc->adc1->setResolution(RESOLUTION); // Set bits of resolution

adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed

adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed

}



void loop() {

char ch;

if (Serial.available()) {

ch = Serial.read();

if (ch == 'n') GetADCData();

}

}



// This ISR reads both ADCs

void adc0_isr() {

uint16_t adc_val1, adc_val2;



// Read analog values from both ADCs

// Read analog values from both ADCs

adc->adc0->startSingleRead(readpin1);

adc_val1 = adc->adc0->readSingle();

adc->adc1->startSingleRead(readpin2);

adc_val2 = adc->adc1->readSingle();







if (adcidx < ADCSAMPLES) { // Storage stops when enough samples collected

adcbuffer1[adcidx] = adc_val1;

adcbuffer2[adcidx] = adc_val2;

adcidx++;

}

}



void GetADCData(void) {

delay(100); // Wait for USB serial to finish

adc->adc0->stopTimer();

adc->adc0->startSingleRead(readpin1); // Setup everything before the Timer starts, differential is also possible

adc->adc1->startSingleRead(readpin2);

delay(1);

adc->adc0->readSingle();

adc->adc1->readSingle();

adcidx = 0;

// Now start the ADC collection timer

adc->adc0->startTimer(SAMPRATE); // Frequency in Hz

adc->adc0->enableInterrupts(adc0_isr);



// do {

// // You could process a sample here with multiple buffers or copying to a new buffer

// // for processing while collection is in progress

// } while (adcidx < ADCSAMPLES);



adc->adc0->stopTimer();

Serial.println("Collection complete.");

// The data is in the global adcbuffer arrays.

ShowADC();

}



// Display the start of data in counts. Send 10 values per line

// Data is in the global variables adcbuffer1 and adcbuffer2.

void ShowADC(void) {

uint32_t i;

Serial.println("ADC Data in Counts");

for (i = 0; i < ADCSAMPLES; i++) {

if ((i % 10) == 0) {

Serial.printf("\n% 3d: ", i);

}

Serial.printf("% 5d, % 5d", adcbuffer1, adcbuffer2);

if ((i + 1) % 10 == 0) {

Serial.println();

}

}

Serial.println();

}
 
May I suggest formatting the code? It’s much easier to read when it’s formatted where everything doesn’t start at the start of the line.
 
....like this:-
Much easier to read
Code:
#include <ADC.h>

const int readpin1 = A14; // First analog input pin
const int readpin2 = A16; // Second analog input pin

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

#define SAMPRATE 200000 // Sampling rate 200 000 Hz
#define AVERAGING 1
#define RESOLUTION 12
#define ADCSAMPLES 10000 // Number of samples to collect

uint16_t adcbuffer1[ADCSAMPLES]; // Buffer for first analog input
uint16_t adcbuffer2[ADCSAMPLES]; // Buffer for second analog input

volatile uint32_t adcidx = 0; // Must be volatile as it is changed in interrupt handler

const char compileTime[] = "ADC Timer test Compiled on " __DATE__ " " __TIME__;

void setup() {

    delay(500);
    Serial.begin(200000);
    delay(1000);
    pinMode(readpin1, INPUT_DISABLE);
    pinMode(readpin2, INPUT_DISABLE);
    delay(1500);
    Serial.print("\n\n");
    Serial.println(compileTime);
    Serial.println("Press <n> to collect and display data");

    adc->adc0->setAveraging(AVERAGING); // Set number of averages
    adc->adc0->setResolution(RESOLUTION); // Set bits of resolution
    adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed
    adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed

    adc->adc1->setAveraging(AVERAGING); // Set number of averages
    adc->adc1->setResolution(RESOLUTION); // Set bits of resolution

    adc->adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set the conversion speed
    adc->adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set the sampling speed
}

void loop() {
    char ch;
    if (Serial.available()) {
        ch = Serial.read();
        if (ch == 'n') GetADCData();
    }
}

// This ISR reads both ADCs

void adc0_isr() {

    uint16_t adc_val1, adc_val2;

    // Read analog values from both ADCs
    // Read analog values from both ADCs

    adc->adc0->startSingleRead(readpin1);
    adc_val1 = adc->adc0->readSingle();
    adc->adc1->startSingleRead(readpin2);
    adc_val2 = adc->adc1->readSingle();

    if (adcidx < ADCSAMPLES) { // Storage stops when enough samples collected
        adcbuffer1[adcidx] = adc_val1;
        adcbuffer2[adcidx] = adc_val2;
        adcidx++;
    }
}

void GetADCData(void) {

    delay(100); // Wait for USB serial to finish
    adc->adc0->stopTimer();
    adc->adc0->startSingleRead(readpin1); // Setup everything before the Timer starts, differential is also possible
    adc->adc1->startSingleRead(readpin2);
    delay(1);
    adc->adc0->readSingle();
    adc->adc1->readSingle();
    adcidx = 0;

    // Now start the ADC collection timer

    adc->adc0->startTimer(SAMPRATE); // Frequency in Hz
    adc->adc0->enableInterrupts(adc0_isr);

    // do {
    // // You could process a sample here with multiple buffers or copying to a new buffer
    // // for processing while collection is in progress
    // } while (adcidx < ADCSAMPLES);

    adc->adc0->stopTimer();
    Serial.println("Collection complete.");

    // The data is in the global adcbuffer arrays.

    ShowADC();
}

// Display the start of data in counts. Send 10 values per line
// Data is in the global variables adcbuffer1 and adcbuffer2.

void ShowADC(void) {

    uint32_t i;
    Serial.println("ADC Data in Counts");
    for (i = 0; i < ADCSAMPLES; i++) {
        if ((i % 10) == 0) {
            Serial.printf("\n% 3d: ", i);
        }
        Serial.printf("% 5d, % 5d", adcbuffer1, adcbuffer2);
        if ((i + 1) % 10 == 0) {
            Serial.println();
        }
    }
    Serial.println();
}
 
Back
Top