Inertial Module

The Librem 5 development board is equipped with a collection of sensors provided by the LSM9DS1 inertial module, including a accelerometer, gyroscope and magnetometer. These sensors can be accessed programmatically via messages sent to the relevant addresses on the appropriate I2C bus. Applications can also receive sensor information by accessing the appropriate system D-Bus interface.

This guide provides a basic overview of the commands that can be used to access each device; first via the D-Bus interface, then using the I2C bus.

D-Bus Interface

Note

Support for this interface is only present in recent kernels. Please update the kernel on your device if you experience problems starting the service.

The gyroscope and magnetometer are exposed to applications via the net.hadess.SensorProxy service on the system D-Bus. This is provided by the iio-sensor-proxy service.

Information about the orientation of the phone and the magnetic field can be obtained by querying the interface provided by the D-Bus service, calling methods to access devices and reading their properties.

Preparations

If the iio-sensor-proxy daemon is not already running, start it from the command line in the following way:

systemctl start iio-sensor-proxy

Check that it is running with this command:

systemctl status iio-sensor-proxy

This should include useful information to help diagnose problems if the service does not start.

I2C Bus

Note

This section contains advice that only works with older Linux kernels that do not have built-in support for the inertial module. If the i2cdetect tool does not produce the expected output then the devices are being managed by the kernel and their I2C interfaces are not accessible to user space programs.

The inertial module exposes a magnetometer via one I2C bus address and both an accelerometer and gyroscope via another. Each device contains a set of registers that can be accessed by their addresses in that device. This means that we need two addresses – a bus address and a device address – to access a register.

The kernel provides abstractions that allow the sensors to be accessed fairly simply without requiring knowledge of the message protocol used for I2C devices.

Preparations

Before trying to access the sensors as the purism user, you need to install the i2c-tools package on the development board:

sudo apt install i2c-tools

Then add the purism user to the i2c group:

sudo usermod -a -G i2c purism

This user should now have permission to read and write the device files for the I2C devices and run the tools to access them.

Magnetometer

The magnetometer is available via address 0x1e on I2C bus 2. This can be verified by running the i2cdetect tool:

purism@pureos:~$ /usr/sbin/i2cdetect -y 2

This should produce output like the following:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- UU -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- UU -- --
60: 60 -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
70: -- -- -- -- -- -- -- --

It should be clear that there is a device at address 0x1e on the I2C bus – this should be the magnetometer.

Reading the Device ID

We check that the device at address 0x1e on I2C bus 2 is the magnetometer by querying its WHO_AM_I_M register, which should be readable at address 0x0f on the device. We can do this with the i2cget tool:

/usr/sbin/i2cget -y 2 0x1e 0x0f

The expected value is 0x3d for the magnetometer. If a different value is returned then the device is not the one we were expecting.

Powering the Device

Initially, the device will be powered down. To determine its state we read its CTRL_REG3_M register at 0x22 on the device:

/usr/sbin/i2cget -y 2 0x1e 0x22

This should return 0x03, indicating an operating mode of binary 11 (power-down mode). Set it to 00 (continuous-conversion mode) with the i2cset tool:

/usr/sbin/i2cset -y 2 0x1e 0x22 0

When we no longer need to read from the device, we set the operating mode to power-down again:

/usr/sbin/i2cset -y 2 0x1e 0x22 3

We can read the state of the device again to verify that it has powered down, if necessary.

Obtaining Readings

We need to enable temperature compensation if we want accurate readings. This is done by setting bit 7 (0x80) in the CTRL_REG1_M register at 0x20 on the device. This is in addition to the existing value of 0x18 that the register contains, so we write a value of 0x98:

/usr/sbin/i2cset -y 2 0x1e 0x20 0x98

It is now possible to obtain readings for the three components of the magnetic field along each axis (x, y and z respectively) from the registers, OUT_X_M, OUT_Y_M and OUT_Z_M, passing the w argument to indicate that these registers are 16-bits in size:

/usr/sbin/i2cget -y 2 0x1e 0x28 w
/usr/sbin/i2cget -y 2 0x1e 0x2a w
/usr/sbin/i2cget -y 2 0x1e 0x2c w

If you reorientate the development board and read these values again, you should notice that the values have changed.