ADC library, with support for Teensy 4, 3.x, and LC

Hello!

I'm trying to do calculations while waiting for conversions to finish.
Is it guaranteed that ADC0 will read sensor A0 and sensor A2? And
ADC1 will always read A1 and A3 in this code? If not, is there a way
I can change the code to do that?



Code:
void loop()
{

adc->startSynchronizedSingleRead(A0, A1);

//Calculations on previous sensor pair
from second time through the loop (A2, A3);

while (adc->adc0->isConverting() || adc->adc1->isConverting());
g_sensorValue[0] = 1023 - (adc->adc0->readSingle());
g_sensorValue[1] = 1023 - (adc->adc1->readSingle());
adc->startSynchronizedSingleRead(A2, A3);

//Calculations on previous sensor pair (A0, A1);

while (adc->adc0->isConverting() || adc->adc1->isConverting());
g_sensorValue[2] = 1023 - (adc->adc0->readSingle());
g_sensorValue[3] = 1023 - (adc->adc1->readSingle());

}
 
Looking at the code, I think it is reasonably safe to assume that:
Code:
bool ADC::startSynchronizedSingleRead(uint8_t pin0, uint8_t pin1)
{
    // check pins
    if (!adc0->checkPin(pin0))
    {
        adc0->fail_flag |= ADC_ERROR::WRONG_PIN;
        return false;
    }
    if (!adc1->checkPin(pin1))
    {
        adc1->fail_flag |= ADC_ERROR::WRONG_PIN;
        return false;
    }

    // check if we are interrupting a measurement, store setting if so.
    adc0->adcWasInUse = adc0->isConverting(); // is the ADC running now?
    if (adc0->adcWasInUse)
    { // this means we're interrupting a conversion
        // save the current conversion config, the adc isr will restore the adc
        __disable_irq();
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
        adc0->saveConfig(&adc0->adc_config);
        __enable_irq();
    }
    adc1->adcWasInUse = adc1->isConverting(); // is the ADC running now?
    if (adc1->adcWasInUse)
    { // this means we're interrupting a conversion
        // save the current conversion config, the adc isr will restore the adc
        __disable_irq();
        //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
        adc1->saveConfig(&adc1->adc_config);
        __enable_irq();
    }

    // no continuous mode
    adc0->singleMode();
    adc1->singleMode();

    // start both measurements
    adc0->startReadFast(pin0);
    adc1->startReadFast(pin1);

    //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
    return true;
}
But what I have not looked at is if those pins are Valid for those ADCs on every Teensy... But you should be able to verify that for whichever teensy you are using by either looking at code, or Reference Manual or easier yet I believe he has a summary of which pins are valid for which ADC...
 
> trying to do calculations while waiting for conversions

Yes, it makes sense to do calculations on A2,A3 values after starting a read on A0,A1. And vice versa.

> ADC0 will read sensor A0 ...

Yes, ADC0 is always assigned to the first pin in the parameter list.
 
Looking at the code, I think it is reasonably safe to assume that.

But what I have not looked at is if those pins are Valid for those ADCs on every Teensy... But you should be able to verify that for whichever teensy you are using by either looking at code, or Reference Manual or easier yet I believe he has a summary of which pins are valid for which ADC...

Thanks, the pins are valid on the teensy 4 which I’m using and he did specify that.

I’m getting some strange values ocassionally and it’s because of my code but wanted to make sure it wasn’t something else before I spend hours looking for a solution.
 
> trying to do calculations while waiting for conversions

Yes, it makes sense to do calculations on A2,A3 values after starting a read on A0,A1. And vice versa.

> ADC0 will read sensor A0 ...

Yes, ADC0 is always assigned to the first pin in the parameter list.

Thanks 🙏 Just needed to be sure
 
Very nice work

Can analogSyncRead() be called from an ISR? For example, can it be used in a function that was launched by the timer ?

Thank you
 
My guess is it probably can. I have not used the syncRead before, but I have done analogReads on an IntervalTimer...

For example with my never finish Well monitoring code, that reads in 4 analog values for 4 different current sensors trying to do a quick and dirty RMS to figure out if a pump is running or not.
My later version I would actually do this with DMA/Timer reads into buffers for two of them, and when this completes I would start it up again on the other two while processing the first two.

I would do this on an IntervalTimer where I would verify the previous analog Reads completed, and then start up the next set and then do a quick and dirty calculation of RMS. My DMA timed reads would maybe give me 50 sample per the 60 hz sine wave and maybe enough for a couple of complete cycles like 150 samples...
 
Hi, nice work.

1) What setup is needed before calling the fast read function?

2) Can analogSyncRead() be called from an ISR?

I notice it appears to disable and enable interrupts. Is there any provision to save and restore the previous interrupt enable state?.
 
Hallo Teensy friends :)

I connected 4 potentiometers to the analog inputs of Teensy 4.1. Each potentiometer has a pin on 3.3V and GND. The ADC result is very noisy and unstable. I've already tried everything, for example RC filters at the input, but without improvement. I changed averaging and resolution without much improvement. What else can I try?

My last idea is an external ADC chip e.g. MCP 3208 without analog inputs on the Teensy :( But I would like to use the analog inputs on the Teensy :)


Code:
//init analog Inputs
	pinMode(14, INPUT_DISABLE);
	pinMode(16, INPUT_DISABLE);
	pinMode(17, INPUT_DISABLE);
	pinMode(22, INPUT_DISABLE);
	analogReadResolution(12);
	analogReadAveraging(16);


