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
Great !
Glad your issue is fixed, and thanks for posting your solution here!
Hi, could you show your implementation of user_spi_read/write and if possible user_i2c_read and write?
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, ®_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