Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    Sort by:
    100% helpful (7/7)
    ‎05-31-2021 12:09 PM
    Frequently Asked Questions (FAQs) about the BME688 sensor
    View full article
    ‎08-02-2023 02:43 PM
    This design guide describes the main features of the BME680, available evaluation tools and software, reference design, layout recommendations, and gives instructions on how to test the sensor’s functionality using sample codes.
    View full article
    ‎10-14-2019 03:27 PM
    BME680 is as combined digital gas, humidity, pressure and temperature sensor based on proven sensing principles. API Link: https://github.com/BoschSensortec/BME680_driver BSEC Link: https://www.bosch-sensortec.com/bst/products/all_products/bme680 Sensor data type Gas sensor data is gas sensor resistance. Humidity sensor data is in type of percentage (10%-90%, in 0°C-65°C). Pressure sensor data is in type of hPa (300hPa-1100hPa, in 0°C-65°C). Temperature sensor data is in type of °C (-40°C-85°C). Use function bme680_get_sensor_data in API to get sensor data. Use BSEC software Library, put gas/humidity/pressure/temperature sensor data as inputs into BSEC, you can also get IAQ(Indoor Air Quality) from outputs. Measurement preiod The BME680 measurement period consists of a temperature, pressure and humidity measurement with selectable oversampling. Moreover, it contains a heating phase for the gas sensor hot plate as well as a measurement of the gas sensor resistance. After the measurement period, the pressure and temperature data can be passed through an optional IIR filter, which removes short-term fluctuations in pressure (e.g. caused by slamming a door). For humidity and gas, such a filter is not needed and has not been implemented Gas resistance sensitivity The sensitivity of BME680 to certain target gas is gas_resistance/gas_resistance_base. The sensitivity equaling to 1 means BME680 is not sensitivity in this concentration of the target gas, while the less value in sensitivity, the more sensitive BME680 to the target gas.  Data Interrupt There is new data interrupt in BME680, below table shows how to enable this feature.  Pressure sensor drift Used to represent errors in measured values. Basically, two drifts will appear on the pressure part in BME680: one is solder drifts and the other is long term drift.  Pressure sensor offset temperature coefficient (TCO) TCO is the change in the pressure signal introduced by a change of the temperature. For pressure sensor, TCO is ±1.5 Pa/K, equiv. to ±12.6 cm at 1 °C temperature change, which means pressure sensor data will change within ±1.5 Pa with 1 °C temperature change at constant pressure. Accuracy of temperature/pressure/humidity This feature is used to represent how much accuracy can be achieved on certain condition. Humidity sensor: ±3 % relative humidity, on condition: 20-80 %r.H., 25°C, including hysteresis Pressure sensor: 0.12 hPa, on condition: 25°C-40°C, 700-1100hPa, at constat humidity Temperature Sensor: ±1°C, on condition: 25°C ±0.5°C, on condition: 0…65°C OSR / Oversampling of humidity/pressure/temperature There are several oversampling options for different sensors. It is possible to reduce noise, but the power consumption will be higher. Humidity sensor OSR  As for how to set osrs_h<2:0>, b000->skip humidity data/no humidity, b001->oversamplingx1, b010->oversamplingx2, b011->oversamplingx4, b100->oversamplingx8, b101/Others->oversamplingx16. Pressure sensor OSR  As for how to set osrs_p<4:2>, b000->skip humidity data/no humidity, b001->oversamplingx1, b010->oversamplingx2, b011->oversamplingx4, b100->oversamplingx8, b101/Others->oversamplingx16. Temperature sensor OSR  As for how to set osrs_t<7:5>, b000->skip humidity data/no humidity, b001->oversamplingx1, b010->oversamplingx2, b011->oversamplingx4, b100->oversamplingx8, b101/Others->oversamplingx16. You can use function bme680_set_sensor_settings in API to set OSR of any sensor. Signal filter The environmental pressure is subject to many short-term changes, caused e.g. by slamming of a door or window, or wind blowing into the sensor. To suppress these disturbances in the output data without causing additional interface traffic and processor work load, the BME680 features an internal IIR filter. Via setting filter coefficient(c), it effectively reduces the bandwidth of the temperature and pressure output signals and increases the resolution of the pressure and temperature output data to 20 bit(Pressure and Temperature OSR must be non-zero). When c is bigger, response time will be longer.  As for how to set filter<4:2>, b000->filter coefficient 0, b001-> filter coefficient 1, b010-> filter coefficient 3, b011-> filter coefficient 7, b100-> filter coefficient 15, b101-> filter coefficient 31,  b110-> filter coefficient 63, b111-> filter coefficient 127. You can use function bme680_set_sensor_settings in API to set filter.    
    View full article
    0% helpful (0/1)
    ‎08-14-2019 10:04 AM
     Introduction This document is meant as a reference guide on how to design using Bosch Sensortec’s BME280 series of humidity sensor. Selecting the right part The BME280 series of humidity sensor contains 1 products: BME280. Table 1 shows an overview of the features.                                                                Table 1: Overview of the products in this family  Common characteristics The main characteristics of this product family are:  Key features The BME280 is an integrated environmental sensor developed specifically for mobile applications where size and low power consumption are key design constraints. The unit combines individual high linearity, high accuracy sensors for pressure, humidity and temperature in an 8-pin metal-lid 2.5 x 2.5 x 0.93 mm³ LGA package, designed for low current consumption (3.6 μA @1Hz), long term stability and high EMC robustness. The humidity sensor features an extremely fast response time which supports performance requirements for emerging applications such as context awareness, and high accuracy over a wide temperature range. The pressure sensor is an absolute barometric pressure sensor with features exceptionally high accuracy and resolution at very low noise. The integrated temperature sensor has been optimized for very low noise and high resolution. It is primarily used for temperature compensation of the pressure and humidity sensors, and can also be used for estimating ambient temperature. The BME280 supports a full suite of operating modes which provide the flexibility to optimize the device for power consumption, resolution and filter performance.  Available evaluation tools and software To best to evaluate the products from the BME280 family, we recommend the following combination of evaluation tools: COINES Desktop software Installer for Windows based systems: https://ae-bst.resource.bosch.com/media/_tech/media/coines/COINES_Installers_v1.1_Windows.zip Installer for Linux based systems: https://ae-bst.resource.bosch.com/media/_tech/media/coines/COINES_Installers_v1.1_Linux.zip Application board 2.0 Without bluetooth. Ordering code 0330.AB0.011 With bluetooth. Ordering code 0330.AB0.111 https://www.bosch-sensortec.com/bst/support_tools/application_boards/overview_application_boards Sensor Shuttle board BME280 Shuttle board. Ordering code 0330.SB4.185  Reference design See Figure 1 for a complete schematic of a typical BME280 use-case.                                                         Fig. 1: Mockup Reference design    Bill of materials                                              Table 3: Bill of materials  Layout recommendations Because the BME280 sensor family contains tiny mechanical structure inside the package, care must be taken during the layout phase to ensure the best performance. The complete handling and soldering guide can be found on the Bosch Sensortec’s website. In addition to the attached guidelines, see below for the typical manufacturing procedure for the BME280 humidity sensor.       Landing Pattern                                                                  Fig. 2: Recommended landing pattern Note: red areas demark exposed PCB metal pads. In case of a solder mask defined (SMD) PCB process, the land dimensions should be defined by solder mask openings. The underlying metal pads are larger than these openings. In case of a non solder mask defined (NSMD) PCB process, the land dimensions should be defined in the metal layer. The mask openings are larger than these metal pads.  Typical Layout                                                                              Figure 3: Typical layout Manufacturing notes                                                             Table 4: Manufacture recommendation   First power-on After powering the sensor for the first time, the initial specs would be to test for communication with the device. This can be done simply by reading the chip identification code in the register 0xD0. See below for the expected values                                                         Table 5: Chip IDs of the BME280 product family Here is some sample code on how to perform this test, using the COINES software as the host. /*! * @brief This internal API is used to initializes the bme280 sensor with default * settings like power mode and OSRS settings * * @param[in] void * * @return void * */ static void init_bme280(void) { int8_t rslt; rslt = bme280_init(&bme280Dev); if (rslt == BME280_OK) { printf("BME280 Initialization Success!\n"); printf("Chip ID 0x%x\n", bme280Dev.chip_id); } else { printf("Chip Initialization failure !\n"); exit(COINES_E_FAILURE); } coines_delay_msec(100); bme280_set_sensor_mode(BME280_NORMAL_MODE, &bme280Dev); } How to read sensor data  Here is some sample code on how to read sensor data, using the COINES software as the host. /*! * @brief This internal API is used to read the streaming data in a while loop and * print in console. * * @param[in] void * * @return void */ static void read_sensor_data(void) { int times_to_read = 0; while (times_to_read < 200) { bme280_get_sensor_data(BME280_ALL, &bme280_comp_data, &bme280Dev); printf("T: %.2f, H: %.2f, P: %.2f \n", (bme280_comp_data.temperature / 100.), (bme280_comp_data.humidity / 1000.), (bme280_comp_data.pressure / 100.)); fflush(stdout); coines_delay_msec(10); times_to_read = times_to_read + 1; } } Sample code The complete sample code shown above can be compiled and executed from the COINES installation directory (by default, C:/COINES under Windows), from the following subfolder: \examples\c\bme280 Usage The COINES installation provides sample code on how to turn on the sensor, configure it and read out data. COINES\v1.0\ examples\c\bme280 Sample code /*! * @brief Main Function where the execution getting started to test the code. * * @param[in] argc * @param[in] argv * * @return status * */ int main(int argc, char *argv[]) { int16_t rslt; struct coines_board_info board_info; init_bme280_sensor_driver_interface(); rslt = coines_open_comm_intf(COINES_COMM_INTF_USB); if (rslt < 0) { printf("\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); exit(rslt); } rslt = coines_get_board_info(&board_info); if (rslt == COINES_SUCCESS) { if (board_info.shuttle_id != BME280_SHUTTLE_ID) { printf("! Warning invalid sensor shuttle. This application will not support this sensor \r\n" "1.Check the sensor shuttle \r\n" "2.Reset the board \r\n"); exit(COINES_E_FAILURE); } } init_sensor_interface(); /* after sensor init introduce 200 msec sleep */ coines_delay_msec(200); init_bme280(); read_sensor_data(); coines_close_comm_intf(COINES_COMM_INTF_USB); return EXIT_SUCCESS; } Further reads Datasheets: BME280 Datasheet https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280-DS002.pdf Handling, soldering  and mounting instructions: BME280 HSMI https://ae-bst.resource.bosch.com/media/_tech/media/application_notes/BST-BME280-HS006.pdf                                          
    View full article
    100% helpful (1/1)
    ‎08-14-2019 10:20 AM
     Introduction This document is meant as a reference guide on how to design using Bosch Sensortec’s BMA400 accelerometer.  Selecting the right part The BMA400 is the first ultra-low power accelerometer with anti-aliasing performance, so strictly speaking, currently there is no compatible sensors in Bosch SensorTec products. However, a comparison between BMA400 & BMA4xy series is helpful for user to understand BMA400’s performance better. Table 1 shows an overview of the features.                                                                                  Table 1 sensor main features   Common characteristics The main characteristics of this product family are:   Key features LGA package (12 pins), 2mm x 2mm x 0.95mm Ultra-low power consumption:      3.5uA @800Hz to 14uA@800Hz (configurable in normal mode) 0.8uA @25Hz to 1.2uA @25Hz (configurable in low power mode) Anti-aliasing: consecutive sampling in normal mode (not duty-cycling) Configurable Acceleration ranges ±2g/±4g/±8g/±16g Configurable output data rate: 12.5Hz to 800Hz (normal mode) 1 KB FIFO Auto-low power/Auto wakeup Activity/In-activity Step Counter (overall device current consumption 4µA) Activity Recognition (Walking, Running, Standing still) Orientation detection Tap/double tap   Free-fall detection Wearables, position Differences between products BMA400 is the only one product with ultra-low power feature from Bosch Sensor tech. The key parameters are listed in Table 2.                                                                     Table 2 Key parameters of BMA400 Available evaluation tools and software To best to evaluate the products from the BMA400 family is the following combination of evaluation tools: COINES Desktop software, BST_download_page -> ‘Software’ Tap -> ‘Communication with Inertial and Environmental Sensors (COINES)’ Application board 2.0 https://ae-bst.resource.bosch.com/media/_tech/media/shuttleboard_flyer/Applicationboard-2-0_Flyer.pdf Sensor Shuttle board BMA400 Shuttle board Reference design See Figure 1 for a complete schematic of a typical use-case. Note: SPI is highly recommended because of the low current consumption. Since if I2C interface is applied, the pull-up resistors will consume significantly high current comparing to BMA400 ultra-low power consumption. The VDDIO of MCU and BMA400 should be connected to same power source (level). GPIO1 & GPIO2 of MCU should be configured as input if connected to INT1/INT2 of BMA400. In case I2C interface is used (even not recommended), connect CSB to VDDIO to prevent unwanted level jumps on CSB pin, which might bring BMA400 from I2C mode to SPI mode, especially during ESD test. Table 3 shows the bill of materials.                                                               Table 3 BMA400 relevant Bill of materials  Layout recommendations Because the BMA400 sensor family contains tiny mechanical structure inside the package, care must be taken during the layout phase to ensure the best performance. The complete handling and soldering guide can be found on the Bosch Sensortec’s website. BST_BMA400 -> ‘downloads’ -> ‘Handling & Soldering instructions’ In addition to the attached guidelines, see below for the typical integration & manufacturing procedure for the BMA400 accelerometer.    Landing Pattern                                                                 Figure 2 Landing pattern      Typical Layout Figure 3 Typical layout Note: No via under sensor. On top layer, where sensor is mounted, no copper under sensor; while on the 2 nd layer (bottom layer of 2-layers PCB), ground copper is welcomed to prevent EMI interference. Traces should be fanned out to the outside of sensor, not inside. In the area of sensor, no trace should be on the 2 nd layer (bottom layer of 2-layers PCB); When there is ground copper on the 2 nd layer, traces can be on 3 rd ( and 4 th /5 th …) layers; But keep high frequency or high current signals away from sensor area, from top to bottom. Manufacturing notes                                                                              Table 4 Manufacturing parameters First power-on After powering the sensor for the first time, the initial specs would be to test for communication with the device. This can be done simply by reading the chip identification code in the register 0x00. See below for the expected values:                                                                   Table 5 Chip ID of the BMA400 product To properly initialize the device, the user must decide which interface to use (I2C or SPI) during hardware design. After power up, BMA400 is by default in I2C mode, until detect a rising edge on CSB pin, then BMA400 will switch to SPI mode until next soft rest or power on reset. Therefore, once BMA400 is connected to SPI interface from host, firstly a rising edge on CSB pin should be triggered, which can be implemented, for example, by a read from CHIPID register. For I2C connect, pulling the CSB pin to VDDIO directly or through a resistor will prevent BMA400 switches to SPI mode during running or ESD. For SPI read, the first byte got from BMA400 is always a dummy byte, which should be skipped. The valuable information start from the second byte. Here is some sample code on how to perform a CHIPID reading, using the COINES software (check Chapter 2.3 for detailed information) as the host. * @brief This internal API is used to initializes the bma400 sensor with default * settings like power mode and OSRS settings * * @param[in] void * * @return void * */ static void init_bma400(void) { int8_t rslt; rslt = bma400_init(&bma400dev); if (rslt == BMA400_OK) { printf("BMA400 Initialization Success!\n"); printf("Chip ID 0x%x\n", bma400dev.chip_id); } else { print_rslt(rslt); exit(COINES_E_FAILURE); } coines_delay_msec(100); } /********************** Global function definitions ************************/ /*! * @brief This API is the entry point, Call this API before using other APIs. * This API reads the chip-id of the sensor which is the first step to * verify the sensor and updates the trim parameters of the sensor. */ int8_t bma400_init(struct bma400_dev *dev) { int8_t rslt; uint8_t chip_id = 0; /* Check for null pointer in the device structure*/ rslt = null_ptr_check(dev); /* Proceed if null check is fine */ if (rslt == BMA400_OK) { /* Initial power-up time */ dev->delay_ms(5); /* Assigning dummy byte value */ if (dev->intf == BMA400_SPI_INTF) { /* Dummy Byte availability */ dev->dummy_byte = 1; /* Dummy read of Chip-ID in SPI mode */ rslt = bma400_get_regs(BMA400_CHIP_ID_ADDR, &chip_id, 1, dev); } else { dev->dummy_byte = 0; } if (rslt == BMA400_OK) { /* Chip ID of the sensor is read */ rslt = bma400_get_regs(BMA400_CHIP_ID_ADDR, &chip_id, 1, dev); /* Proceed if everything is fine until now */ if (rslt == BMA400_OK) { /* Check for chip id validity */ if (chip_id == BMA400_CHIP_ID) { /* Store the chip ID in dev structure */ dev->chip_id = chip_id; } else { rslt = BMA400_E_DEV_NOT_FOUND; } } } } return rslt; } How to test the sensor’s functionality The BMA400 accelerometer features a fully integrated and motionless self-test procedure on the ASIC itself. When the self-test is triggered, the accelerometer uses electric fields to physically move the electrodes in all directions, senses the deflection and compares it with the expected output. Therefore, the built-in self-test features is the recommended way to test the sensor’s functionality. Here are some sample codes on how to perform this self-test, based on BMA400, using the COINES software as the host. Codes from COINS(caller): /*! * @brief This internal API is used to perform the self test * * @param[in] bma400dev: device structure * * @return void * */ static void perform_self_test(struct bma400_dev *bma400dev) { int8_t rslt; /* Doing soft reset */ rslt = bma400_soft_reset(bma400dev); print_rslt(rslt); printf("Running self test...\r\n"); coines_delay_msec(500); rslt = bma400_perform_self_test(bma400dev); print_rslt(rslt); if (rslt == BMA400_OK) { printf("Self test passed!\r\n"); } fflush(stdout); }  Codes from BMA400 API: /*! * @brief This is used to perform self test of accelerometer in BMA400 */ int8_t bma400_perform_self_test(const struct bma400_dev *dev) { int8_t rslt; int8_t self_test_rslt = 0; struct bma400_sensor_data accel_pos, accel_neg; /* Check for null pointer in the device structure */ rslt = null_ptr_check(dev); /* Proceed if null check is fine */ if (rslt == BMA400_OK) { /* pre-requisites for self test*/ rslt = enable_self_test(dev); if (rslt == BMA400_OK) { rslt = positive_excited_accel(&accel_pos, dev); if (rslt == BMA400_OK) { rslt = negative_excited_accel(&accel_neg, dev); if (rslt == BMA400_OK) { /* Validate the self test result */ rslt = validate_accel_self_test(&accel_pos, &accel_neg); } } } } /* Check to ensure bus error does not occur */ if (rslt >= BMA400_OK) { /* Store the status of self test result */ self_test_rslt = rslt; /* Perform soft reset */ rslt = bma400_soft_reset(dev); } /* Check to ensure bus operations are success */ if (rslt == BMA400_OK) { /* Restore self_test_rslt as return value */ rslt = self_test_rslt; } return rslt; } How to test the sensor’s performance There are two performance parameters that can easily be tested with the device motionless: offset and noise. See below for the typical values of the sensors. Note: Typical values are defined as ±1σ, which means that we expect 68.3% of sensors to fall within these values. Min/Max values are defined as ±3σ, which means 99.7% of sensors shall be within these values. For the offset, the test procedure is quite simple. With the device in a known position, such as a flat surface, calculate the average value for each axis, and subtract the expected output (e.g. 0G, 0G, +1G) from the data. The result is the offset of the sensor. Here is some sample code on how to perform this test, based on BMA400, using the COINES software as the host. Missed BMA400 offset calculation examples: /*! * @brief This internal API is used to measure the sensor offset * * @param[out] x_off_mg, y_off_mg, z_off_mg * * @return void * */ static void bma423_get_offset(double *x_off_mg, double *y_off_mg, double *z_off_mg) { uint16_t commrslt; /* Declare an accelerometer configuration structure */ struct bma4_accel_config accel_conf; /* Declare a data buffer for the sensor data structure */ struct bma4_accel sens_data[20]; /* Enable the accelerometer */ The noise calculation is a bit more complicated. First, subtract the offset from each data point. The RMS value can be calculated as the square root of the arithmetic mean of the squares of the noise values. Since the noise value is affected by the bandwidth of the digital filter, we need to convert it back to noise density with the following formula. Note: this applied only to a second order filter. Here is some sample code on how to perform this test, based on BMI160, using the COINES software as the host. Calibrating the sensor The first question to ask concerning calibration is whether it is required for the intended application. Accelerometer calibration mainly consists of calibrating the accelerometer’s offset. The main impact for this is in tilt-sensing application, where the offset will induce an error in the measurement of the horizon. The accelerometer comes from the factory pre-trimmed, but the soldering process and PCB bending due to assembly can vary the offset, therefore it is preferable to calibrate the accelerometer after assembling the device into the device housing. Therefore, it is recommended to calibrate the sensor after assembling the device into the device housing. The acceleration sensor offset consists of two parts: the static “unwanted” offset mainly due to soldering drift, and the offset generated when an acceleration is applied to the sensor. The latter depends on the applied acceleration and its magnitude if defined by the sensor’s sensitivity. However, the sensitivity has a certain tolerance (typ. <1%). This means that in order to compensate for the static offset, the sensor must be oriented in such a way that no external acceleration is applied to the sensing axis. As gravity also causes a sensor signal, the sensing axis must be oriented perpendicular to the gravity field. The compensation process described below focuses on the x/y-axis. The z-axis can also be compensated in the same way, but the user has to consider the applied gravity. Alternatively, the process can be repeated after turning the device, with the z-axis perpendicular to the gravity vector. Place your sensor (the system with the sensor inside) on a well-defined surface, for example, a horizontal table. The expected sensor output for the x/y-axis should be 0 mg. Set the sensor to the lowest g-range (2G) Measure the sensor output to ensure the sensor is fully at rest, without vibrations, inclinations, big temperature changes or strong VDD fluctuations. It is advisable to take several values and generate the average over the values (e.g. 1000 values). Consider the resolution of BMA400, and save the offset in LSB or mg. The offset subtracted from the future accelerometer sensor data.  Usage The COINES installation provides sample code on how to turn on the sensor, configure it and read out the acceleration data.   Sample code The main function shows the initialization process of BMA400 based on COINS software & APP2.0 board. /*! * @brief Main Function where the execution getting started to test the code. * * @param[in] argc * @param[in] argv * * @return status * */ int main(int argc, char const *argv[]) { struct coines_board_info board_info; struct bma400_sensor_data data; struct bma400_dev bma; int8_t rslt; uint8_t n_samples = 200; float t, x, y, z; init_bma400_sensor_driver_interface(&bma); rslt = coines_open_comm_intf(COINES_COMM_INTF_USB); if (rslt < 0) { printf("\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); exit(rslt); } /* Check if the right board is connected (implicitly check if board was reset) */ rslt = coines_get_board_info(&board_info); if (rslt == COINES_SUCCESS) { if(board_info.shuttle_id != BMA400_SHUTTLE_ID) { printf("Invalid sensor shuttle ID (not a BMA400 shuttle)\n(sometimes board power off-power on helps.)\n"); fflush(stdout); exit(COINES_E_FAILURE); } } init_sensor_interface(); /* after sensor init introduce 200 msec sleep */ coines_delay_msec(200); init_bma400(&bma); rslt = bma400_soft_reset(&bma); print_rslt(rslt); rslt = set_sensor_config(&bma); if(rslt != BMA400_OK) { printf("Error setting bma400 config.\n"); fflush(stdout); exit(rslt); } while (n_samples && (rslt == BMA400_OK)) { bma.delay_ms(10); /* Wait for 10ms as ODR is set to 100Hz */ rslt = bma400_get_accel_data(BMA400_DATA_SENSOR_TIME, &data, &bma); print_rslt(rslt); /* 12-bit accelerometer at range 2G */ x = lsb_to_ms2(data.x, 2, 12); y = lsb_to_ms2(data.y, 2, 12); z = lsb_to_ms2(data.z, 2, 12); t = sensor_ticks_to_s(data.sensortime); printf("t[s]:%.4f\tdata[m/s2]: ax:%.4f\tay:%.4f\taz:%.4f\n", t, x, y, z); fflush(stdout); n_samples--; } return 0; } Below function described how to coinfigure the BMA400: /*! * @brief This internal API is used to configure the sensor * * @param[in] bma400dev: bma400 device structure * * @return Results of API execution status. * @retval 0 -> Success * @retval Any non zero value -> Fail * */ static int8_t set_sensor_config(struct bma400_dev *bma400dev) { int8_t rslt; struct bma400_sensor_conf conf; /* Select the type of configuration to be modified */ conf.type = BMA400_ACCEL; /* Get the accelerometer configurations which are set in the sensor */ rslt = bma400_get_sensor_conf(&conf, 1, bma400dev); print_rslt(rslt); /* Modify the desired configurations as per macros * available in bma400_defs.h file */ conf.param.accel.odr = BMA400_ODR_100HZ; conf.param.accel.range = BMA400_2G_RANGE; conf.param.accel.data_src=BMA400_DATA_SRC_ACCEL_FILT_1; /* Set the desired configurations to the sensor */ rslt = bma400_set_sensor_conf(&conf, 1, bma400dev); print_rslt(rslt); rslt = bma400_set_power_mode(BMA400_LOW_POWER_MODE, bma400dev); print_rslt(rslt); return rslt; } Below codes come from BMA400 API, which describe how to read and set BMA400 sensor configuration, and how to read sensor data. /*! * @brief This API is used to get the accel data along with the sensor-time */ int8_t bma400_get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, const struct bma400_dev *dev) { int8_t rslt; /* Check for null pointer in the device structure*/ rslt = null_ptr_check(dev); /* Proceed if null check is fine */ if ((rslt == BMA400_OK) || (accel != NULL)) { /* Read and store the accel data */ rslt = get_accel_data(data_sel, accel, dev); } else { rslt = BMA400_E_NULL_PTR; } return rslt; } /*! * @brief This API is used to set the sensor settings like sensor * configurations and interrupt configurations */ int8_t bma400_set_sensor_conf(const struct bma400_sensor_conf *conf, uint16_t n_sett, const struct bma400_dev *dev) { int8_t rslt; uint16_t idx = 0; uint8_t data_array[3] = { 0 }; /* Check for null pointer in the device structure*/ rslt = null_ptr_check(dev); /* Proceed if null check is fine */ if (rslt == BMA400_OK) { /* Read the interrupt pin mapping configurations */ rslt = bma400_get_regs(BMA400_INT_MAP_ADDR, data_array, 3, dev); if (rslt == BMA400_OK) { for (idx = 0; idx < n_sett; idx++) { switch (conf[idx].type) { case BMA400_ACCEL: /* Setting Accel configurations */ rslt = set_accel_conf(&conf[idx].param.accel, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_DATA_READY_INT_MAP, conf[idx].param.accel.int_chan); } break; case BMA400_TAP_INT: /* Setting TAP configurations */ rslt = set_tap_conf(&conf[idx].param.tap, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_TAP_INT_MAP, conf[idx].param.tap.int_chan); } break; case BMA400_ACTIVITY_CHANGE_INT: /* Setting activity change config */ rslt = set_activity_change_conf(&conf[idx].param.act_ch, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_ACT_CH_INT_MAP, conf[idx].param.act_ch.int_chan); } break; case BMA400_GEN1_INT: /* Setting Generic int 1 config */ rslt = set_gen1_int(&conf[idx].param.gen_int, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_GEN1_INT_MAP, conf[idx].param.gen_int.int_chan); } break; case BMA400_GEN2_INT: /* Setting Generic int 2 config */ rslt = set_gen2_int(&conf[idx].param.gen_int, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_GEN2_INT_MAP, conf[idx].param.gen_int.int_chan); } break; case BMA400_ORIENT_CHANGE_INT: /* Setting orient int config */ rslt = set_orient_int(&conf[idx].param.orient, dev); if (rslt == BMA400_OK) { /* Int pin mapping settings */ map_int_pin(data_array, BMA400_ORIENT_CH_INT_MAP, conf[idx].param.orient.int_chan); } break; case BMA400_STEP_COUNTER_INT: /* Int pin mapping settings */ map_int_pin(data_array, BMA400_STEP_INT_MAP, conf[idx].param.step_cnt.int_chan); break; } } if (rslt == BMA400_OK) { /* Set the interrupt pin mapping configurations */ rslt = bma400_set_regs(BMA400_INT_MAP_ADDR, data_array, 3, dev); } } } return rslt; } /*! * @brief This API is used to get the sensor settings like sensor * configurations and interrupt configurations and store * them in the corresponding structure instance */ int8_t bma400_get_sensor_conf(struct bma400_sensor_conf *conf, uint16_t n_sett, const struct bma400_dev *dev) { int8_t rslt = BMA400_OK; uint16_t idx = 0; uint8_t data_array[3] = { 0 }; if (conf == NULL) { rslt = BMA400_E_NULL_PTR; } if (rslt == BMA400_OK) { /* Read the interrupt pin mapping configurations */ rslt = bma400_get_regs(BMA400_INT_MAP_ADDR, data_array, 3, dev); } for (idx = 0; (idx < n_sett) && (rslt == BMA400_OK); idx++) { switch (conf[idx].type) { case BMA400_ACCEL: /* Accel configuration settings */ rslt = get_accel_conf(&conf[idx].param.accel, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_DATA_READY_INT_MAP, &conf[idx].param.accel.int_chan); } break; case BMA400_TAP_INT: /* TAP configuration settings */ rslt = get_tap_conf(&conf[idx].param.tap, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_TAP_INT_MAP, &conf[idx].param.tap.int_chan); } break; case BMA400_ACTIVITY_CHANGE_INT: /* Activity change configurations */ rslt = get_activity_change_conf(&conf[idx].param.act_ch, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_ACT_CH_INT_MAP, &conf[idx].param.act_ch.int_chan); } break; case BMA400_GEN1_INT: /* Generic int1 configurations */ rslt = get_gen1_int(&conf[idx].param.gen_int, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_GEN1_INT_MAP, &conf[idx].param.gen_int.int_chan); } break; case BMA400_GEN2_INT: /* Generic int2 configurations */ rslt = get_gen2_int(&conf[idx].param.gen_int, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_GEN2_INT_MAP, &conf[idx].param.gen_int.int_chan); } break; case BMA400_ORIENT_CHANGE_INT: /* Orient int configurations */ rslt = get_orient_int(&conf[idx].param.orient, dev); if (rslt == BMA400_OK) { /* Get the INT pin mapping */ get_int_pin_map(data_array, BMA400_ORIENT_CH_INT_MAP, &conf[idx].param.orient.int_chan); } break; case BMA400_STEP_COUNTER_INT: /* Get int pin mapping settings */ get_int_pin_map(data_array, BMA400_STEP_INT_MAP, &conf[idx].param.step_cnt.int_chan); break; default: rslt = BMA400_E_INVALID_CONFIG; } } return rslt; } Further reads Datasheets: BMA400 datasheet -> ‘Download’ -> ‘BST-BMA400-DSxxx’, like BST-BMA400-DS000 Application notes: BMA400 Evaluation Guide Handing soldering and mounting instructions Handling, soldering & mounting instruction                                                                                                                                                                                                                                                                                                                  
    View full article
    ‎06-15-2020 04:52 AM
    General Description The BME280 is a combined digital humidity, pressure and temperature sensor based on proven sensing principles. The API can be downloaded from Github. The BSEC can be downloaded from the Bosch Sensortec website. Sensor Data The humidity sensor data is expressed as a percentage (10% - 90% at 0°C-65°C). The pressure sensor data is in hPa (300hPa - 1100hPa at 0°C-65°C). The temperature sensor data is in °C (-40°C - 85°C). The function bme280_get_sensor_data in the API is used to get the sensor data. Accuracy The accuracy represents how accurate the sensor can be under certain condition. Table 1 lists the accuracy of humidity sensor, pressure sensor, and temperature sensor. Pressure Sensor Drift The pressure sensor drift represents the error in the measured value. Basically, there are two drifts on the pressure part in the BME280, i.e. solder drift and long-term drift. Pressure Sensor TCO The TCO (offset temperature coefficient) is the change in the pressure signal caused by a change in the temperature. For the pressure sensor, the TCO is ±1.5 Pa/K, equivalent to ±12.6 cm at 1 °C temperature change, which means the pressure sensor data changes within ±1.5 Pa, with 1 °C temperature change at constant pressure. Working Mode The BME280 can be operated in three working modes: sleep mode, normal mode, and force mode, which can be selected using the mode [1:0] setting (in register 0xF4 [1:0], sleep mode -> b11, force mode -> b10 and b01, normal mode -> b11). The function bme280_set_sensor_mode in the API can also used to set power mode. During the measurement cycle, the BME280 measures temperature, pressure and humidity, with optional oversampling. After the measurement cycle, the pressure and temperature data can be passed through an optional IIR filter, which removes short-term fluctuations in pressure (e.g. caused by slamming a door). For humidity, such a filter is not needed and has not been implemented. Humidity/Pressure/Temperature OSR Oversampling can be enabled during the measurement, which can reduce noise but also consumes more power. Different sensors have different OSRs (oversampling rate). The osrs_h<2:0> settings are explained as follows: b000-> skip humidity data/no humidity b001-> oversamplingx1 b010-> oversamplingx2 b011-> oversamplingx4 b100-> oversamplingx8 b101, and other settings -> oversamplingx16  The osrs_p<4:2> settings are explained as follows: b000-> skip humidity data/no humidity b001-> oversamplingx1 b010-> oversamplingx2 b011-> oversamplingx4 b100-> oversamplingx8 b101, and other settings-> oversamplingx16 The osrs_t<7:5> settings are explained as follows: b000-> skip humidity data/no humidity b001-> oversamplingx1 b010-> oversamplingx2 b011-> oversamplingx4 b100-> oversamplingx8 b101, and other settings-> oversamplingx16   The function bme280_set_sensor_settings in the API can also be used to set the OSR for any sensor. See below for the example.   ... int8_t rslt; uint8_t settings_sel; dev->settings.osr_h = BME280_OVERSAMPLING_1X; dev->settings.osr_p = BME280_OVERSAMPLING_16X; dev->settings.osr_t = BME280_OVERSAMPLING_2X; ... settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; rslt = bme280_set_sensor_settings(settings_sel, dev); .... return rslt; ... Signal Filter The environmental pressure is subject to many short-term changes caused by, for example, door or window slamming, wind blowing into the sensor, etc. The BME280 features an internal IIR filter which can suppress these disturbances in the output data without causing additional interface traffic and processor workload. By setting the filter coefficient (c), the bandwidth of the temperature and pressure output signals can be effectively reduced and the resolution of the pressure and temperature output data can be increased to 20 bits. The output of the next measurement step is filtered using the following formula:  Where, data_filter_old is the data coming from the current filter memory. data_ADC is the data coming from current ADC acquisition. data_filtered is the new value of filter memory and the value that will be sent to the output registers.   The filter<4:2> settings are explained as follows: b000-> Filter off b001-> filter coefficient 2 b010-> filter coefficient 4 b011-> filter coefficient 8 b100, and other settings-> filter coefficient 16   The function bme280_set_sensor_settings in the API can also be used to set filter. See below for the example. ... int8_t rslt; uint8_t settings_sel; ... dev->settings.filter = BME280_FILTER_COEFF_16; ... settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; ... rslt = bme280_set_sensor_settings(settings_sel, dev); ... return rslt; ​
    View full article
    ‎08-15-2019 11:12 AM
    Introduction This document is intended as a reference guide on how to design using Bosch Sensortec’s BMI08x series IMU. It describes the main features of the BMI08x family, available evaluation tools and software, reference design, layout recommendations, and gives instructions on how to test the BMI08x family’s functionality using sample codes, and how to demonstrate and evaluate it with COINES. Selecting the right part The BMI08x family has two products: BMI085 and BMI088, which are ideally suited for high-performance consumer applications. The BMI085 is designed for virtual augmented and mixed reality applications, high-end gaming, platform stabilization applications such as image stabilization, as well as indoor navigation and dead reckoning, such as robotics applications. The BMI088 is designed for applications in harsh vibration environments such as drones and robotics. The IMU is designed to effectively suppress vibration above several hundred Hz, which may occasionally occur due to resonance on the PCB or the structure of the total system. Table 1 shows an overview of the features.                                                                           Table 1: Overview of the features Key features This section describes the key features of the BMI08x family. Good stability of TCO, TCS, bias and stress Low latency BMI088 has vibration robustness and suppression BMI085 has integrated accelerometer and gyroscope data synchronization function  Differences between products The main differences between the BMI08x family products are the accelerometer part and the overall performance of the MEMS element.                                                                                                                                       Table 2: Main differences Available evaluation tools and software To best evaluate the BMI08x family, the following combination of evaluation tools is recommended: COINES Desktop software (Windows version &Linux version & MacOS) Development Desktop Software Application board 2.0 Sensor shuttle board BMI085 shuttle board BMI088 shuttle board Hardware reference design Figure 1 and Figure 2 show the I2C and SPI reference designs for BMI085 and BMI088                                                                                       Figure 1: I2C connection                                                                       Figure 2: SPI connection Bill of materials Table 3 lists the bill of necessary materials.                                                                                                                                     Table 3: Bill of materials Layout recommendations Because the BMI08x sensor family contains tiny mechanical structures inside the package, care must be taken during the layout phase to ensure optimum performance. The complete handing and soldering guide can be found on the Bosch Sensortec’s website. The typical manufacturing procedures for the BMI08x IMU are described in the following sections. Recommended layout rules The recommended layout rules are as follows: PCB land width = LGA solder pin width PCB land length = LGA solder pin length + 0.1mm on each side Solder mask opening width = PCB land width + 0.05mm on each side Solder mask opening length = PCB land     Landing Pattern The BMI08x family has the same landing pattern. The following dimensioning is recommended.                                            Figure 3: Recommended landing pattern (top view, in mm) Typical Layout Figure 4 shows the typical layout.                                                                                      Figure 4: Typical layout  Manufacturing notes Table 4 lists the recommendations for the manufacture.                                                                           Table 4: Manufacture recommendations First power-on This chapter describes how to test the BMI08x family’s functionality and performance after powering it on for the first time. To properly initialize the device, the user must decide which interface to use (I2C or SPI) during hardware design. With the PS pin, the user can determine which interface the sensor should listen to. The gyroscope part of the BMI08x initializes its I/O pins according to the selection given by the PS pin. The accelerometer part starts and remains in I2C mode. When a rising edge is detected on the CSB1 pin (chip select of the accelerometer), the accelerometer part switches to SPI mode and remains until the next power-up reset. To switch the accelerometer to SPI mode, the user can perform a dummy SPI read operation during the initialization phase. After the power-on reset, the gyroscope enters normal mode, while the accelerometer enters suspend mode. To switch the accelerometer to normal mode, do the following: Power up the sensor. Wait for 1ms Enter normal mode by writing ‘4’ to ACC_PWR_CTRL. Wait for 50ms. The accelerometer enters normal mode. Below are some example codes for performing tests based on BMI08x shuttle board and API, using the COINES software as the host. To test the BMI08x family’s functionality, do the following: 1) Initialize the sensor driver API interface (based on GenAPI and COINES as example) /*! * @brief this internal API is used to set the sensor driver interface to * read/write the data. * * @param[in] void * * @return void * */ static void init_bmi08x_sensor_driver_interface(void) { #if BMI08x_INTERFACE_I2C==1 /* I2C setup */ /* link read/write/delay function of host system to appropriate * bmi08x function call prototypes */ bmi08xdev.write = coines_write_i2c; bmi08xdev.read = coines_read_i2c; bmi08xdev.delay_ms = coines_delay_msec; /* set correct i2c address */ bmi08xdev.accel_id = (unsigned char) BMI08x_ACCEL_DEV_ADDR; bmi08xdev.gyro_id = (unsigned char) BMI08x_GYRO_DEV_ADDR; bmi08xdev.intf = BMI08X_I2C_INTF; #endif #if BMI08x_INTERFACE_SPI==1 /* SPI setup */ /* link read/write/delay function of host system to appropriate * bmi08x function call prototypes */ bmi08xdev.write = coines_write_spi; bmi08xdev.read = coines_read_spi; bmi08xdev.delay_ms = coines_delay_msec; bmi08xdev.intf = BMI08X_SPI_INTF; bmi08xdev.accel_id = COINES_SHUTTLE_PIN_8; bmi08xdev.gyro_id = COINES_SHUTTLE_PIN_14; #endif } 2)  Set up the communication between Bosch Sensortec application board 2.0 and PC, and get the board hardware and software information. struct coines_board_info board_info; int16_t rslt; rslt = coines_open_comm_intf(COINES_COMM_INTF_USB); if (rslt < 0) { printf("\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); exit(rslt); } rslt = coines_get_board_info(&board_info); if (rslt == COINES_SUCCESS) { if ((board_info.shuttle_id != BMI085_SHUTTLE_ID) && (board_info.shuttle_id != BMI088_SHUTTLE_ID)) { printf("! Warning invalid sensor shuttle \n ," "This application will not support this sensor \n"); exit(COINES_E_FAILURE); } } 3)Initialize the sensor interface, protocol, and power on VDD and VDDIO. /*********************************************************************/ /* functions */ /*! * @brief This internal API is used to initialize the sensor interface depending * on selection either SPI or I2C. * * @param[in] void * * @return void * */ static void init_sensor_interface(void) { /* Switch VDD for sensor off */ coines_set_shuttleboard_vdd_vddio_config(0, 0); coines_delay_msec(10); #if BMI08x_INTERFACE_I2C==1 /* set the sensor interface as I2C with 400kHz speed*/ coines_config_i2c_bus(COINES_I2C_BUS_0, COINES_I2C_FAST_MODE); coines_delay_msec(10); /* PS pin is made high for selecting I2C protocol*/ coines_set_pin_config(COINES_SHUTTLE_PIN_9, COINES_PIN_DIRECTION_OUT, COINES_PIN_VALUE_HIGH); #endif #if BMI08x_INTERFACE_SPI==1 /* CS pin is made high for selecting SPI protocol*/ coines_set_pin_config(COINES_SHUTTLE_PIN_8, COINES_PIN_DIRECTION_OUT, COINES_PIN_VALUE_HIGH); /* CS pin is made high for selecting SPI protocol*/ coines_set_pin_config(COINES_SHUTTLE_PIN_14, COINES_PIN_DIRECTION_OUT, COINES_PIN_VALUE_HIGH); /* PS pin is made low for selecting SPI protocol*/ coines_set_pin_config(COINES_SHUTTLE_PIN_9, COINES_PIN_DIRECTION_OUT, COINES_PIN_VALUE_LOW); coines_delay_msec(10); coines_config_spi_bus(COINES_SPI_BUS_0, COINES_SPI_SPEED_5_MHZ, COINES_SPI_MODE3); #endif coines_delay_msec(10); /* Switch VDD for sensor on */ coines_set_shuttleboard_vdd_vddio_config(3300, 3300); } 4) After a delay of approximately 200ms, call the BMI08x API to initialize the BMI08x, including its power mode, ODR, bandwidth, range. /*! * @brief This internal API is used to initialize the bmi08x sensor * settings like power mode and OSRS settings. * * @param[in] void * * @return void * */ static void init_bmi08x(void) { if (bmi08a_init(&bmi08xdev) == BMI08X_OK && bmi08g_init(&bmi08xdev) == BMI08X_OK) { printf("BMI08x initialization success !\n"); printf("Accel chip ID - 0x%x\n", bmi08xdev.accel_chip_id); printf("Gyro chip ID - 0x%x\n", bmi08xdev.gyro_chip_id); } else { printf("BMI08x initialization failure !\n"); exit(COINES_E_FAILURE); } bmi08xdev.accel_cfg.odr = BMI08X_ACCEL_ODR_1600_HZ; #if BMI08X_FEATURE_BMI085 == 1 bmi08xdev.accel_cfg.range = BMI085_ACCEL_RANGE_16G; #elif BMI08X_FEATURE_BMI088 == 1 bmi08xdev.accel_cfg.range = BMI088_ACCEL_RANGE_24G; #endif bmi08xdev.accel_cfg.power = BMI08X_ACCEL_PM_ACTIVE; //user_accel_power_modes[user_bmi088_accel_low_power]; bmi08xdev.accel_cfg.bw = BMI08X_ACCEL_BW_NORMAL; /* Bandwidth and OSR are same */ bmi08a_set_power_mode(&bmi08xdev); coines_delay_msec(10); bmi08a_set_meas_conf(&bmi08xdev); coines_delay_msec(10); bmi08xdev.gyro_cfg.odr = BMI08X_GYRO_BW_230_ODR_2000_HZ; bmi08xdev.gyro_cfg.range = BMI08X_GYRO_RANGE_250_DPS; bmi08xdev.gyro_cfg.bw = BMI08X_GYRO_BW_230_ODR_2000_HZ; bmi08xdev.gyro_cfg.power = BMI08X_GYRO_PM_NORMAL; bmi08g_set_power_mode(&bmi08xdev); coines_delay_msec(10); bmi08g_set_meas_conf(&bmi08xdev); coines_delay_msec(10); } 5. Call the BMI08x API to read Acc and Gyro data in a while loop. int times_to_read = 0; while (times_to_read < 10) { bmi08a_get_data(&bmi08x_accel, &bmi08xdev); printf("ax:%d ay:%d az:%d\n", bmi08x_accel.x, bmi08x_accel.y, bmi08x_accel.z); bmi08g_get_data(&bmi08x_gyro, &bmi08xdev); printf("gx:%d gy:%d gz:%d\n", bmi08x_gyro.x, bmi08x_gyro.y, bmi08x_gyro.z); fflush(stdout); coines_delay_msec(10); times_to_read = times_to_read + 1; } coines_close_comm_intf(COINES_COMM_INTF_USB); Calibration Both accelerometer part and gyroscope part of the BMI08x are pre-trimmed at the factory. However, the soldering process and PCB bending due to assembly can result in offset changing; therefore, it is recommended to calibrate the sensor after assembling the device into the device housing. The acceleration sensor offset consists of two parts: the static “unwanted” offset mainly due to soldering drift, and the offset generated when an acceleration is applied to the sensor. The latter depends on the applied acceleration and its magnitude if defined by the sensor’s sensitivity. However, the sensitivity has a certain tolerance (typ. <1%). This means that in order to compensate for the static offset, the sensor must be oriented in such a way that no external acceleration is applied to the sensing axis. As gravity also causes a sensor signal, the sensing axis must be oriented perpendicular to the gravity field. The compensation process described below focuses on the x/y-axis. The z-axis can also be compensated in the same way, but the user has to consider the applied gravity. Alternatively, the process can be repeated after turning the device, with the z-axis perpendicular to the gravity vector. Place your sensor (the system with the sensor inside) on a well-defined surface, for example, a horizontal table. The expected sensor output for the x/y-axis should be 0 mg. Set the sensor to the lowest g-range (BMI085 to 2G, BMI088 to 3G) Measure the sensor output to ensure the sensor is fully at rest, without vibrations, inclinations, big temperature changes or strong VDD fluctuations. It is advisable to take several values and generate the average over the values (e.g. 1000 values). Consider the resolution of BMI085 and BMI088, and save the offset in LSB or mg. Subtract the offset from the future accelerometer sensor data. The gyroscope part of the BMI08x has outstanding offset performance and very high offset stability. However, small offsets may still occur and change over the operation time (mainly due to changes in the operation temperature). As the needs vary from application to application, the application should take care of the offset compensation. To do this, the application has to ensure that the gyroscope is fully at rest when compensating for the offset. Only at rest the static offset can be separated from any motion-based offset. This can be achieved for example by monitoring the accelerometer signals of all axes and checking the noise of each axis. If the noise is below certain threshold (application specific), the application can assume that the sensor is at rest. While monitoring, the device remains at rest and the host can read sensor values, for example, for ten seconds. The average of the gathered values per axis shows the residual offset and can be subtracted from any future the sensor data. Example code The code below shows how to read the BMI08x sensor data via BMI08x API and COINES system. /*! * @brief This internal API is used to read sensor data * * @param[in] void * * @return void * */ void read_sensor_data(void) { int16_t rslt; int counter = 0; uint8_t lsb, msb; int16_t ax, ay, az, gx, gy, gz; uint32_t valid_sample_count = 0; int idx = 0; int buffer_index = 0; while (counter < 1000) { memset(&bmi08x_accel_stream_buffer[0], 0, COINES_STREAM_RSP_BUF_SIZE); rslt = coines_read_stream_sensor_data(1, 1, &bmi08x_accel_stream_buffer[0], &valid_sample_count); if (rslt == COINES_SUCCESS) { buffer_index = 0; for (idx = 0; idx < valid_sample_count; idx++) { #if BMI08x_INTERFACE_SPI==1 buffer_index++; //dummy byte; ignore for spi #endif lsb = bmi08x_accel_stream_buffer[buffer_index++]; msb = bmi08x_accel_stream_buffer[buffer_index++]; ax = (msb << 😎 | lsb; lsb = bmi08x_accel_stream_buffer[buffer_index++]; msb = bmi08x_accel_stream_buffer[buffer_index++]; ay = (msb << 😎 | lsb; lsb = bmi08x_accel_stream_buffer[buffer_index++]; msb = bmi08x_accel_stream_buffer[buffer_index++]; az = (msb << 😎 | lsb; printf("ax: %-5d \t ay: %-5d \t az: %-5d\n", ax, ay, az); fflush(stdout); } } memset(&bmi08x_gyro_stream_buffer[0], 0, COINES_STREAM_RSP_BUF_SIZE); rslt = coines_read_stream_sensor_data(2, 1, &bmi08x_gyro_stream_buffer[0], &valid_sample_count); if (rslt == COINES_SUCCESS) { buffer_index = 0; for (idx = 0; idx < valid_sample_count; idx++) { lsb = bmi08x_gyro_stream_buffer[buffer_index++]; msb = bmi08x_gyro_stream_buffer[buffer_index++]; gx = (msb << 😎 | lsb; lsb = bmi08x_gyro_stream_buffer[buffer_index++]; msb = bmi08x_gyro_stream_buffer[buffer_index++]; gy = (msb << 😎 | lsb; lsb = bmi08x_gyro_stream_buffer[buffer_index++]; msb = bmi08x_gyro_stream_buffer[buffer_index++]; gz = (msb << 😎 | lsb; printf("gx: %-5d \t gy: %-5d \t gz: %-5d\n", gx, gy, gz); fflush(stdout); } } coines_delay_msec(1); counter++; } }  Further reads Datasheets: BMI085 Datasheet BMI088 Datasheet  Application notes: FIFO usage Handing soldering and mounting instructions: Handling, soldering & mounting instruction
    View full article
    ‎05-06-2022 04:05 PM
    The Self-Learning AI Software can recognize and track more than fifteen pre-learned fitness exercises and has the ability to learn new movements and fitness exercises created by you! Please find attached the ZIP file with the following contents: Never Skip Leg Day This session includes exercises where the sensor is mounted on the ankle and the focus will be on building leg strength. PDF document with all instructions Generated patterns Raw sample data Outdoor Bodyweight Workout This session includes exercises where the sensor is mounted on the arm. This workout is great for strengthening your core, arms and legs muscles. PDF document with all instructions Generated patterns Raw sample data Outdoor Core Workout This session includes exercises where the sensor is mounted on the ankle. This workout is great for strengthening your core. PDF document with all instructions Generated patterns Raw sample data Waist Tracking This session includes exercises where the sensor is mounted on the waist and the arm. PDF document with all instructions Generated patterns Raw sample data The self-learning AI firmware is available on our Nicla Sense ME board here. For more information about the list of virtual sensors, see the Nicla Sense ME Board examples.
    View full article
    100% helpful (1/1)
    ‎05-31-2021 12:09 PM
    Frequently Asked Questions (FAQs) about the BHI260AP sensor
    View full article
    100% helpful (1/1)
    ‎08-06-2019 10:43 AM
     FIFO description The BMI160 integrates a 1024-bytes data FIFO. The FIFO contains frames of data, and each frame contains only one sample per sensor. Each sensor element can be enabled for the FIFO individually. The data frames can be configured into different formats as shown in Figure 1. If each sensor is with different ODRs, then each frame contains samples from different subsets of sensors which are enabled for the FIFO. In that case, the size of frames is not constant.                                                                        Figure 1: FIFO frame configuration The maximum number of frames in the FIFO is determined by different configurations. Assuming that all the sensors are with the same ODR, the following table demonstrates the maximum frames of sensor data can be stored in the FIFO for different frame format modes:                                                                  Table 1: Maximum number of frames in FIFO  The FIFO operates in a mode that collects data constantly. When the FIFO buffer is full, the data collection continues and the oldest entry is discarded. For the example in Figure 2, at the moment Time0, FIFO buffer has room for 9 bytes. So the next frame that contains 13 bytes does not fit in the FIFO. Therefore, at Time1, the oldest frame Frame[0] in FIFO[0…6] is discarded, the remaining frames are shifted down and the new frame Frames[84] is pushed into FIFO[1008…1020]. At Time2, when the new frame is ready, the oldest frame continues to be discarded.                                            Figure 2: FIFO full representation, the Oldest Frames are discarded  When data is being read, data collection continues. An example is shown in Figure 3. At Time0, the new frame Frame[19] is pushed into FIFO and the watermark interrupt is triggered. Then after some delay, the interrupt is serviced and a burst read of FIFO begins. In order to read out all the valid data in FIFO and generate a timestamp in Header mode, the length of the burst read is set to the watermark level plus two maximum-sized frames plus four bytes. At Time2, as the burst read takes longer than the sensor data is generated, a new frame Frame[20] is added into FIFO. At Time3, all the valid data including Frame[20] is read out and a Sensortime frame is returned.   The example below describes the steps of FIFO setting and FIFO data retrieval. After sensor configuration, Accel and Gyro are set to Normal mode. Then FIFO is configured to store Accel and Gyro data in Header mode. By burst reading FIFO data Register 0x24, data is read from FIFO every 50ms.                                 Figure 4: Steps to enable FIFO and retrieve FIFO data every 50ms FIFO register In the following table, the most important registers for FIFO configuration and usage (as excerpt of the full register map in Datasheet Section 2.11) are shown.                                           Table 2: Important registers for FIFO usage FIFO configuration registers (0x46-0x47) FIFO configuration registers can be used to: read or set the current FIFO watermark level set different modes of operation of the FIFO, i.e. which data will be stored in it and which format will be used (header or headerless mode).  fifo_water_mark fifo_water_mark defines the FIFO watermark level. An interrupt will be generated when the number of entries in the FIFO exceeds fifo_water_mark. Note: The unit of fifo_water_mark is 4 bytes. fifo_acc_en,fifo_gyr_en,fifo_mag_en fifo_xxx(acc, gyr, mag)_en defines if the xxx data is stored in FIFO. If fifo_xxx_en = 0, no data is stored in FIFO; if fifo_xxx_en = 1, xxx data is stored in FIFO (for all three axes). When all fifo_xxx_en are ‘0’, the FIFO is disabled, no sensor data is stored in FIFO and no headers are written.  fifo_header_en fifo_header_en defines the FIFO frame mode as discussed in Chapter 4. If fifo_header_en = 1, FIFO is in Header mode, each frame contains a header and data; If fifo_header_en = 0, FIFO is in Headerless mode, each frame contains data only. For Header mode, the output data rates of all enabled sensors for the FIFO can be different. However, for Headerless mode, the output data rates of all enabled sensors for the FIFO should be identical. If the output data rates are different in Headerless mode, the FIFO waits until the data with the lowest output data rate is ready and then stores the frame as shown in Figure 5.                        Figure 5: FIFO frame modes behave differently with not identical ODR for sensors For example, when Accel is set to 100Hz and Gyro is set to 200Hz, the frame of data is generated at 200Hz in Header mode and at 100Hz in Headerless mode. For further discussion about FIFO frame modes, see Chapter 4. fifo_tag_int1_en, fifo_tag_int2_en fifo_tag_int1_en and fifo_tag_int2_en define if the FIFO tags the voltage on interrupt pin 1 or 2 in the FIFO header. To enable this function, int1_input_en and/or int2_input_en should be set to ‘1’ in Register (0x54) INT_LATCH. fifo_time_en fifo_time_en defines if sensortime frame in FIFO is enabled. When fifo_time_en = 0, no sensortime frame will be returned. When fifo_time_en = 1, a sensortime frame will be returned after the last valid frame when the number of data that are read is greater than that of valid frames in the FIFO. When reading from FIFO with burst read, the AP/MCU should read more than the bytes (FIFO byte counter + 4 bytes). These four bytes contain one frame header that indicates the Sensortime frame and 3 bytes for the real sensor time.    FIFO data register (0x24) When reading out data from FIFO, read burst access must be used. The address does not increment when the read burst reads at the address of FIFO_DATA. When a frame is only partially read out, it is retransmitted including the header at the next readout. The data format depends on the setting of FIFO Configuration Registers (0x46-0x47). The FIFO data is organized by frame, as described in Chapter 4. FIFO length registers (0x22-0x23) FIFO length registers contain a FIFO byte counter. It represents the current fill level of the FIFO buffer. This includes the Skip frame for a full FIFO. An empty FIFO corresponds to 0x000. The byte counter can be reset by reading out all frames from the FIFO buffer or when the FIFO is reset through the Register (0x7E) CMD. The byte counter is updated when a complete frame is read or written.  FIFO downsampling register (0x45) The register (0x45) FIFO_DOWN provides xxx_fifo_filt_data and xxx_fifo_downs. Using these bits, the data stored in FIFO is downsampled compared to the ODR settings. If xxx_fifo_filt_data = 0, unfiltered data will be selected as the data source for FIFO downsampling(1600Hz for Accel and 6400Hz for gyro). If xxx_fifo_filt_data = 1, filtered data will be used as the data source for FIFO downsampling. This is identical to the ODR setting. Then the data stored in FIFO is related to the ODR and xxx_fifo_downs. For example, xxx_fifo_downs = 2, then every 4 samples output from data registers (updated based on ODR settings) will be stored in FIFO.  FIFO interrupt The FIFO full interrupt and the watermark interrupt can be enabled/disabled through the Register (0x51) INT_EN_1 and can be mapped/unmapped to interrupt pin 1 or 2 through the Register (0x56) INT_MAP_1. Detailed information can be found in BMI160 Datasheet. When FIFO is full, the FIFO full interrupt is issued and the next full data sample will cause FIFO overflow, which may cause samples to be deleted. Technically, this means that the FIFO full interrupt is issued whenever the remaining space in the FIFO is less than two maximum-sized frames. The FIFO watermark interrupt is fired when the FIFO fill level in fifo_byte_counter in Register (0x22-0x23) FIFO_LENGTH is above the pre-configured watermark defined in fifo_watermark in Register (0x46-0x47) FIFO_CONFIG. FIFO flush function In order to empty the FIFO content, the user should write the command word 0xB0 into the command register 0x7E. Note: This action only clears the data content of FIFO and it does not change any FIFO configuration. FIFO related error code In the Error register, there are two FIFO related error code fields as follows: 0x0110: ODRs of enabled sensors in headless mode do not match, which means when headless mode is enabled for more than one sensor, these sensors are not set to the same ODR. 0x0111: unfiltered data is used in low power mode, which means in low power mode, only filtered data can be selected to fill FIFO. Because there is no real unfiltered data in low power mode, the sensor only gets the data based on the defined time interval. FIFO frame The BMI160 provides two different modes: headerless mode and header mode, as described in Chapter 3.They are detailed in following chapters. Header mode When FIFO is set to “header mode“, the data byte format differs depending on the type of frame. There are two basic frame types, i.e. control frame and regular data frame. Each different type of control frame has its own data byte format. It can contain skipped frames, sensortime data or FIFO configuration information, as described in BMI160 Datasheet. If the frame type is a regular frame (sensor data), the data byte section of the frame depends on how the data is being transmitted in this frame (as specified in the header byte section). It can include data from a single sensor or any combination of accelerometer, gyroscope and external sensor data. The following formula calculates the average size of the frame in Header mode: Frame_Size AVG = (Max(A odr ,G odr ,M odr )*1+6*A odr +6*G odr +8*M odr )/Max(A odr ,G odr ,M odr ) byte (1) The data stored in FIFO uses the following format in header mode:                                                    Table 3: Parts of FIFO data format in header mode Note: The above regular frame header contains the tags of interrupts in the last two bits fh_ext<1:0>. When fifo_tag_int1_en or fifo_tag_int2_en is enabled, the regular frame header may change. Take Accel only as an example, fifo_tag_int1_en and int1_input_en are enabled. If the Accel data is stored in FIFO while the interrupt pin 1 is high, the regular frame header is 0x85 instead of 0x84. There are other FIFO frame headers: 0x48: CFG frame, which indicates the range or other configuration changes of A, G and M during FIFO storing. 0x40: Skip frame, which indicates how many frames are skipped when FIFO is full. If more than 255 frames are skipped, 255 is returned as the number of skipped frames. 0x44: Sensortime frame. The data byte part of a Sensortime frame consists of 3 bytes and contains a 24-bit sensortime. The Sensortime frame does not consume memory in FIFO. 0x80: Overread frame. The data byte part of an Overread frame consists of a redundant byte 0x00. Detailed information on FIFO frame header format can be found in BMI160 Datasheet.    Example: how data stores in FIFO in Header mode Write 0x11, 0x15 into CMD register 0x7E in sequence to set A, G into normal power mode. Write 0x28 into register ACC_CONF (0x40) to set acceleration data rate to 100Hz. Write 0x29 into register GYR_CONF (0x42) to set gyro data rate to 200Hz. Enable and configure M via secondary interface according to AN First steps with the BMI160, set the magnetic data rate to 50Hz. Write 0xF2 into register FIFO_CONFIG_1 (0x47) to enable A, G and M data stored in FIFO. Also enable the header and timestamp for the FIFO. Then FIFO works and stores data in the following format: Table 4: FIFO data in header mode  Headerless mode When the FIFO is set to headerless mode, only sensor data is stored in the FIFO (in the same order as in the data register). Any combination of accelerometer, gyroscope and external sensor data can be stored. External interrupt tags are not supported in headerless mode. After the configuration is complete, the frame size in headerless mode is constant. The data stored in the FIFO uses the following formats in headerless mode:                                            Table 5: FIFO data formats in headerless mode  Note: When overread occurs, a byte stream of 0x0080 (which corresponds to (LSB, MSB) byte order to a data value of 0x8000) is returned in headerless mode. Example: How data stores in FIFO in Headerless mode Write 0x11, 0x15 to CMD register 0x7E in sequence to set A, G to normal power mode. Write 0x28 to register ACC_CONF (0x40) to set the acceleration data rate to 100Hz. Write 0x28 to register GYR_CONF (0x42) to set the gyro data rate to 100Hz. Enable and configure M via the secondary interface according to the application note “BMI160 Secondary Interface: Magnetometer”, and set the magnetic data rate to 100Hz. Write 0xE0 into register FIFO_CONFIG_1 (0x47) to enable A, G and M data stored in FIFO, and disable the header and timestamp for the FIFO. Then the FIFO works and stores data in the following format:                                                                 Table 6: FIFO data in headerless mode  Note: In Headerless mode, the output data rates of all enabled sensors for the FIFO should be identical. If the output data rates are different, the FIFO will wait until the data with the lowest output data rate is ready and then store the frame as described in Section 3.1.3.  Retrieving data from FIFO Communication speed and FIFO fill rate The communication speed determines the rate at which data can be read from the FIFO. To prevent data loss, fill the FIFO with a rate that does not exceed the read rate. The appropriate appropriate data rate of each sensor should be selected. For I2C protocol, a read sequence consists of a one-byte I2C write phase followed by the I2C read phase. Using the formula (1) in Section 4.1, the average frame size is approximately 13 bytes when A odr , G odr and M odr are 1600Hz, 1600Hz and 25 Hz correspondingly. The minimum time necessary for starting the burst read for I2C fast mode is roughly 75 µs. The minimum time to get the above-mentioned frame is roughly 360 µs, including all minimum start and stop setup and hold times and minimum cycle period. As a result, data can still be read out of the FIFO faster than it is put into the FIFO at the data rate of 1600 Hz, corresponding to a period of 625 µs. However, the theoretical maximum FIFO fill rate for the BMI160 FIFO can be calculated as follows: f FIFO_fill = Max(A odr ,G odr ,M odr ) * Frame_Size AVG = Max(A odr ,G odr ,M odr ) * 1+ 6 * A odr + 6 * G odr + 8 * M odr                                          (2) = 6400 + 6 * 1600 + 6 * 6400 + 8 * 800 = 60800 (bytes/second) = 486.4 kbit/s In this case, the maximum FIFO fill rate exceeds the speed of I2C fast mode. The data rates of the sensors can be adjusted for the I2C communication speed. On the other hand, SPI with higher speed can be used to meet the high FIFO fill rate requirement when all the sensors are with high output data rates. Watermark The watermark interrupt is triggered when the FIFO fill level in fifo_byte_counter in FIFO Length Registers (0x22-0x23) is above a pre-configured fifo_watermark in FIFO Configuration Registers (0x46-0x47) and it remains set until the condition causing it is eliminated. To clear the watermark interrupt, read the FIFO until the fill level in fifo_byte_counter is lower than the value stored in fifo_watermark; however, reading more than the valid frames in FIFO is recommended for two reasons: It prevents the watermark interrupt from being triggered too often, without compromising the benefit of using FIFO. A Sensortime frame is returned after the last valid frame when more data than valid frames in FIFO are read.    FIFO operation with watermark interrupt The example in Figure 6 shows how the FIFO operates with watermark interrupt. The pre-configured watermark is 220 bytes so that the unit of fifo_watermark is 4 bytes and is configured as 0x37. At Time0, the FIFO fill level in fifo_byte_counter is 218 bytes. At Time1, the FIFO fill level is updated to 239 bytes when Frame[19] is pushed into the FIFO. Then the FIFO watermark interrupt is fired. After some latency, the interrupt is serviced and a burst read that reads all the frames in the FIFO is issued. At Time2, the complete frame Frame[0] is read, fifo_byte_counter is updated but still above the watermark, so the FIFO watermark interrupt remains set. Until another complete frame Frame[1] is read at Time3, the updated fifo_byte_counter is below the watermark and the watermark interrupt is cleared.   Figure 6: Watermark Interrupt is cleared when FIFO Counter is below pre-configured watermark Watermark level and burst read length The watermark level (WM) can be calculated with the number of frames (F) that triggers a watermark interrupt: WM = F * Frame_Size AVG / 4                                                                                                     (3)        = F * (0.25+1.5*A odr / Max(A odr ,G odr ,M odr ) +1.5*G odr / Max(A odr ,G odr ,M odr ) +2*M odr / Max(A odr ,G odr ,M odr )) In order to read more data than the valid frames in FIFO, the minimum Burst Read Length can be roughly estimated with the calculated watermark level, FIFO fill rate, communication speed (Clock Rate), and the latency of serving watermark interrupt: Read_Length min = (WM*4 + f FIFO_fill * Latency fwm_int ) / (1 – f FIFO_fill / f CLK )                                      (4)   If I2C Fast mode is used and the maximum latency of serving watermark interrupt is 10 ms, the recommended burst read lengths for different sensor and watermark configurations are provided in Table 8.              Table 7: WM configuration and burst read length for different ORDs (I2C fast mode)   Note: New frames can be filled into FIFO during the latency for interrupt service and a long burst read. A high watermark level is not recommended if the sensors are set to high ODRs and the communication speed is not fast enough. Potential risk and possible solution There is a potential risk that watermark is triggered again shortly after it is cleared while the FIFO data is still being read. This may unintentionally call a false watermark interrupt service before the current watermark interrupt service is finished, and thus lead to a system crash. For the same communication speed, the higher the FIFO fill rate, the more likely the potential risk occurs. The risk is illustrated in Figure 7. At Time2, fifo_byte_counter is below the watermark level so the interrupt is cleared. However, at Time3, before the oldest frame Frame[2] is completely read out, the new frame Frame[20] is pushed into FIFO and an unwanted interrupt is triggered.                              Figure 7: Watermark Interrupt is triggered immediately after it is cleared One possible solution is to disable the watermark interrupt by setting bit 6 to ‘0’ in Register (0x51) INT_EN_1 at the beginning of the interrupt service and enable the watermark interrupt again before exiting the interrupt service.  Interrupt-based FIFO read example In the example below, the left hand side describes the steps of FIFO and watermark interrupt configuration for Accel 100 Hz, Gyro 100 Hz and Mag 25 Hz. Interrupt 1 of the BMI160 is set to output, and watermark interrupt is mapped to it. Then the watermark level is set to 148 bytes before the watermark interrupt is enabled. At the end of the configuration, FIFO is enabled for Accel, Gyro and Mag data, frame format is set to Header Mode and the Sensortime frame is enabled. The left hand side of the example below describes the steps of the watermark interrupt service. At the beginning of the service, the watermark interrupt is disabled to avoid the risk mentioned in Section 5.2.3. Then all the valid data frames and the Sensortime frame are read and interpreted. Before exiting the watermark interrupt service, the watermark interrupt must be enabled again.                                Figure 8: Watermark interrupt configuration and interrupt service  
    View full article
    100% helpful (2/2)
    ‎11-12-2019 08:33 AM
    Introduction This document is meant as a reference guide on how to design using Bosch Sensortec’s BHy1. BHy1 family includes two parts, one is BHA250 series, the other is BHI160 series. Selecting the right part The BHA250 contains part number: BHA250 and BHA250B. The BHA250/BHA250B is sensor hub which integrated Accelerometer. Figure1 shows the BHA250 laser marking.                                                                                              Fig1 The BHI160 contains part number: BHI160and BHI160B. The BHI160/ BHI160B is smart sensor which integrated IMU(ACC+Gyro). Figure2 shows the laser marking.                                                                                                  Fig2 Common Characteristics Key features 1xI2C(3.4MHz) Host Interface; 1xI2C(1MHz) Aux Interface; up to 3 GPIOs 32-bit Floating-point; 96 KB ROM; 48 KB RAM Max ODR is 200Hz  Difference between products                                                 Table 1: Difference on BHA250 and BHI160                                           Table 2: Accelerometer Parameter on BHA250 and BHI160                                                        Table 3: BHI160 Gyroscope Parameter  Available evaluation tools and software To best to evaluate the products from the BHy1 family is the following combination of evaluation tools: COINES Desktop software Application board 2.0 Sensor Shuttle board BHI160/BHI160B Shuttle board BHI250/BHA250B Shuttle board Reference design See Figure 3 for BHA250 schematic of a typical use-case.                                                                      Figure3  BHA250/BHA250B typical schematic Bill of materials: Note: R3 and R4 are mandatory, even if no external sensor is attached. Layout recommendations Landing Pattern                                          Figure5: BHA250/BHA250B Landing Pattern                                                       Figure6: BHI160/BHI160B Landing Pattern  Typical Layout                                                       Figure7: BHA250/BHA250B Layout                                                            Figure8: BHI160/BHI160B Layout Manufacturing notes BHy1 on COINES COINES setup       Platform: Windows gcc: "C:\DiaSemi\SmartSnippetsStudio\Tools\mingw64_targeting32\bin\gcc.exe C:\TDM-GCC-64\bin\gcc.exe". [ MKDIR ] build [ CC ] bhy_activity_recognition.c [ CC ] ../../../../sensorAPI/bhy/src/BHy_support.c [ CC ] ../../../../sensorAPI/bhy/src/bhy_uc_driver.c [ CC ] ../../../../sensorAPI/bhy/src/bhy.c [ CC ] ../../../../sensorAPI/bhy/AppBoard_usb_driver/AppBoard_usb_driver.c [ MAKE ] coinesAPI [ MKDIR ] build [ CC ] coines.c [ CC ] comm_intf/comm_intf.c [ CC ] comm_intf/comm_ringbuffer.c [ CC ] comm_driver/usb.c [ CC ] comm_driver/legacy_usb/legacy_usb_support.c [ AR ] libcoines [ LD ] bhy_activity_recognition.exe Operation finished successfully Running on BHy1 shuttle board Connect with APP2.0 board (BHy1 Shuttle board) and compile the sample code (..\..\examples\c\bhy\rotation_vector), Click  to run and get the output on the console. Running example 'bhy_rotation_vector.exe' ... uploading RAM patch... W: 1.000 X: 0.000 Y: 0.000 Z: 0.000 W: 1.000 X:-0.000 Y: 0.000 Z: 0.000 W: 1.000 X:-0.000 Y: 0.000 Z: 0.000 W: 0.999 X: 0.005 Y: 0.018 Z: 0.000 W: 0.999 X: 0.005 Y: 0.018 Z: 0.000 W: 0.999 X: 0.005 Y: 0.018 Z: 0.000 W: 0.999 X: 0.005 Y: 0.018 Z: 0.000 BHy1 example code on COINES Activity recognition example Data parsing for activity recognition is available in COINES. The user can open the “bhy_activity_recognition.c” in COINES, compile and run. The output will be shown in the COINES console. The code is shown as below.     /* @brief This API is used for parsing the activity recognition data from BHY * * @param[in] sensor_data: bhy data * @param[in] sensor_id: bhy id * * @return void * */ void sensors_callback(bhy_data_generic_t * sensor_data, bhy_virtual_sensor_t sensor_id) { float temp; u8 index; /* Since a timestamp is always sent before every new data, and that the callbacks */ /* are called while the parsing is done, then the system timestamp is always equal */ /* to the sample timestamp. (in callback mode only) */ temp = g_system_timestamp / 3200000.; for (index = 6; index <= 8; index++) { outBuffer[index] = floorf(temp) + '0'; temp = (temp - floorf(temp)) * 10; } for (index = 10; index <= 12; index++) { outBuffer[index] = floorf(temp) + '0'; temp = (temp - floorf(temp)) * 10; } /* if there are no changes then it will read X */ outBuffer[22] = 'X'; outBuffer[35] = 'X'; outBuffer[48] = 'X'; outBuffer[61] = 'X'; outBuffer[74] = 'X'; outBuffer[87] = 'X'; /* '0' means "end of activity and '1' means start of activity */ if (sensor_data->data_scalar_u16.data & 0b0000000000000001) outBuffer[22] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000000000010) outBuffer[35] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000000000100) outBuffer[48] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000000001000) outBuffer[61] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000000010000) outBuffer[74] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000000100000) outBuffer[87] = '0'; if (sensor_data->data_scalar_u16.data & 0b0000000100000000) outBuffer[22] = '1'; if (sensor_data->data_scalar_u16.data & 0b0000001000000000) outBuffer[35] = '1'; if (sensor_data->data_scalar_u16.data & 0b0000010000000000) outBuffer[48] = '1'; if (sensor_data->data_scalar_u16.data & 0b0000100000000000) outBuffer[61] = '1'; if (sensor_data->data_scalar_u16.data & 0b0001000000000000) outBuffer[74] = '1'; if (sensor_data->data_scalar_u16.data & 0b0010000000000000) outBuffer[87] = '1'; fprintf(stderr, "%s", outBuffer); /* activity recognition is not time critical, so let's wait a little bit */ mdelay(200); }      Gesture recognition example Data parsing for gesture recognition is available in COINES. The user can open the “bhy_gesture_recognition.c” in COINES, compile and run. The output will be shown in COINES console. In the example code, three gestures are enabled, which are “Glance, Pickup and Significant Motion”. The code is shown as below.     /* @brief This API is used for parsing the activity recognition data from BHY * * @param[in] sensor_data: bhy data * @param[in] sensor_id: bhy id * * @return void * */ void sensors_callback(bhy_data_generic_t * sensor_data, bhy_virtual_sensor_t sensor_id) { float temp; u8 index; /* Since a timestamp is always sent before every new data, and that the callbacks */ /* are called while the parsing is done, then the system timestamp is always equal */ /* to the sample timestamp. (in callback mode only) */ temp = g_system_timestamp / 3200000.; for (index = 6; index <= 8; index++) { outBuffer[index] = floorf(temp) + '0'; temp = (temp - floorf(temp)) * 10; } for (index = 10; index <= 12; index++) { outBuffer[index] = floorf(temp) + '0'; temp = (temp - floorf(temp)) * 10; } sensor_id &= 0x1F; /* gesture recognition sensors are always one-shot, so you need to */ /* re-enable them every time if you want to catch every event */ bhy_enable_virtual_sensor(sensor_id, VS_WAKEUP, 1, 0, VS_FLUSH_NONE, 0, 0); switch (sensor_id) { case VS_TYPE_GLANCE: strcpy(&outBuffer[24], "Glance \r\n"); break; case VS_TYPE_PICKUP: strcpy(&outBuffer[24], "Pickup \r\n"); break; case VS_TYPE_SIGNIFICANT_MOTION: strcpy(&outBuffer[24], "Sig motion\r\n"); break; default: strcpy(&outBuffer[24], "Unknown \r\n"); break; } fprintf(stderr, "%s", outBuffer); fflush(stderr); }     Gravity vector example Data parsing for gravity vector is available in COINES. The user can open the “bhy_gravity_vector.c” in COINES, compile and run. The output will be shown in COINES console. The code is shown as below.     /* @brief This API is used for parsing the activity recognition data from BHY * * @param[in] sensor_data: bhy data * @param[in] sensor_id: bhy id * * @return void * */ void sensors_callback(bhy_data_generic_t * sensor_data, bhy_virtual_sensor_t sensor_id) { float temp; u8 index; temp = sensor_data->data_vector.x / 8192.; outBuffer[3] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[4] = floorf(temp) + '0'; for (index = 6; index <= 8; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } temp = sensor_data->data_vector.y / 8192.; outBuffer[13] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[14] = floorf(temp) + '0'; for (index = 16; index <= 18; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } temp = sensor_data->data_vector.z / 8192.; outBuffer[23] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[24] = floorf(temp) + '0'; for (index = 26; index <= 28; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } fprintf(stderr, "%s", outBuffer); fflush(stderr); }     Rotation vector example Data parsing for Rotation Vector is available in COINES. The user can open the “bhy_rotation_vector.c” in COINES, compile and run. The output will be shown in COINES console. The code is shown as below.     /* @brief This API is used for parsing the activity recognition data from BHY * * @param[in] sensor_data: bhy data * @param[in] sensor_id: bhy id * * @return void * */ void sensors_callback(bhy_data_generic_t * sensor_data, bhy_virtual_sensor_t sensor_id) { float temp; u8 index; temp = sensor_data->data_quaternion.w / 16384.; outBuffer[3] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[4] = floorf(temp) + '0'; for (index = 6; index <= 8; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } temp = sensor_data->data_quaternion.x / 16384.; outBuffer[13] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[14] = floorf(temp) + '0'; for (index = 16; index <= 18; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } temp = sensor_data->data_quaternion.y / 16384.; outBuffer[23] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[24] = floorf(temp) + '0'; for (index = 26; index <= 28; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } temp = sensor_data->data_quaternion.z / 16384.; outBuffer[33] = temp < 0 ? '-' : ' '; temp = temp < 0 ? -temp : temp; outBuffer[34] = floorf(temp) + '0'; for (index = 36; index <= 38; index++) { temp = (temp - floorf(temp)) * 10; outBuffer[index] = floorf(temp) + '0'; } fprintf(stderr, "%s", outBuffer); fflush(stderr); }      Create customer example Customer can create their own case based on the sensor they used in the folder “examples”, for example, BHI160 Shuttle board, we can create a new folder “acc_gyro data output” Create the file and copy “Makefile” from other bhy example(like gravity_vector) Modify the Makefile                                           #CCE_Board_Definitions:BHI160;BHI160B;BHA250;BHA250B COINES_INSTALL_PATH ?= ../../../.. EXAMPLE_FILE ?= acc_gyro data output.c SHUTTLE_BOARD ?= BHI160 CFLAGS += -DBST_APPBOARD_VIA_USB -D$(SHUTTLE_BOARD) include $(COINES_INSTALL_PATH)/examples/c/examples.mk Now, you can make, compile and run your own code via COINES. Further reads BHA250/BHA250B Datasheet BHI160/BHI160B Datasheet BHy1 Handling, Soldering & Mounting Instructions BHy1 MCU Driver Porting Guide BHy1 Interfacing reference code from generic driver                                 
    View full article
    100% helpful (1/1)
    ‎08-14-2019 09:55 AM
     Introduction This document is intended as a reference guide on how to design using Bosch Sensortec’s BMI160 series IMU (inertial measurement unit) Selecting the right part The BMI16x family has two products: BMI160 and BMG250. Table 1 gives an overview of these two products. As the BMM150 can be connected to the secondary interface of BMI160 and BMI120 for 9-axis applications, it is also introduced below.                                                          Table 1: Overview of the products in the BMI16x family     Common characteristics The main characteristics of the BMI16x family are: Highly integrated, low power IMU 16-bit digital, tri-axial accelerometer 16-bit digital, tri-axial gyroscope   Key features 3.0x2.5mm 2 size Pin-to-pin compatibility with products in this family itself and in the BMI2XY family SPI or I 2 C interface Configurable range from ±2g to ±16g for accelerometer and ±125dps to ±2000dps for gyroscope Configurable output data rate up to 1.6kHZ for accelerometer and 6.4kHZ for gyroscope Integrated 1KB FIFO Auxiliary I2C interface for connecting external magnetometer, including data synchronization Built-in smart interrupt controller, with features such as step counter, any motion, no motion, etc    Differences among products The main differences among the BMI160 product family are in the function and overall performance. The BMI160 is the right choice for most standard applications. The BMG250 is a standalone gyroscope for applications where only a gyroscope is required, e.g. OIS etc. See Table 2 for their differences. Table 2: Differences between products in the BMI16x family   Available evaluation tools and software To best evaluate the products from the BMI160 family, the following combination of evaluation tools are recommended: COINES Desktop software (Windows version, Linux version) Application board 2.0 Without Bluetooth With Bluetooth https://www.bosch-sensortec.com/bst/support_tools/application_boards/overview_application_boards Sensor shuttle board BMI160 shuttle board BMG250 shuttle board BMM150 shuttle board  Reference design Figure 1 shows a mockup reference design of the BMI16x family.                                                         Figure 1: Mockup reference design Bill of materials Table 3 lists the bill of necessary materials.                                                                               Table 3: Bill of materials  Layout recommendations Because the BMI160 family contains tiny mechanical structures inside the package, care must be taken during the layout phase to ensure optimum performance. The complete handling and soldering guide can be found on the Bosch Sensortec’s website. The typical manufacturing procedures for the BMI160 accelerometers are described in the following sections. Landing pattern Figure 2 shows the landing pattern of the BMI160 family.                                                                     Figure 2: Landing pattern (in mm) Typical layout Figure 3 shows the typical layout.                                                                      Figure 3: Typical layout (in mm) Manufacturing notes Table 4 lists the recommendations for the manufacture.                                                          Table 4: Manufacture recommendations First power-on After powering on the sensor for the first time, the initial specs would be tested for communication with the device. This can be done by simply reading the chip identification code in the register 0x00. See Table 5 for the chip IDs.                                                            Table 5: Chip IDs of the BMI160 product family Below is some example code on how to perform this test based on the BMI160, using the COINES software as the host. static void init_bmi160(void) { int8_t rslt; rslt = bmi160_init(&bmi160dev); if (rslt == BMI160_OK) { printf("BMI160 initialization success !\n"); printf("Chip ID 0x%X\n", bmi160dev.chip_id); } else { printf("BMI160 initialization failure !\n"); exit(COINES_E_FAILURE); } } /*! * @brief Main Function where the execution getting started to test the code. * * @param[in] argc * @param[in] argv * * @return status * */ int main(int argc, char *argv[]) { struct coines_board_info board_info; int16_t rslt; init_bmi160_sensor_driver_interface(); rslt = coines_open_comm_intf(COINES_COMM_INTF_USB); if (rslt < 0) { printf("\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); exit(rslt); } rslt = coines_get_board_info(&board_info); if (rslt == COINES_SUCCESS) { if (board_info.shuttle_id != BMI160_SHUTTLE_ID) { printf("! Warning invalid sensor shuttle \n ," "This application will not support this sensor \n"); exit(COINES_E_FAILURE); } } init_sensor_interface(); /* after sensor init introduce 200 msec sleep */ coines_delay_msec(200); init_bmi160();hz coines_close_comm_intf(COINES_COMM_INTF_USB); return EXIT_SUCCESS; } Testing sensor functionality The BMI160 series IMU features a fully integrated and motionless self-test procedure on the ASIC itself. When the self-test is triggered, the accelerometer uses electric fields to physically move the electrodes in all directions, senses the deflection and compares it with the expected output. The gyroscope checks the sensor drive amplitude, frequency and stability of the drive control loop. Therefore, it is recommended to test the BMI160’s functionality using the built-in self-test feature. Here is some sample code on how to perform this self-test, based on BMI160, using the COINES software as the host. Testing sensor performance The BMI160 family’s performance parameters, e.g. offset and noise, can be easily tested with the device motionless. See below for the typical values of the BMI160 family.                                      Table 6: Typical performance of the BMI160 product family Note: Typical values are defined as ± 1σ, which means that 68.3% of sensors are expected to fall within these values. Min/Max values are defined as ± 3σ, which means 99.7% of sensors shall be within these values. The offset testing procedure is quite simple. This can be done by putting the device in a known position, e.g. on a flat surface, calculate the average value for each axis, and subtract the expected output (e.g. 0G, 0G, +1G) from the value. The result is the offset of the sensor. The example code on how to perform this test will be provided when available. The noise calculation is a bit more complicated. First, subtract the offset from each data point. The RMS value can be calculated as the square root of the arithmetic mean of the squares of the noise values. Since the noise value is affected by the bandwidth of the digital filter, it needs to be converted back to noise density using the following formula. Note that this applies to a second order filter only. The example code on how to perform noise calculation will be provided when available.  Example Code The complete example code can be compiled and executed from the following subfolder:  /examples/c/bmi160/ under the COINES installation directory (C:/COINES on Windows by default). Calibration The BMI16x family has been pre-trimmed at the factory, but the offset may vary due to the soldering process and PCB bending during assembly. Therefore, it is preferred to calibrate the accelerometer and the gyroscope after assembling the device into its housing. The BMI16x family calibration includes accelerometer offset calibration and gyroscope offset calibration Example code The calibration procedures can be found in the BMI160 Datasheet. Once the offsets are determined, they can be written into the NVM (non-volatile memory) so that the sensor automatically compensates for the soldering offset even after physically diconnecting the power. The example code on how to perform calibration and save calibration data to NVM will be provided when available. The complete example code can be compiled and executed from the subfolder: /examples/c/bmi160/ under the COINES installation directory (by default, C:/COINES on Windows). Usage The COINES installation provides sample code on how to turn on the sensor, configure it and read out the IMU data.  Example code Below is some example code on how to evaluate basic communication based on the BMI160, using the COINES software as the host. int main(int argc, char *argv[]) { struct coines_board_info board_info; int16_t rslt; init_bmi160_sensor_driver_interface(); rslt = coines_open_comm_intf(COINES_COMM_INTF_USB); if (rslt < 0) { printf("\n Unable to connect with Application Board ! \n" " 1. Check if the board is connected and powered on. \n" " 2. Check if Application Board USB driver is installed. \n" " 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n"); exit(rslt); } rslt = coines_get_board_info(&board_info); if (rslt == COINES_SUCCESS) { if (board_info.shuttle_id != BMI160_SHUTTLE_ID) { printf("! Warning invalid sensor shuttle \n ," "This application will not support this sensor \n"); exit(COINES_E_FAILURE); } } init_sensor_interface(); /* after sensor init introduce 200 msec sleep */ coines_delay_msec(200); init_bmi160();hz coines_close_comm_intf(COINES_COMM_INTF_USB); return EXIT_SUCCESS; } Further reads Datasheets: BMI160 BMM150 BMG250 Handling, soldering and mounting instructions: BMI160 HSMI      
    View full article
    ‎01-31-2023 03:42 PM
    The BME688 is the first gas sensor with Artificial Intelligence (AI) with integrated high-linearity and high-accuracy pressure, humidity and temperature sensors. The BME688 can detect gases by measuring their unique electrical fingerprint and therefore distinguish different gas compositions. However, the sensor has to be teached about these different gases first. That means, we have to train the sensor using Machine Learning.  And that’s where the BME AI Studio comes in, it lets the user explore, verify and validate the specific use case based on their application. In these series of short videos we take you through a step by step approach to realize these use case detection. It showcase all the key steps from how to configure the board, data collection, algorithm training and finally deployment of algorithm. The video series features a “quick start” video in the beginning that gives a quick overview of the all the steps involved  and additional videos about each step. The videos have been split in to smaller modular videos that gives an overview of all the key steps, it can be viewed as a playlist (one after the other) or the user can go to a specific video to know more about it. We hope that you will enjoy watching it.   
    View full article
    100% helpful (1/1)
    ‎08-10-2022 04:52 PM
    The Arduino Nicla Sense ME board featuring a rich set of Bosch Sensortec sensors is a robust and versatile development board that enables users to develop smart sensing applications. This series of tutorial videos aim to help users to get started and familiar with the board and quickly explore some of the functionalities and resources around it.  
    View full article
    100% helpful (1/1)
    ‎05-31-2021 12:16 PM
    Frequently Asked Questions (FAQs) about the BMP384 sensor
    View full article
    ‎07-29-2019 10:33 AM
    Introduction Accelerometer (Acc), Gyroscope (Gyro) and Magnetometer (Mag) sensors (components) have their own coordinates. By default BHA and BHI are configured to ENU axis convention (East-North-Up), as commonly used in consumer electronic devices. It is usually obtained by the integration of Accelerometer (Acc), Gyroscope (Gyro) and Magnetometer (Mag) sensors readings. The ENU coordinate system is defined as a direct orthonormal basis where:     x points east and is tangential to the ground.     y points north and is tangential to the ground.     z points towards the sky and is perpendicular to the ground.  Users can download the BHI/BHA firmware from Bosch Sensortec Website. All firmware’s coordinates are the same. Figure 2(left) shows the coordinate of the BHI/BHA shuttle board. Cares must be taken that the direction of BHI/BHA and Magnetometer sensor must follow the BHI/BHA shuttle board when customer do the PCB placement. Figure 2(right) shows the direction of BHI/BHA and Magnetometer on the shuttle board. It is the easiest and best way that customer can reuse the same coordinate of BHI/BHA shuttle board on their product. It is possible to change the coordinate based on customer definition. This document is to tell the customer the way how to do the axis-remapping on their products. Axes definition Define the coordination of your board (X BOARD, Y BOARD, Z BOARD ). Normally this is the default coordination system of your final application (i.e. your system coordination). In standard Android system the ENU (east north up) orientation is required. For other applications, the Z BOARD is normally pointing to the sky or ground when the board is placed on a horizontal surface. Find the coordinates of the sensors mounted on the board in their datasheets. Draw all the coordinates on the paper. Figure 3 shows an example. In Figure 3, it is highly recommended to follow the placement on the BHI160 shuttle board, if the user do not want to pay more effort on it.  If you are using a standard Bosch sensor, their coordinates follow the right-handed coordinate principle (Figure 4). You can apply it to find the sensor axes when it placed on the board.   Orientation matrix When the sensors axes orientation are different to the board, we need to convert it to the board coordinate by following formula: [X Y Z] is the board coordinate [Xs Ys Zs] is the sensor coordinate (C 0 … C 8 ) is the orientation matrix. The coefficient has three possible value: 1, 0 and -1. 1 --- Two axes are paralleled and have same direction -1 --- Two axes are paralleled and have opposite direction 0 --- Two axes are perpendicular Example If we have a board shown in Figure 3. On this board, there are a BHI160 and a BMM150. The dots on the sensor indicate their coordinates. You can try to find the coordinates and write the orientation matrix. Table 1shows the result. Orientation matrix: C s = (0 -1 0 1 0 0 0 0 1), Updating via product API (Host side) Basic configuration When customer follow the requirement (components placement), so only one matrix is needed for the sensor(A,M,G). Users can configure the axes before enable the BHI160/BHA250 by editting the remapping matrix in its .c file. The following code is content of the accelerometer_remapping_example.c in the API. Use this as a reference to update your matrix accordingly. The matrix can also be edited within the product API which is available on GitHub: https://github.com/BoschSensortec/BHy1_driver_and_MCU_solution int main(void) { u8 array[ARRAYSIZE], *fifoptr, bytes_left_in_fifo=0; u16 bytes_remaining, bytes_read; bhy_data_generic_t fifo_packet; bhy_data_type_t packet_type; BHY_RETURN_FUNCTION_TYPE result; s8 mapping[9] = {0}; s8 mapping_all[9] = {0 -1 0 1 0 0 0 0 1}; // new mapping matrix, example on Figure3 … … /* config mapping matrix, it is not necessary to change mapping matrix if its orientation is aligned with the board */ bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_ACC,mapping); // get current ACC mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_ACC,mapping_all); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_ACC,mapping); // check if the matrix is set successfully … … bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_GYRO,mapping); // get current GYRO mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_GYRO,mapping_all); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_GYRO,mapping); // check if the matrix is set successfully … … bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_MAG,mapping); // get current MAG mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_MAG,mapping_all); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_MAG,mapping); // check if the matrix is set successfully ​ Advanced configuration If the sensor placement is not followed the Shuttle Board, the user can configure matrix for each sensor. In this configuration, customer can place the sensor on the board as they need(no need to follow the chip placement on shuttle board). int main(void) { u8 array[ARRAYSIZE], *fifoptr, bytes_left_in_fifo=0; u16 bytes_remaining, bytes_read; bhy_data_generic_t fifo_packet; bhy_data_type_t packet_type; BHY_RETURN_FUNCTION_TYPE result; s8 mapping[9] = {0}; s8 mapping_ACC[9] = {0 -1 0 1 0 0 0 0 1}; // new mapping matrix, example on Figure3 s8 mapping_GYRO[9] = {0 -1 0 1 0 0 0 0 1}; // s8 mapping_MAG[9] = {0 -1 0 1 0 0 0 0 1}; // can be different … … /* config mapping matrix, it is not necessary to change mapping matrix if its orientation is aligned with the board */ bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_ACC,mapping); // get current ACC mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_ACC,mapping_ACC); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_ACC,mapping); // check if the matrix is set successfully … … bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_GYRO,mapping); // get current GYRO mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_GYRO,mapping_GYRO); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_GYRO,mapping); // check if the matrix is set successfully … … bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_MAG,mapping); // get current MAG mapping matrix bhy_set_mapping_matrix (PHYSICAL_SENSOR_INDEX_MAG,mapping_MAG); // set new mapping matrix in the fw bhy_get_mapping_matrix(PHYSICAL_SENSOR_INDEX_MAG,mapping); // check if the matrix is set successfully   For more details and technical support with respect to the product API the *.h file and the MCU porting please refer to the Bosch Sensortec documents “MCU Driver Porting Guide” and “Interfacing Reference Code from Generic Driver” for BHA and/or BHI placed within the section “Application notes”, available onhttps://www.bosch-sensortec.com/bst/support_tools/downloads/overview_downloads Check the orientation After the orientation matrix has been updated, you need to check whether the remapping is successful. You can read the uncalibrated data of the sensors to check if the remapping is successful. Please define the coordination of the board (X BOARD, Y BOARD, Z BOARD ) first. Check the Acc axes (XA, YA, ZA) Enable Acc uncalibrated data; Place the board on a horizontal surface and make sure Z BOARD is pointing to the sky. Z-axis should output 1g. Turn the board at perpendicular position and make sure X BOARD is pointing to the sky. X-axis should output 1g. Turn the board at perpendicular position and make sure Y BOARD is pointing to the sky. Y-axis should output 1g. Check the Gyro axes (XG, YG, ZG) If you use BHI160, the axes of Acc and Gyro are same. In Bosch product, a Gyro axis direction can be found by your right hand. Move your four fingers follow the rotation direction to make a fist and the thumb will be pointing to the positive axis like Figure 5 (This is similar to right-hand crew rule). Enable Gyro uncalibrated data; Place the board on a horizontal surface and make sure Z BOARD is pointing to the sky. Quickly rotate left 180 degree. The output has significant change is the rotation axis. It should be z-axis and output positive data. Rotate the board according to X BOARD and Y BOARD . Check the output with right-hand crew rule respectively. Check the Mag axes (XM, YM, ZM) Method 1 Enable Mag uncalibrated data and only log the first three data, which is the original data; Place the board on the table and make sure the X BOARD is pointing to the planet's North Pole by using a reference compass. Record the (X M, Y M, Z M ) stable output below. Then Point X BOARD to planet's South Pole and record the stable output. The axis output has the maximum difference is parallel to X BOARD Here |X 1 - X 2 | should be the largest, and X 1 > X 2 . Then the remapping is correct.   Apply same method to Y BOARD, Z BOARD to find if the orientation of other two axes are correct.  Method 2 1.Enable Mag uncalibrated data and only log the first three data; 2.Rotate the board in following steps and record the output data: If X1>X2 & X4>X3, min(X1,X2,X3,X4)=X2, and max(X1,X2,X3,X4)=X4; Y1>Y2 & Y4>Y3, min(Y1,Y2,Y3,Y4)=Y3, and max(Y1,Y2,Y3,Y4)=Y1; Z2>Z1. Then the remapping is correct.  
    View full article
    ‎03-28-2019 08:57 AM
     About this guide This guide is intended for users who want to evaluate the performance of Bosch Sensortec’s BMA400. It describes how to install the Development Desktop 2.0 and use it to perform current and noise measurements for the BMA400, as well as introduce the BMA400’s anti-aliasing function, interrupt functions and FIFO usage, etc. General description The BMA400 is Bosch Sensortec’s first ultra-low-power acceleration sensor without compromising performance. It features 12-bit digital resolution, continuous measurement, selectable bandwidth, and ultra-low power consumption, allowing low-noise measurement of accelerations on three perpendicular axes. The BMA400 can sense tilt, orientation, tap/double-tap, and enable “plug and play” step counting with activity recognition, which makes it ideal for wearable devices that require extended battery life. In addition, equipped with two generic interrupts, the BMA400 can detect multiple defined movements and motions, reducing the workload of the MCU/AP. The Bosch Sensortec Application Board 2.0 provides a versatile and universal demonstration and development environment for Bosch Sensortec’s sensor products. It can be used in conjunction with the Bosch Sensortec Development Desktop software 2.0 to configure all sensor parameters and read/display/capture data on the connected PC. The Bosch Sensortec BMA400 shuttle board is a PCB with a BMA400 sensor mounted on it. It allows easy access to the sensor's pins via a simple socket. Since all Bosch Sensortec sensor shuttle boards have an identical footprint, they can be plugged into Bosch Sensortec’s advanced development tools (e.g. the development board). The BMA400 shuttle board can also be used for the user's own implementations as well. Prerequisites To evaluate the BMA400, the following items are required: Bosch Sensortec Application Board 2.0 BMA400 shuttle board Development desktop software 2.0 In addition, the following system requirements must be met: 32 or 64-bit Windows 7, Windows 8, or Windows 10 Microsoft .NET Framework 4.0 or higher 1 GB memory 1 GHz processor or greater USB 2.0 host controllers Hardware connection Prior to evaluation, the BMA400 shuttle board must be attached on to the Bosch Sensortec Application Board 2.0. Figure 1 shows the connected Bosch Sensortec Application Board 2.0 and BMA400 shuttle board and their key components.              Figure 1: Connection of BMA400 shuttle board and Bosch Sensortec Application Board 2.0 Figure 2 shows signals on the BMA400 shuttle board. The power, SPI, I2C, and INT signals are routed out from the BMA400 to the BMA400 shuttle board’s connectors. Pin 10 ~ 14 and pin 23 ~ 28 are internal signals, which can be ignored.                                                                    Figure 2: BMA400 Shuttle Board Signals Figure 3 show the schematic diagram of the BMA400 sensor on the BMA400 shuttle board.                      Figure 3: Schematic Diagram of the BMA400 Sensor on the BMA400 Shuttle Board Development Desktop 2.0 This chapter describes how to download and install the Development Desktop 2.0. Downloading The Development Desktop 2.0 can be downloaded from Bosch Sensortec website at https://www.bosch-sensortec.com/bst/support_tools/downloads/overview_downloads On the Downloads page, click the tab Software. Under Software, click the “+” sign besides Development Desktop Software to expand it, then click the installer and Development Desktop 2.0 user manual to download. See Figure 4.                                      Figure 4: Development Desktop 2.0 Download Page Installing For instructions on how to install the Development Desktop 2.0, see the downloaded Development Desktop 2.0 user manual. Getting started This chapter introduces the Development Desktop 2.0 UI and describes how to start it, use it to capture a data log. Starting the Development Desktop 2.0 To start the Development Desktop 2.0, do the following: Attach the BMA400 shuttle board onto the Bosch Sensortec Application Board 2.0. Connect the Bosch Sensortec Application Board 2.0 to the PC with a USB cable. Turn on the Power switch on the Bosch Sensortec Application Board 2.0. Double-click the Development Desktop 2.0 icon on the PC to start it. The screen shows below. Click Connect.                                                                 Figure 5: Development Desktop 2.0 Start Window Figure 6 shows the Development Desktop 2.0 UI. By default, the sensor is in sleep mode and should be set to normal mode. Once clicking Start Streaming at the lower bottom corner, the sensor data is plotted and displayed in the upper left part. Interrupt(s) will be plotted in the lower left part if enabled.                                                                Figure 6: Development Desktop 2.0 UI Capturing and analysing data log With the Development Desktop 2.0, data logs can be captured for analysis. To capture a data log, do the following(example 😞 Place the Bosch Sensortec Application Board 2.0 connected with the BMA400 shuttle board on a steady table, keeping them away from vibration. Connect the Bosch Sensortec Application Board 2.0 to the PC, then start the Development Desktop 2.0. In the Accelerometer settings section, set the sensor parameters as below: Power Mode = Normal OSR = 0 ODR = 50Hz Range = 2 4     Click Start Streaming to start data plotting.                                                             Figure 7: Settings for Capturing Data Log 5. Click Panels on the menu bar, then click Data Export.                                                                    Figure 8: Open the Data Export Panel 6. On the popup window, click Select Destination to specify a folder where you want to save the log file, set a file name and choose the file type (.csv is recommended) 7. Check Enable Data Log to start data logging.                                                                                  Figure 9: Enable Data Log 8 .    Uncheck Enable Data Log to stop logging. 9 .     Open the destination folder specified in Step 6, the log file can be found. The captured data log can then be used to evaluate the performance of the BMA400. Current measurement The BMA400 features ultra-low power consumption. To measure the BMA400’s current consumption, do the following: Remove the jumper of J504 on the Bosch Sensortec Application Board 2.0.                                                                                Figure 10: J504 Jumper 2.    Connect the multi-meter to the Bosch Sensortec Application Board 2.0. See Figure 11. 3.    Turn the switch on the multi-meter to point it to “μA". 4.   Start the Development Desktop 2.0 software on the PC. By default, the sensor is in Sleep mode, and the current ~0.15 μA. 5. Set the Power mode = Normal, OSR=0. In this case, the current is ~3.5 μA. Trying different ODRs (12.5 ~ 800 Hz), the measured current remains the same. 6. Set the Power mode = Low power, OSR = 0. In this case, the current is ~0.8 μA. In low power mode, the BMA400 ODR is fixed to 25 Hz.                                                       Figure 11: Current Measurement with Multi-meter Table 1 shows the current consumption table extracted from BMA400 Datasheet. When configuring Accelerometer settings, users can refer to this current consumption table to get appropriate values.                                                                   Figure 12: Settings for Low Power Mode                                                                    Figure 13: Settings for Normal Mode Noise measurement With Development Desktop 2.0, the noise generated can also be measured. The measured noise level varies depending on different accelerometer settings. Table 2 shows part of the noise table from BMA400 Datasheet. For example, in normal mode, when OSR = 2, ODR = 100, the RMS noise measured is approximately 1.93mg  as highlighted in the table.                                                                                                              Figure 14: Set OSR to 2 in Normal Mode                                                                              Figure 15: Set ODR to 100Hz After capturing a data log of the BMA400, users can get the noise by calculating the standard deviations for F, G, and H columns (i.e. data of X, Y, and Z axis), as shown in Figure 16.                                                                 Figure 16: Calculate the Noise with Data Log  Anti-aliasing evaluation In order to reduce current consumption, most sensors work in duty cycling sampling mode and the equivalent sampling rate can only be ~ 1/ODR due to the long sleep period. In this case, the output of the accelerometer is inevitably interfered by high frequency noise. However, the BMA400 uses  continuous sampling and filtering, and the actual sampling rate of the BMA400 is much greater than the ODR (output data rate). Therefore, it can easily filter out the high-frequency interference signals and recover real motion signals. Figure 17 illustrates the anti-aliasing principle of the BMA400.                                                                  Figure 17: BMA400 Anti-aliasing Principle Interrupt functions The BMA400 is integrated with multi-functional interrupts, including auto-wakeup/low power, generic interrupts 1 and 2, step counter, and orientation, which can be used in different scenarios. To configure auto-wakeup/low power, generic interrupt 1 and step counter, do the following: Click Panels > Memory Map > Interrupt View to open the Interrupt view.                                                                                  Figure 19: Interrupt View 2    Configure interrupt mapping parameters as shown in Figure 20, and enable Gen1, step counter interrupt, and wake up interrupt, then click Write.                                                                              Figure 20: Interrupt Configuration 3    Configure wakeup interrupt as shown in Figure 21, and check Enable Gen 1 trigger low power.                                                              Figure 21: Wakeup/Auto Low Power Configuration In this example, the condition of auto wakeup is: For x, y, or z axis, if >= 2 continuous acceleration differences of contiguous samples are bigger than 94mg, the wakeup interrupt will be triggered, and the BMA400 will enter normal mode. In low power mode, the sampling rate of the BMA400 is 25Hz, so 2 samples time means 80ms wakeup delay 4     Configure Gen1 (generic interrupt 1) for triggering auto-low-power.                                                        Figure 22: Generic Interrupt Configuration In this example, the trigger condition of Gen1 is: For x, y, and z axes, if >= 100 continuous acceleration differences of contiguous samples are lower than 24 mg, the Gen1 will interrupt and trigger the BMA400 to switch to low power mode. 5     Move the board and simulate the step movement, it can be seen that the BMA400 is switched to normal mode automatically, and the step counter is increasing (the first seven steps will not be displayed until the 8th step comes.)If the sensor stays still for more than 1s, the Gen1 is triggered and the BMA400 automatically goes to low power mode.                                                                                Figure 23: Interrupt Plotting FIFO usage The BMA400 is integrated with 1 Kbyte FIFO, which support watermark and full interrupts to host. To  configure FIFO usage, do the following: 1     Click Panels > Memory Map and choose FIFO View, as shown in Figure 24.                                                                                   Figure 24: Enable FIFO View 2      In the FIFO View, configure interrupt settings and FIFO watermark, click Write, and then click Start streaming.                                                                              Figure 25: FIFO View Additional Development Desktop 2.0 UI menus This chapter describes some useful configuration panels on the Development Desktop 2.0 UI menu. As shown in Figure 26, under Panels > Memory Map, users can switch between four views according to their own needs.                                                                          Figure 26: Configuration Panels Binary View: for reading/writing all the sensor registers Interrupt View: for configure the BMA400 features and interrupts FIFO view: for configuring FIFO SelfTest View: for performing self-test and showing the test result By clicking Panels > Register Access, users can read and write a single register. Figure 27 shows the popup register read and write configuration menu.                                                              Figure 27: Register Access Configuration Menu  
    View full article
    100% helpful (4/4)
    ‎06-19-2020 11:54 AM
    step by step how to use python scripts with our Bosch Sensortec APP 2.0
    View full article
    ‎06-15-2020 05:05 AM
    For customer usage, you need to download the sensor driver package from the website to communicate with sensor after connecting the BMP388 chip to your developing board.  You can find the information from the following link https://github.com/BoschSensortec/BMP3-Sensor-API. The procedure of using BMP388 sensor API is presented in the following flow chart: The detailed example code for integration of API could be found in: https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/README.md Following steps need to be considered to ensure the API/sensor configured correctly. For reading the data information from API, the following example can follow 1.The following static function should be added into your own project static int64_t compensate_temperature static uint64_t compensate_pressure static double bmp3_pow static void parse_calib_data static double compensate_temperature_d static double compensate_pressure_d 2.Define the main function to print the data, the structure for BMP3 and put the trimming data into the correct position as follow. One example shown below calib_data->reg_calib_data.par_t1 = (int16_t)27402; calib_data->reg_calib_data.par_t2 = (int16_t)18868; calib_data->reg_calib_data.par_t3 = (int8_t)-10; calib_data->reg_calib_data.par_p1 = (int16_t)-244; calib_data->reg_calib_data.par_p2 = (int16_t)-3254; calib_data->reg_calib_data.par_p3 = (int8_t)35; calib_data->reg_calib_data.par_p4 = (int8_t)0; calib_data->reg_calib_data.par_p5 = (int16_t)25879; calib_data->reg_calib_data.par_p6 = (int16_t)31477; calib_data->reg_calib_data.par_p7 = (int8_t)-13; calib_data->reg_calib_data.par_p8 = (int8_t)-10; calib_data->reg_calib_data.par_p9 = (int16_t)16342; calib_data->reg_calib_data.par_p10 = (int8_t)29; calib_data->reg_calib_data.par_p11 = (int8_t)-60; 3.Give the correct default value to the uncompensated temperature and pressure, define the version to temperature and pressure. uncomp_data->pressure = 8241776; uncomp_data->temperature = 8329880; double temp = compensate_temperature_d(uncomp_data, calib_data); double press = compensate_pressure_d(uncomp_data, calib_data); double tempurature = temp; double pressure = press; 4.Print out the final value printf("Temperature\t Pressure\t\n"); printf("%0.2f\t\t %0.2f\t\t\n", tempurature, pressure); system("pause");  
    View full article
    ‎07-26-2019 09:30 AM
    Concept of auto-wakeup & auto-low power  Auto Wakeup As shown in the diagram, the wakeup function can generate an interrupt by detecting defined movement, while the auto-wakeup function can switch the BMA400 from low power mode to normal mode. During switching to normal mode, the sensor configurations defined in previous normal mode (before entering low power mode), like ODR, range, OSR, FIFO, interrupts, will be restored automatically. Therefore, the host only need to configure BMA400 once in initialization and no need to reconfigure the parameters after BMA400 enters normal mode by auto-wakeup function. The three possible triggers for wake-up from low-power mode are: by serial command by timeout by wake-up interrupt on activity The three conditions can be enabled in parallel. Please be notified that, the timeout wakeup can only switching BMA400 to normal mode if configured, and cannot be mapped to the interrupt pin(INT1 and INT2). Auto Low Power Except the serial command, there are three possible triggers can switch BMA400 to low-power automatically: by timeout by activity on Gen1(Gen1 interrupt will trigger the switching to low-power mode) by data ready (DRDY) The three conditions can be enabled in parallel. Also in timeout mode, the counter can be reset by interrupt from Gen2 interrupt. This can be used to enlarge the active time (in normal mode) of BMA400 if some activity is detected by Gen2. Relative registers  Use Cases In this section, several typical examples are presented with sample codes; you can modify them for your specific usage. Auto wakeup and Auto low power by timeout Case description In this case, both Auto wakeup & auto low power function are triggered by timeout. So after configuration and enabling, BMA400 will work in below sequence: Repeat:             Low power mode sampling (2.5ms ~ 10.24s)             Auto switches to normal mode by timeout             Normal mode sampling ((2.5ms ~ 10.24s))             Auto switches to low power mode by timeout  Parameters configure In this example, range = 2g, ODR=100Hz, Accel data source = filter1 Auto-lowpower relative Register(0x2A),Register(0x2B): auto_lp_timeout_thres = 400 (400 * 2.5ms = 1s), unsigned 12bit, timeout threshold, 2.5ms/lsb auto_lp_timeout: set to 1 here (enable), timeout as source for auto-low-power condition For mode auto_lp_timeout = 0x02, gen2 interrupt will reset the timeout counter, and this can be used to delay the auto-lowpower if some condition is fulfilled. For example, in watch/band, gen2 can be configured to detect the body movement, and only if no movement is detected, the timeout counter will be continued and after defined time, the sensor eventually goes into low power mode. Auto-wakeup relative wakeup_timeout_thres = 0x0FFF (max value, 0x0fff * 2.5ms = 10.24s) Register (0x2C) and (0x2D), unsigned 12bits, auto-wakeup timeout threshold, 2.5ms/lsb wkup_timeout: set to 1 (enable) Register (0x2D)  AUTOWAKEUP_1. wkup_timeout = 1; enable timerout triggering auto-wakeup  Sample codes #### BMA400 Auto wakeup and Auto low power features ##### _Usage of auto wakeup and auto low power features in sensor_ ``` c /* Auto wake-up timeout testing setting */ int8_t bma400_timeout_autowakeup_auto_lp(struct bma400_dev *dev) { int8_t rslt = 0; uint8_t power_mode; uint16_t int_status; struct bma400_device_setting dev_setting[2]; /* Selecting auto wakeup on timeout */ dev_setting[0].type = BMA400_AUTOWAKEUP_TIMEOUT; /* Selecting auto low power mode*/ dev_setting[1].type = BMA400_AUTO_LOW_POWER; /* Get the previously set settings */ rslt = bma400_get_device_setting(&dev_setting, 2, dev); if (rslt == BMA400_OK) { /* Enable auto wakeup on timeout feature */ dev_setting[0].conf.auto_wakeup.wakeup_timeout = BMA400_ENABLE; /* Set the timeout value as maximum (10.24s) */ dev_setting[0].conf.auto_wakeup.timeout_thres = BMA400_AUTO_WAKEUP_TIMEOUT_MAX; /* Set auto low power on timeout feature */ dev_setting[1].conf.auto_lp.auto_low_power_trigger = BMA400_AUTO_LP_TIMEOUT_EN; /* Set the timeout value as 1s (400*2.5ms) */ dev_setting[1].conf.auto_lp.auto_lp_timeout_threshold = 400; /* Set the configurations in sensor */ rslt = bma400_set_device_setting(&dev_setting, 2, dev); /* The sensor toggles between Low-power mode and Normal mode for every 10.24s * as configured by user which can be tested and verfied by reading the power mode * and printing it continuously as follows * while (1) { * rslt = bma400_get_power_mode(&power_mode, dev); * printf("\n POWER MODE : %d",power_mode); * } * The power mode toggling can be seen from the printed console output */ } return rslt; } Auto wakeup and auto low power by position Case description In this example, the wakeup interrupt is defined to detect the non-flat position of the sensor. A threshold (94mg) is configured, so if the sensor tilt over the threshold, the wakeup interrupt will be set and switch the BMA400 to normal mode(auto-wakeup function). Once entered into normal mode, the Gen1 will continuously detect the sensor position, and check if the sensor returns back into the range of flat, this range should be smaller than 94mg(here gen1 threshold is set to 40mg). So, once the gen1 condition is fulfilled, BMA400 will automatically switch to low power mode by auto-lowpower function.  Parameters configure Range = 4g, ODR=100, OSR=1  Auto-lowpower relative Register (0x2B) AUTOLOWPOW_1.gen1_int = 1; set this bit the interrupt from Gen1 will trigger the switching from normal mode to low power mode 1.1.1.2 Generic interrupt 1 (gen1) relative Register (0x3F) GEN1INT_CONFIG0: Set gen1_act_x_en, gen1_act_y_en, gen1_act_z_en = 1 (enable all 3 axes) gen1_data_src=1; select filter2 (fixed 100Hz) as data source gen1_act_refu = 0; manual update(fixed reference, configured by host) gen1_act_hyst = 0; disable Register (0x40) GEN1INT_CONFIG1: gen1_comb_sel = 1; logic AND gen1_criterion_sel = 0; inactivity interrupt This combination means that ALL (logic AND) three axes value should be WITHIN (inactivity interrupt) the threshold near the reference position. Register (0x41) GEN1INT_CONFIG2: gen1_int_thres = 5 (threshold = 5*8mg/lsb = 40mg) Register (0x42) GEN1INT_CONFIG3/Register (0x43) GEN1INT_CONFIG31 gen1_int_dur = 100 (monitor duration = 100samples * 1/100Hz(filter2) = 1s) Register (0x44) GEN1INT_CONFIG4 to Register (0x49) GEN1INT_CONFIG9: gen1_int_th_refx/y/z = (0, 0, 512); means (0, 0, 1g ) Range sensitive, (512 lsb represents 1g) @4g range So in this configuration gen1 interrupt will be set only if: Condition 1:  (|a_x-ref_x| <40mg) AND (|a_y-ref_y|<40mg) AND (|a_z-ref_z|<40mg) Condition 2: more than 100 continuous past samples fulfill condition 1  Auto-wakeup relative Register (0x2D) AUTOWAKEUP_1 wkup_int = 1; use wake-up interrupt for auto-wake-up Wakeup interrupt relative Register (0x2F) WKUP_INT_CONFIG0 wkup_x_en, wkup_y_en, wkup_z_en = 1; enable three axes num_of_samples = 3; 4(=3+1) continuous samples will be monitored in low power mode wkup_refu = 0; manual update, configured by host Register (0x30) WKUP_INT_CONFIG1 int_wkup_thres = 3; (3 * 1/32 * 1g = 94mg) @4g range, range sensitive, 8 bit unsigned value Register (0x31) WKUP_INT_CONFIG2 to Register (0x33) WKUP_INT_CONFIG4 int_wkup_refx/y/z = (0, 0, 32); (0, 0, 1g) @4g range, range sensitive So the wakeup interrupt will be set only if: Condition 1: (|acc_x - ref_x| > 94mg) OR (|acc_y - ref_y| > 94mg) OR (|acc_z - ref_z| > 94mg) Condition 2: more than 4 continuous past samples fulfill condition 1 Sample codes The sample codes are shown below, and please ignore the configuration of Gen2, which is not relative to this case. /* #### BMA400 Auto wakeup and Auto low power features ##### _Usage of auto wakeup and auto low power features in sensor_ */ /* Auto wake-up based on position testing setting */ int8_t bma400_position_autowakeup_auto_lp(struct bma400_dev *dev) { int8_t rslt = 0; uint8_t power_mode; uint16_t int_status; struct bma400_device_setting dev_setting[2]; /* Interrupt configuration structure */ struct interrupt_enable int_en; /* Selecting auto wakeup on wakeup interrupt event */ dev_setting[0].type = BMA400_AUTOWAKEUP_INT; /* Selecting auto low power mode*/ dev_setting[1].type = BMA400_AUTO_LOW_POWER; /* Get the previously set settings */ rslt = bma400_get_device_setting(&dev_setting, 2, dev); if (rslt == BMA400_OK) { dev_setting[0].conf.wakeup.wakeup_axes_en = BMA400_XYZ_AXIS_EN dev_setting[0].conf.wakeup.wakeup_ref_update = BMA400_MANUAL_UPDATE dev_setting[0].conf.wakeup.sample_count = BMA400_SAMPLE_COUNT_4 dev_setting[0].conf.wakeup.int_wkup_threshold = 3 dev_setting[0].conf.wakeup.int_wkup_ref_x = 0 dev_setting[0].conf.wakeup.int_wkup_ref_y = 0 dev_setting[0].conf.wakeup.int_wkup_ref_z = 32 /* (0, 0, 1g) */ dev_setting[0].conf.wakeup.int_map = BMA400_INT_CHANNEL_1 /* Enable auto low power on Gen1 trigger */ dev_setting[1].conf.auto_lp.auto_low_power_trigger = BMA400_AUTO_LP_GEN1_TRIGGER; /* Set the configurations in sensor */ rslt = bma400_set_device_setting(&dev_setting, 2, dev); if (rslt == BMA400_OK) { /* Enable the Generic interrupts in the sensor */ int_en.int_sel = BMA400_AUTO_WAKEUP_EN; int_en.conf = BMA400_ENABLE; rslt = bma400_enable_interrupt(&int_en, 1, dev); /* The sensor toggles between Low-power mode and Normal mode if tilt the device(sensor) * or place it back to flat * this can be verfied by reading the power mode and printing it continuously as follows * while (1) { * rslt = bma400_get_power_mode(&power_mode, dev); * printf("\n POWER MODE : %d",power_mode); * } * The power mode toggling can be seen from the printed console output */ } return rslt; } /*##### BMA400 Generic interrupt configuration ##### _Usage of Generic interrupt1 and 2 for activity/inactivity detection in sensor_ */ /* Generic Interrupt feature */ int8_t bma400_generic_interrupts_by_position(struct bma400_dev *dev) { int8_t rslt = 0; /* Variable to store interrupt status */ uint16_t int_status; /* Sensor configuration structure */ struct bma400_setting accel_settin[2]; /* Interrupt configuration structure */ struct interrupt_enable int_en[2]; /* Select the GEN1 and GEN2 interrupts for configuration */ accel_settin[0].type = BMA400_GEN1_INT; accel_settin[1].type = BMA400_GEN2_INT; /* Get the configurations set in the sensor */ rslt = bma400_get_sensor_setting(&accel_settin[0], 2, dev); /* Modify the required parameters from the "gen_int" structure present * inside the "bma400_setting" structure to configure the selected * GEN1/GEN2 interrupts */ if (rslt == BMA400_OK) { /* Set the GEN 1 interrupt for activity detection */ accel_settin[0].conf.gen_int.int_map = BMA400_INT_CHANNEL_2; accel_settin[0].conf.gen_int.axes_sel = BMA400_XYZ_AXIS_EN; accel_settin[0].conf.gen_int.criterion_sel = BMA400_INACTIVITY_INT; accel_settin[0].conf.gen_int.evaluate_axes = BMA400_ALL_AXES_INT; accel_settin[0].conf.gen_int.ref_update = BMA400_MANUAL_UPDATE; accel_settin[0].conf.gen_int.data_src=BMA400_DATA_SRC_ACC_FILT2; accel_settin[0].conf.gen_int.gen_int_thres = 0x05; accel_settin[0].conf.gen_int.gen_int_dur = 100; accel_settin[0].conf.gen_int.hysteresis = BMA400_HYST_0_MG; accel_settin[0].conf.gen_int.int_thres_ref_x = 0; accel_settin[0].conf.gen_int.int_thres_ref_y = 0; accel_settin[0].conf.gen_int.int_thres_ref_z = 512; /* (0, 0, 1g) for gen1 reference. */ /* Set the GEN 2 interrupt for in-activity detection */ accel_settin[1].conf.gen_int.int_map = BMA400_INT_CHANNEL_2; accel_settin[1].conf.gen_int.axes_sel = BMA400_XYZ_AXIS_EN; accel_settin[1].conf.gen_int.criterion_sel = BMA400_INACTIVITY_INT; accel_settin[1].conf.gen_int.evaluate_axes = BMA400_ANY_AXES_INT; accel_settin[1].conf.gen_int.ref_update = BMA400_ONE_TIME_UPDATE; accel_settin[1].conf.gen_int.data_src=BMA400_DATA_SRC_ACC_FILT1; accel_settin[1].conf.gen_int.gen_int_thres = 0x10; accel_settin[1].conf.gen_int.gen_int_dur = 0x01; accel_settin[1].conf.gen_int.hysteresis = BMA400_HYST_0_MG; /* Set the configurations in the sensor */ rslt = bma400_set_sensor_setting(&accel_settin[0], 2, dev); if (rslt == BMA400_OK) { /* Enable the Generic interrupts in the sensor */ int_en[0].int_sel = BMA400_GEN1_INT_EN; int_en[0].conf = BMA400_ENABLE; int_en[1].int_sel = BMA400_GEN2_INT_EN; int_en[1].conf = BMA400_DISABLE; rslt = bma400_enable_interrupt(&int_en[0], 2, dev); } } } } return rslt; } Auto wakeup and auto low power by activity Case description This example is suitable for activity detection, where the device (sensor) is not placed into a fixed position, like wearable devices. To achieve this, Gen1 can be used to detect status that the sensor is in stable status, like the user wearing the device is in sleep, standstill, and trigger the Auto-Lowpower to switch BMA400 into low power mode; in contrary, the auto-wakeup function can be configured to detect the activity, and wake the sensor into normal mode. The key differences between the implementation of actvity detecting(this example) and position detecting (example described in chapter 4.2), is the reference update mode and the relative threshold and number of samples. For activity detection, the reference update mode of wakeup & Gen1 functions should be configured as everytime which means every sample of acceleration will be taken as the reference of the coming wakeup & Gen1 calculation, so the reference will be updated continuously and regardless of any fixed position(as described in chapter 4.2). Parameters configure Range = 4g, ODR=100, OSR=1 Auto-lowpower relative Register (0x2B) AUTOLOWPOW_1.gen1_int = 1; set this bit the interrupt from Gen1 will trigger the switching from normal mode to low power mode Generic interrupt 1 (gen1) relative Register (0x3F) GEN1INT_CONFIG0: Set gen1_act_x_en, gen1_act_y_en, gen1_act_z_en = 1 (enable all 3 axes) gen1_data_src=1; select filter2 (fixed 100Hz) as data source gen1_act_refu = 2; everytime (every time automatically updated from the selected filter data) gen1_act_hyst = 0; disable Register (0x40) GEN1INT_CONFIG1: gen1_comb_sel = 1; logic AND gen1_criterion_sel = 0; inactivity interrupt This combination means that ALL (logic AND) three axes value should be WITHIN (inactivity interrupt) the threshold near the reference position. Register (0x41) GEN1INT_CONFIG2: gen1_int_thres = 5 (threshold = 5*8mg/lsb = 40mg) Register (0x42) GEN1INT_CONFIG3/Register (0x43) GEN1INT_CONFIG31 gen1_int_dur = 100 (monitor duration = 100samples * 1/100Hz(filter2) = 1s) Register (0x44) GEN1INT_CONFIG4 to Register (0x49) GEN1INT_CONFIG9: gen1_int_th_refx/y/z, no need to configure, if reference update mode is everytime   So in this configuration gen1 interrupt will be set only if: Condition 1:  (|a_x_current - ref_x_last| < 40mg) AND (|a_y_current - ref_y_last | < 40mg)   AND (|a_z_current - ref_z_last| < 40mg) Condition 2: more than 100 continuous past samples fulfill condition 1  Auto-wakeup relative Register (0x2D) AUTOWAKEUP_1 wkup_int = 1; use wake-up interrupt for auto-wake-up(switch BMA400 to normal) Wakeup interrupt relative Register (0x2F) WKUP_INT_CONFIG0 wkup_x_en, wkup_y_en, wkup_z_en = 1; enable three axes num_of_samples = 3; 4(=3+1) continuous samples will be monitored in low power mode; the less the samples, the more sensitive the wakeup detecting wkup_refu = 2; everytime update Register (0x30) WKUP_INT_CONFIG1 int_wkup_thres = 3; (3 * 1/32 * 1g = 94mg) @4g range, range sensitive, 8 bit unsigned value The smaller the threshold, the more sensitive the wakeup detecting Register (0x31) WKUP_INT_CONFIG2 to Register (0x33) WKUP_INT_CONFIG4 int_wkup_refx/y/z no need to configure if update mode is everytime So the wakeup interrupt will be set only if: Condition 1: (|acc_x_current - ref_x_last| > 94mg) OR (|acc_y_current - ref_y_last| > 94mg) OR (|acc_z_current - ref_z_last| > 94mg) Condition 2: more than 4 continuous past samples fulfill condition 1 Sample codes The sample codes are shown below, and please ignore the configuration of Gen2, which is not relative to this case. In this example, wakeup interrupt is mapped to INT1 pin while GEN1 interrupt to INT2 pin. Since the INT1 & GEN1 is configured mutually-exclusive, so mapping them to one interrupt pin will result in confusion. /* ######## ------------------- ################ */ /* #### BMA400 Auto wakeup and Auto low power features ##### _Usage of auto wakeup and auto low power features in sensor_ */ /* Auto wake-up based on activity testing setting */ int8_t bma400_activity_autowakeup_auto_lp(struct bma400_dev *dev) { int8_t rslt = 0; uint8_t power_mode; uint16_t int_status; struct bma400_device_setting dev_setting[2]; /* Interrupt configuration structure */ struct interrupt_enable int_en; /* Selecting auto wakeup on wakeup interrupt event */ dev_setting[0].type = BMA400_AUTOWAKEUP_INT; /* Selecting auto low power mode*/ dev_setting[1].type = BMA400_AUTO_LOW_POWER; /* Get the previously set settings */ rslt = bma400_get_device_setting(&dev_setting, 2, dev); if (rslt == BMA400_OK) { dev_setting[0].conf.wakeup.wakeup_axes_en = BMA400_XYZ_AXIS_EN dev_setting[0].conf.wakeup.wakeup_ref_update = BMA400_EVERY_TIME_UPDATE dev_setting[0].conf.wakeup.sample_count = BMA400_SAMPLE_COUNT_4 dev_setting[0].conf.wakeup.int_wkup_threshold = 3 /* dev_setting[0].conf.wakeup.int_wkup_ref_x = 0 */ /* dev_setting[0].conf.wakeup.int_wkup_ref_y = 0 */ /* dev_setting[0].conf.wakeup.int_wkup_ref_z = 32 (0, 0, 1g) */ dev_setting[0].conf.wakeup.int_map = BMA400_INT_CHANNEL_1 /* Enable auto low power on Gen1 trigger */ dev_setting[1].conf.auto_lp.auto_low_power_trigger = BMA400_AUTO_LP_GEN1_TRIGGER; /* Set the configurations in sensor */ rslt = bma400_set_device_setting(&dev_setting, 2, dev); if (rslt == BMA400_OK) { /* Enable the Generic interrupts in the sensor */ int_en.int_sel = BMA400_AUTO_WAKEUP_EN; int_en.conf = BMA400_ENABLE; rslt = bma400_enable_interrupt(&int_en, 1, dev); /* The sensor toggles between Low-power mode and Normal mode if tilt the device(sensor) * or place it back to flat * this can be verfied by reading the power mode and printing it continuously as follows * while (1) { * rslt = bma400_get_power_mode(&power_mode, dev); * printf("\n POWER MODE : %d",power_mode); * } * The power mode toggling can be seen from the printed console output */ } return rslt; } /*##### BMA400 Generic interrupt configuration ##### _Usage of Generic interrupt1 and 2 for activity/inactivity detection in sensor_ */ /* Generic Interrupt feature */ int8_t bma400_generic_interrupts_by_activity(struct bma400_dev *dev) { int8_t rslt = 0; /* Variable to store interrupt status */ uint16_t int_status; /* Sensor configuration structure */ struct bma400_setting accel_settin[2]; /* Interrupt configuration structure */ struct interrupt_enable int_en[2]; /* Select the GEN1 and GEN2 interrupts for configuration */ accel_settin[0].type = BMA400_GEN1_INT; accel_settin[1].type = BMA400_GEN2_INT; /* Get the configurations set in the sensor */ rslt = bma400_get_sensor_setting(&accel_settin[0], 2, dev); /* Modify the required parameters from the "gen_int" structure present * inside the "bma400_setting" structure to configure the selected * GEN1/GEN2 interrupts */ if (rslt == BMA400_OK) { /* Set the GEN 1 interrupt for activity detection */ accel_settin[0].conf.gen_int.int_map = BMA400_INT_CHANNEL_2; accel_settin[0].conf.gen_int.axes_sel = BMA400_XYZ_AXIS_EN; accel_settin[0].conf.gen_int.criterion_sel = BMA400_INACTIVITY_INT; accel_settin[0].conf.gen_int.evaluate_axes = BMA400_ALL_AXES_INT; accel_settin[0].conf.gen_int.ref_update = BMA400_EVERY_TIME_UPDATE; accel_settin[0].conf.gen_int.data_src=BMA400_DATA_SRC_ACC_FILT2; accel_settin[0].conf.gen_int.gen_int_thres = 0x05; accel_settin[0].conf.gen_int.gen_int_dur = 100; accel_settin[0].conf.gen_int.hysteresis = BMA400_HYST_0_MG; /* accel_settin[0].conf.gen_int.int_thres_ref_x = 0; */ /* accel_settin[0].conf.gen_int.int_thres_ref_y = 0; */ /* accel_settin[0].conf.gen_int.int_thres_ref_z = 512; */ /* (0, 0, 1g) for gen1 reference, can be ignored here. */ /* Set the GEN 2 interrupt for in-activity detection */ accel_settin[1].conf.gen_int.int_map = BMA400_INT_CHANNEL_2; accel_settin[1].conf.gen_int.axes_sel = BMA400_XYZ_AXIS_EN; accel_settin[1].conf.gen_int.criterion_sel = BMA400_INACTIVITY_INT; accel_settin[1].conf.gen_int.evaluate_axes = BMA400_ANY_AXES_INT; accel_settin[1].conf.gen_int.ref_update = BMA400_ONE_TIME_UPDATE; accel_settin[1].conf.gen_int.data_src=BMA400_DATA_SRC_ACC_FILT1; accel_settin[1].conf.gen_int.gen_int_thres = 0x10; accel_settin[1].conf.gen_int.gen_int_dur = 0x01; accel_settin[1].conf.gen_int.hysteresis = BMA400_HYST_0_MG; /* Set the configurations in the sensor */ rslt = bma400_set_sensor_setting(&accel_settin[0], 2, dev); if (rslt == BMA400_OK) { /* Enable the Generic interrupts in the sensor */ int_en[0].int_sel = BMA400_GEN1_INT_EN; int_en[0].conf = BMA400_ENABLE; int_en[1].int_sel = BMA400_GEN2_INT_EN; int_en[1].conf = BMA400_DISABLE; /* int this case, gen2 is disabled */ rslt = bma400_enable_interrupt(&int_en[0], 2, dev); } } } } return rslt; }                    
    View full article
    Top Contributors
    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