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
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...)