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

Adc_ref_1v2

Hello,

With Teensy 3.2 and the last ADC library, I have an unstable ADC_0 differential mesure when I use 1.2V internal reference

Code:
adc->setReference(ADC_REF_1V2, ADC_0);

But it's ok with ADC_REF3V3.

Do you ever had this problem ?
 
keraba,
I can't reproduce the behavior that you're seeing. Using your code I get expected values when I connect A2 to GND or 3.3V. Check this yourself with the latest version of the library (I don't know which one you're using).

Grezco,
You'll need to provide more details to investigate this. What's your code and your hardware setup? What do you mean by unstable?
 
Last edited:
Pedvide,

I use ADC example : "analogDifferentialRead'.
Without any change in code, when I apply ~11,5V on the resistor divider (A10-A11), I have :

Value ADC0: 1.0435897112
Value ADC0: 1.0435897112
Value ADC0: 1.0443955660
Value ADC0: 1.0435897112
Value ADC0: 1.0452015400
Value ADC0: 1.0435897112
Value ADC0: 1.0435897112
Value ADC0: 1.0435897112


Code:
    ///// ADC0 ////
    // reference can be ADC_REF_3V3, ADC_REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
    adc->setReference(ADC_REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2

    adc->setAveraging(1); // set number of averages
    adc->setResolution(13); // set bits of resolution

    // it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED_16BITS, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
    // see the documentation for more information
    adc->setConversionSpeed(ADC_HIGH_SPEED); // change the conversion speed
    // it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
    adc->setSamplingSpeed(ADC_HIGH_SPEED); // change the sampling speed
With ligne 24 'dc->setReference(ADC_REF_1V2, ADC_0);' ,I have :

Value ADC0: 0.8042490482
Value ADC0: 0.8042490482
Value ADC0: 1.0065200329
Value ADC0: 1.2079852819
Value ADC0: 1.6109156609
Value ADC0: 1.8139926195
Value ADC0: 2.2177288532
Value ADC0: 2.4191939831
Value ADC0: 2.6206593513

ADC_Diff.jpg
 
ADC Error 0x04 on Teensy 3.6 but not on 3.2 with continuous differential read - why?

I am trying to use software adapted from Pedvide example "analogContinuousDifferential Read" on the Teensy 3.6 but with just a single 128line acquisition in "setup" (see picture) and with the "loop"Mod.JPG commented out. It works fine collecting a signal on A10 and A11 on the Teensy 3.2 with the internal 1.2V ref and various other parameter settings. However, when I try to use the same software on the 3.6 it fails, telling me error 0x04 has been commited. I can't find this error in the ADC.h and wonder what has gone wrong. I am using a battery-powered signal generator with a 200mV 200Hz signal on A10 and floating 0V on A11.
 
The errors are in ADC_Module.h, but more importantly is that that's a bug in the library for the Teensy 3.6!
Please, go to https://github.com/pedvide/ADC/tree/dev and use that version of the library. There are a few changes with respect the old version in the setReference, setConversionSpeed, and setSamplingSpeed methods. They now use an enum class instead a define, so for example, if before you had:
Code:
adc->setConversionSpeed(ADC_VERY_LOW_SPEED)
Now the syntax is:
Code:
adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_LOW_SPEED)

The code in the examples has been update if you need help.
Could you test the example readAllPins.ino? Make sure that the values read for the A10, A11, and the differential A10-A11 are correct.
 
I had problems in the T32 in using the dual synced ADC. I had to select two channels whereby both ADCs are used. Does this same situation apply when using the differential mode.
 
Thank you very much for the help. I managed to install the new T3.6 code and ran the readAllPins.ino as requested but without changing parameters or the code. All the pins are unconnected except A10, A11 across which I have +0.4V from a battery sourced pot, with a 0.1mF across its output. Here is a snapshot of the readings. The differential reading on A10, A11 is negative and too high by a factor of 3 and the temperature reading seems high (!).
AllPins_test.JPG

I also gutted your analogContinuousRead.ino to find the speed of acquisition with a 5KHz 0.2V sine signal on A10, A11 using the version below.
I got the following output, displayed using Excel, which shows a sampling rate of about 45ksps, adequate for my purpose but not as fast as I expected.
test.JPG
Will the ADC go faster?
 