// adc polling every 25ms
void read_pots (void)
{
  pot_1 = (analogRead(A0) >> 5);
  pot_2 = (analogRead(A2) >> 5);
  pot_3 = (analogRead(A3) >> 5);
  pot_4 = (analogRead(A8) >> 5);
  
  if(pot_1 != pot_1_old){
  pot_1_old = pot_1;
  pot_1_change = true;
  }
  if(pot_2 != pot_2_old){
  pot_2_old = pot_2;
  pot_2_change = true;
  }
  if(pot_3 != pot_3_old){
  pot_3_old = pot_3;
  pot_3_change = true;
  }
  if(pot_4 != pot_4_old){
  pot_4_old = pot_4;
  pot_4_change = true;
  }
}

My last idea is an external ADC chip e.g. MCP 3208 without analog inputs on the Teensy? But I would like to do without it.
 
Two things:

1) take a few thousand samples and use an average or trimmed mean

2) do a comparison more like "if ((new_ad + 32 < old_ad) || (new_ad > old_ad + 32)) ..."

Code:
// take mean of samples on each side of the median - adjustable,  no dither

double trimmed_mean(const uint16_t array[], const unsigned count, const unsigned n)
{
  qsort(array, count, sizeof(array[0]), compare_u16);

  unsigned sum = 0;
  unsigned n2 = 0;

#if 0
  // classic method is to trim n of the most extreme samples from each end - try n = 20% of count
  for (unsigned i = n; i < (count - n); ++i) {
    sum += array[i];
    ++n2;
  }
#else
  // weight each side method - try n = 1 for a tight histogram
  const int median = array[count / 2];

  for (unsigned i = 0; i < count; ++i) {
    if (((int)array[i] >= median - (int)n) && ((int)array[i] <= median + (int)n)) {
      sum += array[i];
      ++n2;
    }
  } // for
#endif

  //Serial.printf("med %d,n2 %d  %g\n", median, n2,(double)sum / n2);

  return (double)sum / n2;
}
 
Thanks for your tip :)

I think the right way would be to find the cause of the spikes. With 12-bit resolution, a little noise is normal. But at 7Bit it is not normal (see my test results).

12Bit resolution
12-Bit-noise.jpg


10Bit resultion
10-Bit-noise.jpg


8Bit resultion
8-Bit-noise.jpg


All tests with Everanging 16
 
read pots
Code:
//-----------------------------------------------------
// read Pots (ADC resolution 12Bit )
//-----------------------------------------------------
void read_pots (void)
{
  pot_1 = (analogRead(A0) >> 5);
  pot_2 = (analogRead(A2) >> 5);
  pot_3 = (analogRead(A3) >> 5);
  pot_4 = (analogRead(A8) >> 5);
  
  if(pot_1 != pot_1_old){
  pot_1_old = pot_1;
  pot_1_change = true;
  pot_change = true;
  }
  if(pot_2 != pot_2_old){
  pot_2_old = pot_2;
  pot_2_change = true;
  pot_change = true;
  }
  if(pot_3 != pot_3_old){
  pot_3_old = pot_3;
  pot_3_change = true;
  pot_change = true;
  
  }
  if(pot_4 != pot_4_old){
  pot_4_old = pot_4;
  pot_4_change = true;
  pot_change = true;
  }
}
 
OK, now step through your code in the case where analogRead() returns 127 and then 128. What values do you get for pot_1 and what happens?
 
Now I have improved the ADC query.

Code:
//-----------------------------------------------------
// read Pots
//-----------------------------------------------------
void read_pots (void)
{
  pot_1 = (analogRead(A0) >> 5);
  if (pot_1 >= 127){
	  pot_1 = 127;
  }
  pot_2 = (analogRead(A2) >> 5);
  if (pot_2 >= 127){
	  pot_2 = 127;
  }
  pot_3 = (analogRead(A3) >> 5);
  if (pot_3 >= 127){
	  pot_3 = 127;
  }
  pot_4 = (analogRead(A8) >> 5);
  if (pot_4 >= 127){
	  pot_4 = 127;
  }
  
  if(pot_1 != pot_1_old){
  pot_1_old = pot_1;
  pot_1_change = true;
  pot_change = true;
  }
  if(pot_2 != pot_2_old){
  pot_2_old = pot_2;
  pot_2_change = true;
  pot_change = true;
  }
  if(pot_3 != pot_3_old){
  pot_3_old = pot_3;
  pot_3_change = true;
  pot_change = true;
  
  }
  if(pot_4 != pot_4_old){
  pot_4_old = pot_4;
  pot_4_change = true;
  pot_change = true;
  }
}
 
But.. the adc noise is not better :). Now i have installed 100nF caps on the pots.
It's not an improvement. Now I want to try to reduce the sample rate.

Can I do that in Teensy 4.1 board ?
 
Hi luni. Thank you for your great tip with ResponsiveAnalogRead. The ADC noise is very low and my potentiometer settings are very stable. :)
 
Issue with "synchronizedMeasurements" examlpe

Hi guys,
I have troubles running the ADC example "synchronizedMeasurements" as is.

Issue:
After compilation (without any errors reported by the compiler) the serial monitor stays empty and no data is displayed.
I think the reason is the first line in the example
Code:
#ifdef ADC_DUAL_ADCS

Possible reason:
Since ADC_DUAL_ADCS is defined later in the code by including "settings_defines.h" via ADC.h -->ADC_Module.h-->settings_defines.h,
I'm not sure how the compiler reacts to the first line.

Possible solution:
If the first and last lines in the example are commented out the example is running fine.

Could someone provide some insight why I get no error at compile time.
Does anyone else have such a problem or it is due to my particular system?
Thanks!

The above issue was tested on board Teensy 3.5 / Arduino IDE v1.8.13/ Teensyduino v1.53
 
Back
Top