Search by Tags

ADC (Linux)

 

Article updated at 16 Apr 2021
Compare with Revision




Subscribe for this article updates

ADC accessibility in User Space

Apart from Colibri T20, all Toradex Computer-on-Modules use an ADC driver based on the Industrial Input/Output (iio) framework, which can be accessed through sysfs.

Depending on the module type the analog inputs are connected via different ADCs (see ADC).

In contrast to hwmon, which is directed at low sample rate sensors used to monitor and control the system itself, like fan speed control or temperature measurement, the iio framework provides support for devices that in some sense perform either analog-to-digital conversion (ADC) or digital-to-analog conversion (DAC), or both.

Access through sysfs is easy to implement since it only involves reading a regular file corresponding to a given ADC and the desired channel.

There are two ways for userspace interaction with iio drivers:

  • /sys/bus/iio/iio:deviceX/, this represents a hardware sensor and groups together the data channels of the same chip.
  • /dev/iio:deviceX, character device node interface used for buffered data transfer and for events information retrieval.

If the conversion is needed to be performed at slow rates, also called one-shot conversion, sysfs interface is used.

If Continuous conversions of a single channel at a time are required and supported by the device, the dev interface is used with sysfs.

Keep in mind that opening and closing a file for every ADC read-out is relatively slow and rather resource-intensive.

However, the internal ADCs are anyway not meant to be used for high-speed applications.

TorizonCore

Since TorizonCore, our Industrial Linux Platform, is based in our Board Support Packages (BSPs), the information provided in this article also applies to it.

Nevertheless, we recommend that your start with our article How to Use ADC on TorizonCore, which presents a step-by-step guide showing how to access the Analog-to-Digital converter interfaces within a container.

Reference Images for Yocto Project

For access to the Analog-to-Digital (ADC) interfaces in our Reference Images for Yocto Project, you can find detailed instructions in the sections below for each of our Computer-on-Modules.

General information

The ADC Linux drivers usually support two modes of performing conversations:

  • One-shot conversions performed by reading the in_voltage0_raw in_voltage3_raw files in /sys/bus/iio/devices/iio:device0/
  • Continuous conversions of a single channel at a time using the /dev/iio:device0 character device file.

When the ADC sequencer finishes cycling through all the enabled channels, the user can decide if the sequencer should stop (one-shot mode), or loop back and schedule again (continuous mode).

One-shot Mode

To read a single ADC output from a particular channel this interface can be used:

root@colibri-imx6ull:# cat /sys/bus/iio/devices/iio\:device0/in_voltageX_raw
2435

By doing this you just read one raw value of channel X of the ADC.

Continuous Mode

The single-channel continuous conversion mode converts a single channel continuously and indefinitely in regular channel conversion.

The continuous mode feature allows the ADC to work in the background.

The ADC converts the channels continuously without any intervention from the CPU. Additionally, the DMA can be used in circular mode, thus reducing the CPU load.

Warning: The Continuous mode for ADC Conversion is currently only available for Vybrid VF50 and VF61 SoMs. If you need this feature on a different SoM, please contact us at support@toradex.com.

Important folders in the iio:deviceX directory are:

  • buffer directory:
    • data_available: a read-only value indicating the bytes of data available in the buffer.
    • enable: get and set the state of the value buffer
    • length: get and set the length of the value buffer.
    • watermark: a single positive integer specifying the maximum number of scan elements to wait for.
  • scan_elements directory contains interfaces for elements that will be captured for a single sample set in the buffer:
ls -la /sys/bus/iio/devices/iio\:device0/scan_elements/
total 0
drwxr-xr-x 2 root root    0 Dec  3 01:56 .
drwxr-xr-x 6 root root    0 Dec  3 00:57 ..
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_timestamp_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_timestamp_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_timestamp_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0-voltage1_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0-voltage1_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0-voltage1_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage0_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1-voltage0_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1-voltage0_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1-voltage0_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage1_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2-voltage3_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2-voltage3_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2-voltage3_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage2_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3-voltage2_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3-voltage2_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3-voltage2_type
-rw-r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3_en
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3_index
-r--r--r-- 1 root root 4096 Dec  3 17:08 in_voltage3_type

scan_elements exposes 3 files per channel:

  • in_voltageX_en: is this channel enabled for capturing?
  • in_voltageX_index: index of this channel in the buffer's chunks
  • in_voltageX_type: How the ADC stores its data. Reading this file should return you a string something like le:u12/16>>0