Attachments

  • MyCDR.JPG
    MyCDR.JPG
    83.9 KB · Views: 239
Last edited:
I also gutted your analogContinuousRead.ino to find the speed of acquisition with a 5KHz 0.2V sine signal on A10, A11 using the version below.
I got the following output, displayed using Excel, which shows a sampling rate of about 45ksps, adequate for my purpose but not as fast as I expected.
View attachment 8909
Will the ADC go faster?

You can go faster, you will sacrifice accuracy to do it. You can increase the sample/conversion speeds(VERY_HIGH_SPEED instead of HIGH_SPEED). You can also reduce the number of averages. (adc->setAveraging(4) instead of adc->setAveraging(8))


1/45000 = 22.22222uS
22.22222u / 8 = 2.77778uS per sample.
or 380Ksps
 
Thanks for putting me right Donziboy2. I'm not used to such advanced kit with so many options to handle. The T3.6's performance is plenty adequate for my task. However, reducing the averaging to 4 does not increase acquisition speed according to my 128 line acquisition test; it is still 45ksps. I have now looked at averaging at 9, 13, and 16 bit acquisition. Here is a differential reading of data at 9bits without and with 32 averaging. The acquisition speed is identical at all averaging values (0,4,8,16,32) and all resolutions (9,13,16 bits) and is about 45ksps. However, averaging values of 16 or 32 cause doubling up, or more, of identical values as on the 9bit example below. There is no sign that any averaging "improves" output.

9bit.JPG9bitAveraging.JPG

I have also examined the other speed factors. The examples above (including the 16 bit result in my previous posting) were acquired with high speed sampling and conversion. Increasing either or both to "very high speed does not increase the sampling rate, it remains 45ksps for all. I believe I have read that this will be so in one of Pedvide's notes.

HandVH.JPGVHandVH.JPG

It appears too, that setting "very low" and "low" speed parameters for sampling and acquisition make no difference to actual sampling rate, which remains 45ksps. Which puzzles me...

VLandVL.JPGLandL.JPG
 
Last edited:
I'm happy with the speed. Reading ADC.h in detail indicates that my expectations may be based upon misunderstandings. However I have now successfully recorded an AC signal (see image below)
simul.JPG
using the "synchronised measurements" example, on the T3.6, and with two single ended inputs on pins A9 and A3. The correspondence is excellent and the data is recorded at about 20ksps (two channels). However, despite trying every suggestion in ADC.h I have been unable to record simultaneous differential signals in the same way. Using a while statement in setup I get zeroes.

syncDiffAttempt.JPG

Using the loop as suggested in the "synchronised measurements" example, and with a battery DC 0.4V on both pairs of pins, I get constant nonsense values and an error statement as shown below, as in my example posted on 26th Nov. This is despite the software using the changed enum method as mentioned in Pedvide's reply to that post. If I can get the simultaneous differential software working my happiness will be complete...

error.JPG
 
Last edited:
I know in synced mode, you have to select both ADC0 and ADC1 on separate pins. In differential mode, is there a requirement for how/which ADC pins are selected?
 
I know in synced mode, you have to select both ADC0 and ADC1 on separate pins. In differential mode, is there a requirement for how/which ADC pins are selected?



If you upload the latest Teensyduino (version 1.32 beta 1) you will find several example programs for T3.* boards that give the code for pin selection. This works in the latest Arduino version 1.6.13. The Arduino installer removes the previous version automatically. Only the pairs A10, A11 (ADC0) and A12, A13(ADC1) can be used for differential measurements with T3.1 and above. The way in which the code is used is described in detail in the ADC.h file to be found in the download. The Teensyduino 1.32 must be installed in the C:/Program Files(X86)/Arduino directory and replace the one already there. To do this go to Pedvide's github page (see posting above) and find the version you need then click on the download zipfile button. Extract and install this in the Arduino directory. I mention this because it took me a day to find out how to do this myself!
 
Failure to get T3.6 continuous synchronized differential outpout

Here is my best shot at getting synchronized continuous differential measurements using a T3.6 (180MHz clock).

/* MYCDR.ino based upon Example "synchronized measurements" by Pedvide
* to optimise continuous differential acquisition on T3.6
* Open monitor before running program
*/

#include <ADC.h>
ADC *adc = new ADC(); // adc object

