Analog read on Teensy 4.0 slower (compared to Teensy 3.6)

Status
Not open for further replies.

crickert

New member
Hello,

This is my first post here... please be patient with me. :eek:

I'm working on a research project that makes use of the Teensy 3.6 to implement a dynamic clamp system, see Dynamic Clamp for details. In short, the dynamic implementation reads an adc value (from the experimental setup), performs a calculation, and outputs an adc value back to the experimental setup. One of these so-called cycles takes roughly 10 µs to complete on the Teensy 3.6, which is regarded as real-time for our purpose.

However, when switching the same code to the Teensy 4.0, the cycle time increases to around 20 µs. I've identified the analogRead() as the rate-limiting step: it took 8 µs on the Teensy 3.6 and it takes around 20 µs on the Teensy 4.0 to return a value from the ADC. The relevant ADC code for the Teensy 4.0 is posted below, the full code for the Teensy 3.6 is available here.

Code:
// variables
int adcs = 0;                   // raw value from analog in

// constants
const int adcPin = A0;           // analog in pin identifier

/* setup, run once */
void setup(){

    // configure Teensy pins
    analogReadResolution(12);   // (0-4095)

 }

/* loop, run continuously */
 void loop() {

    // read membrane potential (slow, ~20.0µs)
    adcs = float(analogRead(adcPin));

}

In short:
Why is analogRead() returning slower (8 µs vs. 20 µs) on the Teensy 4.0 compared to the Teensy 3.6, given the same resolution?

Best regards,
Christian


P.S.: I'm currently using Arduino 1.8.9 with the Teensyduino 1.47 on Windows Microsoft Windows [Version 10.0.17763.678].
 
The analogRead() code of course is different to fit the 1062's MCU design. Also the MCU at 600 MHz has a different view of analog process on the higher speed silicon involved. There is possibly room for refinement - but generally suspect it is optimized for the steps needed to return the analog value.

Could the version of the code used to determine the timing be provided?
 
I'm not sure, but it may be the default on Teensy 4 to do 4 averages for each call to analogRead(). You can set this with analogReadAveraging(x) where I assume x=1 (single read, no averaging) would be faster than x=4.
I think this is the core code for Teensy 4: https://github.com/PaulStoffregen/cores/blob/master/teensy4/analog.c

The code says:
Code:
#define MAX_ADC_CLOCK 20000000
// 8 bit conversion (17 clocks) plus 8 clocks for input settling
// 10 bit conversion (17 clocks) plus 20 clocks for input settling
// 12 bit conversion (25 clocks) plus 24 clocks for input settling

which taken at face value, means the ADC clock can be as high as 20 MHz, and a 12 bit conversion at that speed should take 25+24=49 clocks or 2.4 microseconds. Lower bit resolution can go faster, with averaging it's slower, of course there is always a speed tradeoff with noise and accuracy.
 
I'm not sure, but it may be the default on Teensy 4 to do 4 averages for each call to analogRead(). You can set this with analogReadAveraging(x) where I assume x=1 (single read, no averaging) would be faster than x=4.
I think this is the core code for Teensy 4: https://github.com/PaulStoffregen/cores/blob/master/teensy4/analog.c

...

Good note - I was just looking at that file for some reason and skipped over that
static uint8_t analog_num_average = 4;

Though I see the same line in Teensy3 code :: https://github.com/PaulStoffregen/cores/blob/master/teensy3/analog.c#L37
 
T4 ADC speed tests

Running this code on a T4, it reports 174825 samples per second as shown with 12 bit resolution and analogReadAveraging(1). That works out to 5.72 microseconds per sample. It is also calculating standard deviation and peak-to-peak noise but I don't think the math is a significant time factor. If you get 20 usec at 12 bit resolution on T4, that strongly suggests you have the 4 averages setting.
Paul's code comments suggest much faster times are possible but I don't know if the ADC clock is at 20 MHz by default, or if there are other parameters to tweak like the ADC sampling time (which was adjustable independently of the ADC clock on the T3.2 device using the Pedvide ADC library, which has not yet been ported to T4).

