BMI08x Custom Driver Polling-Based FIFO Axis Flip Issue


Hello Bosch Sensortec Community,

I’m currently developing a custom Linux kernel driver for the BMI08x series (BMI088/BMI085) to achieve direct control over FIFO-based data acquisition. The main goal is to bypass user-space scheduling jitter and handle sensor timing directly through kernel-space mechanisms.

System Context

  • Platform: NVIDIA Jetson (Linux 5.15 with Linux for Tegra(L4T) modifications)

  • Communication: I²C @ 400 kHz, Through a SerDes System.

  • Frequency of acquisition: @200Hz

  • IMU Count: 4 units connected on the same I²C bus

  • Integration: IMUs are mounted on robotic arms and cameras (properly calibrated)

  • Trigger Method: Polling-based/host clock acquisition (no GPIOs available for INT pins)

  • Tools: SDS2504X oscilloscope for timing verification; turntable with 45° steps at 50°/s peak velocity for validation or in the case of the image below I was just turning the bmi on the same axis with my hand until I saw the problem.

Driver Operation

I’m polling each IMU’s FIFO_STATUS register, determining the number of available frames, and then, 5ms after, performing an i2c_transfer read from the gyroscope FIFO. The register reads and data reads are sequential, not interleaved. What I'm doing is to take the raw accelerometer data and the amount of data inside of the fifo at that time so that I can have time for all the 4 sensors on a 5ms frame.

Phase 1: Read Accelerometer Data, Read Length of Gyro Fifo,
Phase 2: Read Accelerometer Data, Read Fifo data with previously read fifo_status length*6 bytes.

I saw this following article and got some insights for it, but as it's said on the article 100bytes could take 2ms to read, and I would say that on my setup it's even higher than that. I see around 800us bits data transfer in which only ?

sensors-17-02894.pdf
1.62MB

~1.1ms Read Example of a Gyro 2 Packet (12bytes) over the Oscilloscope DECODE.

I was able to confirm that even though I'm using a SerDes system I could see the clock and signal were proper after the Deserializer output. In the Image Data(SDA) is in yellow and Clock(SCL) in pink. Timebase on that is at 2us/div.


The i2c_msg declarations.

	/* Message 0: Write accelerometer register address */
	acc_msg[0].addr = st->i2c_addrs[BMI_HW_ACC];
	acc_msg[0].flags = 0;
	acc_msg[0].len = 1;
	acc_msg[0].buf = &acc_reg;

	/* Message 1: Read 6 bytes from accelerometer */
	acc_msg[1].addr = st->i2c_addrs[BMI_HW_ACC];
	acc_msg[1].flags = I2C_M_RD | I2C_M_STOP;
	acc_msg[1].len = 6;
	acc_msg[1].buf = acc_buf;

	/* Message 2: Write gyroscope FIFO status register address */
	gyr_msg[0].addr = st->i2c_addrs[BMI_HW_GYR];
	gyr_msg[0].flags = 0;
	gyr_msg[0].len = 1;
	gyr_msg[0].buf = &fifo_reg;

	/* Message 3: Read 1 byte from FIFO status */
	gyr_msg[1].addr = st->i2c_addrs[BMI_HW_GYR];
	gyr_msg[1].flags = I2C_M_RD | I2C_M_STOP;
	gyr_msg[1].len = 1;
	gyr_msg[1].buf = &fifo_status;

	/* Message 0: Write accelerometer register address */
	acc_msg[0].addr = st->i2c_addrs[BMI_HW_ACC];
	acc_msg[0].flags = 0;
	acc_msg[0].len = 1;
	acc_msg[0].buf = &acc_reg;

	/* Message 1: Read 6 bytes from accelerometer */
	acc_msg[1].addr = st->i2c_addrs[BMI_HW_ACC];
	acc_msg[1].flags = I2C_M_RD | I2C_M_STOP;
	acc_msg[1].len = 6;
	acc_msg[1].buf = acc_buf;

	/* Message 2: Write gyroscope FIFO register address */
	gyro_msg[0].addr = st->i2c_addrs[BMI_HW_GYR];
	gyro_msg[0].flags = 0;
	gyro_msg[0].len = 1;
	gyro_msg[0].buf = &fifo_reg;

	/* Message 3: Read FIFO bytes from gyroscope */
	gyro_msg[1].addr = st->i2c_addrs[BMI_HW_GYR];
	gyro_msg[1].flags = I2C_M_RD | I2C_M_STOP;
	gyro_msg[1].len = fifo_bytes_to_read;
	gyro_msg[1].buf = fifo_buffer;

Issue Description



I'm not dynamically allocating the buffer i send to i2c_transfer, i have a fixed size buffer of 18 bytes, and when there are more than 3 samples on my read i just trim it and read 3 max. When the queue accumulates and is executed right after sometimes I get length read = 0. And this is when the flip happens.
HAD 4 Samples
Read 3, left 1
Read 0. The 1 left vanished.
Probably I got a PC corruption and the FIFO wasn't zeroed.

I've noticed that by writing on the watermark register and flushing the FIFO the flip would get back to normal(0x3D: FIFO_CONFIG_0)

Questions

  1. Is there a recommended polling frequency or FIFO watermark management approach when INT pins are not available?

  2. Does Bosch recommend delaying between the FIFO_STATUS register read and the actual FIFO data read to ensure data coherency, or they should be read immediately after and all the reads should flush the FIFO stack after?

Any suggestions or clarifications about proper sequencing for polling-based or Host clock based data acquisition would be greatly appreciated or the BMI limitations for the FIFO usage.

Thank you for your support and insights.

Right now I'm considering passing to SPI, using 100 Hz instead of 200Hz when doing multi-sensor acquisition or doing the Raw reads with a host clock and interpolating when I get repeated data. If anyone saw this and fixed it I would love to understand what's happening. I can share my code and a recording of the turning table and the oscilloscope csvs or my live graph if asked, just send me a message.

4 replies