Set up the channels in use (you can enable any combination of the channels you want):

# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage0_en

Set up the buffer length:

# echo 100 > /sys/bus/iio/devices/iio\:device0/buffer/length

Enable the capture:

# echo 1 > /sys/bus/iio/devices/iio\:device0/buffer/enable

Notice: For some ADCs the continuous conversion mode of the ADC driver can only enable one channel at one time or is not even supported at all. For example, for the i.MX 6ULL is a known limitation (this is explicitly mentioned in 53.3 ADC Driver Overview of i.MX Linux Reference Manual and in NXP community question).

You can also use userspace libs like iioutils/libiio. These libraries abstract the low-level details of the hardware and provide a simple yet a complete programming interface that can be used for advanced projects.

Apalis iMX6/Apalis T30/Colibri iMX6/Colibri T30

The STMPE-ADC driver is included since BSP V2.1 beta 2.

The STMPE811 supports up to 8 analog inputs, however, input 1-4 are used for the resistive touchscreen interface. The inputs are 0 indexed, so the usable inputs are 4-7.

SODIMM/MXM3 STMPE811 Input IIO device IIO channel
AN1_ADC0 IN0 iio:device0 in_voltage4_raw
AN1_ADC1 IN1 iio:device0 in_voltage5_raw
AN1_ADC2 IN2 iio:device0 in_voltage6_raw
AN1_ADC3 IN3 iio:device0 in_voltage7_raw

Note that the STMPE811 pin name IN0 goes to the ADC channel 4.

The IIO framework exposes those inputs through the sysfs interface:

# cd /sys/bus/iio/devices/device0/
# ls in*
in4_raw   in5_raw   in6_raw   in7_raw   in_scale
# cat /sys/bus/iio/devices/device0/in4_raw
755

Note: On newer kernels the IIO framework changed its file naming scheme slightly:

root@colibri-imx6:~# cd /sys/bus/iio/devices/iio\:device0/
root@colibri-imx6:/sys/bus/iio/devices/iio:device0# ls in*
in_temp8_raw      in_voltage4_raw   in_voltage5_raw   in_voltage6_raw   in_voltage7_raw   in_voltage_scale
root@colibri-imx6:/sys/bus/iio/devices/iio:device0# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
1089

Note: Since the ADC is shared with the touchscreen it's not recommended to change the ADC characteristics such as sample time.

Apalis iMX8

On Apalis iMX8 the analog to digital inputs are connected directly to the SoC. The table below shows how they are connected.

SODIMM/MXM3 NXP/Freescale Name IIO device IIO channel
AN1_ADC0 ADC0_IN0 iio:device0 in_voltage0_raw
AN1_ADC1 ADC0_IN1 iio:device0 in_voltage1_raw
AN1_ADC2 ADC0_IN2 iio:device0 in_voltage2_raw
AN1_ADC3 ADC0_IN3 iio:device0 in_voltage3_raw

Apalis iMX8X

On Apalis iMX8X the analog to digital inputs are connected directly to the SoC. The table below shows how they are connected.

SODIMM/MXM3 NXP/Freescale Name IIO device IIO channel
AN1_ADC0 ADC_IN0 iio:device0 in_voltage0_raw
AN1_ADC1 ADC_IN1 iio:device0 in_voltage1_raw
AN1_ADC2 ADC_IN4 iio:device0 in_voltage4_raw
AN1_ADC3 ADC_IN5 iio:device0 in_voltage5_raw
root@apalis-imx8x:~# cd /sys/bus/iio/devices/iio:device0
root@apalis-imx8x:/sys/bus/iio/devices/iio:device0# cat in_voltage0_raw in_voltage1_raw in_voltage4_raw in_voltage5_raw
64  # AN1_ADC0
73  # AN1_ADC1
55  # AN1_ADC2
543 # AN1_ADC3

Apalis TK1

The ADC is implemented in the K20 MCU using its internal ADC. The TK1 driver controls and reads the values through SPI from the K20.

