Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    Multiple issues while working with BMM150 on the BMI160 Shuttle Board

    Highlighted
    New Poster

    Multiple issues while working with BMM150 on the BMI160 Shuttle Board

    I am using the BMI160 Shuttle Board for some prototyping and research and I am not using the any of the Bosch API Libraries (BMI160/BMM150). I am running into a few issues while trying communicate with the BMM150. Before I mention the issues, I am connecting the nrf52840 Dev Kit to BMI160 using the I2C(TWI) Communication Interface and have the following setup and configurations.

    HARDWARE SETUP:

    • VDD(pin 1)and  VDDIO(pin2) are connected to 3V VDD.
    • GND(pin 3), SDO(pin 4) and  CSB_BMI160(pin 7) connected to GND.
    • SDA(pin 17) and SCL(pin 18) connected to SDA and SCL respectively.

    SOFTWARE TOOLS:

    • Using SEGGER Embedded Studios for ARM with nRF5 SDK v16.0.0.

    CODE SUMMARY:

    • IF_CONF =  0x20
    • CMD  =  0x11 (ACC normal Mode) wait 100ms than CMD  =  0x15 (Gyro normal Mode) wait 100ms than CMD  =  0x19 (MAG normal Mode) wait 100ms
    • Reading 1 byte of data(X, Y, Z) at a time for Accelerometer, Gyroscope and data(X, Y, Z, RHALL) for Magnetometer and printing to the UART(Within the infinite loop).

    ISSUE:

    1. I am unable to pull data of BMM150 into the BMI160 Data Registers automatically. While debugging the issue, I found both the drdy_mag bit in STATUS REG and mag_drdy_err bit in ERR_REG go HIGH.
    2. To resolve the above issue, I referred to a community post provided for SPI communication by manually enabling the Magnetometer and retrieving data, which when converted to I2C format of communication works but adds to the infinite loop. This solution makes the data to be available in the Registers 0x04 to 0x0B in the BMI160 but it does not make sense.
    3. After bit more research, I found out about the compensation calculation need to be done on raw data to account for temperature and the Hall resistance. To do the compensation calculation, I studied the BMM150 Library and its compensation function and I may not be able to use it as I do not have access to the TRIM Registers of the BMM150 in the BMI160 chip.

    Can anyone help me with solving these issues without using the BMI160/BMM150 API Library?

     

    #include <stdio.h>
    #include "boards.h"
    #include "bsp.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "nrf_drv_twi.h"
    #include "nrf_delay.h"
    #include "math.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    /* TWI instance ID. */
    #define TWI_INSTANCE_ID     0
    
     #define TWI_ADDRESSES      127
    
    /* Common addresses definition for temperature sensor. */
    #define BMI160_ADDR          0x68U
    
    // Registers
    
    #define MAG_X_LSB      0x04U // DATA
    #define MAG_X_MSB      0x05U // DATA
    #define MAG_Y_LSB      0x06U // DATA
    #define MAG_Y_MSB      0x07U // DATA
    #define MAG_Z_LSB      0x08U // DATA
    #define MAG_Z_MSB      0x09U // DATA
    #define MAG_RHALL_LSB      0x0AU // DATA
    #define MAG_RHALL_MSB      0x0BU // DATA
    #define GYR_X_LSB      0x0CU // DATA
    #define GYR_X_MSB      0x0DU // DATA
    #define GYR_Y_LSB      0x0EU // DATA
    #define GYR_Y_MSB      0x0FU // DATA
    #define GYR_Z_LSB      0x10U // DATA
    #define GYR_Z_MSB      0x11U // DATA
    #define ACC_X_LSB      0x12U // DATA
    #define ACC_X_MSB      0x13U // DATA
    #define ACC_Y_LSB      0x14U // DATA
    #define ACC_Y_MSB      0x15U // DATA
    #define ACC_Z_LSB      0x16U // DATA
    #define ACC_Z_MSB      0x17U // DATA
    
    #define SENSORTIME_REG_0      0x18U // DATA
    #define SENSORTIME_REG_1      0x19U // DATA
    #define SENSORTIME_REG_2      0x1AU // DATA
    
    #define CMD_REG      0x7EU // CMD
    
    #define STEP_CONF_0_REG      0x7AU // STEP CONFIG 0
    #define STEP_CONF_1_REG      0x7BU // STEP CONFIG 1
    
    #define STEP_CNT_0_REG           0x78U // STEP COUNT 0
    #define STEP_CNT_1_REG           0x79U // STEP COUNT 1\
    
    #define TEMP_0_REG           0x21U // STEP COUNT 0
    #define TEMP_1_REG           0x22U // STEP COUNT 1
    
    #define INT_MAP_REG_0 0x55U // Interupt Map 0
    #define INT_MAP_REG_1 0x56U // Interupt Map 1
    #define INT_MAP_REG_2 0x57U // Interupt Map 2
    
    #define INT_STATUS_REG_0 0x1CU // Interupt Status 0
    #define INT_STATUS_REG_1 0x1DU // Interupt Status 1
    #define INT_STATUS_REG_2 0x1EU // Interupt Status 2
    #define INT_STATUS_REG_3 0x1FU // Interupt Status 3
    
    #define IF_CONF_REG   0x6BU // IF_CONF
    
    #define MAG_CONF_REG   0x44U // MAG_CONF
    #define MAG_IF_REG_0   0x4BU // MAG_IF_REG
    #define MAG_IF_REG_1   0x4CU // MAG_IF_REG
    #define MAG_IF_REG_2   0x4DU // MAG_IF_REG
    #define MAG_IF_REG_3   0x4EU // MAG_IF_REG
    #define MAG_IF_REG_4   0x4FU // MAG_IF_REG
    
    #define IF_CONF_AUTO_MAG   0x20U // CMD
    #define MAG_ODR_100 0x08U // on MAG ODR to 100Hz
    
    #define INT_EN_REG_0 0x50U // Interupt Map 0
    #define INT_EN_REG_1 0x51U // Interupt Map 1
    #define INT_EN_REG_2 0x52U // Interupt Map 2
    
    #define ACC_RANGE_REG 0x41U // Accelerometer range 
    
    /* Power Mode for BMI160. */
    #define ACC_NORMAL_MODE 0x11U // on ACC
    #define GYR_NORMAL_MODE 0x15U // on GYR
    #define MAG_NORMAL_MODE 0x19U // on MAG
    
    #define ACC_RANGE_4G 0x05U // 4G range
    
    #define STEP_CONF_0_NORMAL 0x15U // Normal Mode
    #define STEP_CONF_1_NORMAL 0x0BU // Normal Mode step cnt enabled 
    
    #define STEP_CONF_0_SENS 0x2DU // Sensitive Mode
    #define STEP_CONF_1_SENS 0x08U // Sensitive Mode step cnt enabled 
    
    #define RESET_STEP_CNT 0xB2U // on REST STEP CNT
    
    #define MAG_IF_I2C  0x20U
    #define ZERO_VALUE 0x00U // Value = 0
    
    #define STATUS_REG 0x1BU // Value = 0
    #define ERR_REG 0x02U // Value = 0
    
    struct Accelerometer{
      float x;
      float y;
      float z;
      }acc;
    
    struct Gyroscope{
      float x;
      float y;
      float z;
      }gyro;
    
    struct Magnetometer{
      float x;
      float y;
      float z;
      float rhall;
      }mag_raw;
    
    /* Indicates if operation on TWI has ended. */
    static volatile bool m_xfer_done = false;
    
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    /* Buffer for samples read from temperature sensor. */
    static uint8_t m_sample;
    
    /**
     * @brief Function for Configuration, Reading and Writing to BMI160 sensor.
     */
    
    void BMI160_CONFIG(uint8_t Register, uint8_t Value)
    {
        ret_code_t err_code;
        
        uint8_t reg[2] = {Register, Value};
        err_code = nrf_drv_twi_tx(&m_twi, BMI160_ADDR, reg, sizeof(reg), false);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);
    }
    
    static void read_sensor_data()
    {
        m_xfer_done = false;
    
        /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. */
        ret_code_t err_code = nrf_drv_twi_rx(&m_twi, BMI160_ADDR, &m_sample, 1);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);
    }
    
    void write_data_to_read_reg(uint8_t Register){
        ret_code_t err_code;
    /* Writing to pointer byte. */
        uint8_t reg[2];
        reg[0] = Register;
        m_xfer_done = false;
        err_code = nrf_drv_twi_tx(&m_twi, BMI160_ADDR, reg, 1, false);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);
    }
    
    void mag_manual_read(){
        BMI160_CONFIG(MAG_IF_REG_1, 128);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_4, 1);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_3, 75); //4B set to 1 Power Control Bit 
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_4, 1);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_3, 81); // 0x51 set to 1 RepXY
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_4, 14);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_3, 82); //0x51 set to 14 RepZ
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_4, 2);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_3, 76); //0x4C set to 2 OPMODE 0x01
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_2, 66);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_CONF_REG, 5);
        nrf_delay_ms(100);
        BMI160_CONFIG(MAG_IF_REG_1, ZERO_VALUE);
    }
    
    int conv_to_16(int8_t lsb, int8_t msb){
        return (msb <<  + lsb;
    }
    
    void read_mag(){
            int8_t lsb = 0;
            int16_t msb = 0;
    
            // Read MAG_X_LSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_X_LSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            lsb = m_sample;
                            
            // Read MAG_X_MSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_X_MSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            msb = m_sample;
            mag_raw.x = conv_to_16(lsb, msb);
                    
            // Read MAG_Y_LSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_Y_LSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            lsb = m_sample;
    
            // Read MAG_Y_MSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_Y_MSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            msb = m_sample;
            mag_raw.y = conv_to_16(lsb, msb);
                            
            // Read MAG_Z_LSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_Z_LSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            lsb = m_sample;   
                 
            // Read MAG_Z_MSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_Z_MSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            msb = m_sample;
            mag_raw.z = conv_to_16(lsb, msb);
    
            // Read MAG_RHALL_LSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_RHALL_LSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            lsb = m_sample;
                    
            // Read MAG_RHALL_MSB
            nrf_delay_ms(5);
            write_data_to_read_reg(MAG_RHALL_MSB);
            do
            {
                __WFE();
            }while (m_xfer_done == false);
            read_sensor_data();
            msb = m_sample;
            mag_raw.rhall = conv_to_16(lsb, msb);
            NRF_LOG_INFO("RHALL: " NRF_LOG_FLOAT_MARKER "\r", NRF_LOG_FLOAT(mag_raw.rhall));
            NRF_LOG_INFO("MAG_X:" NRF_LOG_FLOAT_MARKER "\r", NRF_LOG_FLOAT(mag_raw.x));
            NRF_LOG_INFO("MAG_Y:" NRF_LOG_FLOAT_MARKER "\r", NRF_LOG_FLOAT(mag_raw.y));
            NRF_LOG_INFO("MAG_Z:" NRF_LOG_FLOAT_MARKER "\r", NRF_LOG_FLOAT(mag_raw.z));
    }
    
    /**
    *  @brief Data Handler -> Display the data given to read_sensor_data() function every time the 
    *  NRF_LOG_FLUSH() function is called
     */
    __STATIC_INLINE void data_handler(uint8_t val)
    {
    //    NRF_LOG_INFO("%d ", val);
    }
    
    /**
     * @brief TWI events handler.
     */
    void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
    {
        switch (p_event->type)
        {
            case NRF_DRV_TWI_EVT_DONE:
                if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
                {
                    data_handler(m_sample);
                }
                m_xfer_done = true;
                break;
            default:
                break;
        }
    }
    
    /**
     * @brief UART initialization.
     */
    void twi_init (void)
    {
        ret_code_t err_code;
    
        const nrf_drv_twi_config_t twi_lm75b_config = {
           .scl                = ARDUINO_SCL_PIN,
           .sda                = ARDUINO_SDA_PIN,
           .frequency          = NRF_DRV_TWI_FREQ_100K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
           .clear_bus_init     = false
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_lm75b_config, twi_handler, NULL);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    }
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {  
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
        uint32_t reading = 0;
    
        NRF_LOG_INFO("\r\nTWI sensor example started.");
        NRF_LOG_FLUSH();
        twi_init();
    
        BMI160_CONFIG(IF_CONF_REG, IF_CONF_AUTO_MAG); //Config for I2C as primary and Magnetometer as Secondary
        nrf_delay_ms(100);
        BMI160_CONFIG(CMD_REG, ACC_NORMAL_MODE);
        nrf_delay_ms(100);
        BMI160_CONFIG(CMD_REG, GYR_NORMAL_MODE);
        nrf_delay_ms(100);
        BMI160_CONFIG(CMD_REG, MAG_NORMAL_MODE);
    
        while (true)
        {
            nrf_delay_ms(500);
            NRF_LOG_INFO("\r\nReading: %d", reading);
            reading++;
            mag_manual_read();
            read_mag();
            //Flush all Log Data to the UART
            NRF_LOG_FLUSH();
        }    
    }

     

    1 REPLY 1
    Highlighted
    Community Moderator
    Community Moderator

    Re: Multiple issues while working with BMM150 on the BMI160 Shuttle Board

    Hi Arjun,

    Please refer to this sample code on our official github:
    https://github.com/BoschSensortec/BMI160_driver/wiki/How-to-use-an-auxiliary-sensor-or-magnetometer-....

    "Can anyone help me with solving these issues without using the BMI160/BMM150 API Library?"
    I'm afraid the official API is the only supported software by Bosch Sensortec, otherwise it would be impossible for us to maintain thousands of custom solutions. In case you do not wish to use our API, please test the sample code linked above first, then confirm that your own API writes the the same registers, with the same sequence, without violating any delays.

    To give you a hint at how the process should typically look like, you first have to use indirect addressing to initialize the BMM150, and configure it in forced mode. Then you need to configure the BMI160 delay so that it can trigger the measurement long enough in advance so that it is completed by the data must be read. Then, you need to configure the automatic mode to write the correct register to trigger the sample, and to readout the result in a single burst from the correct register.

    "I found out about the compensation calculation need to be done on raw data to account for temperature and the Hall resistance. To do the compensation calculation, I studied the BMM150 Library and its compensation function and I may not be able to use it as I do not have access to the TRIM Registers of the BMM150 in the BMI160 chip."
    As mentioned above, the API is the only supported software. You must read the registers and apply the compensation even if the BMM150 does not detail the content of these registers.

    o_o
    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