void setup() {
pinMode(A10, INPUT); //Diff Channel 0 Positive
pinMode(A11, INPUT); //Diff Channel 0 Negative
#if ADC_NUM_ADCS>1
pinMode(A12, INPUT); //Diff Channel 1 Positive
pinMode(A13, INPUT); //Diff Channel 1 Negative
#endif
Serial.begin(9600);
// ADC_0
adc->setReference(ADC_REFERENCE::REF_3V3, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
adc->setAveraging(0); // set number of averages
adc->setResolution(16); // set bits of resolution
adc->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed
//ADC_1
#if ADC_NUM_ADCS>1
adc->setAveraging(0, ADC_1); // set number of averages
adc->setResolution(16, ADC_1); // set bits of resolution
adc->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_1); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_1); // change the sampling speed
adc->setReference(ADC_REFERENCE::REF_3V3, ADC_1);

adc->startSynchronizedContinuousDifferential(A10, A11, A12, A13);
#endif
delay(200);
Serial.println("end setup");
ADC::Sync_result result;
int jj = 0;

while(jj<128)
{
result = adc->analogSynchronizedReadDifferential(A10, A11, A12, A13);
result.result_adc0 = (uint16_t)result.result_adc0;
result.result_adc1 = (uint16_t)result.result_adc1;
Serial.print(result.result_adc0*3.3/adc->getMaxValue(ADC_0), DEC);
Serial.print(",");
Serial.println(result.result_adc1*3.3/adc->getMaxValue(ADC_1), DEC);
jj++;
}
}

void loop() {}

The output is unchanged over 128 lines, as follows:

MYCDRoutput.JPG

The input, as before with the single differential input example posted above, is 5KHz, +0.2V to +0.4V. I have tried all the suggestions in ADC.h and the "synchronized measurements" example, with no success. Has anybody been able to get sync diff output that makes sense?
 
I'm looking into these issues, but I have a lot of work. I hope I can do something on the weekend.
Please note that Teensy 3.6 only has one differential pair!
Also I see that you're casting the results to uint, so you won't get negative values, which are possible for a diff measurement.
Also, what happens if you run that while loop inside the loop() function?b
Also, in the loop you're printing every value as you read it. This means that the 45 ksps may very well be because of the constant sending of a value via usb and printing it. Better fill an array and print it at once.
 
T3.6 much faster than I thought!

I'm looking into these issues, but I have a lot of work. I hope I can do something on the weekend.
Please note that Teensy 3.6 only has one differential pair!
Also I see that you're casting the results to uint, so you won't get negative values, which are possible for a diff measurement.
Also, what happens if you run that while loop inside the loop() function?b
Also, in the loop you're printing every value as you read it. This means that the 45 ksps may very well be because of the constant sending of a value via usb and printing it. Better fill an array and print it at once.

Pedvide, thanks so much for your excellent advice. I have rewritten the test program (below) to separately save the data as an array and then print it. I have not yet got the full resolution in the print out but plotting the output:

arraySpeed.JPG

shows that the print instructions did indeed slow the ADC's dramatically. They are operating on both channels at about 130ksps now. This speed makes all sorts of things possible...

Here is the program without comment lines:

// analogSYNCarray, for synchonized measurements using both ADC present in Teensy 3.6
#include <ADC.h>
#define FFTSIZE 128
#define Pi 3.14159265
const int readPin = A9;
const int readPin2 = A3;
float sig1[FFTSIZE];
float sig2[FFTSIZE];
ADC *adc = new ADC(); // adc object
elapsedMicros time;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(readPin, INPUT);
pinMode(readPin2, INPUT);
Serial.begin(9600);
adc->setReference(ADC_REFERENCE::REF_3V3, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
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::HIGH_SPEED); // change the sampling speed
adc->setAveraging(0, ADC_1); // set number of averages
adc->setResolution(16, ADC_1); // set bits of resolution
adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED, ADC_1); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED, ADC_1); // change the sampling speed
adc->setReference(ADC_REFERENCE::REF_3V3, ADC_1);
adc->startSynchronizedContinuous(readPin, readPin2);
delay(1000);
Serial.println("end setup");
int value = 0;
int value2 = 0;
int jj = 0, kk = 0;
ADC::Sync_result result;
while(jj<FFTSIZE) {
result = adc->readSynchronizedContinuous();
result.result_adc0 = (uint16_t)result.result_adc0;
result.result_adc1 = (uint16_t)result.result_adc1;
sig1[jj] =(result.result_adc0*3.3/adc->getMaxValue(ADC_0));
sig2[jj] = (result.result_adc1*3.3/adc->getMaxValue(ADC_1));
jj++;
}
while(kk<FFTSIZE){
Serial.print(time, DEC);
Serial.print(",");
Serial.print(sig1[kk]);
Serial.print(",");
Serial.println(sig2[kk]);
kk++;
}
// End of setup
}
void loop() {}

