3.2.2.1. ADC

Introduction

An analog-to-digital converter (abbreviated ADC) is a device that uses sampling to convert a continuous quantity to a discrete time representation in digital form.

The ADC is a 12-bit, 8-channel, general purpose ADC with a sample rate of 4 MSPS (Megasamples per second or millions of samples per second). The ADC sits idle until a Start of Conversion (SOC) pulse allows the it to start conversion. The ADC samples the analog signal when “start of conversion” signal is high and continues sampling 1 clock cycle after the falling edge. It captures the signal at the end of sampling period and starts conversion. It uses 13 clock cycles to digitize the sampled input; then an “end of conversion” signal is enabled high indicating that the digital data ADCOUT<11:0> is ready for SW to consume. A new conversion cycle can be initiated after the previous data is read. Please note that the ADC output is positive binary weighted data.

Convert Analog voltage to Digital

To cross verify the digital values read use,

D = Vin * (2^n - 1) / Vref
Where:
D = Digital value
Vin = Input voltage
n = No of bits
Vref = reference voltage

Ex: Read value on channel AIN4 for input voltage supplied 1.01:

Formula:

D = 1.01 * (2^12 -1 )/ 1.8
D = 2297.75

Accessing ADC Pins on TI EVMs

On AM64x platform, there is a 20-pin connector (J3) of part number “TSW-110-07-S-D” for connecting ADC signals. The connector includes ADC0_AIN0-7, VDDA_ADC connections and ground connections. For ADC connector (J3) Pin-Out go to the “AM64x User Guide” found here, or see the ADC schematic (PROC101A(001)_SCH) found here.


Driver Configuration

You can enable ADC driver in the kernel as follows.

Device Drivers  --->
         [*]  Industrial I/O support  --->
                  [*]  Enable buffer support within IIO
                       Analog to digital converters  --->
                               <*> TI's AM335X ADC driver

Should the entry “TI’s AM335X ADC driver” be missing the MFD component —>

Device Drivers  --->
    Multifunction device drivers  --->
        <M> TI ADC / Touch Screen chip support

Building as Loadable Kernel Module

  • In-case if you want to build the driver as module, use <M> instead of <*> during menuconfig while selecting the drivers (as shown below). For more information on compiling and installing kernel modules, refer to the Kernel User’s Guide . For more information on loadable modules refer to Loadable Module HOWTO .

Device Drivers  --->
         [M]  Industrial I/O support  --->
                  [*]  Enable buffer support within IIO
                       Analog to digital converters  --->
                               <M> TI's AM335X ADC driver
  1. Use “make modules” during kernel build to build the ADC driver as module. The module should be present in drivers/iio/adc/ti_am335x_adc.ko.

  2. The driver should autoload on filesystem boot. If not, load the driver using

modprobe ti_am335x_adc

Device Tree

ADC device tree data is added in file(arch/arm64/boot/dts/ti/am642-evm.dts) as shown below.

&tscadc0 {
         status = "okay";
         adc {
               ti,adc-channels = <0 1 2 3 4 5 6 7>;
         };
};

The parameter “ti,adc-channels” needs to hold data related to which channels you want to use for ADC; the example above is using channels CH0-CH7.

You can find the source code for ADC in the kernel sources at drivers/iio/adc/ti_am335x_adc.c.

Usage

To test ADC, Connect a DC voltage supply to each of the AIN0 through AIN7 pins (based on your channel configuration), and vary voltage between 0 and 1.8v reference voltage.

CAUTION Make sure that the voltage supplied does not cross 1.8v

On loading the module you would see the IIO device created

root@arago-armv7:~# ls -al /sys/bus/iio/devices/iio\:device0/
drwxr-xr-x    5 root     root             0 Nov  1 22:06 .
drwxr-xr-x    4 root     root             0 Nov  1 22:06 ..
drwxr-xr-x    2 root     root             0 Nov  1 22:06 buffer
-r--r--r--    1 root     root          4096 Nov  1 22:06 dev
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage0_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage1_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage2_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage3_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage4_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage5_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage6_raw
-rw-r--r--    1 root     root          4096 Nov  1 22:06 in_voltage7_raw
-r--r--r--    1 root     root          4096 Nov  1 22:06 name
lrwxrwxrwx    1 root     root             0 Nov  1 22:06 of_node -> ../../../../../../firmware/devicetree/base/ocp/tscadc@44e0d000/adc
drwxr-xr-x    2 root     root             0 Nov  1 22:06 power
drwxr-xr-x    2 root     root             0 Nov  1 22:06 scan_elements
lrwxrwxrwx    1 root     root             0 Nov  1 22:06 subsystem -> ../../../../../../bus/iio
-rw-r--r--    1 root     root          4096 Nov  1 22:06 uevent

Modes of operation

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). If one-shot mode is enabled, then the sequencer will only be scheduled one time (the sequencer HW will automatically disable the StepEnable bit after it is scheduled which will guarantee only one sample is taken per channel). When the user wants to continuously take samples, continuous mode needs to be enabled. One cannot read ADC data from one channel operating in One-shot mode and and other in continuous mode at the same time.

