Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    SOLVED

    BMX160 - Magnetometer do not switch power mode

    BMX160 - Magnetometer do not switch power mode

    Nikosant03
    Long-established Member

    Hi everyone,

    I am using the BMX160 and I wrote the firmware based on the BMI160 API and BMM150 API and the integration procedure

    I am facing issues while switching modes and especially when I try to switch from BMM150_SUSPEND_MODE to BMM150_FORCED_MODE

    When the firmware starts, I first configure the power mode to BMM150_FORCED_MODE. The magnetometer works fine

     

      bmm150.settings.preset_mode = BMM150_PRESETMODE_REGULAR; 
      rslt = bmm150_set_presetmode(&bmm150);
      APP_ERROR_CHECK(rslt);
    
      bmm150.settings.pwr_mode = BMM150_FORCED_MODE; 
      rslt = bmm150_set_op_mode(&bmm150);
    
      sensor.aux_cfg.aux_odr = BMI160_AUX_ODR_100HZ; 
      bmi160_config_aux_mode(&sensor);
      bmi160_set_aux_auto_mode(&aux_addr, &sensor); 

     

     

    Then I want to switch to BMM150_SUSPEND_MODE as follow:

     

    void low_active_state(struct bmi160_dev *dev_bmi160, struct bmm150_dev *dev_bmm150, int state) {
    
      int8_t rslt;
    
      // na - MAG: change the power mode to suspended
      dev_bmm150->settings.pwr_mode = BMM150_SUSPEND_MODE;
      rslt = bmm150_set_op_mode(dev_bmm150);
      APP_ERROR_CHECK(rslt);
      nrf_delay_ms(2);
      NRF_LOG_INFO("info: Enter LOW ACTIVE STATE %d", state);
    }

     

    Until here everything works fine

    Then I want to switch to BMM150_FORCED_MODE as follow:

     

    void active_state(struct bmi160_dev *dev_bmi160, struct bmm150_dev *dev_bmm150, int state) {
      int8_t rslt;
    
      // na - MAG: change the power mode to suspended
      dev_bmm150->settings.pwr_mode = BMM150_FORCED_MODE;
      rslt = bmm150_set_op_mode(dev_bmm150);
      APP_ERROR_CHECK(rslt);
      nrf_delay_ms(2);
    
      NRF_LOG_INFO("info: Enter ACTIVE STATE %d", state);
    }

     

     

    but the magnetometer does not change state.. It remains on suspended mode..

    Looking the bmm150 API I found the function bmm150_set_op_mode(struct bmm150_dev *dev) I found that when I set either  BMM150_NORMAL_MODE or BMM150_FORCED_MODE the system enters to sleep mode calling the function suspend_to_sleep_mode(dev)

     

    int8_t bmm150_set_op_mode(struct bmm150_dev *dev)
    {
        int8_t rslt;
        uint8_t pwr_mode = dev->settings.pwr_mode;
    
        /* Check for null pointer in the device structure*/
        rslt = null_ptr_check(dev);
    
        /* Proceed if null check is fine */
        if (rslt == BMM150_OK)
        {
            /* Select the power mode to set */
            switch (pwr_mode)
            {
                case BMM150_NORMAL_MODE:
    
                    /* If the sensor is in suspend mode
                     * put the device to sleep mode */
                    rslt = suspend_to_sleep_mode(dev);
                    if (rslt == BMM150_OK)
                    {
                        /* write the op mode */
                        rslt = write_op_mode(pwr_mode, dev);
                    }
                    break;
                case BMM150_FORCED_MODE:
    
                    /* If the sensor is in suspend mode
                     * put the device to sleep mode */
                    rslt = suspend_to_sleep_mode(dev);
                    if (rslt == BMM150_OK)
                    {
                        /* write the op mode */
                        rslt = write_op_mode(pwr_mode, dev);
                    }
                    break;
                case BMM150_SLEEP_MODE:
    
                    /* If the sensor is in suspend mode
                     * put the device to sleep mode */
                    rslt = suspend_to_sleep_mode(dev);
                    if (rslt == BMM150_OK)
                    {
                        /* write the op mode */
                        rslt = write_op_mode(pwr_mode, dev);
                    }
                    break;
                case BMM150_SUSPEND_MODE:
    
                    /* Set the power control bit to zero */
                    rslt = set_power_control_bit(BMM150_POWER_CNTRL_DISABLE, dev);
                    break;
                default:
                    rslt = BMM150_E_INVALID_CONFIG;
                    break;
            }
        }
    
        return rslt;
    }

     

      

    Also on the datasheet sais that:

     
     

    So what I understand so far is that:

    1. From suspended mode I have to jump into sleep mode first. That's why the API calls the suspend_to_sleep_mode(dev) for BMM150_FORCED_MODE and BMM150_NORMAL_MODE

    2. Then I have to configure the presetmode (is it necessary?)

    3. Indirectly configure to force mode via magnetometer interface

    Are these steps correct?

    In case that is correct, can you help me with step 3. How do I indirectly configure to force mode using the magnetometer interface?

    Thanks in advance

    Nick

    4 REPLIES 4

    FAE_CA1
    Community Moderator
    Community Moderator

    Hi,

    Thanks for your inquiry.

    It is true that when BMM150 magnetometer inside BMX160 is in suspend mode you need to bring it to sleep mode first. And then you need to reconfigure BMM150 presetmode for x/y/z axes, because in suspend mode your previous configurations of the presetmode are lost. BMI160 IMU inside BMX160 is the I2C master to BMM150 magnetometer and the I2C slave to external host MCU.

    When BMM150 is at lowpower preset the max ODR in forced mode is 300Hz, while regular preset 100Hz. So in your code, you can either change the presetmode to lowpower preset to have 100Hz ODR or change the presetmode to regular preset with 25Hz ODR. Otherwise, you will get repeated data from BMM150.

    Please refer to Table 16 on page 25 of BMX160 datasheet. There is an example about how to indirectly configure BMM150 to normal mode at 12.5Hz ODR. Actually BMM150 forced mode is automatically triggered under normal mode. This means that at 12.5Hz ODR BMI160 IMU inside BMX160 will trigger BMM150 forced mode to take a measurement. Once the measurement is done, BMM150 will go back to sleep mode waiting for the next trigger. BMI160 will then grab the BMM150 data into its own internal data registers for the host MCU to read.

    Nikosant03
    Long-established Member

    Thank you for your great responce FAW_CA1

    Now it seems to work but I have a few issues however. These are the two function I implemented

    The first function sets the accel in low power mode while gyro and mag in suspended mode. In order to put mag in suspended mode I followed the procedure of Table 17 pg 26.

    void low_active_state(struct bmi160_dev *dev_bmi160, struct bmm150_dev *dev_bmm150, uint8_t *bmm150_aux_addr, int state) {
      /*
      ACCEL: LOW POWER (200Hz ODR, AVG=4)
      GYRO:  SUSPENDED
      MAG:   SUSPENDED
      */
    
      // na - Progress to put magnetometer and magnetometer interface into suspended mode
      // na - It is mandatory to put magnetometer into suspend mode before putting magnetometer interface into suspend mode see pg 16 of BMX160 datasheet
      uint8_t reg_data = 0;
      uint8_t data = 0;
      int8_t rslt = BMI160_OK;
    
      reg_data = 0x19;
      bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &reg_data, 1, dev_bmi160);
      nrf_delay_ms(1);
    
      reg_data = 0x80;
      bmi160_set_regs(BMI160_AUX_IF_1_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x00;
      bmi160_set_regs(BMI160_AUX_IF_4_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x4B;
      bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x18;
      bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &reg_data, 1, dev_bmi160);
      nrf_delay_ms(2);
    
      dev_bmi160->gyro_cfg.power = BMI160_GYRO_SUSPEND_MODE; // na - set gyro to suspended mode
      rslt = bmi160_set_sens_conf(dev_bmi160);
      APP_ERROR_CHECK(rslt);
    
      dev_bmi160->accel_cfg.odr = BMI160_ACCEL_ODR_200HZ;
      dev_bmi160->accel_cfg.power = BMI160_ACCEL_LOWPOWER_MODE; // na - set accel to low power mode mode
      rslt = bmi160_set_sens_conf(dev_bmi160);
      APP_ERROR_CHECK(rslt);
      nrf_delay_ms(10); // na - see pg 90 of BMX160 datasheet
    
      rslt = bmi160_get_regs(BMI160_PMU_STATUS_ADDR, &data, 1, dev_bmi160);  
    
      NRF_LOG_INFO("info: Enter LOW ACTIVE STATE %d", state);
      NRF_LOG_INFO("BMI160_PMU_STATUS_ADDR - LOW ACTIVE STATE: %d", rslt);
    }

     

    The second function enters the 

    void active_state(struct bmi160_dev *dev_bmi160, struct bmm150_dev *dev_bmm150, uint8_t *bmm150_aux_addr, int state) {
    
      uint8_t reg_data = 0;
      uint8_t data = 0;
      int8_t rslt = BMI160_OK;
    
      // na - Process to initialize magnetometer sleep mode, low power preset, 12.5Hz ODR and magnetometer interface low power - see pg 25 Table 16 of the BMX160 datasheet
      reg_data = 0x19;
      bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &reg_data, 1, dev_bmi160);
      nrf_delay_ms(2);
    
      reg_data = 0x80;
      bmi160_set_regs(BMI160_AUX_IF_1_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x01;
      bmi160_set_regs(BMI160_AUX_IF_4_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x4B;
      bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x01;
      bmi160_set_regs(BMI160_AUX_IF_4_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x51;
      bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x0E;
      bmi160_set_regs(BMI160_AUX_IF_4_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x52;
      bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x02;
      bmi160_set_regs(BMI160_AUX_IF_4_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x4C;
      bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x42;
      bmi160_set_regs(BMI160_AUX_IF_2_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x05;
      bmi160_set_regs(BMI160_AUX_ODR_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x00;
      bmi160_set_regs(BMI160_AUX_IF_1_ADDR, &reg_data, 1, dev_bmi160);
    
      reg_data = 0x1A;
      bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &reg_data, 1, dev_bmi160);
      nrf_delay_ms(2);
    
      dev_bmi160->accel_cfg.odr = BMI160_ACCEL_ODR_400HZ;
      dev_bmi160->accel_cfg.power = BMI160_ACCEL_NORMAL_MODE; // na - set accel to normal power mode mode
      rslt = bmi160_set_sens_conf(dev_bmi160);
      APP_ERROR_CHECK(rslt);
      nrf_delay_ms(10); // na - see pg 90 of BMX160 datasheet
    
      dev_bmi160->gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;
      rslt = bmi160_set_sens_conf(dev_bmi160);
      APP_ERROR_CHECK(rslt);
      nrf_delay_ms(150); // na - see pg 90 of BMX160 datasheet
    
      rslt = bmi160_get_regs(BMI160_PMU_STATUS_ADDR, &data, 1, dev_bmi160); // na - read the PMU_STATUS register
    
      NRF_LOG_INFO("info: Enter ACTIVE STATE %d", state);
      NRF_LOG_INFO("BMI160_PMU_STATUS_ADDR - ACTIVE STATE: %d", rslt);
    }

     

    It seems to work since in low_active_state only the accel is working while in active_state everything working and I have not any issue while changing states.

    I have however two issues:

    1. I read the PMU_STATUS register and each time is 0... This couldn'd be possible since I receive measurements

    2. I cannot see any impact in current consumption while changing states.. I mean the current consumption for both states low_active_state and active_state is the same. This couldn't be possible if I was succefully change power modes isn't it?

    Any advice on these issues?

    Thanks for your support so far

    Nick

     

     

    FAE_CA1
    Community Moderator
    Community Moderator

    Hi,

    That is strange.

    After you run your first function, PMU_STATUS register 0x03 should show value of 0x20 meaning that accel is in low power mode while gyro and mag are in suspend mode. The current consumption should be around 154uA.

    After you run your second function, PMU_STATUS register 0x03 should show value of 0x15 meaning that accel, gyro and mag are all in normal mode. The current consumption should be around 1585uA.

    Please use a USB logic analyzer to capture the I2C waveforms when you run first and second function respectively to see what is going on.

    Thanks.

    Nikosant03
    Long-established Member

    Hi

    Our company will be closed for the next week, so I will capture the I2C waveform as soon as we are back to office again. I will leave this thread open for now and I will responce after the next week.

    Thanks

    Nick

    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