Changing below code to analogReadAveraging(4); I get 47755 samples/sec or 20.9 microseconds.
Change to 10 bit resolution with no averaging, it's 203252 samples/sec or 4.92 microseconds.
8 bit resolution, no averaging gives you 303582 samples/sec or 3.29 microseconds.

If you want to get the best performance at high ADC sample rates, I think you will also need a very low impedance driving the ADC input. I think some opamps can do better at this than others.

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 (50000)      // 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);          // Teensy 3.0: 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:
Could the version of the code used to determine the timing be provided?

Sure, this is the full code (just the code from the Teensy 3.6 with adjustments to the input/output pins). I didn't thoroughly benchmark the ADC conversion: Instead, I just monitored the cycly times by serial communication using pyClamp before and after commenting out the first line in the loop.
Code:
// imports

#include <math.h>               // enable floating point unit functions


// variables

bool report = false;            // report values live
int adcs = 0;                   // raw value from analog in [1]
int count = 0;                  // cycle counter for benchmarking
int dacs = 0;                   // raw value from analog out [1]
float pamps = 0.0;              // current output [pA]
float msecs = 0.0;              // time past since last cycle (dt) [ms]
float mvolts = 0.0;             // membrane potential [mV]

/* extend this array to add calibration parameters,
   use decrementing negative indices to address elements */
float calibras[] =  {50.0,      // Amplifier input gain (AMP_i) [mV/mV]
                     400.0,     // Amplifier output gain (AMP_o) [pA/V]
                     5.5,       // ADC input slope (ADC_m) [mV/1]
                     -11500.0,  // ADC input intercept (ADC_n) [mV]
                     750.0,     // DAC output slope (DAC_m) [1/pA]
                     2000.0,    // DAC output intercept (DAC_n) [0-4095]
                     0.0};      // Voltage offset (VLT_d) [mV]

/* extend this array to add conductance parameters,
   use incrementing postive indices to address elements */
float conducts[] =  {0.0,       // G_Shunt [nS]
                     0.0,       // G_H [nS]
                     0.0,       // G_Na [nS]
                     0.0,       // OU1_m [nS]
                     0.0,       // OU1_D [nS^2/ms]
                     0.0,       // OU2_m [nS]
                     0.0,       // OU2_D [nS^2/ms]
                     0.0};      // G_EPSC [nS]

/* extend this array to add values for live reports */
float values[] =    {0.0,       // mvolts [mV]
                     0.0,       // pamps [pA]
                     0.0};      // msecs [µs]

elapsedMicros stepTime = 0;     // individual cycle time [µs]
elapsedMillis cmdTime = 0;      // time since last command check [ms]
elapsedMillis ttlTime = 0;      // time since last TTL trigger [ms]

/* serial command strings are identified by their specific format:

    <\r> idx <\t> val <\n>
    
    index:  int
            {-inf, ..., -1} = calibras[+inf-1, ..., +0]
            {0}             = execute a command
            {+1, ..., +inf} = conducts[ 0, ..., inf-1]
    value:  float
            the value written into the specified array and position or
            the command to be executed from a switch...case structure
    
    Examples:

    <\r> -2 <\t> 2000.0 <\n>    changes the second parameter (Amp_o) to 2000.0
    <\r>  0 <\t>    2.0 <\n>    toggles live reports on or off
    <\r>  1 <\t>   10.0 <\n>    changes the first conductance (G_Shunt) to 10.0 */

/* custom struct for serial communication */
typedef struct serialCmd {
    int len = 0;
    int idx = 0;
    int sep = 0;
    float val = 0.0;
    String str = "";
} command;
command cmd;                    // serial command string struct

// constants
const int adcPin = A0;           // analog in pin identifier
const int cmdIntvl = 20;        // command interval [ms]
const int dacPin = 0;         // analog out pin identifier
const int ttlPin = 1;           // trigger pin identifier
const int lenCals = sizeof(calibras)/sizeof(calibras[0]);
const int lenCons = sizeof(conducts)/sizeof(conducts[0]);
const int lenVals = sizeof(values)/sizeof(values[0]);


