3.13. sample_imu Usage Guide

3.13.1. Overview

3.13.1.1. Function Introduction

sample_imu provides multiple IMU data acquisition examples. Users can explore different data path reading methods through the subdirectories under sample_imu:

  • IIO path: Reads IIO device nodes via sysfs, supports interactive single-frame and multi-frame acquisition, and outputs data converted to SI units.

  • Input path: Reads driver-reported EV_MSC events through the Linux Input subsystem, suitable for verifying continuous driver reporting and packet loss.

3.13.1.2. Architecture Description of sample_imu

sample_imu contains multiple test cases. Each subdirectory is described as follows:

Directory Description
sample_imu_iio Reads IMU data via the IIO interface, supporting bmi08x, icm42688-gyro, and icm42688-accel
sample_imu_input Reads driver-reported IMU raw data via the Linux Input subsystem, with support for bmi08x and icm42688

3.13.2. sample_imu_iio

3.13.2.1. Functional Overview

sample_imu_iio is a command-line IMU example based on the IIO interface. It primarily implements the reading, processing, and display of Inertial Measurement Unit (IMU) data. With this program, users can conveniently obtain acceleration and gyroscope data from IMU sensors (magnetometer support can be extended if the sensor provides it), and perform corresponding analysis and applications.

The built-in supported sensor driver names are as follows:

  • bmi08x

  • icm42688-gyro

  • icm42688-accel

When no sensor is specified via -n, the program calls get_default_imu_name() to automatically detect the first available supported IIO device in the system. If no device is detected, the program reports that no device was found and then exits.

3.13.2.2. Software Architecture Description

sample_imu_iio adopts a layered design:

  • Application Layer: sample_imu.c serves as the program entry point, responsible for parsing command-line arguments, initializing sensors, handling user input commands, and reading and displaying sensor data.

  • Management Layer: imu_manager.h and imu_manager.c provide sensor management interfaces, including listing available sensors, initializing sensors, reading data, and releasing resources.

  • Adaptation Layer: imu_interface.h defines the sensor driver interface structure, providing a unified abstraction for specific sensors.

  • Sensor Abstraction Layer: Files such as bmi08x.c and icm42688.c interact with the underlying IIO drivers and convert hardware data into standard data formats usable by upper layers.

Software architecture diagram:

software_architecture_diagram.png

3.13.2.3. Data Flow Description

  1. The application layer uses init_sensor() to find and validate the target IIO device under /sys/bus/iio/devices/.

  2. The sensor abstraction layer reads raw values from nodes such as in_accel_*_raw and in_anglvel_*_raw, and converts them to physical quantities using scale.

  3. The application layer obtains one frame of ImuData via read_sensor_data(), then calls print_imu_data() to output acceleration (m/s²), angular velocity (rad/s), and timestamp.

3.13.2.4. Code Location and Directory Structure

  • Code location: app/samples/platform_samples/sample_imu/sample_imu_iio

  • Directory structure

sample_imu_iio
├── Makefile
├── bmi08x.c
├── icm42688.c
├── imu_interface.h
├── imu_manager.c
├── imu_manager.h
└── sample_imu.c

Description of each file:

  • Makefile: Defines compilation rules; the build output is sample_imu_iio.

  • sample_imu.c: Program entry point, responsible for command-line parsing and interactive data reading.

  • imu_manager.c / imu_manager.h: Sensor management and IIO device detection logic.

  • imu_interface.h: Unified sensor driver interface definition.

  • bmi08x.c: BMI08x sensor abstraction layer implementation.

  • icm42688.c: ICM42688 accelerometer/gyroscope abstraction layer implementation.

To add other IMU sensors, refer to the implementation in bmi08x.c and extend according to the interfaces in imu_interface.h.

3.13.2.5. Background Knowledge

An Inertial Measurement Unit (IMU) is a device used to measure physical quantities such as acceleration, angular velocity, and magnetic field strength of an object. It typically consists of an accelerometer, gyroscope, and magnetometer. By measuring and analyzing these physical quantities, information about the object’s orientation and motion state can be obtained. It should be noted that not all IMUs include all three sensors; in the industry, accelerometers, gyroscopes, and magnetometers are sometimes sold separately, while other IMUs are available in 6-axis or 9-axis configurations.

3.13.2.6. API Process Description

sample_imu_iio is built primarily on standard kernel IIO interfaces. The overall process based on program functions is as follows:

  1. List available sensors: Call list_available_sensors() to traverse the built-in supported sensor driver list and print the names.

  2. Initialize sensor: Call init_sensor(), passing the sensor type to find and validate the corresponding IIO device, then call the specific driver initialization function.

  3. Read sensor data: Call read_sensor_data(); the sensor abstraction layer reads one frame of data and fills ImuData.

  4. Release sensor resources: Call release_sensor() to release the driver context and handle.

