What ADC library to use with Teensy 4.0?

zapta

Well-known member
Hi all,

I am trying to use ADC.h from a Teensy 4.0 Arduino sketch and am getting a build error that the library doesn't support T4.

Any idea what library to use?

I want to trigger periodically (~20khz) from a timer isr two parallel conversions on ADC1 and ADC2 and get an ADC ISR when the two values are available. I did something similar for T3.2 with ADC but now want to migrate to T4.

Thanks.
 
There is no ADC library for the T4 yet that I know of. I think what you want to do is relatively straightforward however. By the way, as I understand it, even the T3.2 ADC library did not do strictly simultaneous ADC reads; but rather in the two-channel mode the two ADCs were simply started one right after the other.
 
... I think what you want to do is relatively straightforward however....

Thanks JBeale. What do you mean? I can do it without ADC.h support? How? Accessing the hardware directly? Any other useful library?

Also, anybody knows the ETA of ADC.h support for T4? I am surprised that PJRC are selling the T4 without A/D software support. Am I missing something? Do they provide other libraries that support it?
 
You can use the A/D in the same way as with other Arduino-style boards without a separate library. For example the below program compiles and runs on Teensy 4. Note that T3.2 has a nominally 16-bit ADC although only 12 or 13 bits are real without averaging. Teensy 4 has a nominally 12 bit ADC of which about 10 bits are real without averaging. So for T4 you can set analogReadRes(12), or select 10 or 8 bits for (slightly) faster operation. Also, T4 does not have an external reference input so you are limited to the power supply 3.3V as ADC Vref.

In this particular example, the code simply reads one ADC channel at 12 bits without extra delays, and it ends up at 174825 samples per second. So two channels at 20 kHz sampling rate should not be a problem.

Code:
// Analog input test for Teensy 3/4    Oct 4 2012 - Feb 2019 J.Beale

// Setup: https://picasaweb.google.com/109928236040342205185/Electronics#5795546092126071650

#define VREF (3.292)         // ADC reference voltage (= power supply)
#define VINPUT (1.328)       // ADC input voltage from NiCd AA battery
#define ADCMAX (4095)        // maximum possible reading from ADC
#define EXPECTED (ADCMAX*(VINPUT/VREF))     // expected ADC reading
#define SAMPLES (100000)      // how many samples to combine for pp, std.dev statistics

const int analogInPin = A0;  // Analog input is AIN0 (Teensy3 pin 14, next to LED)
const int LED1 = 13;         // output LED connected on Arduino digital pin 13

int sensorValue = 0;        // value read from the ADC input
long oldT;

void setup() {    // ==============================================================
      pinMode(LED1,OUTPUT);       // enable digital output for turning on LED indicator
      // analogReference(EXTERNAL);  // set analog reference to internal ref
      analogReadRes(12);          // set ADC resolution to this many bits
      analogReadAveraging(1);    // average this many readings
     
      Serial.begin(115200);       // baud rate is ignored with Teensy USB ACM i/o
      digitalWrite(LED1,HIGH);   delay(1000);   // LED on for 1 second
      digitalWrite(LED1,LOW);    delay(3000);   // wait in case serial monitor still opening
     
      Serial.println("# Teensy ADC test start: ");
} // ==== end setup() ===========

