Bosch SMI240 IIO driver

1. Overview

The driver is intended to work on Bosch SMI240 Inertial Measurement Unit for Non-Safety Automotive Applications. The SMI240 is a combined three axis angular rate and three axis acceleration sensor module with a measurement range of +/-300°/s and up to 16g. SMI240 is a 6 DoF (Degrees of Freedom) sensor module providing acceleration and angular rate signals via a digital interface (SPI). The sensor consists of two Micro Electro Mechanical System (MEMS) elements and a sensor readoutASIC. The ASIC contains analogue front ends and a digital structure for signal processing and communication interface. The sensor module is available in a LGA (Land Grid Array) housing.

2. Hardware Setup

Important

This Hardware Setup serves as a quick startup kit, to help the user to run and understand the driver. It is for demonstration purposes, not supposed to be used in a production environment.

2.1 Hardware Components:

  1. Linux Host Board

  2. SMI240 sensor + Shuttleboard + Motherboard (acquirable from Bosch)

  3. connection cable (female to female)

  4. A micro SD card (if required by the host board)

2.2 Jumpers on the mother board

We need to change the default Jumpers.

  • Remove the jumper “Connection VDDIO” and put this jumper to connect “VDD” and “VDDIO”

Make sure that

  • Both BUS_ID_0 and BUS_ID_1 are connected to GND

2.3 Cable Connection

 .................................                      .................................
.?^^^^^^^^^^~~~~~~~~^^^^^^^^^^^^^~?       VDD          !!^^^^^^^^^~~~~~~~~~~~~~~^^^^^^^^7~
:?          Host Board            Y~~~~~~~~~~~~~~~~~~~~J~ 1    SMI240 Mother Board      !!
:?                               .J      VDDIO         ?^                               !~
:?                               .Y~~~~~~~~~~~~~~~~~~~~J^ 2                             !~
:?                               .J                    7^                               !~
:?                               .J       GND          7^                               !~
:?                               .Y~~~~~~~~~~~~~~~~~~~~J~ 3                             !~
:?                               .J       MISO         ?^                               !~
:?                               .Y~~~~~~~~~~~~~~~~~~~~J~ 4                             !~
:?                               .Y       MOSI         J~                               !~
:?                               .J~~~~~~~~~~~~~~~~~~~~?~ 5                             !~
:?                               .Y       SLK          J~                               !~
:?                               .Y~~~~~~~~~~~~~~~~~~~~J~ 6                             !~
:?                               .J       CSB          7^                               !~
:?                               .J~~~~~~~~~~~~~~~~~~~~7^ 7                             !~
:?                               .J                    7^                               !~
:?                               .J                    7^                               !~
:?                               .J                    7^                      BUS_ID_0 !~~GND
:?                               .Y                    J^                               !~
:?                               .J                    ?^                      BUS_ID_1 !~~GND
:?                                Y                    J^                               !~
:J...............................:J                    7~...............................7~
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                    :^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^.

SMI240 Shuttle Pin

Function

1

VDD

2

VDD IO

3

GND

4

MISO

5

MOSI

6

SCLK

7

CSB

2.4 First Startup

  1. Write Linux Image (32 bit) to SD Card

  2. Insert SD Card Host Board and power on

  3. Enable SSH on Host Board

3. Software Setup

This example is based on a Raspberry Pi 3. If you are using a different host board, the steps are slightly different.

3.1 Required Software

  1. Raspberry Pi 3 as host board (tested Linux kernel versions 6.1.21 and 6.6)

  2. SMI240 IIO Linux driver https://github.com/boschmemssolutions/SMI240-Linux-Driver-IIO

  3. Linux development environment (native or as VM)

Hint

Most board manufacturer provides customized Linux distribution for their boards. Consult with your board manufacturer. And download the Linux distribution for your board, if available.

Note

We do not recommend to build the driver with Linux kernel directly on host board. This takes too long. Build it on PC is much faster. Since the toolchain is Linux based, a Linux environment is required. We use Ubuntu 22.04.5 LTS

  • Install Toolchain and dependences

sudo apt install crossbuild-essential-armhf
sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
  • Clone Linux kernel

git clone --depth=1 --branch <branch_name> https://github.com/raspberrypi/linux

We use kernel v6.6, replace <branch_name> with “rpi-6.6.y”

  • Clone SMI240 IIO Linux driver

