Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    BMI160 & STM32 Strange Behaviour - Sensor Succesfully Inits but Accel and Gyro Reads are always zero

    BMI160 & STM32 Strange Behaviour - Sensor Succesfully Inits but Accel and Gyro Reads are always zero

    DroneKid
    Established Member

    Hello,

    I am trying to use the BMI160 sensor with my STM32G474 Nucleo board. I am working over I2C. I wrote the Read - Write and DelayUS functions.

    I successfully init the sensor. It returns 0 as "rslt", which means everything is fine according to this library. After that, when I configure Accel and Gyro, rslt still returns 0.

    But I am constantly reading 0 from gyro and accel. Also, sometimes I get -7 error after configuring Accel and Gyro. I guess my ODR/BW settings for Accel and Gyro are not working. How can I set the correct ODR/BW and datarate?

    I'm posting the code I'm using, below. In addition to the standard BMI160 library, I write two more codes to be able to use library:

    • common_porting = Holds I2C Read - Write and DelayUs functions
    • bmi160_wrapper = The code I wrote to use Bosch's standard library with common_porting. In the Main() function, I call the BMI160_init() function directly in this code, for example, to initialize the BMI160.

    commom_porting.c:

    common_porting.jpg

     

    bmi160_wrapper.c:

    wrapper_1.jpgwrapper_2.jpg

     

     

     

    8 REPLIES 8

    DroneKid
    Established Member

    Thank you for reference code, I updated my code with help of yours:

    #include "bmi160_wrapper.h"
    
    #define PRINTIF_DEBUG 0
    
    struct bmi160_dev sensor;
    struct bmi160_sensor_data accel;
    struct bmi160_sensor_data gyro;
    struct bmi160_foc_conf foc_conf;
    struct bmi160_offsets offsets;
    struct bmi160_int_settg int_config;
    
    int8_t resultDebug;
    
    int8_t BMI160_init() {
    
    	int8_t rslt;
    
        sensor.id = 0;
        sensor.intf = BMI160_I2C_INTF;
        sensor.read = SensorAPI_I2Cx_Read;
        sensor.write = SensorAPI_I2Cx_Write;
        sensor.delay_ms = HAL_Delay;
        sensor.read_write_len = 32;
    
        rslt = bmi160_soft_reset(&sensor);
        sensor.delay_ms(200);
        rslt = bmi160_init(&sensor);
    
        /********************************************************************/
    
        uint8_t reg_addr = BMI160_CHIP_ID_ADDR;
        uint8_t chipID = 0;
        uint16_t len = 1;
        rslt = bmi160_get_regs(reg_addr, &chipID, len, &sensor);
    
        printf("BMI160 init succesful, Chip ID (must be 209): %d\r\n", chipID);
    
        /********************************************************************/
    
        /* Select the Output data rate, range of accelerometer sensor */
        sensor.accel_cfg.odr = BMI160_ACCEL_ODR_800HZ;
        sensor.delay_ms(100);
        sensor.accel_cfg.range = BMI160_ACCEL_RANGE_8G;
        sensor.delay_ms(100);
    
        /* Select the power mode of accelerometer sensor */
        sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;
        sensor.delay_ms(100);
        sensor.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
        sensor.delay_ms(100);
    
    
        /* Select the Output data rate, range of Gyroscope sensor */
        sensor.gyro_cfg.odr = BMI160_GYRO_ODR_800HZ;
        sensor.delay_ms(100);
        sensor.gyro_cfg.range = BMI160_GYRO_RANGE_500_DPS;
        sensor.delay_ms(100);
    
        /* Select the power mode of Gyroscope sensor */
        sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;
        sensor.delay_ms(100);
        sensor.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
        sensor.delay_ms(100);
    
        /* Set the sensor configuration */
        rslt = bmi160_set_sens_conf(&sensor);
    
        /********************************************************************/
    
        rslt = start_foc();
    	printf("FOC Debug: %d\r\n", rslt);
    
    	/********************************************************************/
    
        /* 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_DATA_RDY_INT;// Choosing Any motion interrupt
        /* 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
    
        /* Set the Any-motion interrupt */
        rslt = bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev  */
    
        return rslt;
    }
    
    int8_t start_foc()
    {
    	int8_t rslt = 0;
    
    	/* Enable FOC for accel with target values of z = 1g ; x,y as 0g */
    	foc_conf.acc_off_en = BMI160_ENABLE;
    	foc_conf.foc_acc_x  = BMI160_FOC_ACCEL_0G;
    	foc_conf.foc_acc_y  = BMI160_FOC_ACCEL_0G;
    	foc_conf.foc_acc_z  = BMI160_FOC_ACCEL_POSITIVE_G;
    	sensor.delay_ms(100);
    
    	/* Enable FOC for gyro */
    	foc_conf.foc_gyr_en = BMI160_ENABLE;
    	foc_conf.gyro_off_en = BMI160_ENABLE;
    	sensor.delay_ms(100);
    
    	rslt = bmi160_start_foc(&foc_conf, &offsets, &sensor);
    
    	if (rslt == BMI160_OK)
    	{
    		printf("\n FOC DONE SUCCESSFULLY\r\n");
    		printf("\n OFFSET VALUES AFTER FOC : ");
    		printf("\n OFFSET VALUES ACCEL X : %d ",offsets.off_acc_x);
    		printf("\n OFFSET VALUES ACCEL Y : %d ",offsets.off_acc_y);
    		printf("\n OFFSET VALUES ACCEL Z : %d ",offsets.off_acc_z);
    		printf("\n OFFSET VALUES GYRO  X : %d ",offsets.off_gyro_x);
    		printf("\n OFFSET VALUES GYRO  Y : %d ",offsets.off_gyro_y);
    		printf("\n OFFSET VALUES GYRO  Z : %d\r\n",offsets.off_gyro_z);
    	}
    	else
    	{
    		printf("FOC failed\r\n");
    	}
    
    	/* After start of FOC offsets will be updated automatically and
    	 * the data will be very much close to the target values of measurement */
    
    	return rslt;
    }
    
    
    //BMI160_t *dataStruct
    int8_t bmi160ReadAccelGyro(){
    
    	int8_t rslt;
    
    	rslt = bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL), &accel, &gyro, &sensor);
    
    	if (PRINTIF_DEBUG){
    		printf("Accel X: %d\r\n", accel.x);
    		printf("Accel Y: %d\r\n", accel.y);
    		printf("Accel Z: %d\r\n", accel.z);
    
    		printf("Gyro X: %d\r\n", gyro.x);
    		printf("Gyro Y: %d\r\n", gyro.y);
    		printf("Gyro Z: %d\r\n", gyro.z);
    
    		printf("* * * * * * * * * * * * * * *\r\n");
    	}
    
    	return rslt;
    
    }

     

    Both FOC and Interrupt pin seems working. I measured the INT1 pin with an oscilloscope. In the example code I posted above, I set the ODRs to 800 Hz. I got values close to exactly 800 Hz from the oscilloscope.

    Everything seems to be working fine now. Could you check the code too? Would it be healthier to read Accel and Gyro data from FIFO instead of reading the current method?

    I am also considering using BMI160 in quadcopter. Would FOC be a sufficient calibration for this or do I need a more detailed calibration?

    Thank you.

    André
    Established Member

    how do you synchronize the call to bmi160ReadAccelGyro() and the interrupt service routine?  You can't call bmi160ReadAccelGyro() from the ISR so some semaphore is required that you poll on a regular interval somehow from the main() loop.

    The best way I think is to use a RTOS task which gets  a signal of the DRDY and fetches the data which will be always there and than goes back to sleep while it waits for the next signal.

    Using the fifo releases you of a lot of headache: you can set the size of the fifo and generate a fifo watermark interrupt on a configurable watermark level. So when you get the fifo watermark Interrupt and signal that to ie a waiting RTOS task than that task can fetch many many readings in one I2C call. You proces that data and wait for the next fifo watermark ISR/signal.  This is very usefull when using the BMX in a low power application : the processor can go to low power mode and wakes up when is gets the fifo watermark interrupt,  Note that the BMX can also gather samples while being in low power modus. 

    I might be wrong but this is my understanding of the datasheet. Please correct ne if I am wrong

     

    André

    bmi160ReadAccelGyro

     

    DroneKid
    Established Member

    I didn't implement my library to any RTOS application yet. I just test it on standart STM32CubeIDE project. I made something like that. When data is ready, INT1 pins goes from HIGH to LOW. 

     

    if(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_9) == 0) {
    	result = bmi160ReadAccelGyro(&BMI160);
    	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
    	FILTER_STATE = NEW_DATA_ARRIVED;
    }

     

     

    I will implement this core library with some sensor fusion and semaphore to RTOS

    BSTRobin
    Community Moderator
    Community Moderator

    Hi DroneKid,

    As you set ODR to 800 Hz, you first need to confirm how long you need the data so that you can better decide which way to read the data.

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist