Use of the AT91 ADC driver
This is the description of the Microchip AT91 ADC driver. It is used for SoC based on ARM9 cores and SAMA5D3 and SAMA5D4. This driver uses the Industrial Input/Output (IIO) subsystem.
For description of the newer ADC driver for SAMA5D2 SoC and onwards, please refer to the dedicated page:
Using the SAMA5D2-compatible ADC device .
Documentation for this Linux subsystem is available in the kernel source code directory:
drivers/staging/iio/Documentation/
.
You can have a look at this documentation inline:
overview.txt.
Get the Linux kernel
The driver has been included in the Linux kernel 3.5 release, and support the AT91SAM9G20-EK, AT91SAM9M10G45 and AT91SAM9x5 boards at that time.
The first step is to get the Linux kernel:
wget http://www.kernel.org/pub/linux/kernel/v3.x/linux-3.5.tar.bz2
tar xvjf linux-3.5.tar.bz2
cd linux-3.5
Configure and Build the Linux kernel
Firstly, use your default kernel configuration:
make ARCH=arm at91sam9xxxx_defconfig
You can enable the AT91 IIO ADC driver by enabling the symbol
CONFIG_AT91_ADC
or using the Linux kernel configuration interface:
make ARCH=arm menuconfig
Device Drivers --->
<*> Industrial I/O support --->
Analog to digital converters --->
<M> Atmel AT91 ADC
-*- Enable buffer support within IIO
<*> Industrial I/O buffering based on kfifo
-*- Enable triggered sampling support
(2) Maximum number of consumers per trigger (NEW)
note that you can also build this device driver into the kernel itself (not as a module).
Build the Linux kernel image:
make ARCH=arm CROSS_COMPILE=<path_to_cross-compiler/cross-compiler-prefix->
path_to_cross-compiler is only needed if it is not in your PATH.
Usually
cross-compiler-prefix- looks like
arm-linux-
,
arm-elf-
or
arm-none-linux-gnueabi-
.
To produce a kernel image suitable for U-Boot:
mkimage -A arm -O linux -C none -T kernel -a 20008000 -e 20008000 -n linux-2.6 -d arch/arm/boot/zImage uImage.bin
Load ADC driver
If the driver isn't already loaded or directly compiled into your running kernel, you can use it as a module.
Check if your ADC driver is already available by using this command:
# dmesg | grep iio
[ 2.450000] iio iio:device0: Resolution used: 10 bits
[ 2.450000] iio iio:device0: ADC Touch screen is disabled.
So you can skip this setup about modules.
If the insertion of the module is needed, this driver's name is
at91_adc
, so you can load it simply using
modprobe at91_adc
or
insmod ./at91_adc.ko
root@at91sam9g20ek:~# insmod /lib/modules/3.5.0/kernel/drivers/iio/adc/at91_adc.ko
Loading the module should have created a sysfs directory in
/sys/bus/iio/devices/iio:deviceN
, N being between 0 and 255. It is most likely to be 0, but you can be sure by looking into the name file in that directory.
root@at91sam9g20ek:~# ls -l /sys/bus/iio/devices/iio\:device0/
drwxr-xr-x 2 root root 0 Mar 10 02:24 buffer
-r--r--r-- 1 root root 4096 Mar 10 02:24 dev
-r--r--r-- 1 root root 4096 Mar 10 02:24 in_voltage0_raw
-r--r--r-- 1 root root 4096 Mar 10 02:24 in_voltage1_raw
-r--r--r-- 1 root root 4096 Mar 10 02:24 in_voltage2_raw
-r--r--r-- 1 root root 4096 Mar 10 02:24 in_voltage3_raw
-rw-r--r-- 1 root root 4096 Mar 10 02:24 in_voltage_scale
-r--r--r-- 1 root root 4096 Mar 10 02:24 name
drwxr-xr-x 2 root root 0 Mar 10 02:24 power
drwxr-xr-x 2 root root 0 Mar 10 02:24 scan_elements
lrwxrwxrwx 1 root root 0 Mar 10 02:24 subsystem -> ../../../../bus/iio
drwxr-xr-x 2 root root 0 Mar 10 02:24 trigger
-rw-r--r-- 1 root root 4096 Mar 10 02:24 uevent
If you have devtmpfs, it will also have created an
iio:deviceN
file under
/dev
.
Software triggers are an ADC operating mode where the software starts the conversion.
This feature is exposed by IIO through the following files:
-
in_voltageX_raw
: raw value of the channel X of the ADC
-
in_voltage_scale
: value you have to multiply in_voltageX_raw with to have a value in microvolts
Reading into
in_voltageX_raw
will perform a software trigger on the ADC, then block until the conversion is completed, and finally return the value of this conversion.
Please note that conversions are done one channel at a time.
Here is the output on the AT91SAM9 console that shows an ADC measure when a
3V
DC power supply is connected between analog ground
AGND
and ADC input 0
AD0
pins:
root@at91sam9g20ek:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
948
root@at91sam9g20ek:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale
3222.000000
We can calculate the result:
948 x 3222
=
3.0V
Hardware triggers are an operating mode of the ADC where conversions are no longer triggered by the software but directly by the hardware.
For the G20, you have two types of hardware triggers, either timer counters are the trigger for the conversion, either an external pin is used to provide such an input.
In either case, the conversion is started on rising edges.
Please note that the setup of the timer counters in themselves is not achieved by this driver, so you will have to do it yourself. However, some dummy example of how to setup the timer-counter-0 is attached to this page.
API
IIO configuration of hardware triggers is also done through sysfs.
Important folders in the
iio:deviceX
directory are:
-
buffer
-
trigger
-
scan_elements
The buffer directory contains 3 files:
-
enabled
: get and set the state of the buffer
-
length
: get and set the length of the buffer.
The trigger directory contains only one file, current_trigger, that reports and get the trigger in use with the driver.
It also refers to the
triggerX
directories in
/sys/bus/iio/devices/
Finally, 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 weird looking string. How to interpret it is explained in the Going Further section
It also contains the same information for the timestamp, under the
in_timestamp_*
files.
How to set it up
Basically, what you should do for launching the hardware triggers is :
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
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage1_en
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage2_en
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage3_en
Set up the trigger we want to use (it must be the name of one of the triggers present in
iio/devices
).
With device tree, name of the device may change to some form like "fc034000.adc" instead of simply "at91_adc": the
name
sysfs file is there to inform you
# echo "at91_adc-dev0-external" > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
or
# echo "fc034000.adc-dev0-continuous" > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
for instance.
Set up the buffer length (Maximum number of data kept in the buffer, if we reach this number, the older data will be dropped)
# echo 100 > /sys/bus/iio/devices/iio:device0/buffer/length
Enable the capture
# echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
#
Now, all the captures are exposed in the character device /dev/iio:device0, with the following format
|
|
8 bytes |
8 bytes |
Chan 0 |
Chan 1 |
Chan 2 |
Chan 3 |
Timestamp |
2 bytes |
2 bytes |
2 bytes |
2 bytes |
|
|
|
This means that you can
poll()
or
select()
on it to wait for data to arrive, and get them by reading the file, just like you would do with any other file.
And to stop the capture, just disable the buffer
# echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
Testing the buffer
In the IIO documentation there is a tool that allows to do quick tests on the buffer from the command-line. The source code is located in
drivers/staging/iio/Documentation/generic_buffer.c
.
First, we need to compile it
arm-linux-gnueabi-gcc --static generic_buffer.c -o generic_buffer
or
<path_to_cross-compiler/cross-compiler-prefix->-gcc --static generic_buffer.c -o generic_buffer
Then copy the
generic_buffer
program on your board.
Below is an example of how to use this tool :
First, load the driver:
# modprobe at91_adc
Then enable the channels:
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage0_en
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage1_en
# echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage3_en
Finally, the
generic_buffer
tool does all the "enable" and "disable" actions for you.
You will only need to specify the IIO driver and the trigger you want to use (
at91_adc
and
at91_adc-dev0-external
respectively or
fc034000.adc
and
fc034000.adc-dev0-external
respectively).
You can also specify the buffer length to use (
2
in this example). The default value is
128
.
# ./generic_buffer -n at91_adc -t at91_adc-dev0-external -l 2
iio device number being used is 0
iio trigger number being used is 3
/sys/bus/iio/devices/iio:device0 at91_adc-dev0-external
7.000000 239.000000 71.000000 480890114100
7.000000 238.000000 72.000000 8365721275892
or with a device tree system:
With device tree, name of the device may change to some form like "fc034000.adc" instead of simply "at91_adc": the
name
sysfs file is there to inform you
# ./generic_buffer -n fc034000.adc -t fc034000.adc-dev0-external -l 2
iio device number being used is 0
iio trigger number being used is 3
/sys/bus/iio/devices/iio:device0 fc034000.adc-dev0-external
7.000000 239.000000 71.000000 480890114100
7.000000 238.000000 72.000000 8365721275892
While running, it displays values that are stored in the buffer. So using the setup above, we have the following trace:
|
|
|
Channel 0 |
Channel 1 |
Channel 3 |
Timestamp |
Sample 1 |
7 |
239 |
71 |
480890114100 |
Sample 2 |
7 |
238 |
72 |
8365721275892 |
|
|
|
Understanding the in_voltageX_type file
Reading the
in_voltageX_type
file should return you something like:
le:u10/16>>0
-
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)
-
10
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.
Pin Muxing
By default, all the pins required by the ADC are multiplexed as ADC outputs as soon as you enable it. However, you might want to change that.
You can do so by modifying the platform_data structure.
The definition of this structure resides in the file
include/linux/platform_data/at91_adc.h
, and the values are filled in the board files (for example
arch/arm/mach-at91/board-at91sam9g20ek.c
for the SAM9G20-EK board).
The important fields of that structure for the multiplexing are :
-
channels_used
: it is a bitmask of the channels available on the board. Every bit is a boolean to use or not the corresponding channel. For example, the SAM9G20-EK board has 4 ADC channels, so the default value is BIT(0) | BIT(1) | BIT(2) | BIT(3)
. If you just want the two first channels, just put BIT(0) | BIT(1)
instead. The pins for the two last channels won't be multiplexed as ADC outputs, and the channels won't be available in the driver.
-
use_external
: it is just a boolean. Just set it to true
or false
whether you want the pin corresponding to the external trigger multiplexed as trigger inputs or not. Of course, if you set it to false
here, all the triggers relying on this pin won't be available to the driver.
It seems that I do not have proper accuracy using AT91SAM9G20-EK ADC?
A: The ADC accuracy is given by the
Electrical Characteristics chapter in the product datasheet.
It has been observed on the AT91SAM9G20-EK that the ADC reference seems not stable enough. We recommend to remove the 0Ohm
R21
resistor and provide an external
3.3V
reference voltage source using
ADVREF
/
VREFP
(
J24
pin 38).
On Sama5d3 Xplained board, I get timeout when I try to convert the channels.
A: The ACT8865 PMIC was not properly initialized, and because of that VDDANA is not configured. According to the errata of the Sama5d3 Xplained board, resistors R177 and R178 need to be removed such that I2C communication with the PMIC works properly.