diff --git a/README.md b/README.md index a29e977..8156688 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,793 @@ -# BMI160 Sensor API - -### Sensor overview - -The small, low power BMI160 is a low noise 16-bit IMU designed for mobile applications such as AR or indoor navigation, providing highly accurate sensor data and real-time sensor data. The low current consumption of BMI160 enables always-on applications in battery-driven devices. This sensor features a configurable on-chip interrupt engine which provides motion-based gesture recognition and context awareness as always-on background functions. - -### Target Application -- Augmented reality and immersive gaming -- Indoor navigation -- 3D-scanning / indoor mapping -- Advanced gesture recognition -- Immersive gaming -- 9-axis motion detection -- Air mouse applications and pointers -- Pedometer / step counting -- Advanced system power management for mobile applications -- Optical image stabilization of camera modules -- Free-fall detection and warranty logging - -### Features -- Any-motion detection (accelerometer) -- Significant motion detection (accelerometer) -- Step detector (accelerometer) -- Tap sensing (accelerometer) -- Orientation recognition (accelerometer) -- Flat detection (accelerometer) -- Low-G / Free-fall detection (accelerometer) -- High-G detection (accelerometer) -- Slow-motion alert / No-motion interrupt (accelerometer) -- Data ready detection (accelerometer, gyroscope and external sensors) -- PMU trigger (gyroscope) -- FIFO interrupts ((accelerometer, gyroscope and external sensors) - -### Important links - -- [BMI160 product page](https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi160/) -- [BMI160 datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi160-ds000.pdf) -- [BMI160 shuttle board flyer](https://www.bosch-sensortec.com/media/boschsensortec/downloads/shuttle_board_flyer/bst-dhw-fl022.pdf) -- [Community support page](https://community.bosch-sensortec.com) - ---- -#### Copyright (C) 2020 Bosch Sensortec GmbH \ No newline at end of file +# BMI160 sensor API +## Introduction +This package contains the Bosch Sensortec's BMI160 sensor driver (sensor API) + +The sensor driver package includes bmi160.h, bmi160.c and bmi160_defs.h files + +## Version +File | Version | Date +--------------|---------|--------------- +bmi160.c | 3.8.2 | 03 Feb 2020 +bmi160.h | 3.8.1 | 11 Jan 2020 +bmi160_defs.h | 3.8.1 | 11 Jan 2020 + +## Integration details +* Integrate bmi160.h, bmi160_defs.h and bmi160.c file in to your project. +* Include the bmi160.h file in your code like below. +``` c +#include "bmi160.h" +``` + +## File information +* bmi160_defs.h : This header file has the constants, macros and datatype declarations. +* bmi160.h : This header file contains the declarations of the sensor driver APIs. +* bmi160.c : This source file contains the definitions of the sensor driver APIs. + +## Supported sensor interface +* SPI 4-wire +* I2C + +## Usage guide +### Initializing the sensor +To initialize the sensor, you will first need to create a device structure. You +can do this by creating an instance of the structure bmi160_dev. Then go on to +fill in the various parameters as shown below. + +#### Example for SPI 4-Wire +``` c +struct bmi160_dev sensor; + +/* You may assign a chip select identifier to be handled later */ +sensor.id = 0; +sensor.interface = BMI160_SPI_INTF; +sensor.read = user_spi_read; +sensor.write = user_spi_write; +sensor.delay_ms = user_delay_ms; + + +int8_t rslt = BMI160_OK; +rslt = bmi160_init(&sensor); +/* After the above function call, accel_cfg and gyro_cfg parameters in the device +structure are set with default values, found in the datasheet of the sensor */ +``` + +#### Example for I2C +``` c +struct bmi160_dev sensor; + +sensor.id = BMI160_I2C_ADDR; +sensor.interface = BMI160_I2C_INTF; +sensor.read = user_i2c_read; +sensor.write = user_i2c_write; +sensor.delay_ms = user_delay_ms; + +int8_t rslt = BMI160_OK; +rslt = bmi160_init(&sensor); +/* 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 */ +``` + +### Configuring accel and gyro sensor +#### Example for configuring accel and gyro sensors in normal mode +``` c + +int8_t rslt = BMI160_OK; + +/* Select the Output data rate, range of accelerometer sensor */ +sensor.accel_cfg.odr = BMI160_ACCEL_ODR_1600HZ; +sensor.accel_cfg.range = BMI160_ACCEL_RANGE_2G; +sensor.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4; + +/* Select the power mode of accelerometer sensor */ +sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE; + +/* Select the Output data rate, range of Gyroscope sensor */ +sensor.gyro_cfg.odr = BMI160_GYRO_ODR_3200HZ; +sensor.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS; +sensor.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE; + +/* Select the power mode of Gyroscope sensor */ +sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE; + +/* Set the sensor configuration */ +rslt = bmi160_set_sens_conf(&sensor); +``` + +### Reading sensor data +#### Example for reading sensor data +``` c + +int8_t rslt = BMI160_OK; +struct bmi160_sensor_data accel; +struct bmi160_sensor_data gyro; + +/* To read only Accel data */ +rslt = bmi160_get_sensor_data(BMI160_ACCEL_SEL, &accel, NULL, &sensor); + +/* To read only Gyro data */ +rslt = bmi160_get_sensor_data(BMI160_GYRO_SEL, NULL, &gyro, &sensor); + +/* To read both Accel and Gyro data */ +bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL), &accel, &gyro, &sensor); + +/* To read Accel data along with time */ +rslt = bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_TIME_SEL) , &accel, NULL, &sensor); + +/* To read Gyro data along with time */ +rslt = bmi160_get_sensor_data((BMI160_GYRO_SEL | BMI160_TIME_SEL), NULL, &gyro, &sensor); + +/* To read both Accel and Gyro data along with time*/ +bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL | BMI160_TIME_SEL), &accel, &gyro, &sensor); +``` + +### Setting the power mode of sensors +#### Example for setting power mode of accel and gyro +``` c + +int8_t rslt = BMI160_OK; + +/* Select the power mode */ +sensor.accel_cfg.power = BMI160_ACCEL_SUSPEND_MODE; +sensor.gyro_cfg.power = BMI160_GYRO_FASTSTARTUP_MODE; + +/* Set the Power mode */ +rslt = bmi160_set_power_mode(&sensor); + +/* Select the power mode */ +sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE; +sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE; + +/* Set the Power mode */ +rslt = bmi160_set_power_mode(&sensor); + +``` + +### Reading sensor data register +#### Example for reading Chip Address +``` c + +int8_t rslt = BMI160_OK; +uint8_t reg_addr = BMI160_CHIP_ID_ADDR; +uint8_t data; +uint16_t len = 1; +rslt = bmi160_get_regs(reg_addr, &data, len, &sensor); +``` + + +### Writing to sensor data register +#### Example for writing data to any motion threshold register +``` c + +int8_t rslt = BMI160_OK; +uint8_t reg_addr = BMI160_INT_MOTION_1_ADDR; +uint8_t data = 20; +uint16_t len = 1; +rslt = bmi160_set_regs(reg_addr, &data, len, &sensor); +``` + +### Resetting the device using soft-reset +#### Example for writing soft-reset command to command register +``` c + +int8_t rslt = BMI160_OK; +rslt = bmi160_soft_reset(&sensor); +``` + + +### Configuring interrupts for sensors +To configure the sensor interrupts, you will first need to create an interrupt +structure. You can do this by creating an instance of the structure bmi160_int_settg. +Then go on to fill in the various parameters as shown below + + +### Configuring Any-motion Interrupt +#### Example for configuring Any-motion Interrupt +Note:- User can check the currently active interrupt(any-motion or sig-motion) by checking the **any_sig_sel** of bmi160_dev structure. +``` c + +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_ANY_MOTION_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 + +/* Select the Any-motion interrupt parameters */ +int_config.int_type_cfg.acc_any_motion_int.anymotion_en = BMI160_ENABLE;// 1- Enable the any-motion, 0- disable any-motion +int_config.int_type_cfg.acc_any_motion_int.anymotion_x = BMI160_ENABLE;// Enabling x-axis for any motion interrupt +int_config.int_type_cfg.acc_any_motion_int.anymotion_y = BMI160_ENABLE;// Enabling y-axis for any motion interrupt +int_config.int_type_cfg.acc_any_motion_int.anymotion_z = BMI160_ENABLE;// Enabling z-axis for any motion interrupt +int_config.int_type_cfg.acc_any_motion_int.anymotion_dur = 0;// any-motion duration +int_config.int_type_cfg.acc_any_motion_int.anymotion_thr = 20;// (2-g range) -> (slope_thr) * 3.91 mg, (4-g range) -> (slope_thr) * 7.81 mg, (8-g range) ->(slope_thr) * 15.63 mg, (16-g range) -> (slope_thr) * 31.25 mg + +/* Set the Any-motion interrupt */ +bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev */ + +``` +### Configuring Flat Interrupt +#### Example for configuring Flat Interrupt +``` c + +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_FLAT_INT;// Choosing flat 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 + +/* Select the Flat interrupt parameters */ +int_config.int_type_cfg.acc_flat_int.flat_en = BMI160_ENABLE;// 1-enable, 0-disable the flat interrupt +int_config.int_type_cfg.acc_flat_int.flat_theta = 8;// threshold for detection of flat position in range from 0° to 44.8°. +int_config.int_type_cfg.acc_flat_int.flat_hy = 1;// Flat hysteresis +int_config.int_type_cfg.acc_flat_int.flat_hold_time = 1;// Flat hold time (0 -> 0 ms, 1 -> 640 ms, 2 -> 1280 ms, 3 -> 2560 ms) + +/* Set the Flat interrupt */ +bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev */ + +``` + + +### Configuring Step Detector Interrupt +#### Example for configuring Step Detector Interrupt +``` c + +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_STEP_DETECT_INT;// Choosing Step Detector 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_ENABLE;// Choosing active High 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 + +/* Select the Step Detector interrupt parameters, Kindly use the recommended settings for step detector */ +int_config.int_type_cfg.acc_step_detect_int.step_detector_mode = BMI160_STEP_DETECT_NORMAL; +int_config.int_type_cfg.acc_step_detect_int.step_detector_en = BMI160_ENABLE;// 1-enable, 0-disable the step detector + +/* Set the Step Detector interrupt */ +bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev */ + +``` + +### Configuring Step counter +To configure the step counter, user need to configure the step detector interrupt as described in above section. +After configuring step detector, see the below code snippet for user space & ISR + +### User space +``` c +int8_t rslt = BMI160_OK; +uint8_t step_enable = 1;//enable the step counter + +rslt = bmi160_set_step_counter(step_enable, &sensor); +``` + +### ISR +``` c +int8_t rslt = BMI160_OK; +uint16_t step_count = 0;//stores the step counter value + +rslt = bmi160_read_step_counter(&step_count, &sensor); +``` + +### Unmapping Interrupt +#### Example for unmapping Step Detector Interrupt +``` c +struct bmi160_int_settg int_config; + +/* Deselect the Interrupt channel/pin */ +int_config.int_channel = BMI160_INT_CHANNEL_NONE; +/* Select the Interrupt type */ +int_config.int_type = BMI160_STEP_DETECT_INT;// Choosing Step Detector interrupt +/* Set the Step Detector interrupt */ +bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev */ +``` + +### Reading interrupt status +#### Example for reading interrupt status for step detector +``` c +union bmi160_int_status interrupt; +enum bmi160_int_status_sel int_status_sel; + +/* Interrupt status selection to read all interrupts */ +int_status_sel = BMI160_INT_STATUS_ALL; +rslt = bmi160_get_int_status(int_status_sel, &interrupt, &sensor); +if (interrupt.bit.step) + printf("Step detector interrupt occured\n"); +``` + +### Configuring the auxiliary sensor BMM150 +It is assumed that secondary interface of bmi160 has external pull-up resistor in order to access the auxiliary sensor bmm150. + +### Accessing auxiliary BMM150 with BMM150 APIs via BMI160 secondary interface. + +## Integration details +* Integrate the souce codes of BMM150 and BMI160 in project. +* Include the bmi160.h and bmm150.h file in your code like below. +* It is mandatory to initialize the bmi160 device structure for primary interface and auxiliary sensor settings. +* Create two wrapper functions , user_aux_read and user_aux_write in order to match the signature as mentioned below. +* Invoke the "bmi160_aux_init" API to initialise the secondary interface in BMI160. +* Invoke the "bmm150_init" API to initialise the BMM150 sensor. +* Now we can use the BMM150 sensor APIs to access the BMM150 via BMI160. + +``` c +/* main.c file */ +#include "bmi160.h" +#include "bmm150.h" +``` +### Initialization of auxiliary sensor BMM150 +``` + +/* main.c file */ +struct bmm150_dev bmm150; + +/* function declaration */ +int8_t user_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len); +int8_t user_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len); + +/* Configure device structure for auxiliary sensor parameter */ +sensor.aux_cfg.aux_sensor_enable = 1; // auxiliary sensor enable +sensor.aux_cfg.aux_i2c_addr = BMI160_AUX_BMM150_I2C_ADDR; // auxiliary sensor address +sensor.aux_cfg.manual_enable = 1; // setup mode enable +sensor.aux_cfg.aux_rd_burst_len = 2;// burst read of 2 byte + +/* Configure the BMM150 device structure by +mapping user_aux_read and user_aux_write */ +bmm150.read = user_aux_read; +bmm150.write = user_aux_write; +bmm150.id = BMM150_DEFAULT_I2C_ADDRESS; +/* Ensure that sensor.aux_cfg.aux_i2c_addr = bmm150.id + for proper sensor operation */ +bmm150.delay_ms = delay_ms; +bmm150.interface = BMM150_I2C_INTF; + +/* Initialize the auxiliary sensor interface */ +rslt = bmi160_aux_init(&sensor); + +/* Auxiliary sensor is enabled and can be accessed from this point */ + +/* Configure the desired settings in auxiliary BMM150 sensor + * using the bmm150 APIs */ + +/* Initialising the bmm150 sensor */ +rslt = bmm150_init(&bmm150); + +/* Set the power mode and preset mode to enable Mag data sampling */ +bmm150.settings.pwr_mode = BMM150_NORMAL_MODE; +rslt = bmm150_set_op_mode(&bmm150); + +bmm150.settings.preset_mode= BMM150_PRESETMODE_LOWPOWER; +rslt = bmm150_set_presetmode(&bmm150); + +``` +### Wrapper functions +``` + +/*wrapper function to match the signature of bmm150.read */ +int8_t user_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len) +{ + int8_t rslt; + + /* Discarding the parameter id as it is redundant*/ + rslt = bmi160_aux_read(reg_addr, aux_data, len, &bmi160); + + return rslt; +} + +/*wrapper function to match the signature of bmm150.write */ +int8_t user_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len) +{ + int8_t rslt; + + /* Discarding the parameter id as it is redundant */ + rslt = bmi160_aux_write(reg_addr, aux_data, len, &bmi160); + + return rslt; +} + +``` + +### Initialization of auxiliary BMM150 in auto mode +Any sensor whose data bytes are less than or equal to 8 bytes can be synchronized with the BMI160 +and read out of Accelerometer + Gyroscope + Auxiliary sensor data of that instance is possible +which helps in creating less latency fusion data + +``` +/* Initialize the Auxiliary BMM150 following the above code + * until setting the power mode (Set the power mode as forced mode) + * and preset mode */ + + /* In BMM150 Mag data starts from register address 0x42 */ + uint8_t aux_addr = 0x42; + /* Buffer to store the Mag data from 0x42 to 0x48 */ + uint8_t mag_data[8] = {0}; + + uint8_t index; + + /* Configure the Auxiliary sensor either in auto/manual modes and set the + polling frequency for the Auxiliary interface */ + sensor.aux_cfg.aux_odr = 8; /* Represents polling rate in 100 Hz*/ + rslt = bmi160_config_aux_mode(&sensor) + + /* Set the auxiliary sensor to auto mode */ + rslt = bmi160_set_aux_auto_mode(&aux_addr, &sensor); + + /* Reading data from BMI160 data registers */ + rslt = bmi160_read_aux_data_auto_mode(mag_data, &sensor); + + printf("\n RAW DATA "); + for(index = 0 ; index < 8 ; index++) + { + printf("\n MAG DATA[%d] : %d ", index, mag_data[index]); + } + + /* Compensating the raw mag data available from the BMM150 API */ + rslt = bmm150_aux_mag_data(mag_data, &bmm150); + + printf("\n COMPENSATED DATA "); + printf("\n MAG DATA X : %d Y : %d Z : %d", bmm150.data.x, bmm150.data.y, bmm150.data.z); + + +``` + +### Auxiliary FIFO data parsing +The Auxiliary sensor data can be stored in FIFO , Here we demonstrate an example for +using the Bosch Magnetometer sensor BMM150 and storing its data in FIFO + +``` +/* Initialize the Aux BMM150 following the above + * code and by creating the Wrapper functions */ + + int8_t rslt = 0; + uint8_t aux_instance = 0; + uint16_t fifo_cnt = 0; + uint8_t auto_mode_addr; + uint8_t i; + + /* Setup and configure the FIFO buffer */ + /* Declare memory to store the raw FIFO buffer information */ + uint8_t fifo_buff[1000] = {0}; + + /* 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 = 1000; + dev->fifo = &fifo_frame; + + /* Declare instances of the sensor data structure to store the parsed FIFO data */ + struct bmi160_aux_data aux_data[112]; //1000 / 9 bytes per frame ~ 111 data frames + + rslt = bmi160_init(dev); + printf("\n BMI160 chip ID is : %d ",dev->chip_id); + + rslt = bmi160_aux_init(dev); + + rslt = bmm150_init(&bmm150); + printf("\n BMM150 CHIP ID : %d",bmm150.chip_id); + + bmm150.settings.preset_mode = BMM150_PRESETMODE_LOWPOWER; + rslt = bmm150_set_presetmode(&bmm150); + + bmm150.settings.pwr_mode = BMM150_FORCED_MODE; + rslt = bmm150_set_op_mode(&bmm150); + + /* Enter the data register of BMM150 to "auto_mode_addr" here it is 0x42 */ + auto_mode_addr = 0x42; + printf("\n ENTERING AUX. AUTO MODE "); + dev->aux_cfg.aux_odr = BMI160_AUX_ODR_25HZ; + rslt = bmi160_set_aux_auto_mode(&auto_mode_addr, dev); + + + /* Disable other FIFO settings */ + rslt = bmi160_set_fifo_config(BMI160_FIFO_CONFIG_1_MASK , BMI160_DISABLE, dev); + + /* Enable the required FIFO settings */ + rslt = bmi160_set_fifo_config(BMI160_FIFO_AUX | BMI160_FIFO_HEADER, BMI160_ENABLE, dev); + + /* Delay for the FIFO to get filled */ + dev->delay_ms(400); + + + printf("\n FIFO DATA REQUESTED (in bytes): %d",dev->fifo->length); + rslt = bmi160_get_fifo_data(dev); + printf("\n FIFO DATA AVAILABLE (in bytes): %d",dev->fifo->length); + + /* Print the raw FIFO data obtained */ + for(fifo_cnt = 0; fifo_cnt < dev->fifo->length ; fifo_cnt++) { + printf("\n FIFO DATA [%d] IS : %x ",fifo_cnt ,dev->fifo->data[fifo_cnt]); + } + + printf("\n\n----------------------------------------------------\n"); + + /* Set the number of required sensor data instances */ + aux_instance = 150; + + /* Extract the aux data , 1frame = 8 data bytes */ + printf("\n AUX DATA REQUESTED TO BE EXTRACTED (in frames): %d",aux_instance); + rslt = bmi160_extract_aux(aux_data, &aux_instance, dev); + printf("\n AUX DATA ACTUALLY EXTRACTED (in frames): %d",aux_instance); + + /* Printing the raw aux data */ + for (i = 0; i < aux_instance; i++) { + printf("\n Aux data[%d] : %x",i,aux_data[i].data[0]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[1]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[2]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[3]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[4]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[5]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[6]); + printf("\n Aux data[%d] : %x",i,aux_data[i].data[7]); + } + + printf("\n\n----------------------------------------------------\n"); + + /* Compensate the raw mag data using BMM150 API */ + for (i = 0; i < aux_instance; i++) { + printf("\n----------------------------------------------------"); + printf("\n Aux data[%d] : %x , %x , %x , %x , %x , %x , %x , %x",i + ,aux_data[i].data[0],aux_data[i].data[1] + ,aux_data[i].data[2],aux_data[i].data[3] + ,aux_data[i].data[4],aux_data[i].data[5] + ,aux_data[i].data[6],aux_data[i].data[7]); + + /* Compensated mag data using BMM150 API */ + rslt = bmm150_aux_mag_data(&aux_data[i].data[0], &bmm150); + + /* Printing the Compensated mag data */ + if (rslt == BMM150_OK) { + printf("\n MAG DATA COMPENSATION USING BMM150 APIs"); + printf("\n COMPENSATED DATA "); + printf("\n MAG DATA X : %d Y : %d Z : %d" + , bmm150.data.x, bmm150.data.y, bmm150.data.z); + + } else { + printf("\n MAG DATA COMPENSATION IN BMM150 API is FAILED "); + } + printf("\n----------------------------------------------------\n"); + } + +``` + +## Self-test +#### Example for performing accel self test +``` +/* Call the "bmi160_init" API as a prerequisite before performing self test + * since invoking self-test will reset the sensor */ + + rslt = bmi160_perform_self_test(BMI160_ACCEL_ONLY, sen); + /* Utilize the enum BMI160_GYRO_ONLY instead of BMI160_ACCEL_ONLY + to perform self test for gyro */ + if (rslt == BMI160_OK) { + printf("\n ACCEL SELF TEST RESULT SUCCESS); + } else { + printf("\n ACCEL SELF TEST RESULT FAIL); + } +``` + + +## FIFO +#### Example for reading FIFO and extracting Gyro data in Header mode +``` +/* An example to read the Gyro data in header mode along with sensor time (if available) + * Configure the gyro sensor as prerequisite and follow the below example to read and + * obtain the gyro data from FIFO */ +int8_t fifo_gyro_header_time_data(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + + /* Declare memory to store the raw FIFO buffer information */ + uint8_t fifo_buff[300]; + + /* 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 = 300; + 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[42]; // 300 bytes / ~7bytes per frame ~ 42 data frames + uint8_t gyro_frames_req = 42; + uint8_t gyro_index; + + /* Configure the sensor's FIFO settings */ + rslt = bmi160_set_fifo_config(BMI160_FIFO_GYRO | BMI160_FIFO_HEADER | BMI160_FIFO_TIME, + BMI160_ENABLE, dev); + + if (rslt == BMI160_OK) { + /* At ODR of 100 Hz ,1 frame gets updated in 1/100 = 0.01s + i.e. for 42 frames we need 42 * 0.01 = 0.42s = 420ms delay */ + dev->delay_ms(420); + + /* Read data from the sensor's FIFO and store it the FIFO buffer,"fifo_buff" */ + printf("\n USER REQUESTED FIFO LENGTH : %d\n",dev->fifo->length); + rslt = bmi160_get_fifo_data(dev); + + if (rslt == BMI160_OK) { + printf("\n AVAILABLE FIFO LENGTH : %d\n",dev->fifo->length); + /* Print the raw FIFO data */ + for (index = 0; index < dev->fifo->length; index++) { + printf("\n FIFO DATA INDEX[%d] = %d", index, + dev->fifo->data[index]); + } + /* Parse the FIFO data to extract gyro data from the FIFO buffer */ + printf("\n REQUESTED GYRO DATA FRAMES : %d\n ",gyro_frames_req); + rslt = bmi160_extract_gyro(gyro_data, &gyro_frames_req, dev); + + if (rslt == BMI160_OK) { + printf("\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++) { + printf("\nFIFO GYRO FRAME[%d]",gyro_index); + printf("\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); + } + /* Print the special FIFO frame data like sensortime */ + printf("\n SENSOR TIME DATA : %d \n",dev->fifo->sensor_time); + printf("SKIPPED FRAME COUNT : %d",dev->fifo->skipped_frame_count); + } else { + printf("\n Gyro data extraction failed"); + } + } else { + printf("\n Reading FIFO data failed"); + } + } else { + printf("\n Setting FIFO configuration failed"); + } + + return rslt; +} +``` + +## FOC and offset compensation +> FOC shouldnot be used in Low-power mode +#### Example for configuring FOC for accel and gyro +``` +/* An example for configuring FOC for accel and gyro data */ +int8_t start_foc(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + /* FOC configuration structure */ + struct bmi160_foc_conf foc_conf; + /* Structure to store the offsets */ + struct bmi160_offsets offsets; + + /* 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; + + /* Enable FOC for gyro */ + foc_conf.foc_gyr_en = BMI160_ENABLE; + foc_conf.gyro_off_en = BMI160_ENABLE; + + rslt = bmi160_start_foc(&foc_conf, &offsets, sen); + + if (rslt == BMI160_OK) { + printf("\n FOC DONE SUCCESSFULLY "); + 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 ",offsets.off_gyro_z); + } + + /* 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; +} +``` + +#### Example for updating the offsets manually +> The offsets set by this method will be reset on soft-reset/POR +``` +/* An example for updating manual offsets to sensor */ +int8_t write_offsets(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + /* FOC configuration structure */ + struct bmi160_foc_conf foc_conf; + /* Structure to store the offsets */ + struct bmi160_offsets offsets; + + /* Enable offset update for accel */ + foc_conf.acc_off_en = BMI160_ENABLE; + + /* Enable offset update for gyro */ + foc_conf.gyro_off_en = BMI160_ENABLE; + + /* offset values set by user */ + offsets.off_acc_x = 0x10; + offsets.off_acc_y = 0x10; + offsets.off_acc_z = 0x10; + offsets.off_gyro_x = 0x10; + offsets.off_gyro_y = 0x10; + offsets.off_gyro_z = 0x10; + + rslt = bmi160_set_offsets(&foc_conf, &offsets, sen); + + /* After offset setting the data read from the + * sensor will have the corresponding offset */ + + return rslt; +} +``` + +#### Example for updating the offsets into NVM +> The offsets set by this method will be present in NVM and will be +> restored on POR/soft-reset +``` +/* An example for updating manual offsets to sensor */ +int8_t write_offsets_nvm(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + /* FOC configuration structure */ + struct bmi160_foc_conf foc_conf; + /* Structure to store the offsets */ + struct bmi160_offsets offsets; + + /* Enable offset update for accel */ + foc_conf.acc_off_en = BMI160_ENABLE; + + /* Enable offset update for gyro */ + foc_conf.gyro_off_en = BMI160_ENABLE; + + /* offset values set by user as per their reference + * Resolution of accel = 3.9mg/LSB + * Resolution of gyro = (0.061degrees/second)/LSB */ + offsets.off_acc_x = 10; + offsets.off_acc_y = -15; + offsets.off_acc_z = 20; + offsets.off_gyro_x = 30; + offsets.off_gyro_y = -35; + offsets.off_gyro_z = -40; + + rslt = bmi160_set_offsets(&foc_conf, &offsets, sen); + + if (rslt == BMI160_OK) { + /* Update the NVM */ + rslt = bmi160_update_nvm(dev); + } + + /* After this procedure the offsets are written to + * NVM and restored on POR/soft-reset + * The set values can be removed to ideal case by + * invoking the following APIs + * - bmi160_start_foc() + * - bmi160_update_nvm() + */ + + return rslt; +} +``` + + + +## Copyright (C) 2016 - 2017 Bosch Sensortec GmbH \ No newline at end of file