git clone --depth=1  https://github.com/boschmemssolutions/SMI240-Linux-Driver-IIO.git

3.2 Build SMI240 IIO Linux driver

Integrate Linux driver into Linux kernel

  • Copy source code into Linux kernel

cp /smi240-linux-driver-iio/drivers/iio/imu/smi240 linux/drivers/iio/imu
  • Add entry in imu Kconfig

Open linux/drivers/iio/imu/Kconfig and add the SMI240 entry at bottom

source "drivers/iio/imu/.../Kconfig"
source "drivers/iio/imu/smi240/Kconfig"
source "drivers/iio/imu/.../Kconfig"
  • Add entry in imu Makefile

Open linux/drivers/iio/accel/Makefile and add the SMI240 entry at bottom

obj-y += smi240/
obj-y += s.../
  • Add devicetree overlay

Create a devicetree overlay file “smi240-spi-overlay.dts” with the following content, and put it under “linux/arch/arm/boot/dts/overlays”

Note

Dependent on your hardware plattform and pin layout, the settings may be diffrent and an adaption to your target system may be required.

/dts-v1/;
/plugin/;

        / {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&spidev0>;
                __dormant__ {
                        status = "disabled";
                };
        };

        fragment@1 {
                target = <&spidev1>;
                __dormant__ {
                        status = "disabled";
                };
        };

        fragment@2 {
                target = <&spi0>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        smi240@0 {
                                compatible = "bosch,smi240";
                                spi-max-frequency = <10000000>;
                                reg = <0>;
                        };
                };
        };

        __overrides__ {
                smi240 = <0>, "=0=2";
        };
};
  • Add entry in devicetree overlay Makefile

dtbo-$(CONFIG_ARCH_BCM2835) += \
    ... \
    smi240-spi.dtbo \
    ... \

Build SMI240 Linux driver with the kernel

  • Config SMI240 Linux driver

cd linux
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

Activate the options as following

Hint

To activate an option, press “y” on the option. A * appears, which means this option is activated as part of the kernel. Alternatively we can press “m” on the option. A “M” appears, which means this option is activated as kernel module (not as part of the kernel). Therefore we need to manually install the kernel module by ourself.

Device Drivers -->
      <*>Industrial I/O support  --->
              Inertial measurement units  --->
                      <*> Bosch Sensor SMI240 Inertial Measurement Unit
  • Build SMI240 Linux driver

make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs

Note

Build process takes quite long on the first time. To reduce the build time, we use the option “-j4”. This is the option to enable the build process to be executed parallelly in 4 threads. To improve the parallel execution, just give a big number e.g. “-j6”. How many parallel thread to use is dependent on your processor core number.

  • Install the kernel with SMI240 Linux driver in SD card

insert the SD card (created in 2.3). A “bootfs” partition and a “rootfs” partition will be mounted. Find out the mount point. In Ubuntu the mount point looks like that

/media/username/bootfs

/media/username/rootfs

write the kernel with SMI240 Linux driver in SD card