// functions

/* clear serial COM port buffers */
void clearBuffers() {
    Serial.flush();                     // clear write buffer
    while (Serial.available() > 0)      // clear read buffer
        Serial.read();
}

/* interprets a command string */
void interpretString(command cmd) {
    cmd.sep = cmd.str.indexOf('\t');
    if (cmd.str.startsWith('\r') && cmd.sep != -1) {  // check format
        cmd.len = cmd.str.length();
        cmd.idx = cmd.str.substring(1,cmd.sep).toInt();
        if (cmd.idx < 0) {          // negative index, update parameters
            cmd.idx = -1 * cmd.idx - 1;
            cmd.val = cmd.str.substring(cmd.sep + 1, cmd.len).toFloat();
            setParameter(cmd.idx, cmd.val);
        } else if (cmd.idx > 0) {   // positive index, update conductances
            cmd.idx = cmd.idx - 1;
            cmd.val = cmd.str.substring(cmd.sep + 1, cmd.len).toFloat();
            setConductance(cmd.idx, cmd.val);
        } else {                    // zero index, execute command instead
            cmd.val = cmd.str.substring(cmd.sep + 1, cmd.len).toInt();
            runCommand(cmd.val);
        }
    }
}

/* receives a string from the serial COM port */
void readString() {
    cmd.str = Serial.readStringUntil('\n') + '\n';  // avoid timeout
}

/* runs predefined commands */
void runCommand(int exec) {
    static bool troper = false;  // remember previous live report state
    troper = report;
    if (report)     // temporarily turn off live reports
        report = false;
    switch (exec) {
        case 0:     // echo test, nothing to do
            break;
        case 1:     // send calibration parameters and conductance values
            writeString(newArray(2));
            break;
        case 2:     // toggle live reports on or off
            report = invertBoolean(troper);
            break;
        default:    // every other (undefined) command
            break;
    }
    if (exec != 2)  // return to previous live report state
        report = troper;
}


/* updates conductance values */
void setConductance(int idx, float val) {
    if (idx < lenCons)
        conducts[idx] = val;
}

/* updates parameter values */
void setParameter(int idx, float val) {
    if (idx < lenCals)
        calibras[idx] = val;
}

/* sends a string to the serial COM port */
void writeString(String str) {
    Serial.print(str);
}

/* returns an inverted boolean value */
bool invertBoolean(bool boo) {
    if (boo) {
        boo = false;
    } else {
        boo = true;
    }
    return boo;
}

/* serial transmission strings are identified by their specific order:
    
    <\r> vals[0] <\t> vals[1] (<\t> vals[2] ... <\t> vals[inf] ) <\n>
    
    values: float[]
    
    Examples:

    <\r> 1.23 <\t> 1337 <\n>    reports two values, which are identified
                                by their order in the transmission string */

/* assembles calibration parameters and conductance values for transmission */
String newArray(int len) {
    String valstr = "";  // initialize before concatenation
    valstr = "";
    for (int i = lenCals-1; i >= 0; i--) {
        int j = -1 * (i + 1);
        values[0] = j;
        values[1] = calibras[i];
        valstr += newString(values, len);
    }
    for (int k = 0; k < lenCons; k++) {
        int l = k + 1;
        values[0] = l;
        values[1] = conducts[k];
        valstr += newString(values, len);
    }
    return valstr;
}

/*creates a new command/report string from an array of values */
String newString(float vals[], int len) {
    static const String cr = '\r';
    static const String tb = '\t';
    static const String lf = '\n';
    static String str;
    str = cr;
    for (int i = 0; i < len; i++ ) {
        if (i > 0)
            str += tb;
        str += vals[i];
    }
    str += lf;
    return str;
}