Note that the speed was measured at a board clock of 48MHz. Increasing that to 180MHz approximately quadruples the ADC speed to about 1/2 cycle (5kHz) in 128 lines of data or about (1000/0.25)*128 = 0.5Msps, approximately - a number consistent with Pedvide's test results in his "analogContinuousRead.ino example. However, plotting results shows that for board speeds of over 72MHz there is doubling or tripling of identical ADC values and the effective Nyquist frequency seems to be just above 100kHz as in this example obtained with a board frequency of 72MHz (see below).

Nyquist.JPG
 

Attachments

  • Nyquist.JPG
    Nyquist.JPG
    57.5 KB · Views: 158
Last edited:
SOLVED:
Pedvide, it maybe helpful to add a tip to the Audio support, users may need to manually edit the Audio library and disable internal reference.
adc->setReference(ADC_REF_3V3, ADC_1) has no effect, must be overwritten by the Audio library which sets to 1V2. Easy fix but difficult to track down.
Pedvide and other experts,

Anyone know if the ADC Library and AnalogReadAudio can still play nice together if implemented seperately on ADC_0 & ADC_1?

After updating my libraries and editing some code I found my adc->analogRead(readPin, ADC_1) resulted in mostly Max Values. I'm reading a log-scale light sensor with AnalogReadAudio, which started reading max values expect in very dark circumstances.

This seems to be the same issue, using the similar code: https://forum.pjrc.com/threads/39377-A-problem-using-the-Audio-library-and-ADC-library.
 
Last edited:
I am starting to play around with this library for the first time. on T3.6. Looks like a very useful library!

I thought I would hack up the Interval timer example as it is closer to what I was thinking of doing.

But my main Analog pin was on

But I was not getting any interrupts on my ADC_1 so I converted all of the calls over and the like,
But I was not getting my void adc1_isr() function to be called.

I found that there was an active issue up on github for this. https://github.com/pedvide/ADC/issues/19

I updated to current code to make sure still issue and found I needed to change my code to new enums:
adc->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_1); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_1); // change the sampling speed


I verified it still was not working. I tried the change proposed in the issue: which did not compile

The problem is the code assumes that IRQ_ADC0 and IRQ_ADC1 are right after each other, which on T3.2 works (57, 58),
But on T3.6 they are 39 and 73...

My changes to the function ADC_Module::ADC_Module (ADC_Module.cpp) are slightly different:

Code:
#if ADC_NUM_ADCS==2
        , IRQ_ADC(ADC_num? IRQ_ADC1 : IRQ_ADC0) // fix by SB (Teensy 3.6)
#else
        , IRQ_ADC(IRQ_ADC0 + ADC_num*1)
#endif
Which appears to be working in this case. My hacked up version is still not fully working, but I probably need to do a little additional work on this ISR. Or maybe I will punt on the ISR. Not sure if it ISR gains me anything?

That is I am thinking instead of having this ISR grab the value and process it (put in queue), couldn't I just have the interval timer grab the value and stuff it out before I start the next ADC... But it would be good to fix this

Kurt

Edit: 2nd issue:
Code:
  uint8_t pin = ADC::sc1a2channelADC1[ADC1_SC1A&ADC_SC1A_CHANNELS]; // the bits 0-4 of ADC1_SC1A have the channel
Does not work on T3.6
The conversion table:
Code:
///////// ADC1
#if defined(ADC_TEENSY_3_1)
const uint8_t ADC::sc1a2channelADC1[]= { // new version, gives directly the pin number
    36, 0, 0, 34, 28, 26, 29, 30, 16, 17, 0, 0, 0, 0, // 0-13. 5a=26, 5b=27, 4b=28, 4a=31
    0, 0, 0, 0, 39, 37, 0, 0, // 14-21
    0, 0, 0, 0, 38, 41, 0, 42, // 22-29. VREF_OUT, A14, temp. sensor, bandgap, VREFH, VREFL.
    43
};
#elif defined(ADC_TEENSY_3_5) || defined(ADC_TEENSY_3_6)
const uint8_t ADC::sc1a2channelADC1[]= { // new version, gives directly the pin number
    36, 0, 0, 34, 28, 26, 29, 30, 16, 17, 0, 0, 0, 0, // 0-13. 5a=26, 5b=27, 4b=28, 4a=31
    0, 0, 0, 0, 39, 37, 0, 0, // 14-21
    0, 0, 0, 0, 38, 41, 0, 42, // 22-29. VREF_OUT, A14, temp. sensor, bandgap, VREFH, VREFL.
    43
};
#endif
Is not correct, currently just copy of T3.2... But I know in my case Pin A13 is 1-15 So the ADC1_SC1A&ADC_SC1A_CHANNELS returns
15 which is correct, but the mapping goes to zero instead of 32(A13)

Will try to build valid table. Question: Should I simply post the updated table or would you prefer I go through the steps to create a Pull request?

Also where to? Should I try to issue PR to main fork(https://github.com/pedvide/ADC/)? and/or should I try to issue to the ones currently in Teensuduino?
Actually I don't see one under Paul... So not sure where that one is coming from as the API changes look like they were done in November?
 
Last edited:
Quick update: I believe the table I mentioned above should be:
Code:
#elif defined(ADC_TEENSY_3_5) || defined(ADC_TEENSY_3_6)
const uint8_t ADC::sc1a2channelADC1[]= { // new version, gives directly the pin number
    0, 69, 0, 0, 35, 36, 37, 38, 0, 0, 49, 50, 0, 0, // 0-13.
    31, 32, 0, 39, 71, 65, 0, 0, // 14-21
    0, 67, 0, 0, 0, 0, 0, 0, // 22-29.
    0
};
#endif
Actually I believe the other table for T3.5/6 is wrong as well, I think it should be:
Code:
#elif defined(ADC_TEENSY_3_5) || defined(ADC_TEENSY_3_6)
const uint8_t ADC::sc1a2channelADC0[]= { // new version, gives directly the pin number
    0, 68, 0, 64, 23, 14, 20, 21, 16, 17, 0, 0, 19, 18, // 0-13
    15, 22, 0, 33, 34, 0, 0, 0, // 14-21
    0, 66, 0, 0, 70, 0, 0, 0, // 22-29
    0 // 31 means disabled, but just in case
};
#endif // defined
 
Last edited:
What is the Pin Layout for this library? I`m trying the analogRead example and connect A9 and A2 to GND and expect the output to be 0 but I get random values (because it is not the correct pin connected) around 2V and around 3V.

I`m using the unmodified example on a Teensy 3.1 24MHz.

What am I doing wrong?

Thanks
 
What is the Pin Layout for this library? I`m trying the analogRead example and connect A9 and A2 to GND and expect the output to be 0 but I get random values (because it is not the correct pin connected) around 2V and around 3V.

I`m using the unmodified example on a Teensy 3.1 24MHz.

What am I doing wrong?

Thanks

Its in the first post.
 
@ Pedvide. When you get a chance can you add some details on SetResolution. I recently found myself being tripped up with some odd readings only to find the limits defined in ADC_Module.cpp not what I was expecting. It may help others to have it detailed in the OP.

/* Change the resolution of the measurement
* For single-ended measurements: 8, 10, 12 or 16 bits.
* For differential measurements: 9, 11, 13 or 16 bits.
* If you want something in between (11 bits single-ended for example) select the inmediate higher
* and shift the result one to the right.
 
Hello Pedvide,

I discovered a possible quirk with the ADC library's setAveraging() function.

adc->setAveraging(1); -- works as expected
adc->setAveraging(2); -- behaves like adc->setAveraging(4)
adc->setAveraging(4); -- works as expected (1/4th rate)
adc->setAveraging(8); -- works as expected (1/8th rate)
adc->setAveraging(16); -- works as expected (1/16th rate)
 
Back
Top