Forum Rule: Always post complete source code & details to reproduce any issue!

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.

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<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 LED = 13;
void measure_log();
double voltage1,voltage2,voltage3,voltage4,voltage5;
static int ifl = 0;
static uint32_t count = 0;
char filename[32];
static uint32_t MaxCount = 100000;
bool blah=0;
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(115200);
if (!sd.begin())
{
digitalWrite(LED, HIGH);
sd.initErrorHalt();
}
adc->setResolution(16); // set bits of resolution

}
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)
{

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 ?

Can someone help me with this . Thanks in advance

2. Search the forum, there have been several threads discussing low latency data logging, e.g.,
In particular, ADC logging example at
https://github.com/greiman/SdFat/tre...wLatencyLogger

effective ADC accuracy is 13-bits for T3.5 -- discussed in several threads

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.

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

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.

5. Originally Posted by abin.ephrem
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. 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. 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. Originally Posted by Laur
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.

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.

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<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;

void open_file();

void setup()
{
delay(500);
Serial.println(" setup() ");
pinMode(LED_BUILTIN, OUTPUT);
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
if (!sd.begin())
{
sd.initErrorHalt();
}
open_file();
}
void loop()
{
Serial.println("loop() ");
while(count<=MaxCount)
{
//file.print(',');
//file.print(voltage,3);
//file.println('V');
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;
}
}
}

10. Originally Posted by WMXZ
Is it possible to obtain 400kS/s using pedvide/ADC library ?

11. 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. Originally Posted by Theremingenieur
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. Originally Posted by Theremingenieur
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

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 ?

14. 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. Originally Posted by abin.ephrem
I have some confusion regarding about the setConversionSpeed() and setSamplingSpeed() functions.

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.

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 '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:

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. 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.

17. Originally Posted by Donziboy2
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. Originally Posted by tni
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.

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. 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.

21. I am getting 16 bits, using the on board ADC, and an instrumentation grade input design with surface mount parts.

See this:

#### Posting Permissions

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