/* setup, run once */
void setup(){

    // configure serial COM port
    Serial.begin(115200);       // [b/s]
    Serial.setTimeout(1);       // [ms]
    clearBuffers();

    // configure Teensy pins
    analogReadResolution(12);   // (0-4095)
    analogWriteResolution(12);  // (0-4095)
    pinMode(ttlPin, INPUT);     // set to high-impedance state

    // pre-calculate lookup tables
    GenerateGaussianNumbers();  // Gaussian number pool for use by the OU processes
    GenerateSodiumLUT();        // sodium activation/inactivation
    GenerateHcnLUT();           // HCN activation

 }


/* loop, run continuously */
 void loop() {

    // read membrane potential (slow, ~8.0µs)
    adcs = float(analogRead(adcPin));
    mvolts = calibras[2] / calibras[0] * adcs + calibras[3] / calibras[0] + calibras[6];

    // calculate cycle interval
    msecs = 0.001 * float(stepTime);
    stepTime = 0;

    // reset current
    pamps = 0.0;

    // add Shunting current (fast, < 0.5µs)
    if (conducts[0] > 0) {
        pamps += Shunting(mvolts);
    }

    // add HCN current (fast, < 0.5µs)
    pamps += HCN(mvolts, conducts[1]);  // reset current after initial run
    
    // add Sodium current (fast, < 0.5µs)
    if (conducts[2] > 0) {
        pamps += Sodium(mvolts);
    }
    
    // add OrnsteinUhlenbeck current (medium, ~1.5µs)
    if (conducts[3] > 0 || conducts[5] > 0) {
        pamps += OrnsteinUhlenbeck(mvolts);
    }
    
    // add EPSC current (fast, ~0.5µs)
    if (conducts[7] > 0) {
        if ((digitalReadFast(ttlPin) == HIGH) && (ttlTime > 2)) {  // check for TTL signal
            UpdateEpscTrain();
            ttlTime = 0;
        }
        pamps += EPSC(mvolts);
    }

    // write calculated current (fast, ~0.5µs)
    dacs = int(calibras[4] / calibras[1] * pamps + calibras[5]);    // with capacitance 1.0 pF
    dacs = constrain(dacs, 0, 4095);    // keep constrain function simple
    analogWrite(dacPin, dacs);

    // update commands & report values
    if (cmdTime > cmdIntvl) {
        if (Serial.available() > 4) {   // read buffer not empty
            readString();
            writeString(cmd.str);
            interpretString(cmd);
        }
        if (report && Serial.availableForWrite() > 63) {  // write buffer empty
            values[0] = mvolts;
            values[1] = pamps;
            values[2] = 1000.0 * msecs;
            writeString(newString(values, lenVals));
        }
        cmdTime = 0;
    }

}
 
Thank you both @defragster and @JBeale for giving me some pointers to investigate!

I'll have to do the testing with the Teensy 4.0 fully replacing the Teensy 3.6 in the dynamic clamp setup. -
I wouldn't want to lose any resolution on the ADC, but a reduction of signal-to-noise ratio might be acceptable.

Might be a week or so until I get to do this...
 
Running this code on a T4, it reports 174825 samples per second as shown with 12 bit resolution and analogReadAveraging(1). That works out to 5.72 microseconds per sample. It is also calculating standard deviation and peak-to-peak noise but I don't think the math is a significant time factor. If you get 20 usec at 12 bit resolution on T4, that strongly suggests you have the 4 averages setting.
Paul's code comments suggest much faster times are possible but I don't know if the ADC clock is at 20 MHz by default, or if there are other parameters to tweak like the ADC sampling time (which was adjustable independently of the ADC clock on the T3.2 device using the Pedvide ADC library, which has not yet been ported to T4).

Changing below code to analogReadAveraging(4); I get 47755 samples/sec or 20.9 microseconds.
Change to 10 bit resolution with no averaging, it's 203252 samples/sec or 4.92 microseconds.
8 bit resolution, no averaging gives you 303582 samples/sec or 3.29 microseconds.