One-shot Mode

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

root@arago-armv7:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
645

This feature is exposed by IIO through the following files:

  • in_voltageX_raw: raw value of the channel X of the ADC

Continuous Mode

Overview

Important folders in the iio:deviceX directory are:

  • buffer

    • enable: get and set the state of the buffer

    • length: get and set the length of the buffer.

root@charlie:~# ls -l /sys/bus/iio/devices/iio\:device0/buffer/
total 0
-rw-r--r-- 1 root root 4096 Nov  3 22:53 enable
-rw-r--r-- 1 root root 4096 Nov  3 22:53 length
-rw-r--r-- 1 root root 4096 Nov  3 22:53 watermark
  • Scan_elements directory contains interfaces for elements that will be captured for a single sample set in the buffer.

root@arago-armv7:~# ls -al /sys/bus/iio/devices/iio\:device0/scan_elements/
drwxr-xr-x    2 root     root            0 Jan  1 00:00 .
drwxr-xr-x    5 root     root            0 Jan  1 00:00 ..
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage0_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage0_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage0_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage1_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage1_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage1_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage2_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage2_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage2_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage3_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage3_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage3_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage4_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage4_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage4_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage5_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage5_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage5_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage6_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage6_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage6_type
-rw-r--r--    1 root     root         4096 Jan  1 00:02 in_voltage7_en
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage7_index
-r--r--r--    1 root     root         4096 Jan  1 00:02 in_voltage7_type
root@arago-armv7:~#

scan_elements exposes 3 files per channel:

  • in_voltageX_en: is this channel enabled?

  • 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 below:

root@arago-armv7:~# cat /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage1_type
le:u12/16>>0

Where:

  • le represents the endianness, here little endian

  • u is the sign of the value returned. It could be either u (for unsigned) or s (for signed)

  • 12 is the number of relevant bits of information

  • 16 is the actual number of bits used to store the datum

  • 0 is the number of right shifts needed.


How to set it up

To read ADC data continuously we need to enable buffer and channels to be used.

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

root@arago-armv7:~# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage0_en
root@arago-armv7:~# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage5_en
root@arago-armv7:~# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage7_en

Set up the buffer length

root@arago-armv7:~# echo 100 > /sys/bus/iio/devices/iio\:device0/buffer/length

Enable the capture

root@arago-armv7:~# echo 1 > /sys/bus/iio/devices/iio\:device0/buffer/enable
Now, all the captures are exposed in the character device /dev/iio:device0

To stop the capture, just disable the buffer

root@arago-armv7:~# echo 0 > /sys/bus/iio/devices/iio\:device0/buffer/enable

Userspace Sample Application

The source code is located under kernel sources at tools/iio/iio_generic_buffer.c.

How to compile:

$ make -C <kernel-src-dir>/tools/iio ARCH=arm

The iio_generic_buffer application does all the ADC channel “enable” and “disable” actions for you. You will only need to specify the IIO driver. Application takes buffer length to use (256 in this example) and the number of iterations you want to run (3 in this example). By just enabling the buffer ADC switches to continuous mode.

root@charlie:~# ./iio_generic_buffer -?
Usage: generic_buffer [options]...
Capture, convert and output data from IIO device buffer
  -a         Auto-activate all available channels
  -A         Force-activate ALL channels
  -c <n>     Do n conversions
  -e         Disable wait for event (new data)
  -g         Use trigger-less mode
  -l <n>     Set buffer length to n samples
  --device-name -n <name>
  --device-num -N <num>
        Set device by name or number (mandatory)
  --trigger-name -t <name>
  --trigger-num -T <num>
        Set trigger by name or number
  -w <n>     Set delay between reads in us (event-less mode)

For example:-

root@charlie:~# ./iio_generic_buffer -N 0 -g -a
iio device number being used is 0
trigger-less mode selected
Enabling all channels
Enabling: in_voltage7_en
Enabling: in_voltage4_en
Enabling: in_voltage6_en
Enabling: in_voltage5_en
525.000000 924.000000 988.000000 1039.000000
754.000000 986.000000 1071.000000 1117.000000
877.000000 1067.000000 1150.000000 1169.000000
1003.000000 1143.000000 1230.000000 1226.000000
1078.000000 1222.000000 1298.000000 1286.000000
1139.000000 1286.000000 1372.000000 1343.000000
...
...
1863.000000 1954.000000 2031.000000 2074.000000
1858.000000 1959.000000 2023.000000 2083.000000
1852.000000 1958.000000 2024.000000 2076.000000
1866.000000 1964.000000 2029.000000 2083.000000
1850.000000 1952.000000 2026.000000 2074.000000
Disabling: in_voltage7_en
Disabling: in_voltage4_en
Disabling: in_voltage6_en
Disabling: in_voltage5_en

ADC Driver Limitations

This driver is based on the IIO (Industrial I/O subsystem), however this driver has limited functionality:

  1. “Out of Range” not supported by ADC driver.