10-06-2019 03:19 PM
Hi
I've been able to get the BMX160 setup to update the Acc & Mag at 50Hz.
I followed the setup in the BMX160 datasheet, Table 16. Only difference is the ODR = 0x07 and REPXY and REPZ are set for to the high accuracy preset.
I have enabled Data Ready on INT1 pin.
When I receive an interrupt from INT1, I check the STATUS (0x1B) register and can confirm that both drdy_acc and drdy_mag are set (value=0xB0).
I then do a block ready from DATA_0 to DATA_19 and confirm that the Acc data is still correct.
However the Mag data does not change. I get an initial non-zero measurement, but then nothing changes further.
Why is the Mag data not changing?
Is there some setting I'm missing in the Mag setup?
Thanks
Solved! Go to Solution.
10-14-2019 03:16 PM
Based on BMI160's Wiki (and the chip ID trick for BMX160), I can successfully run the snipped below in my setup (AppBoard2.0+BMX160 ShuttleBoard+COINES), which outputs refreshed magnetometer data. Note that the interrupts configuration is not included, and that I tried to re-use similar sensor configurations.
/*********************************************************************/
/* system header files */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/*********************************************************************/
/* own header files */
#include "coines.h"
#include "bmi160.h"
#include "bmm150.h"
/*********************************************************************/
/* local macro definitions */
/*! i2c interface communication, 1 - Enable; 0- Disable */
#define BMX160_INTERFACE_I2C 1
/*! spi interface communication, 1 - Enable; 0- Disable */
#define BMX160_INTERFACE_SPI 0
#if (!((BMX160_INTERFACE_I2C==1) && (BMX160_INTERFACE_SPI==0)) && \
(!((BMX160_INTERFACE_I2C==0) && (BMX160_INTERFACE_SPI==1))))
#error "Invalid value given for the macros BMX160_INTERFACE_I2C / BMX160_INTERFACE_SPI"
#endif
/*! bmx160 shuttle id */
#define BMX160_SHUTTLE_ID 0xD8
/*! bmi160 Device address */
#define BMI160_DEV_ADDR BMI160_I2C_ADDR
/*! bmm150 Device address */
#define BMM150_DEV_ADDR BMM150_DEFAULT_I2C_ADDRESS
/*********************************************************************/
/* global variables */
/*! @brief This structure containing relevant bmi160 info */
struct bmi160_dev bmi160dev;
/*! @brief This structure containing relevant bmm150 info */
struct bmm150_dev bmm150dev;
/*! @brief variable to hold the bmi160 accel data */
struct bmi160_sensor_data bmi160_accel;
/*! @brief variable to hold the bmi160 gyro data */
struct bmi160_sensor_data bmi160_gyro;
/* @brief Buffer to store the Mag data from 0x42 to 0x48 */
uint8_t mag_data[8] = {0};
/*********************************************************************/
/* static function declarations */
/*! internal API is used to initialize the sensor interface */
static void init_sensor_interface(void);
/*! This internal API is used to initialize the bmx160 sensor */
static void init_bmx160(void);
/*! This internal API is used to initialize the sensor driver interface */
static void init_bmx160_sensor_driver_interface(void);
/* Auxiliary interface read function */
static int8_t bmm150_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len);
/* Auxiliary interface write function */
static int8_t bmm150_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len);
/*********************************************************************/
/* functions */
static int8_t bmm150_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len)
{
(void) id; /* id is unused here */
return bmi160_aux_read(reg_addr, aux_data, len, &bmi160dev);
}
static int8_t bmm150_aux_write(uint8_t id, uint8_t reg_addr, uint8_t *aux_data, uint16_t len)
{
(void) id; /* id is unused here */
return bmi160_aux_write(reg_addr, aux_data, len, &bmi160dev);
}
/*!
* @brief This internal API is used to initialize the sensor interface depending
* on selection either SPI or I2C.
*
* @param[in] void
*
* @return void
*
*/
static void init_sensor_interface(void)
{
/* Switch VDD for sensor off */
coines_set_shuttleboard_vdd_vddio_config(0, 0);
/* wait until the sensor goes off */
coines_delay_msec(10);
#if BMX160_INTERFACE_I2C==1
/* set the sensor interface as I2C */
coines_config_i2c_bus(COINES_I2C_BUS_0, COINES_I2C_FAST_MODE);
#endif
#if BMX160_INTERFACE_SPI==1
/* set the sensor interface as SPI */
coines_config_spi_bus(COINES_SPI_BUS_0, COINES_SPI_SPEED_5_MHZ, COINES_SPI_MODE3);
#endif
/* Switch VDD for sensor on */
coines_set_shuttleboard_vdd_vddio_config(3300, 3300);
}
/*!
* @brief This internal API is used to initializes the bmx160 sensor
* settings like power mode and OSRS settings.
*
* @param[in] void
*
* @return void
*
*/
static void init_bmx160(void)
{
int8_t rslt = BMI160_OK;
uint8_t bmm150_data_start = BMM150_DATA_X_LSB;
rslt = bmi160_init(&bmi160dev);
if (rslt == BMI160_OK)
{
printf("BMI160 initialization success !\r\n");
printf("Chip ID 0x%X\n", bmi160dev.chip_id);
}
else
{
printf("BMI160 initialization failure !\r\n");
exit(COINES_E_FAILURE);
}
/* Configure the BMI160's auxiliary interface for the BMM150 */
bmi160dev.aux_cfg.aux_sensor_enable = BMI160_ENABLE;
bmi160dev.aux_cfg.aux_i2c_addr = BMM150_DEV_ADDR;
bmi160dev.aux_cfg.manual_enable = BMI160_ENABLE; /* Manual mode */
bmi160dev.aux_cfg.aux_rd_burst_len = BMI160_AUX_READ_LEN_0; /* 1 byte */
rslt = bmi160_aux_init(&bmi160dev);
if (rslt == BMI160_OK)
{
printf("BMI160 aux. interface init success !\r\n");
}
else
{
printf("BMI160 aux. interface init failure !\r\n");
exit(COINES_E_FAILURE);
}
rslt = bmm150_init(&bmm150dev);
if (rslt == BMI160_OK)
{
printf("BMM150 initialization success !\r\n");
printf("Chip ID 0x%X\n", bmm150dev.chip_id);
}
else
{
printf("BMM150 initialization failure !\r\n");
exit(COINES_E_FAILURE);
}
/* Select the Output data rate, range of accelerometer sensor */
bmi160dev.accel_cfg.odr = BMI160_ACCEL_ODR_50HZ;
bmi160dev.accel_cfg.range = BMI160_ACCEL_RANGE_4G;
bmi160dev.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
/* Select the power mode of accelerometer sensor */
bmi160dev.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;
/* Select the Output data rate, range of Gyroscope sensor */
bmi160dev.gyro_cfg.odr = BMI160_GYRO_ODR_50HZ;
bmi160dev.gyro_cfg.range = BMI160_GYRO_RANGE_125_DPS;
bmi160dev.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
/* Select the power mode of Gyroscope sensor */
bmi160dev.gyro_cfg.power = BMI160_GYRO_SUSPEND_MODE;
/* Set the sensor configuration */
rslt = bmi160_set_sens_conf(&bmi160dev);
/* Configure the magnetometer. The regular preset supports up to 60Hz in Forced mode */
bmm150dev.settings.preset_mode = BMM150_PRESETMODE_ENHANCED;
rslt += bmm150_set_presetmode(&bmm150dev);
/* It is important that the last write to the BMM150 sets the forced mode.
* This is because the BMI160 writes the last value to the auxiliary sensor
* after every read */
bmm150dev.settings.pwr_mode = BMM150_FORCED_MODE;
rslt += bmm150_set_op_mode(&bmm150dev);
bmi160dev.aux_cfg.aux_odr = BMI160_AUX_ODR_50HZ;
rslt += bmi160_set_aux_auto_mode(&bmm150_data_start, &bmi160dev);
if (rslt == BMI160_OK)
{
printf("BMX160 configuration success !\r\n");
}
else
{
printf("BMX160 configuration failure !\r\n");
exit(COINES_E_FAILURE);
}
}
/*!
* @brief This internal API is used to set the sensor driver interface to
* read/write the data.
*
* @param[in] void
*
* @return void
*
*/
static void init_bmx160_sensor_driver_interface(void)
{
#if BMX160_INTERFACE_I2C==1
/* I2C setup */
/* link read/write/delay function of host system to appropriate
* bmi160 function call prototypes */
bmi160dev.write = coines_write_i2c;
bmi160dev.read = coines_read_i2c;
bmi160dev.delay_ms = coines_delay_msec;
/* set correct i2c address */
bmi160dev.id = BMI160_DEV_ADDR;
bmi160dev.interface = BMI160_I2C_INTF;
#endif
#if BMX160_INTERFACE_SPI==1
/* SPI setup */
/* link read/write/delay function of host system to appropriate
* bmi160 function call prototypes */
bmi160dev.write = coines_write_spi;
bmi160dev.read = coines_read_spi;
bmi160dev.delay_ms = coines_delay_msec;
bmi160dev.id = 0;
bmi160dev.interface = BMI160_SPI_INTF;
#endif
bmm150dev.dev_id = BMM150_DEV_ADDR;
bmm150dev.intf = BMM150_I2C_INTF;
bmm150dev.read = bmm150_aux_read;
bmm150dev.write = bmm150_aux_write;
bmm150dev.delay_ms = coines_delay_msec;
}
/*!
* @brief Main Function where the execution getting started to test the code.
*
* @param[in] argc
* @param[in] argv
*
* @return status
*
*/
int main(int argc, char *argv[])
{
struct coines_board_info board_info;
int16_t rslt;
int times_to_read = 0;
init_bmx160_sensor_driver_interface();
rslt = coines_open_comm_intf(COINES_COMM_INTF_USB);
if (rslt < 0)
{
printf("\n Unable to connect with Application Board ! \n"
" 1. Check if the board is connected and powered on. \n"
" 2. Check if Application Board USB driver is installed. \n"
" 3. Check if board is in use by another application. (Insufficient permissions to access USB) \n");
exit(rslt);
}
rslt = coines_get_board_info(&board_info);
if (rslt == COINES_SUCCESS)
{
if (board_info.shuttle_id != BMX160_SHUTTLE_ID)
{
printf("! Warning invalid sensor shuttle \n ,"
"This application will not support this sensor \n");
exit(COINES_E_FAILURE);
}
}
init_sensor_interface();
init_bmx160();
/* after sensor init introduce 200 msec sleep */
coines_delay_msec(200);
while (times_to_read < 100)
{
/* To read both Accel and Gyro data */
bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL), &bmi160_accel, &bmi160_gyro, &bmi160dev);
bmi160_read_aux_data_auto_mode(mag_data, &bmi160dev);
rslt = bmm150_aux_mag_data(mag_data, &bmm150dev);
printf("ax:%d\tay:%d\taz:%d\n", bmi160_accel.x, bmi160_accel.y, bmi160_accel.z);
printf("gx:%d\tgy:%d\tgz:%d\n", bmi160_gyro.x, bmi160_gyro.y, bmi160_gyro.z);
printf("mx:%d\tmy:%d\tmz:%d\n", bmm150dev.data.x, bmm150dev.data.y, bmm150dev.data.z);
fflush(stdout);
coines_delay_msec(20); // 50Hz ODR
times_to_read ++;
}
coines_close_comm_intf(COINES_COMM_INTF_USB);
return EXIT_SUCCESS;
}
10-16-2019 10:07 PM
Hi handytech
Thanks for the code snippet. I have implemented it and have the following feedback:
Init of the ACC & MAG completes successfully.
I changed my code to poll the STATUS reg (0x1B) to check when the drdy_acc and drdy_mag bits are set.
Now this is where it gets weird.
Have you encountered this before?
10-16-2019 10:27 PM
Some hardware feedback.
I have two boards.
The first board I reduced the pull-up resistors on the SCX & SDX to get faster I2C speeds. Throught that I may have damaged the BMX160 due to too low pull-up resistors. To confirm I tested the same code on the second board.
When testing with the second board, I had the same result as in my previous post.
I have compared my PCB design to the examples and all is equivalent.
VDD = VDDIO = 3.3V
Since @handytech was able to get his BMX160 working with equivalent code, is there an external pin on the BMX160 that is only connected to the internal MAG sensor?
Is there any hardware reason why the ACC & GYRO would operate as expected, but the MAG sensor does not?
10-19-2019 03:46 PM
Hi o_o
I have attached the schematic of my BMX160 sensor routing (BMX160_schematic.png).
Unfortunately I don't have a logic analyzer, but I have put a printout in the low-level I2C read & write functions.
The READ function is a block operation and prints out "IC2_R" with all the data read following (address, register, length & data read).
The WRITE function is a "single char at a time" operation and prints out "IC2_W" with all the write data following (I2C address, register, data to written)
The order and contents of operation remains unchanged.
Below is the printout with the I2C trace enabled, during BMX160 init.
Each block starts with a description (not really in the code), the I2C write/read operation traces and the return value.
BMX160 init:
Fucntion call I2C Write & Read data: bmi160_init
IC2_R: add:68 reg:00 len:01 data: d8
IC2_W: add:68 reg:7e data:b6
(return value of) bmi160_init:0
Read BMX160 ChipID
IC2_R: add:68 reg:00 len:01 data: d8
chipID:d8
Fucntion call I2C Write & Read data: bmi160_aux_init
IC2_W: add:68 reg:7e data:19
IC2_R: add:68 reg:6b len:01 data: 00
IC2_W: add:68 reg:6b data:20
IC2_R: add:68 reg:4c len:01 data: 80
IC2_W: add:68 reg:4b data:20
IC2_W: add:68 reg:4c data:80
(return value of) bmi160_aux_init:0
Fucntion call I2C Write & Read data: bmm150_init
IC2_W: add:68 reg:4d data:4b
IC2_R: add:68 reg:04 len:01 data: 03
IC2_W: add:68 reg:4f data:03
IC2_W: add:68 reg:4e data:4b
IC2_W: add:68 reg:4d data:40
IC2_R: add:68 reg:04 len:01 data: 32
IC2_W: add:68 reg:4d data:5d
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:5e
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:62
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:63
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:64
IC2_R: add:68 reg:04 len:01 data: 1e
IC2_W: add:68 reg:4d data:65
IC2_R: add:68 reg:04 len:01 data: 1e
IC2_W: add:68 reg:4d data:68
IC2_R: add:68 reg:04 len:01 data: f2
IC2_W: add:68 reg:4d data:69
IC2_R: add:68 reg:04 len:01 data: 02
IC2_W: add:68 reg:4d data:6a
IC2_R: add:68 reg:04 len:01 data: 58
IC2_W: add:68 reg:4d data:6b
IC2_R: add:68 reg:04 len:01 data: 56
IC2_W: add:68 reg:4d data:6c
IC2_R: add:68 reg:04 len:01 data: cd
IC2_W: add:68 reg:4d data:6d
IC2_R: add:68 reg:04 len:01 data: 1a
IC2_W: add:68 reg:4d data:6e
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:6f
IC2_R: add:68 reg:04 len:01 data: 00
IC2_W: add:68 reg:4d data:70
IC2_R: add:68 reg:04 len:01 data: fd
IC2_W: add:68 reg:4d data:71
IC2_R: add:68 reg:04 len:01 data: 1d
(return value of) bmm150_init:0
Read BMM150 ChipID
IC2_W: add:68 reg:4d data:40
IC2_R: add:68 reg:04 len:01 data: 32
BmmID:32
Fucntion call I2C Write & Read data: bmi160_set_sens_conf
IC2_R: add:68 reg:40 len:02 data: 28 03
IC2_W: add:68 reg:40 data:27
IC2_W: add:68 reg:41 data:05
IC2_R: add:68 reg:42 len:02 data: 28 00
IC2_W: add:68 reg:42 data:27
IC2_W: add:68 reg:43 data:04
IC2_R: add:68 reg:40 len:01 data: 27
IC2_W: add:68 reg:7e data:11
IC2_R: add:68 reg:02 len:01 data: 80
(return value of) bmi160_set_sens_conf:0
Fucntion call I2C Write & Read data: bmm150_set_presetmode
IC2_W: add:68 reg:4d data:4c
IC2_R: add:68 reg:04 len:01 data: 06
IC2_W: add:68 reg:4f data:06
IC2_W: add:68 reg:4e data:4c
IC2_W: add:68 reg:4f data:07
IC2_W: add:68 reg:4e data:51
IC2_W: add:68 reg:4f data:1a
IC2_W: add:68 reg:4e data:52
(return value of) bmm150_set_presetmode:0
Fucntion call I2C Write & Read data: bmm150_set_op_mode
IC2_W: add:68 reg:4d data:4c
IC2_R: add:68 reg:04 len:01 data: 06
IC2_W: add:68 reg:4f data:02
IC2_W: add:68 reg:4e data:4c
(return value of) bmm150_set_op_mode:0
Fucntion call I2C Write & Read data: bmi160_config_aux_mode
IC2_W: add:68 reg:4d data:42
IC2_R: add:68 reg:44 len:01 data: 0b
IC2_W: add:68 reg:44 data:07
IC2_R: add:68 reg:4c len:01 data: 80
IC2_W: add:68 reg:4b data:20
IC2_W: add:68 reg:4b data:00
(return value of) bmi160_config_aux_mode:0
Then I used the bmm150_aux_read wrapper function to read the registers from the BMM150. Here is the function I have implemented:
/*wrapper function to match the signature of bmm150.read */
int8_t bmm150_aux_read(uint8_t id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
/* Discarding the parameter id as it is redundant*/
return bmi160_aux_read(reg_addr, reg_data, len, &bmi);
}
I then printed out the BMX160 (BMI160 & BMM150) registers after 1 second of operation. NOTE: no drdy or data reads have been performed by this stage.
Read BMX160/BMI160 registers (REG: DATA)
00: d8
01: 21
02: 80
03: 11
1c: 00
1d: 00
1e: 00
1f: 00
40: 27
41: 05
42: 27
43: 04
44: 07
50: 00
51: 00
52: 00
53: 00
54: 00
55: 00
56: 00
57: 00
58: 00
59: 00
63: 04
64: 0a
Read BMM150 registers (REG: DATA)
4a: 01
4b: 01
4c: 01
4d: 01
4e: 01
4f: 01
50: 01
51: 01
52: 01
Do these I2C traces & registers look correct? (the BMM150 registers don't seem to change. Am I using the bmm150_aux_read function directly, with the assumption that I can use it to "directly" read the BMM150 registers. Is this wrong?)
Please let me know your thoughts.
Thanks
10-21-2019 05:21 PM
The bmi160_aux_read will only work if the auxialiary interface is already enabled and in manual mode.
I've copy-pasted handytech's code under COINES, and added a similar trace function, this is the output:
C:\COINES\v1.2\examples\c\bmx160>read_sensor_data.exe
bmi160_init(&bmi160dev);
I2C_R: add:68 reg:00 len:01 data: d8
I2C_W: add:68 reg:7e data:b6
BMI160 initialization success !
Chip ID 0xD8
bmi160_aux_init(&bmi160dev);
I2C_W: add:68 reg:7e data:19
I2C_R: add:68 reg:6b len:01 data: 00
I2C_W: add:68 reg:6b data:20
I2C_R: add:68 reg:4c len:01 data: 80
I2C_W: add:68 reg:4b data:20
I2C_W: add:68 reg:4c data:83
BMI160 aux. interface init success !
bmm150_init(&bmm150dev);
I2C_W: add:68 reg:4d data:4b
I2C_R: add:68 reg:04 len:08 data: 00 00 00 00 00 00 00 00
I2C_W: add:68 reg:4f data:01
I2C_W: add:68 reg:4e data:4b
I2C_W: add:68 reg:4d data:40
I2C_R: add:68 reg:04 len:08 data: 32 05 01 00 01 00 01 00
I2C_W: add:68 reg:4d data:5d
I2C_R: add:68 reg:04 len:08 data: 00 00 00 4f 76 00 00 1f
I2C_W: add:68 reg:4d data:62
I2C_R: add:68 reg:04 len:08 data: 00 00 1f 1f 08 00 e7 02
I2C_W: add:68 reg:4d data:68
I2C_R: add:68 reg:04 len:08 data: e7 02 f1 57 55 1a 00 00
I2C_W: add:68 reg:4d data:70
I2C_R: add:68 reg:04 len:08 data: fd 1d ff ff ff ff ff ff
BMM150 initialization success !
Chip ID 0x32
bmi160_set_sens_conf(&bmi160dev);
I2C_R: add:68 reg:40 len:02 data: 28 03
I2C_W: add:68 reg:40 data:27
I2C_W: add:68 reg:41 data:05
I2C_R: add:68 reg:42 len:02 data: 28 00
I2C_W: add:68 reg:42 data:27
I2C_W: add:68 reg:43 data:04
I2C_R: add:68 reg:40 len:01 data: 27
I2C_W: add:68 reg:7e data:11
I2C_R: add:68 reg:02 len:01 data: 80
bmm150_set_presetmode(&bmm150dev);
I2C_W: add:68 reg:4d data:4c
I2C_R: add:68 reg:04 len:08 data: 06 3f 07 00 00 00 00 ff
I2C_W: add:68 reg:4f data:06
I2C_W: add:68 reg:4e data:4c
I2C_W: add:68 reg:4f data:07
I2C_W: add:68 reg:4e data:51
I2C_W: add:68 reg:4f data:1a
I2C_W: add:68 reg:4e data:52
bmm150_set_op_mode(&bmm150dev);
I2C_W: add:68 reg:4d data:4c
I2C_R: add:68 reg:04 len:08 data: 06 3f 07 00 00 07 1a ff
I2C_W: add:68 reg:4f data:02
I2C_W: add:68 reg:4e data:4c
bmi160_set_aux_auto_mode(&bmm150_data_start, &bmi160dev);
I2C_W: add:68 reg:4d data:42
I2C_R: add:68 reg:44 len:01 data: 0b
I2C_W: add:68 reg:44 data:07
I2C_R: add:68 reg:4c len:01 data: 83
I2C_W: add:68 reg:4b data:20
I2C_W: add:68 reg:4c data:03
BMX160 configuration success !
I2C_R: add:68 reg:0c len:0c data: 00 00 00 00 00 00 d4 ff 1a ff a0 20
I2C_R: add:68 reg:04 len:08 data: c1 00 a9 fd 03 ff 6d 66
ax:-44 ay:-230 az:8352
gx:0 gy:0 gz:0
mx:8 my:-28 mz:-49
I would look no further than here in your trace:
IC2_W: add:68 reg:4b data:20
IC2_W: add:68 reg:4b data:00
Unless the register 0x4C is written again, the part will not start the automatic sampling.
**PS: Handytech's code incorrectly sets the burst length to 1 byte, it should be 8 bytes.