ADC conversion time

Status
Not open for further replies.
Hi guys,

I'm using a teensy 3.5 to measure an incoming signal using the ADC library. Does anyone know how fast I can read from the ADC with the fastest setting? Theoretically I would need to take a measurement every 6.25uS using a timer interrupt. Do you reckon that's feasible?

Thanks
 
If you want a consistent sampling rate / sample timing, you can't use a timer interrupt and do a read in the interrupt (jitter due interrupt triggering delays). Teensy 3.5 has the PDB timer block which can trigger a periodic ADC conversion with 0-jitter timing. You can get an interrupt when the conversion is finished.

Here is some sample code that does an ADC conversion at 200'000Hz (5 microseconds). A 50'000 Hz PWM output is measured.

Code:
#include <ADC.h>
#include <array>

// connect out_pin to adc_pin, PWM output on out_pin will be measured
// via adc_pin.

const uint8_t adc_pin = A9;
const uint8_t out_pin = 2;

ADC adc;

std::array<volatile uint16_t, 4096> buffer;
volatile size_t write_pos = 0;

volatile uint16_t adc_val = 0;

void setup() {
    pinMode(adc_pin, INPUT);
    Serial.begin(9600);
    delay(2000);
    Serial.println("Starting");

    adc.setAveraging(1);
    adc.setResolution(12);

    adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED);
    adc.setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
    adc.adc0->analogRead(adc_pin); // performs various ADC setup stuff

    adc.enableInterrupts(ADC_0);

    if(adc.adc0->fail_flag) {
        Serial.print("ADC error: ");
        Serial.println(adc.adc0->fail_flag, HEX);
    }

    adc.adc0->stopPDB();
    const uint32_t pdb_trigger_frequency = 200000;
    adc.adc0->startPDB(pdb_trigger_frequency);
    
    analogWriteFrequency(out_pin, 50000);
    analogWrite(out_pin, 100);
}

void loop() {
    // Print first 100 measurements in buffer.
    for(size_t i = 0; i < 100; i++) {
        Serial.print(buffer[i]);
        if(i % 20 == 19) Serial.println();
        else Serial.print(" ");
    }
    Serial.println();

    if(adc.adc0->fail_flag) {
        Serial.print("ADC error: ");
        Serial.println(adc.adc0->fail_flag, HEX);
    }
    delay(1000);
}

void adc0_isr() {
    size_t write_pos_ = write_pos;
    buffer[write_pos_] = adc.adc0->readSingle();
    write_pos_++;
    if(write_pos_ >= buffer.size()) write_pos_ = 0;
    write_pos = write_pos_;
}

void pdb_isr(void) {
    PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
}

Expected output:
4095 1 1 1 4095 1 3 1 4095 1 1 4 4095 1 3 1 4095 1 2 3
4095 1 1 1 4095 1 1 1 4095 3 1 1 4095 2 2 1 4095 1 1 1
4095 2 1 1 4095 3 1 2 4095 1 1 1 4095 1 1 1 4095 3 1 1
4095 1 3 2 4095 2 1 1 4095 1 2 1 4095 3 1 2 4095 1 2 1
4095 2 3 1 4095 2 1 1 4095 1 1 5 4095 2 1 3 4095 1 4 1
...

Instead of the interrupt, it would also be possible to do DMA transfer.
 
Status
Not open for further replies.
Back
Top