void loop() {  // ================================================================ 
     
      long datSum = 0;  // reset our accumulated sum of input values to zero
      int sMax = 0;
      int sMin = 65535;
      long n;            // count of how many readings so far
      double x,mean,delta,sumsq,m2,variance,stdev;  // to calculate standard deviation
     
      oldT = millis();   // record start time in milliseconds

      sumsq = 0; // initialize running squared sum of differences
      n = 0;     // have not made any ADC readings yet
      mean = 0; // start off with running mean at zero
      m2 = 0;
     
      for (int i=0;i<SAMPLES;i++) {
        x = analogRead(analogInPin);
        datSum += x;
        if (x > sMax) sMax = x;
        if (x < sMin) sMin = x;
              // from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
        n++;
        delta = x - mean;
        mean += delta/n;
        m2 += (delta * (x - mean));
      } 
      variance = m2/(n-1);  // (n-1):Sample Variance  (n): Population Variance
      stdev = sqrt(variance);  // Calculate standard deviation

      Serial.print("# Samples/sec: ");
      long durT = millis() - oldT;
      float datAvg = (1.0*datSum)/n;
      Serial.print((1000.0*n/durT),2);

      Serial.print(" Avg: ");     Serial.print(datAvg,2);
      Serial.print(" Offset: ");  Serial.print(datAvg - EXPECTED,2);
      Serial.print(" P-P noise: ");  Serial.print(sMax-sMin);
      Serial.print(" St.Dev: ");  Serial.print(stdev,3);
      Serial.print(" T(deg.C): "); Serial.print(tempmonGetTemp(),1);
      Serial.println();
} // end main()  =====================================================
 
Last edited:
Thanks JBeale. What do you mean? I can do it without ADC.h support? How? Accessing the hardware directly? Any other useful library?

Also, anybody knows the ETA of ADC.h support for T4? I am surprised that PJRC are selling the T4 without A/D software support. Am I missing something? Do they provide other libraries that support it?

As you see from JBeale example, direct access to analog ports is part of the Teensy core, so always implemented with ALL Teensies that have build-in ADC
 
If you're curious, here's the implementation of ADC in the Teensy 4 core code: https://github.com/PaulStoffregen/cores/blob/master/teensy4/analog.c
To (not) answer an earlier question, the adc.h library was done by forum user pedevide (Pedro Villanueva) who AFAIK is a "regular" teensy user like the rest of us here. I do not know if or when he has plans to port it to T4.
The library code for earlier Teensys is available though if anyone is interested. https://github.com/pedvide/ADC
 
Last edited:
Thanks JBeale. That example is of ADC with blocking calls, right? Is there an example for a non blocking ADC for T4? For example, something similar to what described here https://www.pjrc.com/teensy/adc.html ?

I would expect PJRC to clarify for potential buyers that some of the examples they provide with Arduino, for example the ADC | test_pdb which is listed when I select board=t4, where not yet ported to T4.
 
Correct, analogRead() is a blocking call in my example, just as in all other Arduino-alike devices AFAIK. The return value is the ADC reading just made. It is not a terribly long delay on T4; less than 6 microseconds as shown. If that's still too long to wait, then you need to write your own non-blocking implementation, since I'm not aware of one yet for T4. If you look at Paul's core T4 ADC code implementing int analogRead(uint8_t pin) it is not terribly complex, here is the heart of it (omitting the ADC2 code, which is basically a copy of this):

Code:
uint8_t ch = pin_to_channel[pin];  // convert Arduino style channel number to Teensy internal numbering

if(!(ch & 0x80)) {
  ADC1_HC0 = ch;                       // set ADC channel number
  while (!(ADC1_HS & ADC_HS_COCO0)) ;  // wait until ADC result ready
  return ADC1_R0;                      // return new ADC result
}

Here's a reasonably current list of the status of libraries for T4. Under ADC it just says "pedvide's lib needs work" https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=193717&viewfull=1#post193717
 
Last edited:
Thanks JBeale, this is very useful! I will look also at the existing ADC.h.

I can squeeze from T3.2 50k double samplings and shallow processing in the ISR, leaving about 60% CPU time to main but I like to have the larger margins that T4 may provide.
 
On a second thought, I don't need two interrupts, one for the timer (which starts the ADC) and one for the ADC result. I can do everything in the timer ISR, reading previous value and then triggering next one. Will try to make it work without ADC.h for T3.2 (based on core/analog.c) and then migrate to T4.
 
Zapta,

I did just finish a T4 translation of the ADC library. It's not polished, but it works. I put up a thread about it, I hope you can find it useful
 
Thanks a lot Bumbler, I will take a look.

I have a primitive working version that access the registers directly but it doesn't allow to set thing such as sampling and conversions speeds.
 
Back
Top