Interesting behavior by ADC library

Status
Not open for further replies.

Constantin

Well-known member
Hey everyone,

I wonder if someone out there could replicate my results regarding some interesting behavior by the ADC library by Pedvide. As you all likely know, the library is simply awesome. It's a great way to access both ADCs without much fuss and I love being able to scan multiple channels at once. Even better, it can handle doing a differential reading on two sets of channels at once!

Anyhow, I did note one strange behavior and that relates to the comparator having a bad day and throwing a "0x10" fault if the ADC input is left floating. I have to post the code from another machine, so I'll edit this post in a second to show the code and what led to the issue. Even casting the output as a uint16_t doesn't seem to prevent the library from outputting an impossibly large number.
 
OK, so here is the code in question. It comes straight from the synchronized example with some minor changes.

1) I use a 3V external shunt so the code includes a const float reference to that.
2) The speeds of the ADC were changed to allow good behavior while doing 12-bit conversions.

I later attached some inputs to the ADC1 that were ground or shunt level. In either case, the code is happy. The only time that the comparator is unhappy it appears is when the input to the ADC channel is left floating. I wonder if instead of casting the results to a uint16_t, you may be better off ANDing them with the max value. That way you at least prevent impossibly large numbers of sneaking through.

i.e. replace result.result_adc0 = (uint16_t)result.result_adc0;
with result.result_adc0 = result.result_adc0 & adc->getMaxValue(ADC_0);

and

result.result_adc1 = (uint16_t)result.result_adc1;
with result.result_adc1 = result.result_adc1 & adc->getMaxValue(ADC_1);


Code:
/* Example for synchonized measurements using both ADC present in Teensy 3.1
*  You can change the number of averages, bits of resolution and also the comparison value or range.
*/

#include <ADC.h>

const int readPin = A11;
const int readPin2 = A10;
const uint8_t ADC_Resolution = 12;
const float External_Shunt_Voltage = 3.00;

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

elapsedMicros time;

void setup() {

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

    Serial.begin(9600);

    ///// ADC0 ////
    // reference can be ADC_REF_3V3, ADC_REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
    adc->setReference(ADC_REF_EXT, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
    adc->setAveraging(1,ADC_0); // set number of averages
    adc->setResolution(ADC_Resolution, ADC_0); // set bits of resolution
    adc->setConversionSpeed(ADC_LOW_SPEED, ADC_0); // change the conversion speed
    adc->setSamplingSpeed(ADC_LOW_SPEED, ADC_0); // change the sampling speed
    // always call the compare functions after changing the resolution!
    adc->enableCompare(1.0/External_Shunt_Voltage*adc->getMaxValue(ADC_0), 0, ADC_0); // measurement will be ready if value < 1.0V
    adc->enableCompareRange(1.0*adc->getMaxValue(ADC_0)/External_Shunt_Voltage, 2.0*adc->getMaxValue(ADC_0)/External_Shunt_Voltage, 0, 1, ADC_0); // ready if value lies out of [1.0,2.0] V

    ////// ADC1 /////
    adc->setReference(ADC_REF_EXT, ADC_1); // change all 3.3 to 1.2 if you change the reference to 1V2
    adc->setAveraging(1, ADC_1); // set number of averages
    adc->setResolution(ADC_Resolution, ADC_1); // set bits of resolution
    adc->setConversionSpeed(ADC_LOW_SPEED, ADC_1); // change the conversion speed
    adc->setSamplingSpeed(ADC_LOW_SPEED, ADC_1); // change the sampling speed
    // always call the compare functions after changing the resolution!
    adc->enableCompare(1.0/External_Shunt_Voltage*adc->getMaxValue(ADC_1), 0, ADC_1); // measurement will be ready if value < 1.0V
    adc->enableCompareRange(1.0*adc->getMaxValue(ADC_1)/External_Shunt_Voltage, 2.0*adc->getMaxValue(ADC_1)/External_Shunt_Voltage, 0, 1, ADC_1); // ready if value lies out of [1.0,2.0] V

   delay(100);
   Serial.println("end setup");
}

int value = 0;
int value2 = 0;

ADC::Sync_result result;

void loop() {

    result = adc->analogSynchronizedRead(readPin, readPin2);

    // if using 16 bits and single-ended is necessary to typecast to unsigned,
    // otherwise values larger than 3.3/2 will be interpreted as negative
    result.result_adc0 = (uint16_t)result.result_adc0;
    result.result_adc1 = (uint16_t)result.result_adc1;

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

    //Serial.print("Value ADC0: ");
    Serial.print(time, DEC);
    Serial.print(" ");
    Serial.print(result.result_adc0*External_Shunt_Voltage/adc->getMaxValue(ADC_0), DEC);
    Serial.print(" ");
    Serial.println(result.result_adc1*External_Shunt_Voltage/adc->getMaxValue(ADC_1), DEC);


    /* fail_flag contains all possible errors,
        They are defined in  ADC_Module.h as

        ADC_ERROR_OTHER
        ADC_ERROR_CALIB
        ADC_ERROR_WRONG_PIN
        ADC_ERROR_ANALOG_READ
        ADC_ERROR_COMPARISON
        ADC_ERROR_ANALOG_DIFF_READ
        ADC_ERROR_CONT
        ADC_ERROR_CONT_DIFF
        ADC_ERROR_WRONG_ADC
        ADC_ERROR_SYNCH

        You can compare the value of the flag with those masks to know what's the error.
    */
    if(adc->adc0->fail_flag) {
        Serial.print("ADC0 error flags: 0x");
        Serial.println(adc->adc0->fail_flag, HEX);
        if(adc->adc0->fail_flag == ADC_ERROR_COMPARISON) {
            adc->adc0->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
            Serial.println("Comparison error in ADC0");
        }
    }
    #if defined(ADC_TEENSY_3_1)
    if(adc->adc1->fail_flag) {
        Serial.print("ADC1 error flags: 0x");
        Serial.println(adc->adc1->fail_flag, HEX);
        if(adc->adc1->fail_flag == ADC_ERROR_COMPARISON) {
            adc->adc1->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
            Serial.println("Comparison error in ADC1");
        }
    }
    #endif

    digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
  delay(100);
}
 
Last edited:
One other thing... where can I find more complete documentation re: the functions in the ADC library?

I have tried to use the doxygen folder but the data in it seems somewhat sparse unless I'm missing something. For example, the included ADC example files call for the use of the enable compare function to be used after every resolution change, yet in the examples, these enablecompares are commented out.

When the library is used without the compare functions, the results seem to be OK. Bizarre! :)
 
Last edited:
Status
Not open for further replies.
Back
Top