05-10-2019 03:36 PM - edited 05-10-2019 03:37 PM
Hello,
I bought a BMX160 shuttleboard and connected it to master chip via 4-wire SPI. By following the instructions in the data sheet I was able to setup and read the data from accelerometer and gyroscope. Unfortunately I wasn't able to do the same with magnetometer. The readings from magnetometer constantly return zeros. What is the procedure for configuring magnetometer and fetching data? Is the procedure described in table 16, section 2.4.3.1.3 of BMX160 data sheet enough? I fetched the data by reading data registers (0x04-0x0B) described in section 2.11.4.
Magnetometer configuration code:
write_spi(0x7E, 0x19);
delay_ms(1);
write_spi(0x4C, 0x80);
write_spi(0x4F, 0x01);
write_spi(0x4E, 0x4B);
write_spi(0x4F, 0x01);
write_spi(0x4E, 0x51);
write_spi(0x4F, 0x0E);
write_spi(0x4E, 0x52);
write_spi(0x4F, 0x02);
write_spi(0x4E, 0x4C);
write_spi(0x4D, 0x42);
write_spi(0x44, 0x05);
write_spi(0x4C, 0x00);
write_spi(0x7E, 0x1A);
delay_ms(1);
Magnetometer fetch data code:
uint8_t data; //X-axis read_spi(0x05, &data); //MSB *mag_x = data; *mag_x = *mag_x << 8; read_spi(0x04, &data); //LSB *mag_x |= data; //Y-axis read_spi(0x07, &data); //MSB *mag_y = data; *mag_y = *mag_y << 8; read_spi(0x06, &data); //LSB *mag_y |= data; //Z-axis read_spi(0x09, &data); //MSB *mag_z = data; *mag_z = *mag_z << 8; read_spi(0x08, &data); //LSB *mag_z |= data; //RHALL read_spi(0x0B, &data); //MSB *rhall = data; *rhall = *rhall << 8; read_spi(0x0A, &data); //LSB *rhall |= data;
Kind regards,
Marko Njirjak
Solved! Go to Solution.
05-17-2019 01:01 AM
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
05-17-2019 08:46 AM
Great !
Glad your issue is fixed, and thanks for posting your solution here!
08-05-2020 05:15 AM
Hi, could you show your implementation of user_spi_read/write and if possible user_i2c_read and write?
09-18-2020 03:55 PM
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