api_process

3.13.2.7. Compilation and Deployment

Compilation

  • Enter the sample_imu_iio directory and run make to compile

  • The output is sample_imu_iio in the source directory

  • For detailed compilation instructions, refer to the Compilation Method section

Hardware Environment Setup

Refer to the following connection method (using BMI08x sensor):

40pin_connect

After confirming the hardware connection is correct, verify whether the corresponding driver configuration is enabled. (Since this sensor is not an onboard device, the following configurations may be disabled by default in the SDK. Please check whether they are enabled in the actual code before use.)

First, check the dts file. For the EVB board, the x5-evb.dtsi file is used. Check whether the corresponding i2c5 node is configured. If not, refer to the following configuration:

&i2c5 {
	status = "okay";
    ......
	bmi08a@19 {
		compatible = "bmi08xa";
		reg = <0x19>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};

	bmi08g@69 {
		compatible = "bmi08xg";
		reg = <0x69>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <6 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};
};

This IMU also supports the SPI interface. If you want to use SPI, refer to the device tree configuration below:

&spi1 {
	/*When dual chip select is used, the number of SPI chip selects must be set to 2.*/
	/*num-cs = <2>;*/
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_spi1 &pinctrl_spi1_ssn1>;
	dma-names = "tx", "rx";
	dmas = <&axi_dmac 23>, <&axi_dmac 22>;

	bmi08g@0 {
		compatible = "bmi088_gyro";
		reg = <0>;
		spi-max-frequency = <5000000>;
		interrupt-parent = <&dsp_gpio_porta>;
		interrupts = <12 IRQ_TYPE_EDGE_RISING>;
		gyro-irq-gpio = <&dsp_gpio_porta 12 GPIO_ACTIVE_HIGH>;
		status = "okay";
	};

	bmi08a@1 {
		compatible = "bmi08a";
		reg = <1>;
		spi-max-frequency = <5000000>;
		interrupt-parent = <&ls_gpio0_porta>;
		interrupts = <2 IRQ_TYPE_EDGE_RISING>;
		accel-irq-gpio = <&ls_gpio0_porta 2 GPIO_ACTIVE_HIGH>;
		status = "okay";
	};
};

Note: Only one interface (I2C or SPI) can be used at a time. Unused interfaces can be set to disabled in the device tree.

Then check whether the corresponding defconfig (e.g., hobot_x5_soc_defconfig used by default on EVB) has enabled:

CONFIG_BMI08X_SUPPORT_I2C_BUS=m
CONFIG_BMI08X_SUPPORT_SPI_BUS=m

These can be enabled via menuconfig. The search location can refer to the screenshot below:

boot_menuconfig_search

The enabling method can refer to the screenshot below:

boot_menuconfig_config

Finally, compile the entire image and flash it. After flashing, check whether the IMU has been successfully registered using one of the following two methods:

(1) Check via LOG:

root@buildroot:~# dmesg | grep BS
[    0.084965] CPU features: detected: Speculative Store Bypassing Safe (SSBS)
               [I]\x016<BS_LOG><bmi08_i2c_probe><187>client->name:bmi08xa / addr: 0x19
               [I]\x016<BS_LOG><bmi08_i2c_probe><187>client->name:bmi08xg / addr: 0x69
               [I]\x016<BS_LOG><sensor_init><1057>accel initilized
               [I]\x016<BS_LOG><sensor_init><1064>gyro initilized
               [I]\x016<BS_LOG><sensor_init><1065>sensor initilized
               [I]\x016<BS_LOG><sensor_init><1072>soft reset done
               [I]\x016<BS_LOG><sensor_init><1080>config stream loaded successfully
               [I]\x016<BS_LOG><sensor_init><1090>Accel power mode set to NORMAL
               [I]\x016<BS_LOG><sensor_init><1099>Gyro power mode set to NORMAL
               [I]\x016<BS_LOG><bmi08_probe><2216>Acc chip ID : 0x1e, Gyro chip ID : 0xf
               [I]\x016<BS_LOG><bmi08_request_irq><544>ACC IRQ requested for pin : 56
               [I]\x016<BS_LOG><bmi08_probe><2227>ACC IRQ requested
               [I]\x016<BS_LOG><bmi08_gyr_request_irq><563>GYR IRQ requested for pin : 57
               [I]\x016<BS_LOG><bmi08_probe><2234>GYR IRQ requested
               [I]\x016<BS_LOG><bmi08_probe><2236>sensor bmi088 probed successfully
[    4.687140] CAM_SUBSYS soc:cam:cam_sys@0: [FRT:D] camsys_probe(0)
root@buildroot:~#

You can see the sensor ID has been read correctly:

[I]\x016<BS_LOG><bmi08_probe><2216>Acc chip ID : 0x1e, Gyro chip ID : 0xf

(2) Check the name node in the IIO subsystem:

root@buildroot:~# cd /sys/bus/iio/devices/iio\:device1/
root@buildroot:/sys/bus/iio/devices/iio:device1# cat name
bmi08x
root@buildroot:/sys/bus/iio/devices/iio:device1#

Program Deployment

After uploading sample_imu_iio to the development board, run chmod +x sample_imu_iio to grant executable permission.

Default deployment path on board:

/app/platform_samples/sample_imu/sample_imu_iio/sample_imu_iio

3.13.2.8. Running

Program Usage Method

Run the program directly to obtain help information:

./sample_imu_iio -h

When run without parameters, the program automatically detects and uses the first available supported IMU in the system:

./sample_imu_iio

You can also explicitly specify the sensor name via -n, for example:

./sample_imu_iio -n bmi08x
./sample_imu_iio -n icm42688-gyro

Program Parameter Options Description

Usage: sample_imu_iio [OPTIONS]
Options:
  -n <imu_name>         Specify IMU name (default: auto-detected)
  -h                    Show this help message
Supported sensors: bmi08x icm42688-gyro icm42688-accel

Parameter description:

  • -n <imu_name>: Specifies the IMU sensor name. If not specified, the program automatically detects the first available device.

  • -h: Displays help information and lists the built-in supported sensor names.

Running Effect

After the program runs, it displays a command menu where users can input commands to retrieve sensor data:

root@buildroot:/app/platform_samples/sample_imu/sample_imu_iio# ./sample_imu_iio
No IMU specified, using detected default: bmi08x
Using IMU: bmi08x

=== Detected IIO Devices ===
  Device: iio:device1     | Name: bmi08x
  Device: iio:device0     | Name: 34190000.adc
============================

Device validation passed at: /sys/bus/iio/devices/iio:device1
BMI08x: Initializing with params:

***************  Command Lists  ***************
 g    -- Get a single frame of imu data
 l    -- Get multiple frames of imu data
 q    -- Quit the program
 h    -- Print this help message
Enter command:

Command description:

  • g: Get one frame of IMU data.

  • l: Get multiple frames of IMU data; requires entering the number of frames.

  • q: Quit the program.

  • h: Display help information.

Example of getting one frame of data:

Enter command: g
Data received (Frame 1):
  Accelerometer: [-117.836021, -118.283142, 9.569026] m/s²
  Gyroscope:     [0.006392, -69.885605, 0.049002] rad/s
  Timestamp:     00:01:38.917.929

Example of getting multiple frames of data:

Enter command: l
Enter number of frames to read: 3
Data received (Frame 1):
  Accelerometer: [-117.870140, -118.261597, 9.597756] m/s²
  Gyroscope:     [0.019175, 0.010653, -69.857903] rad/s
  Timestamp:     00:01:50.861.640
Data received (Frame 2):
  Accelerometer: [-117.825249, -118.283142, 9.574412] m/s²
  Gyroscope:     [0.014914, -69.857903, -69.887733] rad/s
  Timestamp:     00:01:50.867.500
......

3.13.2.9. Common Issues

Device connected but not recognized

  • First, ensure the hardware connection is correct. Check whether the connection between the IMU and the development board is loose, short-circuited, or incorrectly connected. Refer to the 40PIN connection description in the development board user guide.

  • Second, check whether the driver has been properly registered with the IIO framework. When sample_imu_iio runs, it lists all devices under IIO. If the expected device is not found, check the driver registration status. For details, refer to Hardware Environment Setup above.

  • To support a new IMU model, first complete driver registration under the IIO framework, then extend the sensor abstraction layer in sample_imu_iio by referring to bmi08x.c.

3.13.3. sample_imu_input

3.13.3.1. Functional Overview

sample_imu_input demonstrates how to read IMU data reported by the driver through the Linux Input subsystem. Unlike the sysfs polling/reading approach in sample_imu_iio, this example reads the /dev/input/eventX node, parses six-axis raw values, hardware timestamps, and IRQ counts continuously reported by the driver via EV_MSC events, and performs packet loss detection based on timestamp intervals.

Features of this example:

  • Continuously reads driver-reported events; no interactive g/l/q menu

  • Outputs six-axis raw LSB values and 64-bit hardware timestamps (ns)

  • When the interval between adjacent frame timestamps exceeds 3.5 ms, it is treated as possible packet loss and a warning is printed

For prerequisites such as hardware connection, device tree, and kernel configuration, refer to sample_imu_iio Hardware Environment Setup. For basic IMU concepts, refer to Background Knowledge.

3.13.3.2. Software Architecture Description

sample_imu_input.c starts from the main entry, opens the /dev/input/eventX device, and enters a read loop. Each time an input_event is read, it parses EV_MSC fields, assembles a frame on SYN_REPORT, prints six-axis data and timestamps, and performs packet loss detection based on adjacent frame timestamp intervals. The program runs continuously until the user presses Ctrl+C to exit.

Software architecture diagram:

software_architecture_diagram.png

3.13.3.3. Data Flow Description

  1. After each sampling completes, the kernel BMI088 driver reports multiple EV_MSC events through the Input subsystem (code = BMI088_MSC_DATA).

  2. One frame ends with SYN_REPORT; when the application receives SYN_REPORT, it assembles the cached 9 MSC fields into one frame of IMU data.

  3. The application prints ACC/GYRO raw values, timestamp, and IRQ count, and statistics packet loss based on adjacent timestamp differences.

MSC field order per frame:

Index Meaning
0 ~ 2 Accelerometer X/Y/Z raw values
3 ~ 5 Gyroscope X/Y/Z raw values
6 ~ 7 Hardware timestamp high/low 32 bits
8 IRQ count

3.13.3.4. Code Location and Directory Structure

  • Code location: app/samples/platform_samples/sample_imu/sample_imu_input

  • Directory structure

sample_imu_input
├── Makefile
├── sample_imu_input.c
└── sample_imu_input

3.13.3.5. API Process Description

sample_imu_input is implemented based on standard Linux Input interfaces. The main process is as follows:

  1. open() opens the /dev/input/eventX device node.

  2. Loop read() to read the input_event structure.

  3. Cache fields on EV_MSC events; assemble and print the frame on SYN_REPORT events.

  4. Determine packet loss based on the difference between adjacent hardware timestamps.

  5. On program exit, close() the device and output statistics.

api_process

3.13.3.6. Compilation and Deployment

Compilation

  • Enter the sample_imu_input directory and run make to compile

  • The output is sample_imu_input in the source directory

  • For detailed compilation instructions, refer to the Compilation Method section

Program Deployment

After uploading sample_imu_input to the development board, run chmod +x sample_imu_input to grant executable permission.

Default deployment path on board:

/app/platform_samples/sample_imu/sample_imu_input/sample_imu_input

After the driver is loaded successfully, you can confirm the Input device node with the following commands:

cat /proc/bus/input/devices
ls -l /dev/input/event*

Select the correct event node according to the actual device name; the program uses /dev/input/event1 by default.

3.13.3.7. Running

Program Usage Method

Use the default device node:

./sample_imu_input

Specify the Input device path:

./sample_imu_input /dev/input/event2

After the program starts, it continuously reads and prints data. Press Ctrl+C to exit.

Program Parameter Options Description

This program does not use getopt-style parameters. It supports the following invocation:

./sample_imu_input [input_device_path]
  • input_device_path (optional): Input device node path; default is /dev/input/event1.

Running Effect

========================================
BMI088 input reader (unified MSC code)
Device path: /dev/input/event1
Press Ctrl+C to exit
========================================

ACC(-117,-118,9) | GYRO(0,-69,0) | TS:9876543210 ns | Lost: 0 | EventCount: 9 | up_count: 128 | lower_count: -
ACC(-117,-118,9) | GYRO(0,-69,0) | TS:9879876543 ns | Lost: 0 | EventCount: 9 | up_count: 129 | lower_count: -
[ERROR] IMU data lost: last ts 0.009876s, current ts 0.009883s, diff 0.000007s
......

Field description:

  • ACC(x,y,z) / GYRO(x,y,z): Six-axis raw LSB values

  • TS: Hardware timestamp (ns) assembled from high/low 32 bits reported by the driver

  • Lost: Cumulative suspected packet loss count

  • EventCount: Number of input events received in the current frame

  • up_count: IRQ count reported by the driver

  • [ERROR] IMU data lost: Packet loss indicator; the packet loss time interval threshold may need to be modified in the program according to specific solution requirements.

3.13.3.8. Common Issues

Failed to open /dev/input/eventX

  • First confirm that the IMU driver has been loaded successfully. For hardware connection and kernel configuration, refer to sample_imu_iio Hardware Environment Setup.

  • Use cat /proc/bus/input/devices to confirm the event node number corresponding to the IMU, and pass the correct path in the startup command.

Device opens but no data is output

  • Confirm that the driver has enabled data stream reporting; in some scenarios, IIO/Input driver probe and interrupt configuration must be completed first.

  • Check whether the wrong event node was selected (other Input devices such as keyboard or touchpad may exist in the system).

How to determine packet loss

  • By default, the program uses an adjacent frame hardware timestamp difference greater than 3.5 ms as the packet loss threshold; when packet loss occurs, it prints the [ERROR] IMU data lost log.