BMI160 - missing FIFO frames (?)

Hi

 

I'm trying to get the FIFO to trigger an interrupt after a certain period (s) using downsampling and the watermark interrupt.

I have found that I can get the interrupt to trigger very close to what I want using a specific equation. I'm only interested in the accelerometer data, and I have configured the FIFO to send only that. The equation I have found, after reading datasheet, is this:

((odr / 2^downs) * (1 + 2*3) * delay_in_s) / 4 = watermark
 
ODR = 100
DOWNS = 4
delay_in_s = 5 (s)
=> watermark = 54
 

This seems to work, but only if I flush the FIFO after each read, even if I toggle the interrupt off/on when it's triggered - as is recommended in the "Advanced usage guide" (/knowledge-base-pg631enp/post/bmi160-fifo-advanced-usage-n7HOuG4Le1uKOSU).

So far so good, however, when I read the available data (using https://github.com/BoschSensortec/BMI160_driver) I don't get the expected number of frames.

 

[ 65.156567] .(3)[4101:sh][Gsensor] Set new fifo downsampling to 4.
[ 65.157571] .(3)[4101:sh][Gsensor] Set new fifo watermark level to 54.
[ 65.158977] .(3)[4101:sh][Gsensor] Set new trigger delay to 5s.

...

[ 75.495595] .(0)[185:kworker/0:1][Gsensor] bmi160_get_fifo_data
[ 75.496390] .(0)[185:kworker/0:1][Gsensor] reset_fifo_data_structure
[ 75.497212] .(0)[185:kworker/0:1][Gsensor] get_fifo_byte_counter
[ 75.498534] .(0)[185:kworker/0:1][Gsensor] Bytes to read = 219
[ 75.506369] .(0)[185:kworker/0:1][Gsensor] Setting up sensor data buffer... for 30 frames
[ 75.508203] .(0)[185:kworker/0:1][Gsensor] \x0a AVAILABLE FIFO LENGTH : 244
[ 75.509280] .(0)[185:kworker/0:1][Gsensor] \x0a REQUESTED ACC DATA FRAMES : 30\x0a
[ 75.509988] [Gsensor] \x0a AVAILABLE ACC DATA FRAMES : 0\x0a
[ 75.511083] .(0)[185:kworker/0:1][Gsensor] SENSOR TIME DATA : 0
[ 75.511863] .(0)[185:kworker/0:1][Gsensor] SKIPPED FRAME COUNT : 0

 

Sometimes the AVAILABLE ACC DATA FRAMES is 0, sometimes it's 17. Can you help me understand why I'm not getting the full 30 expected frames? I am using the code from your Github repo to read FIFO - and my interrupt handler looks like this:

 

static void bmi_fifo_watermark_handle(struct bmi160_acc_i2c_data *client_data)
{
int err = 0;
u8 should_enable_fifo = 0;
struct bmi160_fifo_frame *fifo = fifo_frame;

/* Declare memory to store the raw FIFO buffer information */
uint8_t *fifo_buff = kzalloc(sizeof(uint8_t) * fifo_watermark_level * 4 + 25, GFP_KERNEL);

/* Modify the FIFO buffer instance and link to the device instance */
struct bmi160_fifo_frame new_fifo_config;

new_fifo_config.data = fifo_buff;
new_fifo_config.length = fifo_watermark_level * 4 + 25;
new_fifo_config.fifo_time_enable = 0x02;
fifo = &new_fifo_config;

wake_lock(&wl_bmi160_irq);

// It's recommended by Bosch to pause interrupt during read of FIFO and later re-enable it.
should_enable_fifo = BMI160_ACC_ToggleFifoWatermark(bmi160_acc_i2c_client, DISABLE);
if (should_enable_fifo < 0) {
GSE_ERR("Failed to disable FIFO interrupt.\n");
}

/* Read data from the sensor's FIFO and store it the FIFO buffer,"fifo_buff" */
printf("\n USER REQUESTED FIFO LENGTH : %d\n", fifo->length);

err = bmi160_get_fifo_data(client_data, fifo);

if (err < 0) {
GSE_ERR("Error getting fifo data.\n");
return;
}

err = bmi_check_fifo(client_data, fifo);
if (err < 0) {
GSE_ERR("Error detecting data.\n");
return;
}

// TODO: This shouldn't be needed... when reading the fifo all data that was read should be removed. Or?
/* Flush FIFO */
bmi160_set_command_register(0xB0);
p_bmi160->write_delay(); // Pauses 2 or 450 us, depending on current power-mode

if
(should_enable_fifo >= 0) {
// It's recommended by Bosch to pause FIFO during interrupt read of FIFO and later re-enable it.
err = BMI160_ACC_ToggleFifoWatermark(bmi160_acc_i2c_client, ENABLE);
}
}

 

static int bmi_check_fifo(struct bmi160_acc_i2c_data *client_data, struct bmi160_fifo_frame *fifo)
{
int8_t rslt = 0;
struct i2c_client *client = bmi160_acc_i2c_client;
/* Declare instances of the sensor data structure to store the parsed FIFO data */
// struct bmi160_sensor_data acc_data[42]; // 300 bytes / ~7bytes per frame ~ 42 data frames
struct bmi160_sensor_data *acc_data = kzalloc(sizeof(struct bmi160_sensor_data) * fifo_requested_frames, GFP_KERNEL);
uint8_t acc_frames_req = fifo_requested_frames;
uint8_t acc_index;
int ret = 0;
uint16_t index = 0;

// ... unrelated code

GSE_LOG("\n AVAILABLE FIFO LENGTH : %d\n", fifo->length);
/* Print the raw FIFO data */

for (index = 0; index < fifo->length; index++) {
// GSE_LOG("\n FIFO DATA INDEX[%d] = %d\n", index, fifo->data[index]);
}

/* Parse the FIFO data to extract acc data from the FIFO buffer */
GSE_LOG("\n REQUESTED ACC DATA FRAMES : %d\n ", acc_frames_req);
rslt = bmi160_extract_accel(acc_data, &acc_frames_req, fifo);

if (rslt == BMI160_OK) {
GSE_LOG("\n AVAILABLE ACC DATA FRAMES : %d\n ", acc_frames_req);
/* Print the parsed acc data from the FIFO buffer */
for (acc_index = 0; acc_index < acc_frames_req; acc_index++) {
GSE_LOG("FRAME[%d] ==> x: %d, y: %d, z: %d\n", acc_index, acc_data[acc_index].x, acc_data[acc_index].y, acc_data[acc_index].z);
}

/* Print the special FIFO frame data like sensortime */
GSE_LOG("SENSOR TIME DATA : %d \n", fifo->sensor_time);
GSE_LOG("SKIPPED FRAME COUNT : %d\n", fifo->skipped_frame_count);
} else {
GSE_LOG("\n Accel data extraction failed\n");
}
return ret;
}

Other than that, the code in all of the FIFO related functions are the same as your Github, with the exception of a few log messages that are less verbose (for example printing the accelerometer data for all axis...)

Best reply by agoransson

The underlying problem was the driver that this was based on (mediatek), which truncated the length of the i2c messages to 8 bits... 😣

 

This is not the root of our source, just a very, very, very similar code base that we're working with here.

View original
4 replies
Resolved