MXM3 K20 Input IIO Device IIO Channel
AN1_ADC0 PTB0\ADC0_SE8 iio:device0 in_voltage0_raw
AN1_ADC1 PTB1\ADC0_SE9 iio:device0 in_voltage1_raw
AN1_ADC2 PTB2\ADC0_SE12 iio:device0 in_voltage2_raw
AN1_ADC3 PTB3\ADC0_SE13 iio:device0 in_voltage3_raw
# cd /sys/bus/iio/devices/iio:device0/
# ls in*
in_voltage0_raw    in_voltage0_scale  in_voltage1_raw    in_voltage1_scale  in_voltage2_raw    in_voltage2_scale  in_voltage3_raw    in_voltage3_scale
# cat /sys/bus/iio/devices/device0/in_voltage0_raw
755

Colibri iMX6ULL

On the Colibri iMX6ULL modules the AD functionality is making use of the integrated 12-Bit ADC peripheral of the i.MX 6ULL SoC.

SODIMM i.MX 6ULL ADC IIO device IIO channel
ANALOG_IN0 ADC1_IN0 iio:device0 in_voltage0_raw
ANALOG_IN1 ADC1_IN1 iio:device0 in_voltage1_raw
ANALOG_IN2 ADC1_IN8 iio:device0 in_voltage8_raw
ANALOG_IN3 ADC1_IN9 iio:device0 in_voltage9_raw
root@colibri-imx6ull:~# cd /sys/bus/iio/devices/iio\:device0
root@colibri-imx6ull:/sys/bus/iio/devices/iio:device0# ls
dev                            in_voltage9_raw
in_voltage0_raw                in_voltage_sampling_frequency                    
in_voltage1_raw                in_voltage_scale
in_voltage2_raw                name
in_voltage3_raw                of_node
in_voltage4_raw                power
in_voltage5_raw                sampling_frequency_available
in_voltage6_raw                subsystem
in_voltage7_raw                uevent
in_voltage8_raw
root@colibri-imx6ull:/sys/bus/iio/devices/iio:device0# cat in_voltage0_raw in_voltage1_raw in_voltage8_raw in_voltage9_raw
3978
3970
3985
11

The following table lists the software interfaces of the ADC driver. To get raw ADC data:

# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw

To get available sample rate group:

# cat /sys/bus/iio/devices/iio\:device0/sampling_frequency_available

To show/set the sample rate:

# cat /sys/bus/iio/devices/iio\:device0/in_voltage_sampling_frequency
# echo value > /sys/bus/iio/devices/iio\:device0/in_voltage_sampling_frequency

Colibri iMX7

On the Colibri iMX7 modules the AD functionality is making use of the integrated 12-Bit ADC peripheral of the i.MX 7 SoC.

SODIMM i.MX 7 ADC IIO device IIO channel
ANALOG_IN0 ADC1_IN0 iio:device0 in_voltage0_raw
ANALOG_IN1 ADC1_IN1 iio:device0 in_voltage1_raw
ANALOG_IN2 ADC1_IN2 iio:device0 in_voltage2_raw
ANALOG_IN3 ADC1_IN3 iio:device0 in_voltage3_raw

Note: The ADC channels are only 1.8V capable! This is a limitation of the i.MX 7 SoC.

root@colibri-imx7:~# cd /sys/bus/iio/devices/iio\:device0/
root@colibriimx7:/sys/bus/iio/devices/iio:device0# ls
dev               in_voltage12_raw  in_voltage1_raw  in_voltage5_raw  in_voltage9_raw                of_node
in_voltage0_raw   in_voltage13_raw  in_voltage2_raw  in_voltage6_raw  in_voltage_sampling_frequency  power
in_voltage10_raw  in_voltage14_raw  in_voltage3_raw  in_voltage7_raw  in_voltage_scale               subsystem
in_voltage11_raw  in_voltage15_raw  in_voltage4_raw  in_voltage8_raw  name                           uevent
root@colibriimx7:/sys/bus/iio/devices/iio:device0# cat in_voltage0_raw in_voltage1_raw in_voltage2_raw in_voltage3_raw
1860
3057
3050
3735

Colibri iMX8X

SODIMM NXP/Freescale Name IIO device IIO channel
ANALOG_IN0 ADMA_ADC_IN1 iio:device0 in_voltage0_raw
ANALOG_IN1 ADMA_ADC_IN2 iio:device0 in_voltage1_raw
ANALOG_IN2 ADMA_ADC_IN4 iio:device0 in_voltage4_raw
ANALOG_IN3 ADMA_ADC_IN5 iio:device0 in_voltage5_raw

Colibri T20

