Achievement unlocked: First IIO driver

I just completed my first IIO driver for Hoperf TH06 humidity and temperature sensor. Within this post I will explain how to connect the sensor to the PC, I will reveal the mysteries of reading a datasheet and I will present the anatomy of an IIO driver. Stay tuned !

The Hardware:

Meet TH06:

TH06 is a humidity an temperature sensor. The first image emphasises the hardware logic performing the measurements and the second image shows the available pins.

TH06 communicates on an I2C interface. I2C is popular multi-master, multi-slave bus protocol used to connect lower speed peripherals to a processor. It uses two bidirectional lines: one for data (SDA – serial data line) and one for clock (SCL – serial clock line). The second image shows the above mentioned pins plus the pins for power supply (VDD) and ground (GND).

The computer does not have an I2C interface to directly receive input from the sensor so an additional device will be used. The Diolan, shown in the next image, makes the conversion from I2C protocol to USB and enhances communication between the sensor and the PC.


The Diolan is connected to the PC by an USB cable and the sensor is connected to the I2C interface of the Diolan via standard wires with labelled heads:


The complete assembly looks like this:


When connecting the Diolan to the PC, the kernel will log the discovery of a new USB device:

$ dmesg | tail -5
[ 3339.902024] usb 3-2: new full-speed USB device number 2 using xhci_hcd
[ 3340.031671] usb 3-2: New USB device found, idVendor=a257, idProduct=2013
[ 3340.031682] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 3340.031687] usb 3-2: Product: Diolan DLN2
[ 3340.031692] usb 3-2: Manufacturer: Diolan

But we will not test the driver directly on the PC, but on the virtual machine. So we have to make sure that the virtual machine’s kernel includes the settings for the Diolan. For this, at make menuconfig search for the keywords Diolan and DLN2 and select all options that show up as results. Recompile.

Also, we have to “announce” the virtual machine of the presence of the sensor as  a new I2C device. For this, we will use the I2C interface provided by the operating system /sys/bus/i2c/ to set the name and the register address of the new device. This configuration is available until the VM is closed so I suggest writing it in the qemu/fsimg/etc/rcS file to be done each time when is started. At the end of the file, add the following line:

echo th06 0x40 > /sys/bus/i2c/devices/i2c-0/new_device

If you have done this settings correctly, at boot time, you should see the following output:

diolan and sensor2


The Driver:

Before writing a driver you must read the datasheet of the device to see how to send / receive data and commands to / from it. For TH06, the datasheet provides the following information:

TH06 provides a 7-bit configuration register placed at address 0x40 and a series of  supported commands for performing measurements, reset, configuration etc. (Page 16). Also, the sensor measurements return some raw values so, to obtain a more human-readable values, the datasheet provides a couple of formulas for data processing (Pages 19, 2o).

The driver for TH06 registers the sensor as an I2C client and uses the I2C API for sending data via I2C bus.

When loading the driver into the kernel, devices on the I2C bus are enumerated in search of the one referred by the driver. The logical link between the physical device and the driver is done by a name identification: for this, we must set an id that must be identical with the sensor name declared in /sys/bus/i2c.

static const struct i2c_device_id th06_id[] = {
    {“th06”, 0},

Firstly, the driver declares the device’s channels: there are two channels – IIO_HUMIDITYRELATIVE and IIO_TEMP – both providing 3 descriptive values: the raw data, the scale and the offset.

The driver implements the device registration in function probe, called when the I2C bus matches the I2C device with the driver and function read_raw to be called when a measurement is triggered from userspace.

Function read_raw checks the requested channel and then analyses which is the requested information from that channel. If the raw information is requested, the driver triggers a relative-humidity/temperature measurement using the appropriate command TH06_READ_RH/TH06_READ_TEMP and the I2C API function i2c_smbus_read_word_swapped to read 16 bits from the sensor.

The scale and the offset are precalculated from the formulas from the datasheet and returned as 2 values (characteristic and mantissa) because the kernel does not provide a floating point unit.

When the driver is inserted into the kernel, an associated entry in /sys/bus/i2c is available:

i2c dev

The files in_temp_* and in_humidityrelative_* are associated with the channels I have declared within the driver. Reading them will call the declared function read_raw.

dev read

The driver is sent to the linux-iio maintainers for review. Wish me good luck ! 🙂


2 thoughts on “Achievement unlocked: First IIO driver

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s