04-24-2023 05:14 PM
Hello, everyone
I am trying to implement your driver on my evaluation board EFM32. Everything went smoothly until I got to the part where I had to implement HW interrupt for any-motion feature. I didn't find in your example (GitHub) where you configure the INT1_IO_CTRL, INT2_IO_CTRL and INT_LATCH registers (and didn't see any behavior on the pin either), so I went further and tried to write the needed configuration manually, but for some reason, register INT1_IO_CTRL didn't change (when INT_LATCH did). I2C and the rest of the driver work fine, I can read the status register and validate if the interrupt had been fired.
Here is what I get when I am printing the register values (the first line I get before bmi270_set_gpio_config function and the second line comes right after):
Could you please kindly explain to me what am I missing?
The code is attached below.
BR, Genadi
/*******************************************************************************
*
* BBBBBBB IIII NNN N AA TTTTTTTT AA
* B B II N N N AAA TTTT AAA
* B BB II N N N AAAA TT AAAA
* BBBBBBBBB II N N N AAAAA TT AAAAA
* B BB II N N N AA A TT AA A
* B BB II N N N AA A TT AA A
* BBBBBBBBBB IIII N NNNN AA A TTTT AA A
*
********************************************************************************
* All software (C)
******************************************************************************/
/*******************************************************************************
* Module name: BMI270_Handler.c
*
* Module contents: BMI270 API
*
* Description: Accelerometer and gyroscope HAL driver.
*
* Author: Genadi Manoilenko
*
* Date: 04/2023
*
******************************************************************************/
/*******************************************************************************
* Includes
******************************************************************************/
#include "BMI270_Handler.h"
/*******************************************************************************
* Variables structures
*******************************************************************************/
/*******************************************************************************
* BMI270 object
*******************************************************************************/
/* Sensor initialization configuration. */
struct bmi2_dev bmi2_dev;
/* Create an instance of sensor data structure. */
/* Assign accel sensor to variable. */
uint8_t sensor_list[2] = { BMI2_ACCEL, BMI2_ANY_MOTION };
/* Initialize the interrupt status of accel. */
uint16_t int_status = 0;
struct bmi2_sens_data sensor_data =
{
.acc = { 0 },
.gyr = { 0 },
.aux_data = { 0 },
.sens_time = 0,
};
struct bmi2_acc_mps2_data acc_mps2 =
{
.x_mps2 = 0,
.y_mps2 = 0,
.z_mps2 = 0,
};
/*******************************************************************************
* Constants and Macros
******************************************************************************/
/*******************************************************************************
* Static Data Declarations
******************************************************************************/
/*******************************************************************************
* Data types
******************************************************************************/
/*******************************************************************************
* Private Functions Prototypes
******************************************************************************/
/*!
* @brief This internal API is used to set configurations for any-motion.
*
* @param[in] bmi2_dev : Structure instance of bmi2_dev.
*
* @return Status of execution.
*/
static int8_t set_any_motion_config(struct bmi2_dev *bmi2_dev);
/*!
* @brief This function prints the accelerometer data to the log.
*
*/
static void bmi270_print_acc_data(void);
/*!
* @brief This internal API is used to set configurations for accel.
*
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Status of execution.
*/
static int8_t set_accel_config(struct bmi2_dev *bmi2_dev);
/*!
* @brief This function converts lsb to meter per second squared for 16 bit accelerometer at
* range 2G, 4G, 8G or 16G.
*
* @param[in] val : LSB from each axis.
* @param[in] g_range : Gravity range.
* @param[in] bit_width : Resolution for accel.
*
* @return Gravity.
*/
static float lsb_to_mps2(int16_t val, float g_range, uint8_t bit_width);
static int8_t bmi270_set_gpio_config(void);
/*******************************************************************************
* Public Function Bodies
******************************************************************************/
/*****************************************************************************
* Function name: bmi270_I2C_Transmit
*
* Description: This is a warper function which call I2C transmit function to perform:
* S + SALVE_ADDR(W) + DATA0(REG_ADD), DATA1-n(write data) + P.
*
* Parameters: TxWriteBuf - a pointer to Tx array which include:
* register address,
* write data
* txsize - number of bytes to transmit.
* Returns: The status of the I2C operation.
******************************************************************************/
uint16_t bmi270_I2C_Transmit(uint8_t *TxWriteBuf, uint16_t txsize)
{
I2C_TransferReturn_TypeDef status;
status = I2C0_D_Write(ADPD4101_ADDRESS, TxWriteBuf, txsize);
return (status);
}
/*****************************************************************************
* Function name: bmi270_I2C_TxRx
*
* Description: This is a warper function which call I2C transmit & receive
* function to perform:
* S + SLAVE_ADDR(W) + DATA(REG_ADD) + Sr + SLAVE_ADDR(R) + DATA + P.
*
* Parameters: register_address - a pointer to array which hold register address.
* buffer - array to hold read data.
* txsize - number of bytes in register_address.
* rxsize - number of bytes to read.
* Returns: The status of the I2C operation.
******************************************************************************/
uint16_t bmi270_I2C_TxRx(uint8_t *register_address, uint8_t *buffer, uint16_t txsize, uint16_t rxsize)
{
I2C_TransferReturn_TypeDef status;
status = I2C0_D_WriteRead(ADPD4101_ADDRESS, register_address, txsize, buffer, rxsize);
return (status);
}
void bmi270_test()
{
uint8_t rslt;
uint8_t data[3] = {0};
rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data, 3, &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
printf("0x53 = %d, 0x54 = %d, 0x55 = %d\n", data[0], data[1], data[2]);
rslt = bmi270_set_gpio_config();
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data, 3, &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
printf("0x53 = %d, 0x54 = %d, 0x55 = %d\n", data[0], data[1], data[2]);
}
/******************************************************************************/
/*! Functions */
/* This function starts the execution of program. */
void bmi270_Init(void)
{
/* Status of api are returned to this variable. */
int8_t rslt;
/* Select features and their pins to be mapped to. */
struct bmi2_sens_int_config sens_int = { .type = BMI2_ANY_MOTION, .hw_int_pin = BMI2_INT1 };
/* Trigger a soft reset */
bmi2_soft_reset(&bmi2_dev);
/* Interface reference is given as a parameter
* For I2C : BMI2_I2C_INTF
* For SPI : BMI2_SPI_INTF
*/
rslt = bmi2_interface_init(&bmi2_dev, BMI2_I2C_INTF);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
/* Initialize bmi270. */
rslt = bmi270_init(&bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
/* Accel configuration settings. */
rslt = set_accel_config(&bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
/* Set feature configurations for any-motion. */
rslt = set_any_motion_config(&bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
/* Map the feature interrupt for any-motion. */
rslt = bmi270_map_feat_int(&sens_int, 1, &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
// TODO: delete me
bmi270_test();
/* NOTE:
* Accel enable must be done after setting configurations
*/
rslt = bmi270_sensor_enable(sensor_list, sizeof(sensor_list), &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
Error_Handler(Err_BMI270_Init);
}
printf("BMI270 init complited\n");
}
/*!
* @brief This internal API is used to set configurations for accel.
*/
static int8_t set_accel_config(struct bmi2_dev *bmi2_dev)
{
/* Status of api are returned to this variable. */
int8_t rslt;
/* Structure to define accelerometer configuration. */
struct bmi2_sens_config config;
/* Configure the type of feature. */
config.type = BMI2_ACCEL;
/* Get default configurations for the type of feature selected. */
rslt = bmi270_get_sensor_config(&config, 1, bmi2_dev);
bmi2_error_codes_print_result(rslt);
if (rslt == BMI2_OK)
{
/* Set Output Data Rate */
config.cfg.acc.odr = BMI270_OUTPUT_RATE;
/* Gravity range of the sensor (+/- 2G, 4G, 8G, 16G). */
config.cfg.acc.range = BMI270_ACC_RANGE;
/* The bandwidth parameter is used to configure the number of sensor samples that are averaged
* if it is set to 2, then 2^(bandwidth parameter) samples
* are averaged, resulting in 4 averaged samples.
* Note1 : For more information, refer the datasheet.
* Note2 : A higher number of averaged samples will result in a lower noise level of the signal, but
* this has an adverse effect on the power consumed.
*/
config.cfg.acc.bwp = BMI270_AVRG_SAMPLES;
/* Enable the filter performance mode where averaging of samples
* will be done based on above set bandwidth and ODR.
* There are two modes
* 0 -> Ultra low power mode
* 1 -> High performance mode(Default)
* For more info refer datasheet.
*/
config.cfg.acc.filter_perf = BMI270_POWER_MODE;
/* Set the accel configurations. */
rslt = bmi270_set_sensor_config(&config, 1, bmi2_dev);
bmi2_error_codes_print_result(rslt);
/* Map data ready interrupt to interrupt pin. */
rslt = bmi2_map_data_int(BMI2_DRDY_INT, BMI2_INT1, bmi2_dev);
bmi2_error_codes_print_result(rslt);
}
return rslt;
}
/*!
* @brief This function converts lsb to meter per second squared for 16 bit accelerometer at
* range 2G, 4G, 8G or 16G.
*/
static float lsb_to_mps2(int16_t val, float g_range, uint8_t bit_width)
{
float half_scale = ((float)(1 << bit_width) / 2.0f);
return (GRAVITY_EARTH * val * g_range) / half_scale;
}
/*!
* @brief This internal API is used to set configurations for any-motion.
*/
static int8_t set_any_motion_config(struct bmi2_dev *bmi2_dev)
{
/* Status of api are returned to this variable. */
int8_t rslt;
/* Structure to define the type of sensor and its configurations. */
struct bmi2_sens_config config;
/* Configure the type of feature. */
config.type = BMI2_ANY_MOTION;
/* Get default configurations for the type of feature selected. */
rslt = bmi270_get_sensor_config(&config, 1, bmi2_dev);
bmi2_error_codes_print_result(rslt);
if (rslt == BMI2_OK)
{
/* 1LSB equals 20ms. Default is 100ms. */
config.cfg.any_motion.duration = BMI270_ANY_MOTION_DURATION_mSEC / 20;
/* 1LSB equals to 0.48mg. Default is 83mg. */
config.cfg.any_motion.threshold = (uint16_t)(BMI270_ANY_MOTION_THRESHOLD_mG / 0.48);
printf("select_x = %u\n", config.cfg.any_motion.select_x);
printf("select_y = %u\n", config.cfg.any_motion.select_y);
printf("select_z = %u\n", config.cfg.any_motion.select_z);
/* Set new configurations. */
rslt = bmi270_set_sensor_config(&config, 1, bmi2_dev);
bmi2_error_codes_print_result(rslt);
}
return rslt;
}
/*****************************************************************************
* Function name: bmi270_Interrupt_Service
*
* Description: This function manages received interrupt from INT1 and INT2.
*
* Parameters: None.
*
* Returns: RetVal_t.
******************************************************************************/
RetVal_t bmi270_Interrupt_Service()
{
int8_t rslt;
/* To get the status of accel data ready interrupt. */
rslt = bmi2_get_int_status(&int_status, &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
return FuncFailed;
}
/* To check the accel data ready interrupt status. */
if (int_status & BMI2_ACC_DRDY_INT_MASK)
{
rslt = bmi2_get_sensor_data(&sensor_data, &bmi2_dev);
if(rslt != FuncSuccess)
{
bmi2_error_codes_print_result(rslt);
return FuncFailed;
}
bmi270_print_acc_data();
}
/* To check the interrupt status of any-motion. */
if (int_status & BMI270_ANY_MOT_STATUS_MASK)
{
printf("Any-motion interrupt is generated\n");
}
return FuncSuccess;
}
/*****************************************************************************
* Function name: bmi270_print_acc_data
*
* Description: This function prints the accelerometer data to the log.
*
* Parameters: None.
*
* Returns: None.
******************************************************************************/
static void bmi270_print_acc_data()
{
#ifndef BMI270_PRINT_ACC_DATA
return;
#endif
/* Get accelerometer data for x, y and z axis. */
printf("Acc_X = %d, Acc_Y = %d, Acc_Z = %d\n", sensor_data.acc.x, sensor_data.acc.y, sensor_data.acc.z);
/* Converting lsb to meter per second squared for 16 bit accelerometer at 2G range. */
acc_mps2.x_mps2 = lsb_to_mps2(sensor_data.acc.x, 2, bmi2_dev.resolution);
acc_mps2.y_mps2 = lsb_to_mps2(sensor_data.acc.y, 2, bmi2_dev.resolution);
acc_mps2.z_mps2 = lsb_to_mps2(sensor_data.acc.z, 2, bmi2_dev.resolution);
/* Print the data in m/s^2. */
printf("Acc_ms2_X = %4.2f, Acc_ms2_Y = %4.2f, Acc_ms2_Z = %4.2f\n", acc_mps2.x_mps2, acc_mps2.y_mps2, acc_mps2.z_mps2);
}
/*****************************************************************************
* Function name: bmi270_set_gpio_config
*
* Description: Setup the bmi270 GPIO configuration for the application.
*
* Parameters: None.
*
* Returns: rslt.
******************************************************************************/
static int8_t bmi270_set_gpio_config(void)
{
/* Status of api are returned to this variable. */
int8_t rslt;
const struct bmi2_int_pin_config int_pin_config =
{
.pin_type = BMI2_INT1,
/*! Latched or non-latched mode*/
.int_latch = BMI2_INT_LATCH,
/*! Structure to define Interrupt pin configuration */
.pin_cfg[0] =
{
/*! Configure level of interrupt pin */
.lvl = BMI2_INT_ACTIVE_HIGH,
/*! Configure behavior of interrupt pin */
.od = BMI2_INT_PUSH_PULL,
/*! Output enable for interrupt pin */
.output_en = BMI2_INT_OUTPUT_ENABLE,
/*! Input enable for interrupt pin */
.input_en = BMI2_INT_INPUT_DISABLE,
},
};
rslt = bmi2_set_int_pin_config(&int_pin_config, &bmi2_dev);
return rslt;
}
/*****************************************************************************
* Function name: bmi270_Int_1_Handler
*
* Description: INT1 interrupt handler.
*
* Parameters: None.
*
* Returns: None.
******************************************************************************/
void bmi270_Int_1_Handler(uint8_t intNo)
{
(void)intNo;
printf("BMI270_INT_1_FIRED\n");
}
04-25-2023 09:01 AM
Hi Genadi,
BMI270 sensor API on github provide interface to configure interrupt pins INT1, INT2. You could refer the following example code.
int8_t Open_BMI270_RDRY_INT(struct bmi2_dev *dev)
{
int8_t rslt = BMI2_OK;
struct bmi2_int_pin_config int_cfg;
/* Map data ready interrupt to interrupt pin. */
rslt = bmi2_map_data_int(BMI2_DRDY_INT, BMI2_INT1, dev);
bmi2_error_codes_print_result(rslt);
bmi2_get_int_pin_config(&int_cfg, dev);
int_cfg.pin_type = BMI2_INT1;
int_cfg.pin_cfg[0].lvl = BMI2_INT_ACTIVE_HIGH;/*Config INT1 rising edge trigging*/
int_cfg.pin_cfg[0].od = BMI2_INT_PUSH_PULL;
int_cfg.pin_cfg[0].output_en= BMI2_INT_OUTPUT_ENABLE;
bmi2_set_int_pin_config(&int_cfg, dev);
bmi2_error_codes_print_result(rslt);
return rslt;
}
04-25-2023 06:32 PM
Thank you Robin for your fast reply.
Your answer helped me a lot, but I had to make some moderation to your code. I had to disable advance power save in order to make the change in the register. Is it a necessary step or did I mess up with the setup?
BR, Genadi
05-30-2023 10:09 AM
Hi Genadi,
If you would like to enable/disable BMI270 features or modify parameters in config file, you have to disable advance power save.