ADC adc_pdb example, pdb_isr() does not run

Status
Not open for further replies.

DrM

Well-known member
Following is the adc_pdb example. modified to save data to a buffer for each ADC, and increment counters in each ISR. The output shows that a count missing from one of the adc_isr(), and the PDB isr counter has not advanced from zero.

Code:
#include <ADC_Module.h>
#include <ADC.h>
#include <RingBuffer.h>
#include <RingBufferDMA.h>

/* Example for triggering the ADC with PDB
*   Valid for Teensy 3.0 and 3.1, not LC
*/


#include <ADC.h>

const int readPin = A9; // ADC0
const int readPin2 = A2; // ADC1

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

void setup() {

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

    Serial.begin(9600);

    Serial.println("Begin setup");

    ///// ADC0 ////
    adc->setAveraging(1); // set number of averages
    adc->setResolution(8); // 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

    ////// ADC1 /////
    #if ADC_NUM_ADCS>1
    adc->setAveraging(1, ADC_1); // set number of averages
    adc->setResolution(8, ADC_1); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED, ADC_1); // change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED, ADC_1); // change the sampling speed
    #endif

    Serial.println("End setup");

}

#define BUFLEN 1024

int buf[BUFLEN] = { 0 };
int nbuf = 0;

int buf2[BUFLEN] = { 0 };
int nbuf2 = 0;

int pdbknt = 0;

char c=0;
int value;
int value2;

void loop() {

    if (Serial.available()) {
        c = Serial.read();
        if(c=='v') { // value
            Serial.print("Value ADC0: ");
            value = (uint16_t)adc->readSingle(ADC_0); // the unsigned is necessary for 16 bits, otherwise values larger than 3.3/2 V are negative!
            Serial.println(value*3.3/adc->getMaxValue(ADC_0), DEC);
            #if ADC_NUM_ADCS>1
            Serial.print("Value ADC1: ");
            value2 = (uint16_t)adc->readSingle(ADC_1); // the unsigned is necessary for 16 bits, otherwise values larger than 3.3/2 V are negative!
            Serial.println(value2*3.3/adc->getMaxValue(ADC_1), DEC);
            #endif
        } else if(c=='s') { // start pdb, before pressing enter write the frequency in Hz
            uint32_t freq = Serial.parseInt();
            if (freq == 0) {
                Serial.println("Stop pdb.");
                adc->adc0->stopPDB();
                adc->adc1->stopPDB();
            }
            else {
                Serial.print("Start pdb with frequency ");
                Serial.print(freq);
                Serial.println(" Hz.");
                pdbknt = 0;
                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
                #if ADC_NUM_ADCS>1
                adc->adc1->stopPDB();
                adc->adc1->startSingleRead(readPin2); // call this to setup everything before the pdb starts
                adc->enableInterrupts(ADC_1);
                adc->adc1->startPDB(freq); //frequency in Hz
                #endif
            }
        } else if(c=='p') { // pbd stats
            Serial.print("Frequency: ");
            Serial.println(adc->adc0->getPDBFrequency());
            Serial.print("knts adc0 " );
            Serial.print( nbuf );
            Serial.print(" adc1 " );
            Serial.print( nbuf2 );
            Serial.print(" pdb " );
            Serial.println( pdbknt );
        }

    }


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

    //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));

    delay(10);
}


// Make sure to call readSingle() to clear the interrupt.
void adc0_isr() {
        buf[nbuf++] = adc->adc0->readSingle();
        if (nbuf >= BUFLEN-1) {
          //adc->disableInterrupts(ADC_0);
          adc->adc0->stopPDB();
        }
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}

#if ADC_NUM_ADCS>1
void adc1_isr() {
        buf2[nbuf2++] = adc->adc1->readSingle();
        if (nbuf2 >= BUFLEN-1) {
          //adc->disableInterrupts(ADC_1);
          adc->adc1->stopPDB();
        }
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}
#endif

// pdb interrupt is enabled in case you need it.
void pdb_isr(void) {
        pdbknt++;
        
        PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
        
}


After entering the command 's1000', the output is

Code:
Frequency: 1000
knts adc0 1024 adc1 1023 pdb 0

Note that the adc1 counter is short one count, and the pdb counter is still at zero.
 
with BUFLEN at 1024 and this code:
Code:
        if ([B][U]nbuf >= BUFLEN-1[/U][/B]) {
          //adc->disableInterrupts(ADC_0);
          adc->adc0->stopPDB();
        }