On the Colibri T20 the WM9715 supports ADC read-out through the battery driver. Currently, only AD0 and AD1 are supported.

root@colibri_t20:~# cat /sys/class/power_supply/colibri_t20-analog_inputs/voltage_now
4095

root@colibri_t20:~# cat /sys/class/power_supply/colibri_t20-analog_inputs/temp
1044

Colibri VFxx

On the Colibri VFxx modules, the AD functionality is making use of the two integrated 12-Bit ADC peripherals of the Vybrid SoC.

SODIMM Vybrid ADC IIO device IIO channel
ANALOG_IN0 ADC0, Channel 8 iio:device0 in_voltage8_raw
ANALOG_IN1 ADC1, Channel 8 iio:device1 in_voltage8_raw
ANALOG_IN2 ADC0, Channel 9 iio:device0 in_voltage9_raw
ANALOG_IN3 ADC1, Channel 9 iio:device1 in_voltage9_raw

These four analog inputs are compatible within the Colibri family and are dedicated ADC inputs. Additional some of the GPIO capable pins on the SODIMM connector feature with alternative function ADC capability. The ADC function of these pins is not compatible with other Colibri modules. It should be noted, that the noise level on these pins might be higher than on the dedicated ADC input signals, as these are routed as digital signals on the module.

For BSP versions 2.3 Beta3 and earlier, the driver is called mvf-adc and supports access through a character device only. We created a test program to show how the driver can be used, see adc-test.c.

Starting with BSP versions 2.3 Beta5, the vf610_adc driver makes use of the Industrial Input/Output (IIO) framework. The IIO framework exposes the ADC channels through the sysfs interface. The inputs are indexed through 0 to 15 with the channels 8 and 9 for ADC0 and ADC1 being usable by default. The ADC peripherals also include an internal temperature sensor. The readout of them is given by in_temp_input in degree celsius times 1000.

root@colibri-vf:~# cd /sys/bus/iio/devices/iio\:device0
root@colibri-vf:/sys/bus/iio/devices/iio:device0# ls
dev                            in_voltage5_raw
in_temp_input                  in_voltage6_raw
in_voltage0_raw                in_voltage7_raw
in_voltage10_raw               in_voltage8_raw
in_voltage11_raw               in_voltage9_raw
in_voltage12_raw               in_voltage_sampling_frequency
in_voltage13_raw               in_voltage_scale
in_voltage14_raw               name
in_voltage15_raw               power
in_voltage1_raw                sampling_frequency_available
in_voltage2_raw                subsystem
in_voltage3_raw                uevent
in_voltage4_raw
root@colibri-vf:/sys/bus/iio/devices/iio:device0# cat in_temp_input 
41304
root@colibri-vf:/sys/bus/iio/devices/iio:device0# cat in_voltage8_raw 
1377
root@colibri-vf:~# cd /sys/bus/iio/devices/iio\:device1
root@colibri-vf:/sys/bus/iio/devices/iio:device1# cat in_temp_input 
40760
root@colibri-vf:/sys/bus/iio/devices/iio:device1# cat in_voltage9_raw 
4035

Continuous Sampling

Vybrid provides support for continuous sampling with its ADC peripheral. Currently, only software triggers are supported, they are accessible through sysfs. The necessary driver support is available with version 2.6 Beta1 and above. The 2.6 Beta1 release image is missing the sysfs trigger configuration option (CONFIG_IIO_SYSFS_TRIGGER) and hence requires a custom kernel build.

root@colibri-vf:~# cd /sys/bus/iio/devices/
root@colibri-vf:/sys/bus/iio/devices# ls
iio:device0        iio:device1        iio_sysfs_trigger
root@colibri-vf:/sys/bus/iio/devices# cd iio:device0
root@colibri-vf:/sys/bus/iio/devices/iio:device0# ls
buffer                         in_voltage13_raw               in_voltage6_raw                power
dev                            in_voltage14_raw               in_voltage7_raw                sampling_frequency_available
in_conversion_mode             in_voltage15_raw               in_voltage8_raw                scan_elements
in_temp_input                  in_voltage1_raw                in_voltage9_raw                subsystem
in_voltage0_raw                in_voltage2_raw                in_voltage_sampling_frequency  trigger
in_voltage10_raw               in_voltage3_raw                in_voltage_scale               uevent
in_voltage11_raw               in_voltage4_raw                name
in_voltage12_raw               in_voltage5_raw                of_node

