IIO
Version
This section refers to the code available in Linux-3.1. Previously, I studied and commented on version 2.6.39, but the code has significantly improved since that release.
Documentation
The IIO documentation is available in the kernel staging tree at
iio/Documentation/
. The documentation provides an overview of the main
features and a quick indication of the functions to use for a rapid
test.
Documentation does not provides a full guide to writing an IIO driver; for further information you need to read the drivers already developed for IIO and use them as examples. Another source of information are the dummy files developed to understand how to write an IIO driver.
Documentation does not provide an exhaustive description of the mechanisms implement in the IIO core, buffers and triggers; again, for a deeper knowledge you need to see all the code which is not always well commented.
Device Organization
IIO is organized as two levels: device and channels.
-
device is the top level of the hierarchy and it represents the
acquisition chip. A device is described by the structures
iio_info
andiio_dev
.
-
channel is part of device; it represents a single acquisition
source of the device. A channel is described by the
iio_chan_spec structure.
IIO allocates a char device region of 256 minors; IIO assigns a minor for each device registered, so there is only one char special file for each device, so you can register a maximum of 256 devices.
The char device management use a single char device file for each device. The main purpose of this file is accessing the buffer from user space; another use is delivering events.
Aim and Features
The main purpose of IIO is providing support for analogue input devices, typically connected through I2C or SPI; there is no support at all for output signals. In this release there are no specific functionality to handle digital signals, but it is not forbidden.
Channels specificity is the focus of the IIO hierarchy and the core. Channels must have a specified type which can be only one that IIO has defined: accelerometers, inclinometers, temperature sensors, and similar well-defined use classes. These devices are usually based on SPI or I2C, and this is the main IIO target. Again, IIO builds the sysfs name with these devices in mind, so it provides modifiers for the three axis of an accelerometers or a gyroscope, or for the light of a light sensor.
I think that IIO target is not the industrial sector intended as a serious industrial setup with a complex sensors network, but only basic acquisition systems for small industrial applications or personal equipments, as well as the sensors included in atypical PC.
The functionality provided by IIO framework is aimed to create a standard interface for driver development for acquisition chips; part of this interface are triggers, buffers, events and sysfs. Events and sysfs management is integrated within the IIO core, which exports utility functions towards low-level drivers. Buffers and triggers follow the modular approach so each developer can implement his/her buffers or triggers and use them with IIO. Some buffer and trigger implementations are already developed and are available in the kernel configuration; developers with no special needs can use them.
In a context where data transfers are several mega-samples per second, it's important to have meta-information about samples. Meta-information allows a delayed analysis of the streams, and a logging activity about the acquisitions. IIO does not provide this important feature; the only meta-information exported to user space is in the so-called events which are not really useful for logging or delayed analysis.
Over Engineering
IIO sometimes suffers from over-engineering. Four examples are:
- IIO sysfs attributes accept floating point numbers in input; then
kernel can handle only integer values so IIO must convert
a float number ASCII string into two integer variables: the integral part and the fractional part. All this conversion is useless because the kernel can not handle floating point values. Only integer values should be allowed, using very fine granularity (e.g., micro-volts).
- The sysfs attribute system is centralized into IIO, it creates and destroys attributes and calculates a name for each of them. The name is calculated from the channel features by the concatenation of some suffixes and prefixes, thus can create very long names. A sysfs name should be small and it should not describe the channel features.
- each channel has 2 different indexes; one is the
scan_index
which is used to order channels in scans within a buffer (a scan is a set of channels to acquire); the other one,channel
, is the channel index on device, but if theindexed
flag is false, thenchannel
is just a numerical name. Using two indexes is generally not needed: a single index should be enough for both purposes; if a device scans its channels in a different order from channel indexes, then you should change channel indexes to meet the scan order, which is more important than channel order.
- IIO channels provide different precision formats and a function to
query the device about this; format precision is applied to the
fractional part. In my opinion, a framework should not handle these
details because it is a needless overhead for low-level drivers, the
framework itself and user-space. The precision may change among
devices, so each part of the acquisition system must handle this
possibility. With a fixed precision format, the meaning of each data
item in each part of the acquisition system is well known, so it is
easy to handle; if a different precision format is absolutely
required,
low-level drivers or user-space can change it, but not the framework.
IIO Interfaces
IIO Buffer Interface
The IIO buffer interface has three main structures:
-
*iio_buffer_setup_ops*
. They are used when a buffer instance is enabled or disabled.
-
*iio_buffer_access_funcs*
. It contains the buffer operations used to gain access to the buffer.
-
*iio_buffer*
. It is the general descriptor of a buffer. It contains the information about the buffer status, about
channels scan and the pointers to the buffer functions, both setup and access. Developers can also add here buffer specific sysfs attributes.
The IIO buffer interface provides the file operations for all the
buffers, and does not allow developers to define their own. The file
operations provided by IIO are really simple; for data transfer only
read()
function is available, and it is just a wrap function around
the buffer operation read_first_n()
, so developers when implement this
buffer operation must bear in mind that is a file operation.
read_first_n()
is effectively the read()
file operations but with a
subset of parameters, so limiting functionality and making it difficult
to recognize without reading the IIO core.
IIO does not handle buffer reference counting; it asks to the buffer
developers to implement an use counter of the buffer. IIO uses
mark_in_use()
and unmark_in_use()
from iio_buffer_access_funcs
functions to check if buffer is in use or not. IIO buffer interface does
not handle any concurrency issue and leaves them to developers of each
individual buffer implementation.
IIO does not allow users to change the buffer implementation in use; a low-level driver chooses which implementation uses and can not be changed.
The IIO buffer interface handles an individual sample or a group of
samples from different channels; such group is called a scan. The
buffer operation store_to()
accepts a single scan to store in the
buffer; the read operations read_last()
and
read_first_n()
return a single scan and n
scans, respectively.
For our purpose this buffer interface is not good. In our main case buffer handles millions of samples for second and we can not waste time on the single sample, but we need to move large amount of samples between user space and devices. Again, it is useful to have flexibility in choosing the buffer type. IIO does not currently provide such flexibility.
IIO Trigger Interface
IIO trigger interface has two main structures:
* *iio_trigger_ops*
. It is the container for the triggers functions
which are handled by IIO.
* *iio_trigger*
. It is the general descriptor of a trigger. It
contains information about trigger and a pointer to the trigger
functions. In IIO triggers are devices, so trigger implementations can
use device
functionality; for example to define trigger specific sysfs
attributes. These sysfs attributes can not be declared in iio_trigger
but developers must use device
by adding new attribute to
iio_trigger->dev->groups
* *iio_poll_func*
. It is a structure which contains the functions to
run on trigger fire.
A specific trigger can be associated to an IIO device by registering a
new trigger and set it in iio_device->trig
. A generic trigger suitable
for different IIO device should be declared as separate module; but the
IIO mechanism to associate a trigger to a device it is no intuitive, and
it can discourage developers to create independent modules for triggers.
IIO takes track of all the registered triggers to allow users to change
the current trigger through sysfs by naming it. This operation is
possible only if the IIO device has the INDIO_BUFFER_TRIGGERED
mode
enable. When the trigger implementation is an independent module, it
must provides the functions to add and remove instances of itself. A
trigger instance is the only object that an IIO device can use. The
instance management take place on user space side, so it is the user
that creates an instance and associates it to the device.
When an user tries to associate a trigger instance to an IIO device, IIO makes a double check: it verifies if trigger is compatible with the device in use, and it verifies if the device is compatible with the requested trigger; if both trigger and device are compatible, framework assigns the trigger to device.
It is not explicit, but events can be used to configure a trigger value. Event attributes have their own methods to read and write; these methods access to the value used as reference to generate the event. For example, for the threshold event the value is the threshold limit for trigger.
SYSFS Interface
In the last release IIO creates the common attributes but lefts to
developers the freedom to add their own; the IIO sysfs interface is
built on device
which creates the sysfs tree prepared by IIO.
In IIO Developers can declare their attributes for event, buffer, trigger and device, but not for channels. This can works for small chip, but acquisition boards can have many register for each channel and it is desirable that a framework allows developers to add attributes on channel level.
The attributes provided by IIO have an address
field which should be
used to set up the device register addresses correspondent to the
attributes; IIO uses the field to store the bit flag which generate the
sysfs attribute and don't allow developer to specify a valid address.
Developers are free to use address
to store a valid address, but only
for their own attributes.
IIO base its sysfs attributes interface on device
interface, so it is
not semaphored. Concurrent processes can try to change the same
attribute at the same time with unpredictable result.
Events Interface
The events interface aim is to provide events notification to user space. They are typically used to notify when trigger fires or when hardware interrupt occurs. IIO defines a few kind of events; developers can add their own.
IIO manage the events with a list. The iio_push_event()
function add a
new occurred event to the list; the function is used
by the low-level drivers. The read()
file_operations
extracts an
event from the event list with FIFO policy and copy it to user space.
The file_operations
to gain access to events are hide behind the
ioctl()
; ioctl()
calls anon_inode_get_fd()
which create a file
without an inode, so without consume minors. This choice forces users to
use specific programs to read the events.
IIO allows the driver to push events although char device file is not open; when char device file is open and it is going to be closed, IIO flush the detected events list. This is incorrect because this procedure deletes events which are not returned to user space. IIO applies two opposite policies: it allows to enqueue events when file is closed; but it flush the events list on close.
Use IIO From User Space
IIO communicate with user-space via char device and SYSFS interface. The main purpose of SYSFS interface is to configure driver options; it is also used to acquire a single sample from a device channel without buffer. Char devices are used to fetch data from a buffer and from the event list.
There is not an official user-space library for IIO programs development.
Developing a Driver
The aim of this paragraph it is not to provide a full guide to develop a driver within IIO, because each device has different features and requires different driver implementation. This is a rapid introduction for a fast test of IIO.
The minimum lines of code to get work a low-level driver with IIO,
requires to implement the IIO functions in iio_info
and an array of
iio_chan_spec
, respectively to implement the device operations and to
describe the device channels; then register the device in IIO.
For example, for a simple acquisition chip the read_raw()
implementation can be enough; this operation acquires a value from
device, so it implements the low-level communication between kernel and
device; the value can be both a configuration value or a sample, the
mask parameter specifies which value acquire. You can implement the
other operations if your driver need them. Driver specific sysfs
attributes can be also defined within iio_info->attrs
.
The IIO targets are the SPI and I2C devices, so you have to create the
driver for the bus in use and then register it. The driver method
probe()
must be used for IIO initialization and registration, and the
driver method remove()
to un-register from IIO and free data.
To register a device in IIO you have to follow the following steps in the exact order:
* allocate an iio_device
with iio_allocate_device()
.
* fill the iio_device
fields and private date if it is needed.
* configure an iio_buffer
with one of the available implementations
or your own one.
* register the configured iio_buffer
with iio_buffer_register()
* register the iio_device
with iio_device_register()
The registrations iio_buffer_register()
and iio_device_register()
must be executed in this exact order, otherwise the sysfs creation is
wrong; there is not error or message to warn you about this.
Compare with Requirements
The following table shows how the Requirements list items are supported by COMEDI.
requirements | IIO | Note |
---|---|---|
Digital/Analog I/O | no | There is no output, only analogue signals are explicit support. |
TDC and DTC | no | There is no explicit support. |
One-shot, burst, and streaming support | yes | |
Layered structure | half | The layer structure is thought for small chips, so it provides only two level: device and channels |
No hard limits on the number of bits or channels | no | The numer of devices is limited to 256 |
High-data rate, little storage overhead | no | IIO buffer interface handles data sample by sample, we need to handle very large amout of samples |
Easy and general configuration | half | Only IIO specific applications can handle events; manage trigger instanse it is not clear |
Offset, gain, number of bits, ... | no | A different set is considered "common" and does not have always the same name in each devices |
Extensibility | yes | |
Little code overhead | yes | |
Centralized semaphores | no | IIO handle semaphores only for internal use and for standard syfs attribute. Each implementations (driver, buffer, trigger) must handle with semaphores. |
Flexible buffer management | no | IIO buffer interface handles data sample by sample, we need to handle very large amout of samples |
Device-driven data transfers | yes | |
Hardware time stamps | half | IIO make assumption on timestamp; it is a 64bit signed integer which represent nanoseconds |