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 and iio_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 the indexed flag is false, then channel 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