the nbuf will stop when it is 1023 or larger.

Putting in BOLD or marking the edits made might make it easier to see the changes from the stock sample.

I'm only scanning this - not really looking. What happens with minimal changes to the Stock Sample to print and show the same values - maybe edit to do first one ADC then the other.
 
Look at the PDB ISR. There you will see that it increments a counter pdbknt

Also, each of the two ADC ISRs has its own counter, for ADC0 it is nbuf, and for ADC1 it is nbuf2

When the routine finishes, all three counters should be at 1023.

In fact only one of the ADCs reaches this value. The other is short by one count. And, the PDB counter is still at 0!

Therefore, the ADC's were called 1023 or 1022 times, but the PDB ISR was not called even once.
 
Okay, here is a truly, minimum example. The only edits are that each ISR has its own counter, and increments that counter each time it is called. The 'p' command lists the three counters.

The result is that the ADC1 counter is always one less than the ADC0 counter, and, the PDB counter is always 0.

That is seriously messed up. It qualifies as a fatal bug for the software. Consider the library or example code as broken, and please lets get it fixed.

Here is the code, with changes from the stock example (adc_pdb) highlighted, as you asked.

Code:
/* Example for triggering the ADC with PDB
*   Valid for Teensy 3.0 and 3.1, not LC
*/


#include <ADC.h>

const int readPin = A9; // ADC0
const int readPin2 = A2; // ADC1

[B]
int adc0knt = 0;
int adc1knt = 0;
int pdbknt = 0;
[/B]

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

void setup() {

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

    Serial.begin(9600);

    Serial.println("Begin setup");

    ///// ADC0 ////
    adc->setAveraging(1); // set number of averages
    adc->setResolution(8); // 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

    ////// ADC1 /////
    #if ADC_NUM_ADCS>1
    adc->setAveraging(1, ADC_1); // set number of averages
    adc->setResolution(8, ADC_1); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED, ADC_1); // change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED, ADC_1); // change the sampling speed
    #endif

    Serial.println("End setup");

}

char c=0;
int value;
int value2;

void loop() {

    if (Serial.available()) {
        c = Serial.read();
        if(c=='v') { // value
            Serial.print("Value ADC0: ");
            value = (uint16_t)adc->readSingle(ADC_0); // the unsigned is necessary for 16 bits, otherwise values larger than 3.3/2 V are negative!
            Serial.println(value*3.3/adc->getMaxValue(ADC_0), DEC);
            #if ADC_NUM_ADCS>1
            Serial.print("Value ADC1: ");
            value2 = (uint16_t)adc->readSingle(ADC_1); // the unsigned is necessary for 16 bits, otherwise values larger than 3.3/2 V are negative!
            Serial.println(value2*3.3/adc->getMaxValue(ADC_1), DEC);
            #endif
        } else if(c=='s') { // start pdb, before pressing enter write the frequency in Hz
            uint32_t freq = Serial.parseInt();
            if (freq == 0) {
                Serial.println("Stop pdb.");
                adc->adc0->stopPDB();
                adc->adc1->stopPDB();
            }
            else {
                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
                #if ADC_NUM_ADCS>1
                adc->adc1->stopPDB();
                adc->adc1->startSingleRead(readPin2); // call this to setup everything before the pdb starts
                adc->enableInterrupts(ADC_1);
                adc->adc1->startPDB(freq); //frequency in Hz
                #endif
            }
        } else if(c=='p') { // pbd stats
            Serial.print("Frequency: ");
            Serial.println(adc->adc0->getPDBFrequency());
[B]            Serial.print("Counters: ");
            Serial.print(adc0knt);
            Serial.print(' ');
            Serial.print(adc1knt);
            Serial.print(' ');
            Serial.println(pdbknt);
[/B]        }

    }


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

    //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));

    delay(10);
}


// Make sure to call readSingle() to clear the interrupt.
void adc0_isr() {
[B]        adc0knt++;
[/B]        adc->adc0->readSingle();
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}

#if ADC_NUM_ADCS>1
void adc1_isr() {
 [B]       adc1knt++;[/B]
        adc->adc1->readSingle();
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}
#endif

// pdb interrupt is enabled in case you need it.
void pdb_isr(void) {
 [B]       pdbknt++;[/B]
        PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}
 
Status
Not open for further replies.
Back
Top