export KERNEL=kernel7
export SD_BOOT_PATH=/media/username/bootfs
export SD_ROOTFS_PATH=/media/username/rootfs
sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=$SD_ROOTFS_PATH modules_install
sudo cp $SD_BOOT_PATH/$KERNEL.img $SD_BOOT_PATH/$KERNEL-backup.img
sudo cp arch/arm/boot/zImage $SD_BOOT_PATH/$KERNEL.img
sudo cp arch/arm/boot/dts/*.dtb $SD_BOOT_PATH
sudo cp arch/arm/boot/dts/overlays/*.dtb* $SD_BOOT_PATH/overlays/
sudo cp arch/arm/boot/dts/overlays/README $SD_BOOT_PATH/overlays/
  • adapt the boot configuraion

open the “config.txt” in “bootfs” partition, and add the following entries

# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=spi=on
dtoverlay=smi240-spi,smi240

Take the SD card out and put it back in board.

4. Work with SMI240 Linux driver

4.1 Preparation

Power on the board. If the driver was installed properly, a folder will be created. A number of devicefiles are created in the folders, which we can use to read/write data from/to the sensor

/sys/bus/iio/devices/iio:device0

Note

Folder name is assigned automatically by the system, therefore does not reflect the sensor type. There is a “name” file in the devicefolder, that we can read to find out the sensor type

cd /sys/bus/iio/devices/iio:device0
cat name
smi240

Work with driver using command line

Note

To change sensor settings we need root access. It is not sufficient just using “sudo …” .

sudo su

4.2 Read data from sensor

$ cat in_accel_x_raw
37
$ cat in_accel_y_raw
4
$ cat in_accel_z_raw
2030
$ cat in_anglvel_x_raw
-16
$ cat in_anglvel_y_raw
33
$ cat in_anglvel_z_raw
35
$ cat in_temp_object_raw
610

To convert raw data to physical values, we can read scale and offset values

$ cat in_accel_scale
0.000500
$ cat in_anglvel_scale
0.010000
$ cat in_temp_object_scale
0.003906250
$ cat in_temp_object_offset
6400
Accel[g] = accel_raw * accel_scale
Anglvel[°/s] = anglvel_raw * anglvel_scale
T[°C] = (temp_raw + temp_offset) * temp_scale

4.3 Change sensor settings

Set the -3dB cut-off frequency for the accelerometer

$ echo 50 > in_accel_filter_low_pass_3db_frequency

Note

50 = 50 hz, 400 = 400 Hz

Set the -3dB cut-off frequency for the gyroscope

$ echo 50 > in_anglvel_filter_low_pass_3db_frequency

Note

50 = 50 hz, 400 = 400 Hz

4.4 Read synchronized data from IIO buffer

The driver uses IIO buffer to push the synchronized sensor data to the user space application. To read the data from user space, the Linux kernel provides a C program under tools/iio. We need to compile and upload it to the target board first.

$ cd tools
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- iio
$ scp tools/iio/iio_generic_buffer to your board

We also need to create a trigger (e.g. sysfs trigger):

$ echo 0 > /sys/devices/iio_sysfs_trigger/add_trigger

Hint

Maybe you need to modprobe iio-trig-sysfs

In one terminal we can trigger events:

$ echo 1 > /sys/bus/iio/devices/trigger0/trigger_now

In another terminal we can execute the iio_generic_buffer program:

$ sudo ./iio_generic_buffer -n smi240 -a -l 256 -c -1 -T 0
iio device number being used is 0
iio trigger number being used is 0
Enabling all channels
Enabling: in_accel_y_en
Enabling: in_temp_object_en
Enabling: in_anglvel_z_en
Enabling: in_accel_x_en
Enabling: in_timestamp_en
Enabling: in_anglvel_y_en
Enabling: in_accel_z_en
Enabling: in_anglvel_x_en
/sys/bus/iio/devices/iio:device0 sysfstrig0
27.453125 0.022000 0.001500 1.012000 -0.240000 0.330000 0.130000 1723918279362596240
27.480469 0.027500 0.003500 1.013500 0.060000 0.530000 0.140000 1723918280416508114
27.503906 0.020000 0.004000 1.015000 0.210000 0.610000 0.090000 1723918283157345249
27.476562 0.023000 0.002000 1.017500 -0.120000 0.090000 -0.100000 1723918283626415613
27.453125 0.021000 0.002500 1.014000 -0.080000 0.670000 0.250000 1723918284054354467
27.464844 0.020000 0.001500 1.013000 0.400000 0.500000 0.190000 1723918284499537905
27.492188 0.022000 0.002500 1.014500 -0.110000 0.400000 0.080000 1723918284874394675
^CCaught signal 2
Disabling: in_accel_y_en
Disabling: in_temp_object_en
Disabling: in_anglvel_z_en
Disabling: in_accel_x_en
Disabling: in_timestamp_en
Disabling: in_anglvel_y_en
Disabling: in_accel_z_en
Disabling: in_anglvel_x_en

The first value represents the temperature in °C. The next three values are x, y and z of the accelerometer in g. The next three values are x, y and z of the gyroscope in °/s. The last value is the timestamp in ns.

Instead of auto-activate all channels, we can de-/activate the channels manually

$ echo 0 > buffer0/in_anglvel_x_en
$ echo 0 > buffer0/in_anglvel_y_en
$ echo 0 > buffer0/in_anglvel_z_en
$ echo 1 > buffer0/in_accel_x_en
$ echo 1 > buffer0/in_accel_y_en
$ echo 1 > buffer0/in_accel_z_en
$ echo 1 > buffer0/in_timestamp_en
$ echo 0 > buffer0/in_temp_object_en