Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: Teensy 3.5 ADC characteristcs

  1. #1

    Teensy 3.5 ADC characteristcs

    Hello all , I have a couple of doubts about the ADC capabilities of Teensy

    1) Whats the maximum resolution of the ADC ? Is it 12bit or 16bit ? The datasheet is a bit confusing , (K64P144M120SF5RM) says Teensy have two 16-bit SAR ADC where as (K64P144M120SF5) says The 16-bit accuracy are achievable on the differential pins ADCx_DP0, ADCx_DM0. All other ADC channels meet the 13-bit differential/12-bit single-ended accuracy
    specifications. Can someone please explain what it exactly means !

    2) Currently working an analog pressure sensor (Honeywell HSC series , Analog output , 3.3V ,HSCDRRN002NDAA3) and a five hole probe. I'm using Teensy analog pins from A0 to A5 and I am able to get 16 bit data on each channel using the ADC Library. But according to the data sheet Teensy have only two ADC channels that support 16bit data . Does that indicates the ADC value I'm getting is wrong or does teensy can actually support 16bit data on all analog pins ?

    3) What is the maximum sampling rate that Teensy ADC can give and how can I use it in my code ? According to the datasheet ADC can give up to some 460K samples/sec . But when I try to log the data directly to the teensy SD card I can barely get up to 4Kz per channel.

    Click image for larger version. 

Name:	loop_time.jpg 
Views:	279 
Size:	57.3 KB 
ID:	10822Click image for larger version. 

Name:	loop_time.jpg 
Views:	279 
Size:	57.3 KB 
ID:	10822 Click image for larger version. 

Name:	F0000TEK.png 
Views:	232 
Size:	6.1 KB 
ID:	10823



    Using the above sketch and oscilloscope we can see that the loop rate is about 160Kz ( toggling the LED 13 pin without a delay ). How can we increase the loop rate ?

    I'm using Tessny 3.5 Analog pins to read the analog voltage of the pressure sensor and then dump the values into the SD card .
    Code:
    #include <ADC.h>
    #include<math.h>
    #include<SPI.h>
    #include <SdFat.h>
    
    #define VREF 3.3
    #define resolution (VREF/((pow(2,16))-1));
    SdFatSdio sd;
    File file;
    
    const int readPin1 = A0; 
    const int readPin2 = A1;
    const int readPin3 = A2;
    const int readPin4 = A3;
    const int readPin5 = A4;
    const int LED = 13;
    ADC *adc = new ADC(); // adc object
    void measure_log();
    double voltage1,voltage2,voltage3,voltage4,voltage5;
    double adc_value1,adc_value2,adc_value3,adc_value4,adc_value5;
      static int ifl = 0;
      static uint32_t count = 0;
      char filename[32];
      static uint32_t MaxCount = 100000;
      bool blah=0;
    void setup() 
    {
        pinMode(readPin1, INPUT);
        pinMode(readPin2, INPUT);
        pinMode(readPin3, INPUT);
        pinMode(readPin4, INPUT);
        pinMode(readPin5, INPUT);
        pinMode(LED, OUTPUT);
        Serial.begin(115200);
        if (!sd.begin()) 
        {
          digitalWrite(LED, HIGH);
          sd.initErrorHalt();             
        }
        adc->setResolution(16); // set bits of resolution
        adc->setConversionSpeed(ADC_MED_SPEED);
        adc->setSamplingSpeed(ADC_HIGH_SPEED);
    
    }
    void loop() 
    {
       measure_log();
    }
    void measure_log()
    {
      // following is for logging
    
      if(count==0)
      {
         sprintf(filename,"Multiple_Log%04d.txt",ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT))
         {
          digitalWrite(LED, HIGH);
          sd.errorHalt("open failed");
          //count=MaxCount+1;
         }
      } 
      while(count<=MaxCount)
      {
        adc_value1=adc->analogRead(readPin1);
        voltage1 = adc_value1*resolution;
       
        adc_value2=adc->analogRead(readPin2);
        voltage2 = adc_value2*resolution;
        
        adc_value3=adc->analogRead(readPin3);
        voltage3 = adc_value3*resolution;
        
        adc_value4=adc->analogRead(readPin4);
        voltage4 = adc_value4*resolution;
        
        adc_value5=adc->analogRead(readPin5);
        voltage5 = adc_value5*resolution;
    
        file.println(String(millis())+","+String(adc_value1)+","+String(adc_value2)+","+String(adc_value3)+","+String(adc_value4)+","+String(adc_value5)+","+String(voltage1,4)+","+String(voltage2,4)+","+String(voltage3,4)+","+String(voltage4,4)+","+String(voltage5,4));
        blah=!blah;
        digitalWrite(LED,blah);
         
        count++;
      }
      count=0;
      if(count==0)
      {
         // close file
         file.close();
        
      }
    }
    If I comment ou file.println() to dump my values to the SD card then the loop ins running only at frequency close to 5Khz which is very very small. And if tried to run the code with file.println() , then the loop rate is close to 1Khz. How can I increase this ? How can I achieve a sampling rate close 200samples/sec per channel and dump that values to the SD card ?

    Click image for larger version. 

Name:	F0001TEK.png 
Views:	179 
Size:	5.6 KB 
ID:	10824 Click image for larger version. 

Name:	F0002TEK.png 
Views:	185 
Size:	5.8 KB 
ID:	10825

    Can someone help me with this . Thanks in advance

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,879
    Search the forum, there have been several threads discussing low latency data logging, e.g.,
    https://forum.pjrc.com/threads/43708...gging-at-10kHz
    In particular, ADC logging example at
    https://github.com/greiman/SdFat/tre...wLatencyLogger

    the ADC lib has comments about expected ADC acquisition rates
    https://github.com/pedvide/ADC


    effective ADC accuracy is 13-bits for T3.5 -- discussed in several threads
    Last edited by manitou; 06-18-2017 at 11:58 PM.

  3. #3
    Back when I was playing with my Tiny Scope project, I was able to read 1.1 Msamples/second at 8 bit precision, probably 800Ksps at 10bit IIRC.

    See https://forum.pjrc.com/threads/27824...ll=1#post99864

    Last edited by Laur; 06-17-2017 at 06:56 PM.

  4. #4
    [QUOTE=manitou;146243]Search the forum, there have been several threads discussing low latency data logging, e.g.,
    https://forum.pjrc.com/threads/43708...gging-at-10kHz
    In particular, ADC logging example at
    https://github.com/greiman/SdFat/tre...wLatencyLogger

    the ADC lib has comments about expected ADC acquisition rates
    https://github.com/pedvide/ADC


    effective ADC accuracy is 13-bits for T3.5 -- discussed in several threads[/QUOTE]

    Thanks for the reply. I am bit new to the teensy board so kinda bit confused here .

    I am getting only single ended measurements on analog pins A0-A5 . If teensy ADC accuracy is 13 bit then why/how I am able to get 16bit data ? Or why even the data sheet say two 16bit SAR ADC's ?

    Using the ADC library I can set adc->setResolution(); as either 8,10,12,12 and 16 . If i tried setting as 13 bit still I'm receiving only 12 bit data.

    Please help to get a clear understanding of this !

  5. #5
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,091
    Quote Originally Posted by abin.ephrem View Post
    effective ADC accuracy is 13-bits for T3.5 -- discussed in several threads
    Means that, even if you set resolution to 16 bit, the lower 3 bits are noise (introduced by ADC internals)

  6. #6
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,332
    There is a difference between physical resolution and usable resolution. The latter is lower since noise, differential ADC non-linearities, etc., will "eat" a few least significant bits away.

  7. #7
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,868
    The hardware is 16 bit, since silicon is cheap and it means registers line up in sensible ways but enough noise from surrounding parts gets in the disrupt the bottom 2-3 bits. And if you are not careful with your own hardware design it's very easy to end up back at 9-10 effective bits.

    Basic idea to use the ADC is to use 12 or 14 bit and then average or otherwise post process to extract what you want from it and not make any particular assumptions to what your last decimal place is giving you.

  8. #8
    Quote Originally Posted by Laur View Post
    Back when I was playing with my Tiny Scope project, I was able to read 1.1 Msamples/second at 8 bit precision, probably 800Ksps at 10bit IIRC.

    See https://forum.pjrc.com/threads/27824...ll=1#post99864

    Thanks for the reply...a couple of questions

    Which ADC library are you using ? I'm using the pedvide/ADC library but I'm not able to log the data more than 4000 samples/sec per channel.

    I have some confusion regarding about the setConversionSpeed() and setSamplingSpeed() functions.

    The adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_LOW _SPEED) and adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED) ; // change the sampling speed calls the function definition in ADC_Module.cpp . Should I use this definition or the one in ADC.cpp.

    Supposedly I should be able to 400KHz if I set the number of averages to 1 , and since SPI is used for writing to the SD I should be able to get atleast 250-200Khz .

    Code:
    #include "ADC.h"
    #include<math.h>
    #include<SPI.h>
    #include <SdFat.h>
    
    #define resolution (3.3/((pow(2,16))-1));
    SdFatSdio sd;
    File file;
    
    static uint32_t count = 0;
    static uint32_t MaxCount = 100000;
    const int readPin = A9; // ADC0
    
    ADC *adc = new ADC(); // adc object
    void open_file();
    
    void setup() 
    { 
       delay(500);
       Serial.println(" setup() ");
       pinMode(LED_BUILTIN, OUTPUT);
       pinMode(readPin, INPUT);
       Serial.begin(115200);
       adc->setAveraging(0); // set number of averages
       adc->setResolution(16); // set bits of resolution
       adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED)  // change the conversion speed    // it can be any of the ADC_MED_SPEED enum: VERY_LOW_SPEED, LOW_SPEED, MED_SPEED, HIGH_SPEED or VERY_HIGH_SPEED
       adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
       adc->startContinuous(readPin,ADC_0);
       if (!sd.begin()) 
        {
          sd.initErrorHalt();
        }
       open_file();
    }
    void loop() 
    {
      Serial.println("loop() ");
      while(count<=MaxCount)
      {
        double adc_value=adc->analogRead(readPin);
        double voltage = adc_value*resolution;
        //Serial.print(adc_value);Serial.print(",");Serial.println(voltage,3);
        //file.print(adc_value);
        //file.print(',');
        //file.print(voltage,3);
        //file.println('V');
        file.println(String(millis())+","+String(adc_value)+","+String(voltage));
        count++;
      }
      count=0;
      if(!count)
      {
         // close file
         file.close();
      }
      open_file();
    }
    void open_file()
    {
      Serial.println("open_file()");
      static int ifl = 0;
      static uint32_t count = 0;
      char filename[32];
      static uint32_t MaxCount = 100000;
      if(!count)
      {
         sprintf(filename,"Log_Test%04d.txt",ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT))
         {
           sd.errorHalt("open failed");
           count=1;
         }
      }
    }
    Please help to identify the error in my code !!

    Thanks in advance

  9. #9
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,091
    I would start with audio/examples/recorder and modify from Audio board (I2S) to ADC

  10. #10
    Quote Originally Posted by WMXZ View Post
    I would start with audio/examples/recorder and modify from Audio board (I2S) to ADC
    Is it possible to obtain 400kS/s using pedvide/ADC library ?

  11. #11
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,332
    Yes it is. I recommend strongly that you look at the code of that library until you understand everything and you see yourself how you can achieve that sampling rate. Then, you will be able to have a maximum of benefit from it. Using libraries without deep understanding what these do and how they do it, is like driving a car without understanding how the motor works. Not acceptable IMNSHFO.

  12. #12
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,408
    Quote Originally Posted by Theremingenieur View Post
    Yes it is. I recommend strongly that you look at the code of that library until you understand everything and you see yourself how you can achieve that sampling rate.
    Totally agree and I would add reading up on the hardware specs published by Freescale. The more I got into it, the more I realized just how unlikely it is that anyone gets remotely close to 16 bits of real ADC accuracy out of the MKL20 series of chips. I don't doubt it can be done but the warnings are out there, starting with the source impedance and so on. Resolution is not the issue, repeatability and accuracy is. For slow-moving signals, you might be able to use decimation to your advantage.

    To get 16 bits, you can only use two channels in differential mode (all others are good to 13, 12 bits, respectively), you likely have to power down most of the chip, have a perfect front end, strong signal, and so on. None of these things are likely in the real world; the way we use these chips. It's a tribute to the care that Paul put into the Teensy PCBs that the chips perform as admirably as they do (i.e. 13, 12 bits for differential vs single-ended DAQ, respectively).

    For anyone making better claims than what Paul achieved and tested extensively, I'd like to see the documentation and testing apparatus.

  13. #13
    Quote Originally Posted by Theremingenieur View Post
    Yes it is. I recommend strongly that you look at the code of that library until you understand everything and you see yourself how you can achieve that sampling rate. Then, you will be able to have a maximum of benefit from it. Using libraries without deep understanding what these do and how they do it, is like driving a car without understanding how the motor works. Not acceptable IMNSHFO.
    Thanks man..I haven't done much embedded coding so kinda having a bit of confusions and doubts.

    Played with ADC Library a bit today (also read up on the ADC hardware specs ) and using the analogContinuousRead() example I'm able to get data around 280kS/s single channel but using this settings :
    adc->setAveraging(1); // set number of averages
    adc->setResolution(16); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIG H_SPEED);
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED );

    But now I end up with another issue. Let me just explain what I want to do.
    I have 5 analog pressure sensor (3.3V) and I need to read the voltage reading sequentially at a very high rate. ( Something close to 100kS/s for 5 channels will do it ) . How will I read 5 channel values at high rate using analogContinuousRead() example ? Since each channel doesn't have its own data register , how will I do that ?
    Last edited by abin.ephrem; 06-20-2017 at 02:24 PM.

  14. #14
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,332
    For the required speed and number of channels, you'll most probably have to write your own code instead of using the library with its overhead. The algorithm would be using DMA triggered by the conversions done by ADC0 to evacuate the current result into a ring buffer, and reconfiguring the input channel in the inner DMA loop before launching the next conversion. I remember having seen such a code snippet here in the forums, you'll for sure find it using the search function.

    You could do things in a still smarter way, using both ADCs to convert always two channels simultaneously.

  15. #15
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by abin.ephrem View Post
    I have some confusion regarding about the setConversionSpeed() and setSamplingSpeed() functions.

    The adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_LOW _SPEED) and adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED) ; // change the sampling speed calls the function definition in ADC_Module.cpp . Should I use this definition or the one in ADC.cpp.
    The SAR ADC first charges a sampling capacitor and then performs the conversion using that. Sampling speed is the time allowed for charging the sampling cap, if your source impedance is low you can set it to fast. Conversion speed is the time allowed for the actual measurement and affects accuracy. It makes very little sense to have a high conversion speed and perform 16-bit conversions. Better use 12-bit conversions with a lower conversion speed.

    Supposedly I should be able to 400KHz if I set the number of averages to 1 , and since SPI is used for writing to the SD I should be able to get atleast 250-200Khz .
    Where did you get that idea from? SPI isn't even used. SdFatSdio is very slow for small writes.

    Please help to identify the error in my code !!
    With regards to performance, everything is wrong.

    Everything you do is synchronous. The hardware is capable of doing various things in parallel.

    Either perform large 32kB writes with SdFatSdio or use SdFatSdioEX. Writing the data as ASCII strings is pretty much out of the question. A float -> string conversion can take 10'000+ clock cycles; an int -> string conversion 3'000+ clock cycles. Don't use the Stream functions (all the 'print()' stuff), use 'write()' with a decent buffer size.

    Don't use double. Teensy 3.5 has an FPU, but it only supports float. Double is emulated, a multiplication will cost you around 70 clock cycles.

    Don't use 'adc->analogRead(...)', it has has unnecessary overhead to dispatch to the right ADC. Use 'adc->adc0->analogRead()' instead. Even then, it has unnecessary checking that you could eliminate by writing your own function.

    Don't use 'digitalWrite()', it has substantial overhead (costs you around 45 clock cycles). Use 'digitalWriteFast()' instead.

    ( Something close to 100kS/s for 5 channels will do it ) .
    Is that 100kS/s or 500kS/s total? 100kS/s is doable with 'analogRead()', 500kS/s is not. At 500kS/s you would have 240 CPU clock cycles per sample, that's not exactly a lot.

    How will I read 5 channel values at high rate using analogContinuousRead() example ? Since each channel doesn't have its own data register , how will I do that ?
    You can't. The ADC mux needs to be reconfigured, you can't do that with continuous reads. While the manual talks about the great PDB capabilities for sequentially scanning channels, the sad reality is that only 2 are supported.

    The easiest way to very quickly scan multiple channels is to use DMA for reconfiguring the IO mux. Code doing that is in this thread:
    https://forum.pjrc.com/threads/30171...el-Acquisition

    The code posted there actually uses both ADCs, which you probably want to do. You can use slower, more accurate conversions.

    There is an additional gotcha, make sure all the pins use the same 'ADCx_CFG2[MUXSEL]' so that you don't need to change ADCx_CFG2. Look at the manual, '3.7.1.3.1.1 ADC0 Channel Assignment' / 3.7.1.3.2.1 ADC1 Channel Assignment / '35.3.3 ADC Configuration Register 2 (ADCx_CFG2)'.

  16. #16
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    tni, your knowledge is scary sometimes

    I have not done much testing with the DMA on the T3.6 yet, looking at some of my notes its possible you may get faster analog speeds at 192MHz vs 216MHz/240MHz. This has to do with how the ADC clock dividers are setup for the various speeds. I think 6(5 plus 1 discard in your case) channels at 100K Cycles/s is going to be tough but you may get there. My guess is 60-70K Cycles/s based on values I got from testing the T3.2.

    @abin.ephrem, I placed a list of values for calling the T3.6 DMA ADC's in the thread tni mentioned, it should work on the T3.5 also. I have not confirmed any of them yet.
    Last edited by Donziboy2; 06-21-2017 at 06:50 PM.

  17. #17
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by Donziboy2 View Post
    I have not done much testing with the DMA on the T3.6 yet, looking at some of my notes its possible you may get faster analog speeds at 192MHz vs 216MHz/240MHz. This has to do with how the ADC clock dividers are setup for the various speeds. I think 6(5 plus 1 discard in your case) channels at 100K Cycles/s is going to be tough but you may get there. My guess is 60-70K Cycles/s based on values I got from testing the T3.2.
    Performance numbers for the DMA scanning, Teensy 3.5 @ 120Mhz:

    Using both ADCs, ADC resolution 12, conversion speed MED_SPEED, sampling speed MED_SPEED runs at 154'000 samples per second per channel, total of 6 channels, 3 per ADC (926'000 samples per second total).

    Using 1 ADC, scanning 5 channels, conversion speed MED_SPEED, sampling speed HIGH_SPEED runs at 108'000 samples per second per channel (542'000 samples per second total).

  18. #18
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Quote Originally Posted by tni View Post
    Performance numbers for the DMA scanning, Teensy 3.5 @ 120Mhz:

    Using both ADCs, ADC resolution 12, conversion speed MED_SPEED, sampling speed MED_SPEED runs at 154'000 samples per second per channel, total of 6 channels, 3 per ADC (926'000 samples per second total).

    Using 1 ADC, scanning 5 channels, conversion speed MED_SPEED, sampling speed HIGH_SPEED runs at 108'000 samples per second per channel (542'000 samples per second total).
    Ah, your right, I was looking at my breakdowns from values I recorded and not doubling them since they are based on 4(ADC0) of 8(ADC0/1) channels I was reading.

    CPU speed (FBus) and Resolution will affect the speeds, along with conversion and sample settings.
    Highlighted yellow are out of spec for T3.1/3.2, I have an open Github issue asking Paul if it could damage them over time.
    Click image for larger version. 

Name:	ADC DMA Speeds.JPG 
Views:	225 
Size:	76.7 KB 
ID:	10859

  19. #19
    Thank you so much guys ... @Donziboy2 @ tni @ Theremingenieur

    I'm still working out on the code. Will post it once it completes. It will take some time as I'm just a kid when it comes to embedded programming !!

  20. #20
    Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    71

  21. #21
    Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    71
    See my post at https://forum.pjrc.com/threads/53173...ith-the-Teensy

    Scroll down to post #6, the analog input noise is at 1 bit in 16 bits.

  22. #22
    Member
    Join Date
    Apr 2018
    Location
    Eastern Time, USA
    Posts
    71
    I am getting 16 bits, using the on board ADC, and an instrumentation grade input design with surface mount parts.

    See this:

    https://forum.pjrc.com/threads/53173...ith-the-Teensy

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •