Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    Knowledge base

    Sort by:
    2 weeks ago
    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
    3 weeks ago
    Selecting the right part BMA456 is 16bit, digital, triaxial acceleration sensor with intelligent on-chip motion triggered interrupt features optimized for wearable and hearable applications. BMA456 support different advanced features via different configure file. Table 1 shows an overview of the features. Parameter BMA456 Digital resolution 16bit Range and sensitivity +/-2g: 16384LSB/g +/-4g: 8192LSB/g +/-8g: 4096LSB/g +/-4g: 2048LSB/g Zero-g offset(typ.) +/-20mg Noise density(typ.) 120µg/√Hz Bandwidths 5Hz …684Hz Interfaces SPI & I2C, 2 x digital interrupt pins Supply voltage VDD: 1.62 to 3.6V VDDIO: 1.2 to 3.6V LGA package(mm3) 2.0 x 2.0 x 0.65 Feature/Interrupts Step Counter/Step detector (optimized for wearables) Activity recognition: running, walking, still Tilt on wrist Tab/Double Tab Any-motion/No-motion High-g/ low-g Table 1: Overview BMA456 features Common characteristics The main characteristics of this product family are: Key features: 2.0 x 2.0 mm² size Pin to pin compatibility with all other 2.0 x 2.0 accelerometers from Bosch Sensortec SPI or I²C interface Configurable range from ±2G to ±16g Configurable output data rate up to 1.6kHz Integrated 1kB FIFO Auxiliary I²C interface for connecting external magnetometer, including data synchronization Built-in smart interrupt controller, with features such as step-counter which offers high performance for all wearing positions, including wrist-worn. BMA456 parameters BMA456 offers higher performance and stability in a smaller package. See the complete description in Table 2. Parameter BMA456 Units Height 0,65 mm Digital resolution 16 bits Zero-g offset (typ.) ±20 mg Noise density (typ.) 120 µg/√Hz TCO (X&Y axis) 0.2 mg/K TCO (Z axis) 0.35 mg/K TCS 0.005 %/K Cross Axis Sensitivity 0.5 % Table 2: BMA456 parameter value Available evaluation tools and software To best to evaluate the products from the BMA456 family, we recommend the following combination of evaluation tools: COINES Desktop software Application board 3.0 Sensor Shuttle board BMA456 Shuttle board . Layout recommendations Because the BMA4xy 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 . 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: Device Chip ID BMA456 0x16 Table 3: Chip IDs of the BMA4xy product family Here is some sample code on how to perform this test, based on BMA456, using the COINES software as the host. /*!  * @brief This internal API is used to initializes the bma456 and verify the  *communication by reading the chip id.  *  * @param[in] void  * @return void  *  */ static void init_comm_test_bma456(void) {     int8_t rslt;                    struct bma4_dev bma456dev = { 0 };       rslt = bma4_interface_init(&bma456dev, BMA4_I2C_INTF, BMA45X_VARIANT);     rslt = bma456_init(&bma456devbma425dev);     if (rslt == BMA4_OK)     {         printf("BMA456 Initialization Success!\n");         printf("Test #1: Communication. PASSED. Chip ID 0x%x\n", bma456dev.chip_id);     }       else     {         char err_string[255];         printf("BMA456 Initialization Failure!\n");                                        if (BMA4_E_INVALID_SENSOR == rslt)         {              sprintf(err_string, "Test #1: Communication. FAILED. Expected Chip ID: 0x%x. Received 0x%x\n",\                             BMA456_CHIP_ID, bma456dev.chip_id);         }         else         {              sprintf(err_string, "Test #1: Communication. FAILED. No response from the sensor.");         }                                        coines_exit_error(err_string);     }     coines_delay_msec(100); } How to test the sensor's functionality The BMA4xy series of accelerometers feature 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 is some sample code on how to perform this self-test, based on BMA456, using the COINES software as the host. /*!  * @brief This internal API is used to test if the sensor is working by triggering the self-test.  *  * @param[in] void  * @return void  *  */ static void function_test_bma456(void) {     uint16_t rslt;     uint8_t testrslt;       rslt = bma4_perform_accel_selftest(&testrslt, &bma456dev);                    if ( 0 != rslt ) coines_exit_error("Test #2: Functionnality. FAILED. Unknown communication error\n");                if ( BMA4_SELFTEST_PASS == testrslt ) {         printf("Test #2: Functionnality. PASSED. Sensor self-test successful\n");     } else {         printf("Test #2: Functionnality. FAILED. Sensor self-test failed\n");     }                } How to test the sensor's performance There are 2 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. Parameter BMA456 units Offset ±20 mg Noise 120 µg/√Hz Table 4: Typical performance of BMA456 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 substract 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 BMA456, using the COINES software as the host. /*! Average value calculation */ double x_avg_mg=0; double y_avg_mg=0; double z_avg_mg=0; for (int i=0; i<1000; ++i) {     double xval, yval, zval;     /* ( 'datapoint' * '4G' * '2' * '1000mg') / ('scaling factor for 16 bits') */     xval = (((double)sens_data[i].x) * 4. * 2. * 1000) / pow(2,16);     yval = (((double)sens_data[i].y) * 4. * 2. * 1000) / pow(2,16);     zval = (((double)sens_data[i].z) * 4. * 2. * 1000) / pow(2,16);                                    x_avg_mg += xval / 1000.;     y_avg_mg += yval / 1000.;     z_avg_mg += zval / 1000.; }                /*! Offset Calculation */ double x_off_mg=x_avg_mg - X_REST_POSITION_MG; double y_off_mg=y_avg_mg - Y_REST_POSITION_MG; double z_off_mg=z_avg_mg - Z_REST_POSITION_MG;                if( OFFSET_THRESHOLD_MG > x_off_mg && OFFSET_THRESHOLD_MG > y_off_mg && \                                OFFSET_THRESHOLD_MG > z_off_mg ) {     printf("Test #3: Performance. Offset. PASSED: X=%4.1lfmg Y=%4.1lfmg Z=%4.1lfmg Threshold <\        %4.1lf\n",       x_off_mg, y_off_mg, z_off_mg, OFFSET_THRESHOLD_MG); } else {     printf("Test #3: Performance. Offset. FAILED: X=%4.1lfmg Y=%4.1lfmg Z=%4.1lfmg Threshold <\ %4.1lf\n", x_off_mg, y_off_mg, z_off_mg, OFFSET_THRESHOLD_MG); } The noise calculation is a bit more complicated. First, subtract the offset from each datapoint. The RMS value can be calculated as the square root of the arithmetic mean of the squares of the noise values.  x_rms = sqrt[1/n( x_1^2 + x_2^2 + .... + x_n^2)] 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 noise_density = noise_RMS/[sqrt(1.22 x bandwidth)] Here is some sample code on how to perform this test, based on BMA456, using the COINES software as the host. /*! RMS Noise Calculation */ double x_rms_noise_mg=0; double y_rms_noise_mg=0; double z_rms_noise_mg=0; for (int i=0; i<1000; ++i) {     double xval, yval, zval;     /* ( 'datapoint' * '4G' * '2' * '1000mg') / ('scaling factor for 12 bits') */     xval = (((double)sens_data[i].x) * 4. * 2. * 1000.) / pow(2,16);     yval = (((double)sens_data[i].y) * 4. * 2. * 1000.) / pow(2,16);     zval = (((double)sens_data[i].z) * 4. * 2. * 1000.) / pow(2,16);                                    x_rms_noise_mg += pow(xval - x_avg_mg,2) / 1000.;     y_rms_noise_mg += pow(yval - y_avg_mg,2) / 1000.;     z_rms_noise_mg += pow(zval - z_avg_mg,2) / 1000.; }                /* rms noise is the square root of the arithmetic mean of the squares of the noise values */ x_rms_noise_mg = sqrt(x_rms_noise_mg); y_rms_noise_mg = sqrt(y_rms_noise_mg); z_rms_noise_mg = sqrt(z_rms_noise_mg);                /*! RMS Noise to RMS noise density convertion */ /* noise density = RMS noise  / sqrt ( 1.22 * bandwidth) */ /* BMA456 has 40.5Hz bandwidth at 100Hz normal mode */   double x_noise_dens_ug = 1000 * x_rms_noise_mg / sqrt(1.22 * 40.5); double y_noise_dens_ug = 1000 * y_rms_noise_mg / sqrt(1.22 * 40.5); double z_noise_dens_ug = 1000 * z_rms_noise_mg / sqrt(1.22 * 40.5);   if( NOISE_THRESHOLD_MG > x_noise_dens_ug &&                                NOISE_THRESHOLD_MG > y_noise_dens_ug &&                                NOISE_THRESHOLD_MG > z_noise_dens_ug ) {     printf("Test #3: Performance. Noise. PASSED: X=%4.1lfug/sqrt(Hz) Y=%4.1lfug/sqrt(Hz) \ Z=%4.1lfug/sqrt(Hz) Threshold < %4.1lf\n", x_noise_dens_ug, y_noise_dens_ug, z_noise_dens_ug,\ NOISE_THRESHOLD_MG); } else {     printf("Test #3: Performance. Noise. FAILED: X=%4.1lfug/sqrt(Hz) Y=%4.1lfug/sqrt(Hz) \   Z=%4.1lfug/sqrt(Hz) Threshold < %4.1lf\n", x_noise_dens_ug, y_noise_dens_ug,\ z_noise_dens_ug,NOISE_THRESHOLD_MG);   } 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. Pre- and post-calibration accuracy     Sample code The calibration procedure is outlined in the inline calibration application note . Here is some sample code on how to perform this calibration, based on BMA456, using the COINES software as the host. Note : Although the concept is the same, the BMA4xy family of accelerometers does not include a built-in offset calculation on the ASIC. Since the offset are calculated inside of the Sensor API itself, it allows for a much more flexible target position.  rslt = bma456_init(&bma456dev); if (rslt == BMA4_OK) {     printf("BMA456 Initialization Success!\n"); } else {                  coines_exit_error("BMA456 Initialization Failure!\n"); } coines_delay_msec(100); rslt = bma456_write_config_file(&bma456dev); /* Enable the accelerometer */ rslt = bma4_set_accel_enable(BMA4_ENABLE, &bma456dev); /* Set the accel configurations */ struct bma4_accel_config accel_conf = { 0 }; accel_conf.odr = BMA4_OUTPUT_DATA_RATE_50HZ; accel_conf.bandwidth = BMA4_ACCEL_NORMAL_AVG4; accel_conf.perf_mode = BMA4_CIC_AVG_MODE; accel_conf.range = BMA4_ACCEL_RANGE_8G; rslt = bma4_set_accel_config(&accel_conf, &bma456dev); dev.delay_us(20000, dev.intf_ptr);                         if (rslt == BMA4_OK) {     /* Set accel foc axis and it's sign (x, y, z, sign)*/ struct bma4_accel_foc_g_value g_value_foc = { 0, 0, 0, 0 };       rslt = bma4_perform_accel_foc( &g_value_foc, &bma456dev);                          if (rslt == BMA4_OK) {         printf("BMA456 perform FOC successful!\n");         /* Delay after performing Accel FOC */         dev->delay_us(30000, bma456dev ->intf_ptr);         /*! calculates the offset after compensation */         rslt = bma4_read_regs(BMA4_OFFSET_0_ADDR, data_array, 3, & bma456dev);         printf("Post-calibration offset : X=%4.1lfmg Y=%4.1lfmg Z=%4.1lfmg", data_array[0],\                data_array[1], data_array[3]);     } else {                  coines_exit_error("Unknown communication error. Exiting...\n");     } } Once the offsets are determined, they can be written into the NVM so that the sensor automatically compensates for the soldering offset even after physically removing the power. Here is some sample code on how to save calibration data to NVM, based on BMA456, using the COINES software as the host. /*!  * @brief This internal API is used to update the nvm content  *  * @param[in] void  * @return void  *  */ static void bma456_update_nvm(void) {     uint16_t rslt;     uint8_t data;       /* unlocks the NVM for writing */     data = 0x02;     bma4_write_regs(0x6A, &data, 1, &bma456dev);                    /* makes sure the BMA456 is not executing another command */ do {         rslt = bma4_read_regs(BMA4_STATUS_ADDR, &data, 1, &bma456dev);         if ( 0 != rslt ) coines_exit_error("Unknown communication error. Exiting...\n");     } while ( 0 == (data&0x10) );                    /* performs the writing of the NVM */     rslt = bma4_set_command_register( 0xA0,  &bma456dev);     if ( 0 != rslt ) coines_exit_error("Unknown communication error. Exiting...\n");                        /* wait for the command to be completed */ do {         rslt = bma4_read_regs(BMA4_STATUS_ADDR, &data, 1, &bma456dev);         if ( 0 != rslt ) coines_exit_error("Unknown communication error. Exiting...\n");     } while ( 0 == (data&0x10) );                    /* locks the NVM writing */     data = 0x00;     bma4_write_regs(0x6A, &data, 1, &bma456dev); }   Further reads Datasheets: BMA456 Datasheet Application notes: Inline calibration of accelerometers Handling, soldering and mounting instructions, Accelerometers HSMI  
    View full article
    100% helpful (1/1)
    ‎02-16-2022 09:24 AM
    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
    ‎05-31-2021 12:16 PM
    Frequently Asked Questions (FAQs) about the BMP384 sensor
    View full article
    100% helpful (2/2)
    ‎05-31-2021 12:09 PM
    Frequently Asked Questions (FAQs) about the BME688 sensor
    View full article
    ‎05-31-2021 12:09 PM
    Frequently Asked Questions (FAQs) about the BHI260AP sensor
    View full article
    ‎04-01-2021 10:22 AM
    Please find attached the two white papers for our BHI260AP self-learning AI sensor: White paper: Me, myself and AI How the new self-learning AI sensor pesonalizes your home workout Fitness tracking is presently experiencing a huge upswing in popularity. The market for fitness trackers and step counters has surged by 65% year-on-year  [1] , with just the Fitbit platform alone claiming nearly 30 million active users  [2] . Current activity tracking devices have demonstrated the huge market potential of this segment and have laid the groundwork for next-generation AI-enabled devices to take centre stage as individual fitness tracking goes mainstream. White paper: Swim like a fish with Artificial Intelligence Combining AI and sensors to create a new generation of intelligent wearables Artificial intelligence (AI) is rapidly becoming a natural and integral part of our everyday lives – working silently and unnoticed in the background. AI makes sense of the multitude of data streaming in from various sensors to deliver detailed and precise insights, which have the potential to increase the utility of virtually all electronic devices on the market today. This defining technology can accurately determine whether the user of a device is walking, running, sitting, sleeping – or even swimming in real-time. This article explores how sensors synergize with AI in wearables to deliver valuable information to users – even in demanding environments like swimming pools.
    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
    ‎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
    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
    ‎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
    ‎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
    ‎08-15-2019 10:27 AM
    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
    ‎08-14-2019 10:25 AM
     Selecting the right part The BMP series of pressure sensor contains 2 products: BMP280 and BMP388. Table 1 shows an overview of the features.                                                     Table 1: Overview of the products in this family Key features LGA with metal lid package SPI or I2C interface Built-in IIR filter.  Differences between products The main differences in the BMP product family are in the thickness of the package, and the overall performance of the MEMS element. BMP388 offers higher performance in a smaller package compared to BMP280. See the complete list of differences in Table 2.                                                                                             Table 2: Differences between BMP product family members Available evaluation tools and software To best to evaluate the products from the BMP family, we recommend the following combination of evaluation tools: COINES Desktop software ( Windows version & Linux version & MacOS) Development Desktop Software Application board 2.0 BMP280 shuttle board BMP388 shuttle board Reference design Figure 1 shows a complete schematic of a typical use case.                                                                                           BMP280                                                                                        BMP388                                                        Figure 1: Exemplary Reference design   Bill of materials                                             Table 3: Bill of materials Layout recommendations Because the BMP 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. BMP28x Handling, soldering & mounting instructions BMP380 Handling,soldering & mounting instructions In addition to the attached guidelines, see below for the typical manufacturing procedure for the BMP388 pressure sensor. Landing Pattern                                                                                          BMP280                                                                                      BMP388                                                          Figure 2: Recommended landing pattern Typical Layout                                                                                                   BMP280                                                                                           BMP388                                                                          Figure 3: Typical layout Manufacturing notes                                                               Table 4: Manufacture recommendation 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 simply by reading the chip identification code in the register 0xD0 (BMP280) 0x00 (BMP388). See below for the expected values:                                                          Table 5: Chip IDs of the BMP product family Here is some sample code on how to perform this test, based on the BMP388   , using the COINES software as the host. /*! * @brief This internal API is used to check the bmp388 sensor chip ID * * @param[in] void * * @return void * */ static void init_bmp3(void) { int8_t rslt; rslt = bmp3_init(&bmp3Dev); if (rslt == BMP3_OK) { printf("BMP3 Initialization Success!\n"); printf("Chip ID 0x%X\n", bmp3Dev.chip_id); } else { printf("Chip Initialization failure !\n"); exit(COINES_E_FAILURE); } } How to read sensor data  Here is some sample code on how to read sensor data, based on the BMP388, 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) { bmp3_get_sensor_data(BMP3_ALL, &bmp3_comp_data, &bmp3Dev); printf("T: %.2f, P: %.2f \n", (bmp3_comp_data.temperature / 100.), (bmp3_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\bmp3 Usage The COINES installation provides sample code on how to turn on the sensor, configure it and read out the pressure data. COINES\v1.0\examples\c\bmp3 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_bmp3_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 != BMP3_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_bmp3(); read_sensor_data(); coines_close_comm_intf(COINES_COMM_INTF_USB); return EXIT_SUCCESS; Further reads Datasheets: BMP280 Datasheet BMP388 Datasheet Application notes: BMP388 self-test Handling, soldering and mounting instructions BMP280 HSMI BMP388 HSMI
    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
    ‎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 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
    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:                                                                  T able 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_e n 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_e n or fifo_tag_int2_en is enabled, the regular frame header may change. Take Accel only as an example, fifo_tag_int1_e n 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:                                            T able 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 a ppropriate 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
    ‎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 1 shows 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 on https://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
    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