Hello everybody,
This ADC library implements most of the Teensy ADC functionality. https://github.com/pedvide/ADC
The library supports Teensy 3.0, 3.1/3.2, LC, 3.5, 3.6, and 4.
The main class is ADC.
This object controls the ADCs. For example, to measure the voltage at pin A9, you can do
just as with the old version of this library. If you have a Teensy 3.0 it will return the value measured by the only ADC module.
If you have a Teensy with more than omne ADC module (3.1, 3.2, 3.5, 3.6 and 4), it will look whether this pin can be accessed by ADC0, ADC1 or both. If only one ADC module can access it, it will use it. If both can do it, it will assign this measurement to the ADC with less workload (for example if one is doing a continuous measurement already).
If you have a preference for one module in particular you can do:
If the pin can't be accessed by the ADC you selected it will return ADC_ERROR_VALUE.
It's also possible to access directly the adc modules with
Overview of modes of conversion
All modes of conversion of the ADC are implemented in the same fashion:
Programmable Gain Amplifier
PGA can be activated with enablePGA(gain), where gain=1, 2, 4, 8, 16, 32 or 64. It will amplify signals of less that 1.2V only in differential mode (see examples). Only for Teensy 3.1/3.2.
Periodic conversions
There are two ways to do periodic conversions: using an IntervalTimer or using the PDB.
It's possible (and easy) to use the IntervalTimer library with this library, see analogReadIntervalTimer.ino in the examples folder.
Teensy 3.x have the PDB, supported on both ADCs, see the adc_pdb.ino example. The same frequency is used for both ADCs, unlike using IntervalTimers.
Error detection
Use adc->adcX->fail_flag has any internal error (wrong pin, etc.). Use the functions in ADC_util.h to translate the number to text.
Use adc->resetError() to clean any errors.
Pins
All analog pins can be measured, but not by both ADCs. The following images show which ADC can access each pin.
If the text next to the pin number says ADC0_SE## then it can be measured by ADC0, if it says ADC1_SE## by ADC1. Some pins can be measured by both.
Teensy 3.0:
Teensy 3.1/3.2:
Teensy 3.5:
Teensy 3.6:
Teensy 4:
Synchronous measurements
It will set up both ADCs and measure pin1 with ADC0 and pin2 with ADC1. The result is stored in the struct ADC::Sync_result, with members .result_adc0 and .result_adc1 so that you can get both. ADC0 has to be able to access pin1 (same for pin2 and ADC1), to find out see in the image that next to the pin number is written ADC0_xxxx or ADC1_xxx (or both).
I've made a simple test with a wavefunction generator measuring a sine wave of 1 Hz and 2 V amplitude with both ADCs at the same time.
I've measured it synchronously in the loop(){} with a delay of 50ms (so 20Hz sampling), the results are here:
In red and black are the measurements on each pin, as you see, the difference is very small, so the system seems to work.
Voltage reference
The measurements are done comparing to a reference of known voltage. There are a few options depending on the board
where option is ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_EXT, or ADC_REFERENCE::REF_1V2.
ADC_REFERENCE is a class enum. The advantage of class enums with respect to #defines is that the values are checked at compile time, that is, if you write something like ADC_REFERENCE::REF_5V5, the compiler will tell you that value doesn't exist. If you try to use an int (from a define, for example), the compiler will complain again. This may save you from very sneaky bugs, where you use a value that does something different than what you expect.
Sampling and conversion speed
The measurement of a voltage takes place in two steps:
You can select the speed at which the sampling step takes place. Usually you can increase the speed if what you measure has a low impedance. However, if the impedance is high you should decrease the speed.
speed can be any from the ADC_SAMPLING_SPEED class enum: see the documentation for each board.
For Teensy LC and 3.x:
The conversion speed can also be changed, and depends on the bus speed:
speed can be any from the ADC_CONVERSION_SPEED class enum: see the documentation of each board.
This will change the ADC clock, ADCK. And affects all stages in the measurement. You can check what the actual frequency for the current bus speed is in the header settings_defines.h.
For Teensy 3.x, LC:
There's another option for the ADC clock, the asynchronous ADC clock, ADACK. It's independent on the bus frequency.
For Teensy 3.x, LC:
Both the sampling and the conversion speed affect the time it takes to measure, there are some tests in the continuous conversion examples.
Other conversion sources
All boards have a few additional internal conversion sources. The possible options are in the ADC_INTERNAL_SOURCE class enum.
For Teensy 3.x, LC:
The constants 1.7 mV/ºC and 0.72 mV depend somewhat on the specific board, so a calibration is recommended.
For Teensy 4 the only extra source is VREFSH, which is connected to VDD.
Library size
The library uses both program and RAM space. The exact amount depends on the Teensy used and whether optimizations were used.
The results in bytes are the respective progmem or ram of the analogRead.ino example minus that of the blinky example, the percentages are the memory used out of the total:
Teensy 3.0, 96 MHz, Serial: 5744 B (11%) program storage space and 132 B (14%) dynamic memory space used.
Teensy 3.1, 96 MHz, Serial, no optimizations: 6176 B (6%) program storage space and 136 B (3%) dynamic memory space used.
Teensy 3.1, 96 MHz, Serial, with optimizations (default): 9244 B (8%) program storage space and 1116 B (7%) dynamic memory space used.
Teensy LC, 48 MHz, Serial, no optimizations (default): 11120 B (33%) program storage space and 128 B (28%) dynamic memory space used.
Teensy LC, 48 MHz, Serial, with optimizations: 14212 B (41%) program storage space and 1112 B (53%) dynamic memory space used.
The progmem usage for Teensy LC is higher due to the use of floats (multiplying by 3.3). If possible, don't use floats at all in Teensy LC as they use about 6 kB of space (2 kB for Teenst 3.x).
Updates
Now it works with the Audio library:
Teensy 3.0 is compatible, except if you try to use the Audio library ADC input (AudioInputAnalog), because there's only one ADC module so you can't use it for two things.
Teensy 3.1 is compatible. If you want to use AudioInputAnalog and the ADC you have to use the ADC_1 module, the Audio library uses ADC_0. Any calls to functions that use ADC_0 will most likely crash the program. Note: make sure that you're using pins that ADC_1 can read (see pictures above)! Otherwise the library will try to use ADC_0 and it won't work!!
ADC library now supports Teensy LC!! Finally!
PDB is supported on both ADCs
Support for Teensy 3.5 and 3.6
New format for setReference, setSamplingSpeed, and setConversionSpeed. The information above has been updated.
Added support for pins A25, A26 in Teensy 3.5
Support for Teensy 4.
Still TODO:
See issues in GitHub.
This ADC library implements most of the Teensy ADC functionality. https://github.com/pedvide/ADC
The library supports Teensy 3.0, 3.1/3.2, LC, 3.5, 3.6, and 4.
The main class is ADC.
Code:
ADC *adc = new ADC(); // adc object
Code:
int value = adc->analogRead(A9);
If you have a Teensy with more than omne ADC module (3.1, 3.2, 3.5, 3.6 and 4), it will look whether this pin can be accessed by ADC0, ADC1 or both. If only one ADC module can access it, it will use it. If both can do it, it will assign this measurement to the ADC with less workload (for example if one is doing a continuous measurement already).
If you have a preference for one module in particular you can do:
Code:
int value = adc->analogRead(A9, ADC_0);
It's also possible to access directly the adc modules with
Code:
adc->adc0->function
adc->adc1->function
Overview of modes of conversion
All modes of conversion of the ADC are implemented in the same fashion:
Using 1 ADC | ||
Single-shot mode | Single-shot mode | Continuous mode |
return value | return immediately | |
analogRead | startSingleRead | startContinuous |
analogReadDifferential | startSingleDifferential | startContinuousDifferential |
readSingle() | analogReadContinuous() | |
stopContinuous() | ||
Using both ADCs (Synchronous mode) | ||
Single-shot mode | Single-shot mode | Continuous mode |
return value | return immediately | |
analogSyncRead | startSynchronizedSingleRead | startSynchronizedContinuous |
analogSyncReadDifferential | startSynchronizedSingleDifferential | startSynchronizedContinuousDifferential |
readSynchronizedSingle | readSynchronizedContinuous | |
stopSynchronizedContinuous |
Programmable Gain Amplifier
PGA can be activated with enablePGA(gain), where gain=1, 2, 4, 8, 16, 32 or 64. It will amplify signals of less that 1.2V only in differential mode (see examples). Only for Teensy 3.1/3.2.
Periodic conversions
There are two ways to do periodic conversions: using an IntervalTimer or using the PDB.
It's possible (and easy) to use the IntervalTimer library with this library, see analogReadIntervalTimer.ino in the examples folder.
Teensy 3.x have the PDB, supported on both ADCs, see the adc_pdb.ino example. The same frequency is used for both ADCs, unlike using IntervalTimers.
Error detection
Use adc->adcX->fail_flag has any internal error (wrong pin, etc.). Use the functions in ADC_util.h to translate the number to text.
Use adc->resetError() to clean any errors.
Pins
All analog pins can be measured, but not by both ADCs. The following images show which ADC can access each pin.
If the text next to the pin number says ADC0_SE## then it can be measured by ADC0, if it says ADC1_SE## by ADC1. Some pins can be measured by both.
Teensy 3.0:
Teensy 3.1/3.2:
Teensy 3.5:
Teensy 3.6:
Teensy 4:
Synchronous measurements
Code:
ADC::Sync_result result = adc->analogSyncRead(pin1, pin2);
I've made a simple test with a wavefunction generator measuring a sine wave of 1 Hz and 2 V amplitude with both ADCs at the same time.
I've measured it synchronously in the loop(){} with a delay of 50ms (so 20Hz sampling), the results are here:
In red and black are the measurements on each pin, as you see, the difference is very small, so the system seems to work.
Voltage reference
The measurements are done comparing to a reference of known voltage. There are a few options depending on the board
- REF_3V3: All boards have the 3.3 V output of the regulator (VOUT33 in the schematics). If VIN is too low, or you are powering the Teensy directly to the 3.3V line, this value can be lower. In order to know the value of the final measurement you need to know the value of the reference in some other way. This is the default option.
- REF_EXT: The second option is available on the Teensy 3.x and LC boards. It is the external reference, the pin AREF. Simply connect this pin to a known voltage and it will be used as reference.
- REF_1V2: Teensy 3.x have an internal 1.2V reference. Use it when voltages are lower than 1.2V or when using the PGA in Teensy 3.1/3.2.
Code:
adc->setReference(option, ADC_x);
ADC_REFERENCE is a class enum. The advantage of class enums with respect to #defines is that the values are checked at compile time, that is, if you write something like ADC_REFERENCE::REF_5V5, the compiler will tell you that value doesn't exist. If you try to use an int (from a define, for example), the compiler will complain again. This may save you from very sneaky bugs, where you use a value that does something different than what you expect.
Sampling and conversion speed
The measurement of a voltage takes place in two steps:
- Sampling: Load an internal capacitor with the voltage you want to measure. The longer you let this capacitor be charged, the closest it will resemble the voltage.
- Conversion: Convert that voltage into a digital representation that is as close as possible to the selected resolution.
You can select the speed at which the sampling step takes place. Usually you can increase the speed if what you measure has a low impedance. However, if the impedance is high you should decrease the speed.
Code:
adc->setSamplingSpeed(speed); // change the sampling speed
For Teensy LC and 3.x:
- VERY_LOW_SPEED is the lowest possible sampling speed (+24 ADCK). (ADCK is the ADC clock speed, see below).
- LOW_SPEED adds +16 ADCK.
- MED_SPEED adds +10 ADCK.
- HIGH_SPEED adds +6 ADCK.
- VERY_HIGH_SPEED is the highest possible sampling speed (0 ADCK added).
- VERY_LOW_SPEED: is the lowest possible sampling speed (+22 ADCK, 24 in total).
- LOW_SPEED adds +18 ADCK, 20 in total.
- LOW_MED_SPEED adds +14, 16 in total.
- MED_SPEED adds +10, 12 in total.
- MED_HIGH_SPEED adds +6 ADCK, 8 in total.
- HIGH_SPEED adds +4 ADCK, 6 in total.
- HIGH_VERY_HIGH_SPEED adds +2 ADCK, 4 in total
- VERY_HIGH_SPEED is the highest possible sampling speed (0 ADCK added, 2 in total).
The conversion speed can also be changed, and depends on the bus speed:
Code:
adc->setConversionSpeed(speed); // change the conversion speed
This will change the ADC clock, ADCK. And affects all stages in the measurement. You can check what the actual frequency for the current bus speed is in the header settings_defines.h.
For Teensy 3.x, LC:
- VERY_LOW_SPEED is guaranteed to be the lowest possible speed within specs for resolutions less than 16 bits (higher than 1 MHz), it's different from ADC_LOW_SPEED only for 24, 4 or 2 MHz.
- LOW_SPEED is guaranteed to be the lowest possible speed within specs for all resolutions (higher than 2 MHz).
- MED_SPEED is always >= ADC_LOW_SPEED and <= ADC_HIGH_SPEED.
- HIGH_SPEED_16BITS is guaranteed to be the highest possible speed within specs for all resolutions (lower or eq than 12 MHz).
- HIGH_SPEED is guaranteed to be the highest possible speed within specs for resolutions less than 16 bits (lower or eq than 18 MHz).
- VERY_HIGH_SPEED may be out of specs, it's different from ADC_HIGH_SPEED only for 48, 40 or 24 MHz.
- VERY_LOW_SPEED is guaranteed to be the lowest possible speed within specs (higher than 4 MHz).
- LOW_SPEED is equal to VERY_LOW_SPEED
- MED_SPEED is always >= ADC_LOW_SPEED and <= ADC_HIGH_SPEED.
- HIGH_SPEED is guaranteed to be the highest possible speed within specs (lower or eq than 40 MHz).
- VERY_HIGH_SPEED is equal to HIGH_SPEED
There's another option for the ADC clock, the asynchronous ADC clock, ADACK. It's independent on the bus frequency.
For Teensy 3.x, LC:
- ADACK_2_4: 2.4 MHz
- ADACK_4_0: 4 MHz
- ADACK_5_2: 5.2 MHz
- ADACK_6_2: 6.2 MHz
- ADACK_10: 10 MHz
- ADACK_20: 20 MHz
Both the sampling and the conversion speed affect the time it takes to measure, there are some tests in the continuous conversion examples.
Other conversion sources
All boards have a few additional internal conversion sources. The possible options are in the ADC_INTERNAL_SOURCE class enum.
For Teensy 3.x, LC:
- TEMP_SENSOR
- VREF_OUT: The 1.2 V reference (not for Teensy LC)
- BANDGAP: 1 V bandgap, see VREF.h how to enable it.
- VREFH
- VREFL
Code:
value = adc->analogRead(ADC_INTERNAL_SOURCE::TEMP_SENSOR);
float volts = value*3.3/adc->getMaxValue(ADC_0);
25-(volts-0.72)/1.7*1000
For Teensy 4 the only extra source is VREFSH, which is connected to VDD.
Library size
The library uses both program and RAM space. The exact amount depends on the Teensy used and whether optimizations were used.
The results in bytes are the respective progmem or ram of the analogRead.ino example minus that of the blinky example, the percentages are the memory used out of the total:
Teensy 3.0, 96 MHz, Serial: 5744 B (11%) program storage space and 132 B (14%) dynamic memory space used.
Teensy 3.1, 96 MHz, Serial, no optimizations: 6176 B (6%) program storage space and 136 B (3%) dynamic memory space used.
Teensy 3.1, 96 MHz, Serial, with optimizations (default): 9244 B (8%) program storage space and 1116 B (7%) dynamic memory space used.
Teensy LC, 48 MHz, Serial, no optimizations (default): 11120 B (33%) program storage space and 128 B (28%) dynamic memory space used.
Teensy LC, 48 MHz, Serial, with optimizations: 14212 B (41%) program storage space and 1112 B (53%) dynamic memory space used.
The progmem usage for Teensy LC is higher due to the use of floats (multiplying by 3.3). If possible, don't use floats at all in Teensy LC as they use about 6 kB of space (2 kB for Teenst 3.x).
Updates
Now it works with the Audio library:
Teensy 3.0 is compatible, except if you try to use the Audio library ADC input (AudioInputAnalog), because there's only one ADC module so you can't use it for two things.
Teensy 3.1 is compatible. If you want to use AudioInputAnalog and the ADC you have to use the ADC_1 module, the Audio library uses ADC_0. Any calls to functions that use ADC_0 will most likely crash the program. Note: make sure that you're using pins that ADC_1 can read (see pictures above)! Otherwise the library will try to use ADC_0 and it won't work!!
ADC library now supports Teensy LC!! Finally!
PDB is supported on both ADCs
Support for Teensy 3.5 and 3.6
New format for setReference, setSamplingSpeed, and setConversionSpeed. The information above has been updated.
Added support for pins A25, A26 in Teensy 3.5
Support for Teensy 4.
Still TODO:
See issues in GitHub.
Last edited: