ENG | Zephyr RTOS: I2C Sensors, part II
Playing with 6-axis inertial measurement unit (acceleration, gyroscope)
This is short article maybe expanded in the future. I have some ideas what to do with this sensor, but I don’t have a LiPo battery.
This time, Windows were used and XIAO-RP2040 board.
Bosch BMI160 inertial measurement unit
Files
CMakeLists.txt
1
2
3
4
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(project_name_placeholder)
target_sources(app PRIVATE src/main.c)
xiao_rp2040.overlay
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/ {
aliases {
imu-sensor = &bmi160;
};
};
&i2c1 {
status = "okay";
bmi160: bmi160@69 {
compatible = "bosch,bmi160";
reg = <0x69>;
status = "okay";
};
};
prj.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CONFIG_BMI160=y
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_BMI160=y
CONFIG_BMI160_TRIGGER_NONE=y
# I guess either normal or low power, but i would prefer interrupt per revolution
CONFIG_BMI160_ACCEL_PMU_NORMAL=y
# CONFIG_BMI160_ACCEL_PMU_LOW_POWER is not set
CONFIG_BMI160_ACCEL_RANGE_16G=y
# Sampling freq 25Hz
CONFIG_BMI160_ACCEL_ODR_25=y
# Gyroscope not used
CONFIG_BMI160_GYRO_PMU_SUSPEND=y
This one was a bit tricky to create. I entered first three lines and then used west build -t menuconfig -b xiao_rp2040
![zephyr_menuconfig_bmi160.webp]
It created config file in file build/zephyr/.config
and I copied some lines containing BMI160
back.
src/main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
int main(void)
{
const struct device *const sensor = DEVICE_DT_GET(DT_ALIAS(imu_sensor));
if (!device_is_ready(sensor)) {
printk("Sensor %s not ready!\n", sensor->name);
return -1;
}
while (1) {
int ret = sensor_sample_fetch(sensor);
if (ret != 0) {
printk("sensor_sample_fetch returned %d\n", ret);
continue;
}
struct sensor_value accel[3];
ret = sensor_channel_get(sensor, SENSOR_CHAN_ACCEL_XYZ, accel);
if (ret == 0) {
printk("x=%4d.%06d, y=%4d.%06d, z=%4d.%06d\n",
accel[0].val1, accel[0].val2,
accel[1].val1, accel[1].val2,
accel[2].val1, accel[2].val2
);
}
k_sleep(K_MSEC(200)); // 5Hz
}
return 0;
}
This file was based on my previous environmental sensors and example for similar sensor. Because I don’t have a clue how to quess which channel to read and that it reads three values at once.
Compiling this project on Windows this time:
1
2
3
west build -p -b xiao_rp2040 -S cdc-acm-console -- -DCONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y
west flash
mpremote connect COM16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Connected to MicroPython at COM16
Use Ctrl-] or Ctrl-x to exit this shell
*** Booting Zephyr OS build v4.1.0-5418-g98ba754013b0 ***
x= -2.-954489, y= 0.-378289, z= 9.078951
x= -2.-978432, y= 0.-373501, z= 9.136412
x= -2.-988009, y= 0.-373501, z= 9.174720
x= -2.-983220, y= 0.-373501, z= 9.174720
x= -3.-02374, y= 0.-373501, z= 9.193874
x= -3.-174759, y= 0.-402232, z= 9.136412
x= -3.-136452, y= 0.-383078, z= 9.236970
x= -2.-662392, y= 0.-397443, z= 9.481183
x= -2.-940124, y= 0.-335193, z= 9.213028
x= 3.514741, y= 1.177965, z= 15.471567
x= 1.652024, y= -1.-450908, z= 3.754165
x= 0.-181962, y= -7.-407772, z= 5.870672
Value encoding is really interesting, but i guess it makes conversion easier by float value = raw_value.val1 + 1.0e-6 * raw_value.val2
.
TODO acceleration vectors, pins, connection
flat = z=9.8 usb up y9 pins up x9
Some fun
This is only in attached files, I composed this from examples, board definition file and with help of Claude.AI. Main problem was enabling PIO (Raspberry Pico feature) and who would expect that floating point support for printf must be enabled.
Files
- (zephyr_sensor-accel-ws2812.7z) Accelerometer readings
- (zephyr_sensor-accel-ws2812.7z) WS2812 RGB LED on XIAO RP2040 used as indicator of readings.