Bosch Sensortec Community

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

    BMX160 magnetometer problem

    mnjirjak
    Established Member

    Re: BMX160 magnetometer problem

    OK, I figured it out. Unfortunately I forgot to connect VDDIO pin to the power supply. After I did so and tried the sample code, everything worked like a charm. Thank you very much for your assistance, I really appreciate it.

    For anyone else experiencing the same problem, please make sure you connect VDDIO to power supply. The code that I used can be found here. I modified it a bit and tested everything by reading all three sensors. Here's the code that I used:

     

    #include "bmi160.h"
    #include "bmm150.h"
    
    struct bmi160_dev bmi;
    struct bmm150_dev bmm;
    
    struct bmi160_sensor_data accel;
    struct bmi160_sensor_data gyro;
    
    int8_t bmm150_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len);
    int8_t bmm150_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len);
    
    int main(void)
    {
        bmi.id = 0;
        bmi.interface = BMI160_SPI_INTF;
        bmi.read = spi_read_transfer;
        bmi.write = spi_write_transfer;
        bmi.delay_ms = delay;
    
        bmm.dev_id = BMM150_DEFAULT_I2C_ADDRESS;
        bmm.intf = BMM150_I2C_INTF;
        bmm.read = bmm150_aux_read;
        bmm.write = bmm150_aux_write;
        bmm.delay_ms = delay;
    
        bmi160_init(&bmi);
      
        bmi.aux_cfg.aux_sensor_enable = BMI160_ENABLE;
        bmi.aux_cfg.aux_i2c_addr = bmm.dev_id;
        bmi.aux_cfg.manual_enable = BMI160_ENABLE;
        bmi.aux_cfg.aux_rd_burst_len = BMI160_AUX_READ_LEN_3;
    
        bmi160_aux_init(&bmi);
        bmm150_init(&bmm);
    
        bmi.accel_cfg.odr = BMI160_ACCEL_ODR_100HZ;
        bmi.accel_cfg.range = BMI160_ACCEL_RANGE_2G;
        bmi.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
        bmi.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;
    
        bmi.gyro_cfg.odr = BMI160_GYRO_ODR_100HZ;
        bmi.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS;
        bmi.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
        bmi.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;
    
        bmi160_set_sens_conf(&bmi);
    
        bmm.settings.preset_mode = BMM150_PRESETMODE_REGULAR;
        bmm150_set_presetmode(&bmm);
    
        bmm.settings.pwr_mode = BMM150_FORCED_MODE;
        bmm150_set_op_mode(&bmm);
    
    
    	uint8_t aux_addr = 0x42;	
    	uint8_t mag_data[8] = {0};
    	
    	uint8_t index;
    
    	bmi.aux_cfg.aux_odr = 8;
    	bmi160_config_aux_mode(&bmi);
    	
    	bmi160_set_aux_auto_mode(&aux_addr, &bmi);
    
    
        while(1) {
            bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL), &accel, &gyro, &bmi);
        	bmi160_read_aux_data_auto_mode(mag_data, &bmi);
        	bmm150_aux_mag_data(mag_data, &bmm);
    
            printf("****************\n");
            printf("ACC X: %d, Y: %d, Z: %d\n", accel.x, accel.y, accel.z);
            printf("GYRO X: %d, Y: %d, Z: %d\n", gyro.x, gyro.y, gyro.z);
        	printf("MAG X : %d Y : %d Z : %d\n", bmm.data.x, bmm.data.y, bmm.data.z);
            printf("################\n");
        }
    }
    
    int8_t bmm150_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) {
        (void) id;
        return bmi160_aux_read(reg_addr, reg_data, len, &bmi);
    }
    
    int8_t bmm150_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) {
        (void) id;
        return bmi160_aux_write(reg_addr, reg_data, len, &bmi);
    }

    where spi_read_transfer, spi_write_transfer and delay represent master-chip-specific functions for spi transfers and delay.

    The sample data that I got:

    ****************
    ACC X: -16140, Y: 27, Z: -551
    GYRO X: 7, Y: 3, Z: -5
    MAG X : 37 Y : -12 Z : 6
    ################
    ****************
    ACC X: -16171, Y: -18, Z: -516
    GYRO X: 8, Y: 2, Z: -5
    MAG X : 36 Y : -12 Z : 7
    ################
    ****************
    ACC X: -16132, Y: -13, Z: -550
    GYRO X: 8, Y: 3, Z: -5
    MAG X : 37 Y : -12 Z : 8
    ################

    Once again, thank you for your help!

    Kind regards,

    Marko Njirjak

     

    o_o
    Contributor

    Re: BMX160 magnetometer problem

    Great !

     

    Glad your issue is fixed, and thanks for posting your solution here! Robot Happy

    swapnilsayan
    New Poster

    Re: BMX160 magnetometer problem

    Hi, could you show your implementation of user_spi_read/write and if possible user_i2c_read and write?

    mnjirjak
    Established Member

    Re: BMX160 magnetometer problem

    Hi swapnilsayan,

    sorry for the late response. While working on this project, I used Nordic nRF52840 as the master chip. Accordingly, the SPI and I2C functions are somewhat connected to the Nordic SDK.

    SPI:

     

    void delay(uint32_t period) {
        nrf_delay_ms(period);
    }
    
    int8_t spi_read_transfer(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
    {
        ret_code_t ret;
        uint8_t read_temp[length + 1];
        uint8_t counter = 0;
    
        while (counter < 3) {
            ret = nrf_drv_spi_transfer(&spi, &reg_addr, 1, read_temp, length + 1);
            if (ret == NRF_SUCCESS) {
                break;
            } else {
                ++counter;
            }
        }
    
        if (counter >= 3) {
            APP_ERROR_CHECK(ret);
        }
    
        nrf_delay_us(500); 
    
        for (int i = 1; i < length + 1; ++i) {
            reg_data[i - 1] = read_temp[i];
        }
        return (int8_t)ret;	
    }
    
    int8_t spi_write_transfer(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
    {
        ret_code_t ret;
        uint8_t write_temp[length + 1];
        write_temp[0] = reg_addr;
        uint8_t counter = 0;
    
        for (int i = 1; i < length + 1; ++i) {
            write_temp[i] = reg_data[i-1];
        }
    
        while (counter < 3) {
            ret = nrf_drv_spi_transfer(&spi, write_temp, length + 1, NULL, 0);
            if (ret == NRF_SUCCESS) {
                break;
            } else {
                ++counter;
            }
        }
    
        if (counter >= 3) {
            APP_ERROR_CHECK(ret);
        }
        
        nrf_delay_us(500) ;
    
        return (int8_t)ret;	
    }
    
    void setupSPI() {
        nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
        spi_config.frequency = NRF_DRV_SPI_FREQ_8M;
        spi_config.ss_pin   = SPI_SS_PIN;
        spi_config.miso_pin = SPI_MISO_PIN;
        spi_config.mosi_pin = SPI_MOSI_PIN;
        spi_config.sck_pin  = SPI_SCK_PIN;
        APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL));
    }

     

     I didn't actually use I2C, but it was used internally by the BMI160 and BMM150 drivers, I guess. I used BMX160, which can be controlled with BMI160+BMM150 drivers. Sensors are initialized as follows:

     

    struct bmi160_dev bmi;
    struct bmm150_dev bmm;
    
    void initializeSensors() {
        bmi.id = 0;
        bmi.interface = BMI160_SPI_INTF;
        bmi.read = spi_read_transfer;
        bmi.write = spi_write_transfer;
        bmi.delay_ms = delay;
    
        bmm.dev_id = BMM150_DEFAULT_I2C_ADDRESS;
        bmm.intf = BMM150_I2C_INTF;
        bmm.read = bmm150_aux_read;
        bmm.write = bmm150_aux_write;
        bmm.delay_ms = delay;
    
        APP_ERROR_CHECK(bmi160_init(&bmi));
      
        bmi.aux_cfg.aux_sensor_enable = BMI160_ENABLE;
        bmi.aux_cfg.aux_i2c_addr = bmm.dev_id;
        bmi.aux_cfg.manual_enable = BMI160_ENABLE;
    
        APP_ERROR_CHECK(bmi160_aux_init(&bmi));
        APP_ERROR_CHECK(bmm150_init(&bmm));
    }

     

     More details about this can be found on the official Bosch Github repos (https://github.com/BoschSensortec/BMI160_driver, https://github.com/BoschSensortec/BMM150-Sensor-API).

    Kind regards,

    Marko Njirjak

    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