If you want to get the best performance at high ADC sample rates, I think you will also need a very low impedance driving the ADC input. I think some opamps can do better at this than others.

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 (50000)      // 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);          // Teensy 3.0: 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()  =====================================================

Hi JBeale,

I've run your code on the Teensy 4.0 with different settings for analogReadAveraging(n) at 12-bit resolution and got some interesting results:

adc_t4.png

There's discrete time steps for n = 0-3; 4-7; 8-15; 16-31; and 32-x that match parameter overrides in the definition of analogReadAveraging.

With Teensy 3.6 the steps are n = 0-4; 5-8; 9-16; and 32 and the parameters overrides are, again, defined in analogReadAveraging.
To my surprise, your code returned average times of 1.0 ms [sic!] instead of µs for different averaging settings (0-32) on the Teensy 3.6.
A minor code change was necessary to make the code run though:

Code:
//Serial.print(" T(deg.C): "); Serial.print(tempmonGetTemp(),1);

Can you reproduce that on a Teensy 3.6?
 
My pure analogRead test shows that T3.6 reads over twice as fast as the T4.1.

Code:
#define NUM_READS 100000.f

elapsedMicros testTime;

bool testComplete = false;

int temp = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  analogReadResolution(12);
  analogReadAveraging(1);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (!testComplete) {

    testTime = 0;

    for (int i = 0; i < NUM_READS; i++) {
      
      int pin = A0;

      temp += analogRead(pin);
    }

   Serial.print(testTime / NUM_READS);
   Serial.println(" microseconds per read");
  }

  else {
    delay(300);
    testComplete = false;
  }
}
 
I modified JBeale's code to separate the AnalogRead from the double precision floating point calculations. I connected the A0 to an opAmp buffer to get a nice stable voltage.

Here's what I got:
Teensy 3.6 - Samples/sec: 384568.03 Process Time (us): 392176 P-P noise: 11 St.Dev: 0.842
Teensy 4.1 - Samples/sec: 176467.69 Process Time (us): 6667 P-P noise: 32 St.Dev: 1.563

As you can see, the Teensy reads more than twice as fast, and gives much more accurate readings. In terms of double precision floating point math, the Teensy 4.1 slaughters in the T3.6. I will repeat the test with single precision floats. I suspect the difference in the Process time should all but disappear.



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

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

// T4.1 Samples/sec: 176467.69 Process Time (us): 6667 P-P noise: 32 St.Dev: 1.563
// T3.6 Samples/sec: 384568.03 Process Time (us): 392176 P-P noise: 11 St.Dev: 0.842


#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 (50000)      // 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;

elapsedMicros timer;

uint32_t readTime = 0;
uint32_t processTime = 0;

uint16_t samples[SAMPLES];

void setup() {    // ==============================================================
      pinMode(LED1,OUTPUT);       // enable digital output for turning on LED indicator
      // analogReference(EXTERNAL);  // set analog reference to internal ref
      analogReadRes(12);          // Teensy 3.0: 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;

      timer = 0;
      for (int i=0;i<SAMPLES;i++) {
        samples[i] = analogRead(analogInPin);
      }

      readTime = timer;
      
      timer = 0;
      for (int i=0;i<SAMPLES;i++) {
        x = samples[i];
        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
      
      processTime = timer;

      Serial.print("# Samples/sec: ");
      float avergeReaTime_us = (float)readTime / SAMPLES;
      Serial.print(1000000 / avergeReaTime_us);
      Serial.print(" Process Time (us): "); Serial.print(processTime);

      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()  =====================================================
 
And here are the results when 'double' is changed to 'float'
T3.6 Samples/sec: 384568.03 Process Time (us): 11959 P-P noise: 10 St.Dev: 0.759
T4.1 Samples/sec: 176675.33 Process Time (us): 4333 P-P noise: 35 St.Dev: 1.663

Look like T4.1 can still process floats almost 3 times as fast at T3.6, which like reflects the mhz bump.
 
Status
Not open for further replies.
Back
Top