The generic buffer code present in the Linux kernel source tree can be used to test the continuous sampling functionality.

root@colibri-vf:~# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_temp_en
root@colibri-vf:~# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_timestamp_en
root@colibri-vf:~# echo 0 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
root@colibri-vf:~# ./generic_buffer -n 4003b000.adc -t sysfstrig0 -l 512 -c 1                                              
iio device number being used is 0
iio trigger number being used is 0
/sys/bus/iio/devices/iio:device0 sysfstrig0
835.000000 1463058211407519734 
835.000000 1463058211407532489 
834.000000 1463058211407542708 
835.000000 1463058211407556933 
835.000000 1463058211407572004 
835.000000 1463058211407587044 
836.000000 1463058211407601449 
835.000000 1463058211407615464 
835.000000 1463058211407629923 
835.000000 1463058211407644663 
835.000000 1463058211407659362 
835.000000 1463058211407674031 
836.000000 1463058211407688639 
835.000000 1463058211407703164 
835.000000 1463058211407717683 
834.000000 1463058211407731968 
root@colibri-vf:~# echo 0 > /sys/bus/iio/devices/iio:device0/scan_elements/in_timestamp_en
root@colibri-vf:~# echo 0 > /sys/bus/iio/devices/iio:device0/scan_elements/in_temp_en
root@colibri-vf:~# echo 0 > /sys/bus/iio/devices/iio_sysfs_trigger/remove_trigger

Verdin iMX8M Mini/Plus

The ADC functionality is implemented using an on-module TI TLA2024 ADC chip. TI TLA2024 ADC datasheet

The following interconnection is available on the Verdin Development Board V1.1A.

SODIMM ADC input IIO Device IIO Channel Sampling Rate
ADC_1 AIN0 iio:device0 in_voltage3_raw in_voltage3_sampling_frequency
ADC_2 AIN1 iio:device0 in_voltage2_raw in_voltage2_sampling_frequency
ADC_3 AIN2 iio:device0 in_voltage1_raw in_voltage1_sampling_frequency
ADC_4 AIN3 iio:device0 in_voltage0_raw in_voltage0_sampling_frequency

The following ADC nodes are available in sysfs:

root@verdin-imx8mm:~# cd /sys/bus/iio/devices/iio\:device0/

root@verdin-imx8mm:/sys/bus/iio/devices/iio:device0# ls in*
in_voltage0-voltage1_raw                 in_voltage0_scale                        in_voltage2-voltage3_sampling_frequency
in_voltage0-voltage1_sampling_frequency  in_voltage1-voltage3_raw                 in_voltage2-voltage3_scale
in_voltage0-voltage1_scale               in_voltage1-voltage3_sampling_frequency  in_voltage2_raw
in_voltage0-voltage3_raw                 in_voltage1-voltage3_scale               in_voltage2_sampling_frequency
in_voltage0-voltage3_sampling_frequency  in_voltage1_raw                          in_voltage2_scale
in_voltage0-voltage3_scale               in_voltage1_sampling_frequency           in_voltage3_raw
in_voltage0_raw                          in_voltage1_scale                        in_voltage3_sampling_frequency
in_voltage0_sampling_frequency           in_voltage2-voltage3_raw                 in_voltage3_scale

The following sampling frequencies are available:

root@verdin-imx8mm:/sys/bus/iio/devices/iio:device0# cat /sys/bus/iio/devices/iio\:device0/sampling_frequency_available
128 250 490 920 1600 2400 3300

The default sampling frequency is 1600 samples per second. The rate may be changed for each channel individually:

echo 128 > /sys/bus/iio/devices/iio:device0/in_voltage1_sampling_frequency
echo 489 > /sys/bus/iio/devices/iio:device0/in_voltage2_sampling_frequency
echo 3300 > /sys/bus/iio/devices/iio:device0/in_voltage3_sampling_frequency

Reading ADC channel:

root@verdin-imx8mp:~# cat /sys/bus/iio/devices/iio:device0/in_voltage3_raw  
1799
root@verdin-imx8mp:~# cat /sys/bus/iio/devices/iio:device0/in_voltage2_raw                                                                                                                                          
0
root@verdin-imx8mp:~# cat /sys/bus/iio/devices/iio:device0/in_voltage1_raw                                                                                                                                          
285
root@verdin-imx8mp:~# cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw                                                                                                                                          
288