03-02-2021 04:38 PM
Dear,
We are integrating your BMI Bosch driver https://github.com/BoschSensortec/BMI160_driver in our code.
We have rewritten the FIFO example in to a FIFO watermark interrupt handler.
We are able to get the watermark interrupt trigger, but are not able to see the FIFO accelero nor gyro data updated as you can see in the following snippet:
<info> app: Buffer FULL
<info> app:
REQUESTED GYRO DATA FRAMES : 33
<info> app:
AVAILABLE GYRO DATA FRAMES : 33
<info> app:
GYRO X-DATA : -29120 Y-DATA : 8192 Z-DATA : -1138
<info> app: SKIPPED FRAME COUNT : 0
<info> app:
REQUESTED ACCEL DATA FRAMES : 33
<info> app:
AVAILABLE ACCEL DATA FRAMES : 33
<info> app:
ACCEL X-DATA : 8195 Y-DATA : -29120 Z-DATA : 8192
<info> app: SKIPPED FRAME COUNT : 0
<info> app: Buffer FULL
<info> app:
REQUESTED GYRO DATA FRAMES : 33
<info> app:
AVAILABLE GYRO DATA FRAMES : 33
<info> app:
GYRO X-DATA : -29120 Y-DATA : 8192 Z-DATA : -1138
<info> app: SKIPPED FRAME COUNT : 0
<info> app:
REQUESTED ACCEL DATA FRAMES : 33
<info> app:
AVAILABLE ACCEL DATA FRAMES : 33
<info> app:
ACCEL X-DATA : 8195 Y-DATA : -29120 Z-DATA : 8192
Do you have an idea what could possibly is going on? We are able to read correct data without the usage of the FIFO (with the function bmi160_get_sensor_data()).
Here is some code below for your reference.
Within our main code, we do the configuration of the sensor BMI160 and its FIFO in the following order:
////Init and dev IMU
inertial_sensor_init();
inertial_sensor_self_test();
inertial_sensor_config();
inertial_sensor_fifo_config(&inertial_sensor);
inertial_sensor_fifo_interrupt_config(&inertial_sensor);
inertial_sensor_interrupt_init();
The driver inertial_sensor is an abstraction layer that integrates your BOSCH driver.
The driver inertial_sensor has the following code:
void inertial_sensor_init(void){
inertial_sensor.id = BMI160_I2C_ADDR;
inertial_sensor.interface = BMI160_I2C_INTF;
inertial_sensor.read = &inertial_sensor_i2c_read;
inertial_sensor.write = &inertial_sensor_i2c_write;
inertial_sensor.delay_ms = &inertial_sensor_delay_ms;
rslt = bmi160_init(&inertial_sensor);
if(rslt == BMI160_OK){
NRF_LOG_INFO("Inertial sensor initialized.");
} else {
NRF_LOG_INFO("Inertial sensor not initialized.");
}
/* After the above function call, accel and gyro parameters in the device structure
are set with default values, found in the datasheet of the sensor */
}
void inertial_sensor_config(void){
/*Configuring accel and gyro sensors in normal mode */
/* Select the Output data rate, range of accelerometer sensor */
inertial_sensor.accel_cfg.odr = BMI160_ACCEL_ODR_50HZ; //BMI160_ACCEL_ODR_1600HZ
inertial_sensor.accel_cfg.range = BMI160_ACCEL_RANGE_4G; //To avoid overshoot when going over + or - 1G. //BMI160_ACCEL_RANGE_2G;
inertial_sensor.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;//No oversampling --> equidistant points over time, just normal mode. See p20 datasheet. AVG = 4 means 4 averaging cycles
/* Select the power mode of accelerometer sensor */
inertial_sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;
/* Select the Output data rate, range of Gyroscope sensor */
inertial_sensor.gyro_cfg.odr = BMI160_GYRO_ODR_50HZ; //BMI160_GYRO_ODR_3200HZ;
inertial_sensor.gyro_cfg.range = BMI160_GYRO_RANGE_500_DPS; //From magic numbers, 500 DPS seems to be okay. //BMI160_GYRO_RANGE_2000_DPS;
inertial_sensor.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;//No oversampling --> equidistant points over time, just normal mode. See p21 datasheet
/* Select the power mode of Gyroscope sensor */
inertial_sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;
/* Set the sensor configuration */
rslt = bmi160_set_sens_conf(&inertial_sensor);
if(rslt == BMI160_OK){
NRF_LOG_INFO("Inertial sensor configured.");
} else {
NRF_LOG_INFO("Inertial sensor not configured.");
}
}
void inertial_sensor_fifo_config(struct bmi160_dev *dev)
{
int8_t rslt = 0;
/* Disable other FIFO settings */
rslt = bmi160_set_fifo_config(BMI160_FIFO_CONFIG_1_MASK , BMI160_DISABLE, dev);
/* Modify the FIFO buffer instance and link to the device instance */
fifo_frame.data = fifo_buff;
fifo_frame.length = FIFO_BUFFER_LEN_BYTES;
dev->fifo = &fifo_frame;
/*Configure the sensor's FIFO settings */
//rslt = bmi160_set_fifo_config(BMI160_FIFO_HEADER, BMI160_DISABLE, dev);
rslt = bmi160_set_fifo_config(BMI160_FIFO_GYRO | BMI160_FIFO_ACCEL ,
BMI160_ENABLE, dev);
/* Set the FIFO watermark level for the interrupt */
rslt = bmi160_set_fifo_wm(97, dev); // Note the watermark is in units of words (4 bytes) so 141
// * 4 is 564 bytes which is equal to the FIFO_BUFFER_LEN_BYTES
return rslt;
}
void inertial_sensor_fifo_interrupt_config(struct bmi160_dev *dev)
{
int8_t rslt;
struct bmi160_int_settg int_config;
/* Select the Interrupt channel/pin */
int_config.int_channel = BMI160_INT_CHANNEL_1;// Interrupt channel/pin 1
/* Select the Interrupt type */
int_config.int_type = BMI160_ACC_GYRO_FIFO_WATERMARK_INT; //Choosing watermark interrupt //BMI160_ACC_GYRO_FIFO_FULL_INT;
/* Select the interrupt channel/pin settings */
int_config.int_pin_settg.output_en = BMI160_ENABLE;// Enabling interrupt pins to act as output pin
int_config.int_pin_settg.output_mode = BMI160_DISABLE;// Choosing push-pull mode for interrupt pin
int_config.int_pin_settg.output_type = BMI160_DISABLE;// Choosing active low output
int_config.int_pin_settg.edge_ctrl = BMI160_ENABLE;// Choosing edge triggered output
int_config.int_pin_settg.input_en = BMI160_DISABLE;// Disabling interrupt pin to act as input
int_config.int_pin_settg.latch_dur = BMI160_LATCH_DUR_NONE;// non-latched output
/* */
int_config.fifo_full_int_en = 0; // 1- Enable, 0- Disable the full interrupt
int_config.fifo_wtm_int_en = 1; // 1- Enable, 0- Disable the watermark interrupt
/*Configure the sensor's interrupt settings */
rslt = bmi160_set_int_config(&int_config, dev);
return rslt;
}
void inertial_sensor_fifo_read(struct bmi160_dev *dev){
int8_t rslt = 0;
/* Declare memory to store the raw FIFO buffer information */
//uint8_t fifo_buff[FIFO_BUFFER_LEN_BYTES]; //220
/* Modify the FIFO buffer instance and link to the device instance */
//struct bmi160_fifo_frame fifo_frame;
//fifo_frame.data = fifo_buff;
//fifo_frame.length = FIFO_BUFFER_LEN_BYTES; //max window size algo is 235 samples ==>235*12bytes=2820 ==> 5 fifo_frame burst and the window size is filled.
//dev->fifo = &fifo_frame;
uint16_t index = 0;
/* Declare instances of the sensor data structure to store the parsed FIFO data */
struct bmi160_sensor_data gyro_data[33];
struct bmi160_sensor_data accel_data[33];
uint8_t gyro_frames_req = 33; // fifo_frame_length or size (bytes) / #bytes per frame(=6*gyro bytes+6*accel bytes) ==> 564/12 = 47 data frames
uint8_t accel_frames_req = 33; // fifo_frame_length or size (bytes) / #bytes per frame(=6*gyro bytes+6*accel bytes) ==> 564/12 = 47 data frames
uint8_t gyro_index;
uint8_t accel_index;
//NRF_LOG_INFO("\n USER REQUESTED FIFO LENGTH : %d\n",dev->fifo->length);
rslt = bmi160_get_fifo_data(dev);
if (rslt == BMI160_OK) {
// NRF_LOG_INFO("\n AVAILABLE FIFO LENGTH : %d\n",dev->fifo->length);
/* Print the raw FIFO data */
//for (index = 0; index < dev->fifo->length; index++) {
// NRF_LOG_INFO("\n FIFO DATA INDEX[%d] = %d", index,
// dev->fifo->data[index]);
// nrf_delay_ms(1); //allow printing
//}
NRF_LOG_INFO("\n REQUESTED GYRO DATA FRAMES : %d\n ",gyro_frames_req);
rslt = bmi160_extract_gyro(&gyro_data, &gyro_frames_req, dev);
if (rslt == BMI160_OK) {
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n AVAILABLE GYRO DATA FRAMES : %d\n ",gyro_frames_req);
/* Print the parsed gyro data from the FIFO buffer */
//for (gyro_index = 0 ; gyro_index <gyro_frames_req ; gyro_index++) {
// NRF_LOG_INFO("\nFIFO GYRO FRAME[%d]",gyro_index);
//NRF_LOG_INFO("\nGYRO X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
// ,gyro_data[gyro_index].x ,gyro_data[gyro_index].y
// ,gyro_data[gyro_index].z);
// //nrf_delay_ms(1); //allow printing
//}
/*Print last sample as speed is too high*/
NRF_LOG_INFO("\nGYRO X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
,gyro_data[32].x ,gyro_data[32].y
,gyro_data[32].z);
/* Print the special FIFO frame data like sensortime */
//nrf_delay_ms(2); //allow printing
//NRF_LOG_INFO("\n SENSOR TIME DATA : %d \n",dev->fifo->sensor_time);
NRF_LOG_INFO("SKIPPED FRAME COUNT : %d",dev->fifo->skipped_frame_count);
} else {
NRF_LOG_INFO("\n Gyro data extraction failed");
}
/* Parse the FIFO data to extract accel data from the FIFO buffer */
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n REQUESTED ACCEL DATA FRAMES : %d\n ",accel_frames_req);
rslt = bmi160_extract_accel(&accel_data, &accel_frames_req, dev);
if (rslt == BMI160_OK) {
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n AVAILABLE ACCEL DATA FRAMES : %d\n ",accel_frames_req);
/* Print the parsed accel data from the FIFO buffer */
//for (accel_index = 0; accel_index < accel_frames_req; accel_index++) {
// printf("\nFIFO ACCEL FRAME[%d]",accel_index);
// printf("\nACCEL X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
// ,accel_data[accel_index].x ,accel_data[accel_index].y
// ,accel_data[accel_index].z);
// //nrf_delay_ms(1); //allow printing
//}
/*Print last sample as speed is too high*/
NRF_LOG_INFO("\nACCEL X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
,accel_data[32].x ,accel_data[32].y
,accel_data[32].z);
/* Print the special FIFO frame data like sensortime */
//nrf_delay_ms(2);//allow printing
//NRF_LOG_INFO("\n SENSOR TIME DATA : %d \n",dev->fifo->sensor_time);
NRF_LOG_INFO("SKIPPED FRAME COUNT : %d",dev->fifo->skipped_frame_count);
} else {
NRF_LOG_INFO("\n Accel data extraction failed");
}
} else {
NRF_LOG_INFO("\n Reading FIFO data failed");
}
return rslt;
//bmi160_set_fifo_flush(dev);
}
void inertial_sensor_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
uint8_t rslt;
NRF_LOG_INFO("Buffer FULL");
nrf_gpio_pin_toggle(TOGGLE_PIN);
struct bmi160_int_settg int_config;
uint8_t data = 0x00;
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, &inertial_sensor); // disable the WM interrupt
/* Read data from the sensor's FIFO and store it the FIFO buffer,"fifo_buff" */
inertial_sensor_fifo_read(&inertial_sensor);
data = BMI160_FIFO_WATERMARK_INT_EN_MASK; //BMI160_FIFO_FULL_INT_EN_MASK; //BMI160_FIFO_WATERMARK_INT_EN_MASK;
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, &inertial_sensor); // enable the WM
nrf_gpio_pin_clear(TOGGLE_PIN);
}
Thanks in advance for your answer.
Kind regards,
Tom
Solved! Go to Solution.
03-02-2021 07:38 PM
Hello tmeeusen,
FIFO interrupt is generated once your device reaches to the watermark level.
It looks like you only read one byte, it means that FIFO is generated interrupt again while you read one byte.
For proper test, you should read all FIFO data before FIFO is reached to the water mark level.
Thanks,
03-03-2021 09:07 AM
Hi Minhwan,
Thanks for your prompt reply.
I only print out one line as the burst is otherwise difficult to print out.
That's why you see only one byte.
However, I do call the function bmi160_get_fifo_data() first, which I assume is the one reading out all the data and thereby, emptying the FIFO?
Afterwards bmi160_extract_gyro() and bmi160_extract_accel() adds the accel and gyr data to the arrays.
Here is a code snippet of the inertial_sensor_fifo_read function I call in my interrupt handler:
/* Declare memory to store the raw FIFO buffer information */
uint8_t fifo_buff[FIFO_BUFFER_LEN_BYTES]; //616
/* Modify the FIFO buffer instance and link to the device instance */
struct bmi160_fifo_frame fifo_frame;
fifo_frame.data = fifo_buff;
fifo_frame.length = FIFO_BUFFER_LEN_BYTES;
dev->fifo = &fifo_frame;
/* Declare instances of the sensor data structure to store the parsed FIFO data */
struct bmi160_sensor_data gyro_data[47];
struct bmi160_sensor_data accel_data[47];
void inertial_sensor_fifo_read(struct bmi160_dev *dev){
int8_t rslt = 0;
uint16_t index = 0;
uint8_t gyro_frames_req = 47; // fifo_frame_length or size (bytes) / #bytes per frame(=6*gyro bytes+6*accel bytes) ==> 564/12 ~ 47 data frames
uint8_t accel_frames_req = 47; // fifo_frame_length or size (bytes) / #bytes per frame(=6*gyro bytes+6*accel bytes) ==> 564/12 ~ 47 data frames
uint8_t gyro_index;
uint8_t accel_index;
//NRF_LOG_INFO("\n USER REQUESTED FIFO LENGTH : %d\n",dev->fifo->length);
rslt = bmi160_get_fifo_data(dev);
if (rslt == BMI160_OK) {
// NRF_LOG_INFO("\n AVAILABLE FIFO LENGTH : %d\n",dev->fifo->length);
/* Print the raw FIFO data */
//for (index = 0; index < dev->fifo->length; index++) {
// NRF_LOG_INFO("\n FIFO DATA INDEX[%d] = %d", index,
// dev->fifo->data[index]);
// //nrf_delay_ms(1); //allow printing
//}
NRF_LOG_INFO("\n REQUESTED GYRO DATA FRAMES : %d\n ",gyro_frames_req);
rslt = bmi160_extract_gyro(&gyro_data, &gyro_frames_req, dev);
if (rslt == BMI160_OK) {
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n AVAILABLE GYRO DATA FRAMES : %d\n ",gyro_frames_req);
/* Print the parsed gyro data from the FIFO buffer */
//for (gyro_index = 0 ; gyro_index <gyro_frames_req ; gyro_index++) {
// NRF_LOG_INFO("\nFIFO GYRO FRAME[%d]",gyro_index);
//NRF_LOG_INFO("\nGYRO X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
// ,gyro_data[gyro_index].x ,gyro_data[gyro_index].y
// ,gyro_data[gyro_index].z);
// //nrf_delay_ms(1); //allow printing
//}
/*Print last sample as speed is too high*/
NRF_LOG_INFO("\nGYRO X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
,gyro_data[32].x ,gyro_data[32].y
,gyro_data[32].z);
/* Print the special FIFO frame data like sensortime */
//nrf_delay_ms(2); //allow printing
//NRF_LOG_INFO("\n SENSOR TIME DATA : %d \n",dev->fifo->sensor_time);
NRF_LOG_INFO("SKIPPED FRAME COUNT : %d",dev->fifo->skipped_frame_count);
} else {
NRF_LOG_INFO("\n Gyro data extraction failed");
}
/* Parse the FIFO data to extract accel data from the FIFO buffer */
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n REQUESTED ACCEL DATA FRAMES : %d\n ",accel_frames_req);
rslt = bmi160_extract_accel(&accel_data, &accel_frames_req, dev);
if (rslt == BMI160_OK) {
//nrf_delay_ms(1); //allow printing
NRF_LOG_INFO("\n AVAILABLE ACCEL DATA FRAMES : %d\n ",accel_frames_req);
/* Print the parsed accel data from the FIFO buffer */
//for (accel_index = 0; accel_index < accel_frames_req; accel_index++) {
// printf("\nFIFO ACCEL FRAME[%d]",accel_index);
// printf("\nACCEL X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
// ,accel_data[accel_index].x ,accel_data[accel_index].y
// ,accel_data[accel_index].z);
// //nrf_delay_ms(1); //allow printing
//}
/*Print last sample as speed is too high*/
NRF_LOG_INFO("\nACCEL X-DATA : %d \t Y-DATA : %d \t Z-DATA : %d"
,accel_data[32].x ,accel_data[32].y
,accel_data[32].z);
/* Print the special FIFO frame data like sensortime */
//nrf_delay_ms(2);//allow printing
//NRF_LOG_INFO("\n SENSOR TIME DATA : %d \n",dev->fifo->sensor_time);
NRF_LOG_INFO("SKIPPED FRAME COUNT : %d",dev->fifo->skipped_frame_count);
} else {
NRF_LOG_INFO("\n Accel data extraction failed");
}
} else {
NRF_LOG_INFO("\n Reading FIFO data failed");
}
return rslt;
//bmi160_set_fifo_flush(dev);
}
Or is my watermark level and buffer size not okay?
We want to use a headerless FIFO for accelero and gyro with the watermark interrupt at a level of 564 bytes.
Sensors are configured at ODR=50Hz.
Therefore, I chose buffer burst length = length watermark + 2xMaxframes + 4bytes = 564bytes + 2*(12bytes)+4 bytes = 616 bytes.
Further the frames requested are calculated via 564/12 ~47 bytes gyro and acc frames. The watermark is set by 564/4 = 141.
Thanks in advance for your solution.
Kind regards,
Tom
03-03-2021 09:25 AM - edited 03-03-2021 09:36 AM
In addition to my previous reply, I saw that printing the first four sample instead of the last, gave me the samples update I expected.
Along with that, I analyzed the timings of the interrupt generated and every 4 samples (=4*(2bytes acc + 2bytes gyro) = 48 byte) my interrupt is generated:
Therefore, I am not sure if the lenghts of the buffers, wm level, frame size and number of frames are correctly chosen.
Some clear guidance would be helpful.
Thanks,
Tom
03-11-2021 11:18 PM
Hello tmeeusen,
Sorry for late response.
I think you already referred our example,
https://github.com/BoschSensortec/BMI160_driver
But, could you test with our code without modification.
From my side, I could get it properly. Of course, printf would be burden for you if you are using low speed of UART.
But, if not, please try it. If it is burden for your system, you need to capture thru logic analyzer and check it.
If you seem like your system is not capable of our example, please slow down ODR.
Then, our FIFO would reach out to water level slower.
Thanks,