Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
/*
****************************************************************************
* Copyright (C) 2015 - 2016 Bosch Sensortec GmbH
*
* File :bmi088_gyro.c
*
* Date: 30 Oct 2017
*
* Revision:
*
* Usage: Sensor Driver for BMI088 family of sensors
*
****************************************************************************
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry.
* They may only be used within the parameters of the respective valid
* product data sheet. Bosch Sensortec products are provided with the
* express understanding that there is no warranty of fitness for a
* particular purpose.They are not fit for use in life-sustaining,
* safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system
* or device malfunctions. In addition,Bosch Sensortec products are
* not fit for use in products which interact with motor vehicle systems.
* The resale and or use of products are at the purchasers own risk and
* his own responsibility. The examination of fitness for the intended use
* is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party
* claims, including any claims for incidental, or consequential damages,
* arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by
* Bosch Sensortec and reimburse Bosch Sensortec for all costs in
* connection with such claims.
*
* The purchaser must monitor the market for the purchased products,
* particularly with regard to product safety and inform Bosch Sensortec
* without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e).
* Samples may vary from the valid technical specifications of the product
* series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal
* client testing. The testing of an engineering sample may in no way
* replace the testing of a product series. Bosch Sensortec assumes
* no liability for the use of engineering samples.
* By accepting the engineering samples, the Purchaser agrees to indemnify
* Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information
* on application-sheets (hereinafter called "Information") is provided
* free of charge for the sole purpose to support your application work.
* The Software and Information is subject to the following
* terms and conditions:
*
* The Software is specifically designed for the exclusive use for
* Bosch Sensortec products by personnel who have special experience
* and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed
* or implied warranties,including without limitation, the implied warranties
* of merchantability and fitness for a particular purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability
* for the functional impairment
* of this Software in terms of fitness, performance and safety.
* Bosch Sensortec and their representatives and agents shall not be liable
* for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable.
* Bosch Sensortec assumes no responsibility for the consequences of use
* of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
**************************************************************************/
/*! \file bmi088_gyro.c
\brief Sensor Driver for BMI088 family of sensors */
/***************************************************************************/
/**\name Header files
****************************************************************************/
#include "bmi088.h"
/***************************************************************************/
/**\name Local structures
****************************************************************************/
/***************************************************************************/
/*! Static Function Declarations
****************************************************************************/
/*!
* @brief This API is used to validate the device structure pointer for
* null conditions.
*
* @param[in] dev : Structure instance of bmi088_dev.
*
* @return Result of API execution status
* @retval zero -> Success
* @retval Any non zero value -> Fail
*/
static uint16_t null_ptr_check(struct bmi088_dev *dev);
/*!
* @brief This API sets the data ready interrupt for gyro sensor.
*
* @param[in] int_config : Structure instance of bmi088_int_cfg.
* @param[in] dev : Structure instance of bmi088_dev.
*
* @return Result of API execution status
* @retval zero -> Success
* @retval Any non zero value -> Fail
*/
static uint16_t set_gyro_data_ready_int(const struct bmi088_int_cfg *int_config, struct bmi088_dev *dev);
/*!
* @brief This API configures the pins which fire the
* interrupt signal when any interrupt occurs.
*
* @param[in] int_config : Structure instance of bmi088_int_cfg.
* @param[in] dev : Structure instance of bmi088_dev.
*
* @return Result of API execution status
* @retval zero -> Success
* @retval Any non zero value -> Fail
*/
static uint16_t set_int_pin_config(const struct bmi088_int_cfg *int_config, struct bmi088_dev *dev);
/***************************************************************************/
/**\name Extern Declarations
****************************************************************************/
/***************************************************************************/
/**\name Globals
****************************************************************************/
/* Copy of gyro_cfg structure of device structure. It
* prevents overwriting same gyro configuration data */
static struct bmi088_cfg gyro_cfg_copy;
/***************************************************************************/
/**\name Function definitions
****************************************************************************/
/*!
* @brief This API is the entry point for gyro sensor.
* It performs the selection of I2C/SPI read mechanism according to the
* selected interface and reads the chip-id of gyro sensor.
*/
uint16_t bmi088_gyro_init(struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, data = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
reg_addr = BMI088_GYRO_CHIP_ID_REG;
/* Read gyro chip id */
rslt |= bmi088_get_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
/* Assign Chip Id */
dev->gyro_chip_id = data;
/* Initializing gyro sensor parameters with default values */
dev->gyro_cfg.bw = BMI088_GYRO_ODR_RESET_VAL;
dev->gyro_cfg.power = BMI088_GYRO_PM_NORMAL;
dev->gyro_cfg.range = BMI088_GYRO_RANGE_2000_DPS;
/* Copying gyro_cfg parameters of device structure to
* gyro_cfg_copy structure to maintain a copy. This will
* help us to prevent writing same configuration data
* again and again */
gyro_cfg_copy.bw = dev->gyro_cfg.bw;
gyro_cfg_copy.power = dev->gyro_cfg.power;
gyro_cfg_copy.range = dev->gyro_cfg.range;
}
else
{
rslt = BMI088_E_COM_FAIL;
}
}
return rslt;
}
/*!
* @brief This API reads the data from the given register address
* of gyro sensor.
*/
uint16_t bmi088_get_gyro_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
/* Configuring reg_addr for SPI Interface */
if (dev->interface == BMI088_SPI_INTF)
{
reg_addr = (reg_addr | BMI088_SPI_RD_MASK);
}
/* read a gyro register */
rslt = dev->read(dev->gyro_id, reg_addr, data, len);
if (rslt != BMI088_OK)
{
rslt = BMI088_E_COM_FAIL;
}
}
return rslt;
}
/*!
* @brief This API writes the given data to the register address
* of gyro sensor.
*/
uint16_t bmi088_set_gyro_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMI088_OK) && (data != NULL) && (len != 0))
{
/* Configuring reg_addr for SPI Interface */
if (dev->interface == BMI088_SPI_INTF)
{
reg_addr = (reg_addr & BMI088_SPI_WR_MASK);
}
/* write to a gyro register */
rslt = dev->write(dev->gyro_id, reg_addr, data, len);
if (rslt != BMI088_OK)
{
rslt = BMI088_E_COM_FAIL;
}
}
return rslt;
}
/*!
* @brief This API resets the gyro sensor.
*/
uint16_t bmi088_gyro_soft_reset(struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t data, reg_addr;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
/* Reset gyro device */
reg_addr = BMI088_GYRO_SOFTRESET_REG;
data = BMI088_SOFT_RESET_VAL;
rslt = bmi088_set_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
/* delay 30 ms after writing reset value to its register */
dev->delay_ms(BMI088_GYRO_SOFTRESET_DELAY);
}
}
return rslt;
}
/*!
* @brief This API sets the power mode, range and bandwidth
* of gyro sensor.
*/
uint16_t bmi088_set_gyro_meas_conf(struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr;
bool is_range_invalid = false, is_odr_invalid = false;
uint8_t odr, range;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
odr = dev->gyro_cfg.odr;
range = dev->gyro_cfg.range;
/* Check if range is not previously configured range */
if (range != gyro_cfg_copy.range)
{
/* Check for valid range */
if (range <= BMI088_GYRO_RANGE_125_DPS)
{
reg_addr = BMI088_GYRO_RANGE_REG;
/* Write range value to range register */
rslt = bmi088_set_gyro_regs(reg_addr, &range, BMI088_ONE, dev);
/* If rslt is ok, copy the current range to previous range to maintain a copy */
if (rslt == BMI088_OK)
{
gyro_cfg_copy.range = range;
}
}
else
{
/* Set range as invalid */
is_range_invalid = true;
}
}
/* Check if odr is not previously configured odr */
if (odr != gyro_cfg_copy.odr)
{
/* Check for valid odr */
if (odr <= BMI088_GYRO_BW_32_ODR_100_HZ)
{
reg_addr = BMI088_GYRO_BANDWIDTH_REG;
/* Write odr value to odr register */
rslt = bmi088_set_gyro_regs(reg_addr, &odr, BMI088_ONE, dev);
/* If rslt is ok, copy the current odr to previous odr to maintain a copy */
if (rslt == BMI088_OK)
{
gyro_cfg_copy.odr = odr;
}
}
else
{
/* Set odr as invalid */
is_odr_invalid = true;
}
}
}
/* If invalid conditions take place, make rslt as invalid */
if ((is_range_invalid) || (is_odr_invalid))
{
rslt = BMI088_E_INVALID_INPUT;
}
return rslt;
}
/*!
* @brief This API sets the power mode of the gyro sensor.
*/
uint16_t bmi088_set_gyro_power_mode(struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, power;
bool is_power_switching_mode_valid = true;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
power = dev->gyro_cfg.power;
/* Check if power is not previously configured power */
if (power != gyro_cfg_copy.power)
{
/* Check for invalid power switching (i.e) deep suspend to suspend */
if ((power == BMI088_GYRO_PM_SUSPEND) && (gyro_cfg_copy.power == BMI088_GYRO_PM_DEEP_SUSPEND))
{
is_power_switching_mode_valid = false;
}
/* Check for invalid power switching (i.e) from suspend to deep suspend */
if ((power == BMI088_GYRO_PM_DEEP_SUSPEND) && (gyro_cfg_copy.power == BMI088_GYRO_PM_SUSPEND))
{
is_power_switching_mode_valid = false;
}
/* Check if power switching mode is valid*/
if (is_power_switching_mode_valid)
{
reg_addr = BMI088_GYRO_LPM1_REG;
/* Write power to power register */
rslt = bmi088_set_gyro_regs(reg_addr, &power, BMI088_ONE, dev);
/* If rslt is fine, copy current power to previous power to maintain a copy */
if (rslt == BMI088_OK)
{
gyro_cfg_copy.power = power;
}
}
}
}
return rslt;
}
/*!
* @brief This API reads the gyro data from the sensor,
* store it in the bmi088_sensor_data structure instance
* passed by the user.
*/
uint16_t bmi088_get_gyro_data(struct bmi088_sensor_data *gyro, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t index = 0, reg_addr, data[6];
uint32_t lsb, msb, msblsb;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMI088_OK) && (gyro != NULL))
{
reg_addr = BMI088_GYRO_X_LSB_REG;
/* read gyro sensor data */
rslt = bmi088_get_gyro_regs(reg_addr, data, BMI088_SIX, dev);
if (rslt == BMI088_OK)
{
lsb = (uint32_t)data[index++];
msb = (uint32_t)data[index++];
msblsb = (msb << BMI088_EIGHT) | lsb;
gyro->x = (int16_t)msblsb; /* Data in X axis */
lsb = (uint32_t)data[index++];
msb = (uint32_t)data[index++];
msblsb = (msb << BMI088_EIGHT) | lsb;
gyro->y = (int16_t)msblsb; /* Data in Y axis */
lsb = (uint32_t)data[index++];
msb = (uint32_t)data[index++];
msblsb = (msb << BMI088_EIGHT) | lsb;
gyro->z = (int16_t)msblsb; /* Data in Z axis */
}
}
return rslt;
}
/*!
* @brief This API configures the necessary gyro interrupt
* based on the user settings in the bmi088_int_cfg
* structure instance.
*/
uint16_t bmi088_set_gyro_int_config(const struct bmi088_int_cfg *int_config, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
switch (int_config->gyro_int_type)
{
case BMI088_GYRO_DATA_RDY_INT:
{
/* Data ready interrupt */
rslt = set_gyro_data_ready_int(int_config, dev);
}
break;
default:
break;
}
return rslt;
}
/*!
* @brief This API enables or disables the Gyro Self test feature in the
* sensor.
*/
uint16_t bmi088_set_gyro_selftest(uint8_t selftest, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, data = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
/* Check for valid selftest input */
if ((selftest == BMI088_ENABLE) || (selftest == BMI088_DISABLE))
{
reg_addr = BMI088_GYRO_SELF_TEST_REG;
/* Read self test register */
rslt = bmi088_get_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
/* Enable self-test */
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_SELF_TEST_EN, selftest);
/* write self test input value to self-test register */
rslt = bmi088_set_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
}
}
else
{
rslt = BMI088_E_INVALID_INPUT;
}
}
return rslt;
}
/*!
* @brief This API checks whether the self test functionality of the
* gyro sensor is working or not.
*/
uint16_t bmi088_perform_gyro_selftest(int8_t *result, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, data = 0, loop_break = 1;
*result = BMI088_SELFTEST_FAIL;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMI088_OK)
{
/* Enable the gyro self-test */
rslt = bmi088_set_gyro_selftest(BMI088_ENABLE, dev);
if (rslt == BMI088_OK)
{
/* Loop till self-test ready bit is set */
while (loop_break)
{
reg_addr = BMI088_GYRO_SELF_TEST_REG;
/* Read self-test register to check if self-test ready bit is set */
rslt = bmi088_get_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
data = BMI088_GET_BITSLICE(data, BMI088_GYRO_SELF_TEST_RDY);
/* If self-test ready bit is set, exit the loop */
if (data)
{
loop_break = 0;
}
}
else
{
/* Exit the loop in case of communication failure */
loop_break = 0;
}
}
if (rslt == BMI088_OK)
{
/* Read self-test register to check for self-test Ok bit */
rslt = bmi088_get_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
data = BMI088_GET_BITSLICE(data, BMI088_GYRO_SELF_TEST_RESULT);
/* Update the self-test result based on self-test Ok bit */
if (!data)
{
*result = BMI088_SELFTEST_PASS;
}
}
}
}
}
return rslt;
}
/*****************************************************************************/
/* Static function definition */
/*!
* @brief This API is used to validate the device structure pointer for
* null conditions.
*/
static uint16_t null_ptr_check(struct bmi088_dev *dev)
{
uint16_t rslt;
if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL))
{
/* Device structure pointer is not valid */
rslt = BMI088_E_NULL_PTR;
}
else
{
/* Device structure is fine */
rslt = BMI088_OK;
}
return rslt;
}
/*!
* @brief This API sets the data ready interrupt for gyro sensor.
*/
static uint16_t set_gyro_data_ready_int(const struct bmi088_int_cfg *int_config, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMI088_OK) && (int_config != NULL))
{
reg_addr = BMI088_GYRO_INT_CTRL_REG;
/* Data to enable new data ready interrupt */
data = BMI088_GYRO_DRDY_INT_ENABLE_VAL;
/* write data to interrupt control register */
rslt = bmi088_set_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
reg_addr = BMI088_GYRO_INT3_INT4_IO_MAP_REG;
/* update data to map data ready interrupt to appropriate pins */
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_3)
{
data = BMI088_GYRO_MAP_DRDY_TO_INT3;
}
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_4)
{
data = BMI088_GYRO_MAP_DRDY_TO_INT4;
}
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_BOTH)
{
data = BMI088_GYRO_MAP_DRDY_TO_BOTH_INT3_INT4;
}
/* write data to interrupt map register */
rslt = bmi088_set_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
/* Configure interrupt pin */
rslt |= set_int_pin_config(int_config, dev);
}
}
return rslt;
}
/*!
* @brief This API configures the pins which fire the
* interrupt signal when any interrupt occurs.
*/
static uint16_t set_int_pin_config(const struct bmi088_int_cfg *int_config, struct bmi088_dev *dev)
{
uint16_t rslt = BMI088_OK;
uint8_t reg_addr, data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMI088_OK) && (int_config != NULL))
{
reg_addr = BMI088_GYRO_INT3_INT4_IO_CONF_REG;
/* Read interrupt configuration register */
rslt = bmi088_get_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
if (rslt == BMI088_OK)
{
/* Interrupt pin or channel 3 */
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_3)
{
/* Update data with user configured bmi088_int_cfg structure */
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT3_LVL, int_config->gyro_int_pin_3_cfg.lvl);
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT3_OD, int_config->gyro_int_pin_3_cfg.output_mode);
}
/* Interrupt pin or channel 4 */
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_4)
{
/* Update data with user configured bmi088_int_cfg structure */
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT4_LVL, int_config->gyro_int_pin_4_cfg.lvl);
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT4_OD, int_config->gyro_int_pin_4_cfg.output_mode);
}
/* Both Interrupt pins or channels */
if (int_config->gyro_int_channel == BMI088_INT_CHANNEL_BOTH)
{
/* Update data with user configured bmi088_int_cfg structure */
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT3_LVL, int_config->gyro_int_pin_3_cfg.lvl);
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT3_OD, int_config->gyro_int_pin_3_cfg.output_mode);
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT4_LVL, int_config->gyro_int_pin_4_cfg.lvl);
data = BMI088_SET_BITSLICE(data, BMI088_GYRO_INT4_OD, int_config->gyro_int_pin_4_cfg.output_mode);
}
/* write to interrupt configuration register */
rslt = bmi088_set_gyro_regs(reg_addr, &data, BMI088_ONE, dev);
}
}
return rslt;
}
/** @}*/
/**
* Copyright (C) 2015 - 2016 Bosch Sensortec GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility
* for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*
* @file bmi160.c
* @date 6 Apr 2017
* @version 3.4.0
* @brief
*
*/
/*!
* @defgroup bmi160
* @brief
* @{*/
#include "bmi160.h"
/*********************************************************************/
/* Static function declarations */
/*!
* @brief This API configures the pins to fire the
* interrupt signal when it occurs.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_intr_pin_config(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the any-motion interrupt of the sensor.
* This interrupt occurs when accel values exceeds preset threshold
* for a certain period of time.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_any_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev);
/*!
* @brief This API sets tap interrupts.Interrupt is fired when
* tap movements happen.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_tap_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the data ready interrupt for both accel and gyro.
* This interrupt occurs when new accel and gyro data come.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_gyro_data_ready_int(const struct bmi160_int_settg *int_config,
const struct bmi160_dev *dev);
/*!
* @brief This API sets the significant motion interrupt of the sensor.This
* interrupt occurs when there is change in user location.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_sig_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev);
/*!
* @brief This API sets the no motion/slow motion interrupt of the sensor.
* Slow motion is similar to any motion interrupt.No motion interrupt
* occurs when slope bet. two accel values falls below preset threshold
* for preset duration.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_no_motion_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the step detection interrupt.This interrupt
* occurs when the single step causes accel values to go above
* preset threshold.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_step_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the orientation interrupt of the sensor.This
* interrupt occurs when there is orientation change in the sensor
* with respect to gravitational field vector g.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_orientation_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the flat interrupt of the sensor.This interrupt
* occurs in case of flat orientation
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_flat_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the low-g interrupt of the sensor.This interrupt
* occurs during free-fall.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_low_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the high-g interrupt of the sensor.The interrupt
* occurs if the absolute value of acceleration data of any enabled axis
* exceeds the programmed threshold and the sign of the value does not
* change for a preset duration.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_high_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets the default configuration parameters of accel & gyro.
* Also maintain the previous state of configurations.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static void default_param_settg(struct bmi160_dev *dev);
/*!
* @brief This API is used to validate the device structure pointer for
* null conditions.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t null_ptr_check(const struct bmi160_dev *dev);
/*!
* @brief This API set the accel configuration.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_conf(struct bmi160_dev *dev);
/*!
* @brief This API check the accel configuration.
*
* @param[in] data : Pointer to store the updated accel config.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t check_accel_config(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the accel odr.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_accel_odr(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the accel bandwidth.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_accel_bw(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the accel range.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_accel_range(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API checks the invalid settings for ODR & Bw for Accel and Gyro.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t check_invalid_settg(const struct bmi160_dev *dev);
/*!
* @brief This API set the gyro configuration.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_gyro_conf(struct bmi160_dev *dev);
/*!
* @brief This API check the gyro configuration.
*
* @param[in] data : Pointer to store the updated gyro config.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t check_gyro_config(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the gyro odr.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_gyro_odr(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the gyro bandwidth.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_gyro_bw(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API process the gyro range.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_gyro_range(uint8_t *data, const struct bmi160_dev *dev);
/*!
* @brief This API sets the accel power mode.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_accel_pwr(struct bmi160_dev *dev);
/*!
* @brief This API process the undersampling setting of Accel.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t process_under_sampling(uint8_t *data,
const struct bmi160_dev *dev);
/*!
* @brief This API sets the gyro power mode.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t set_gyro_pwr(struct bmi160_dev *dev);
/*!
* @brief This API reads accel data along with sensor time if time is requested
* by user. Kindly refer the user guide(README.md) for more info.
*
* @param[in] len : len to read no of bytes
* @param[out] accel : Structure pointer to store accel data
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t get_accel_data(uint8_t len, struct bmi160_sensor_data *accel, const struct bmi160_dev *dev);
/*!
* @brief This API reads accel data along with sensor time if time is requested
* by user. Kindly refer the user guide(README.md) for more info.
*
* @param[in] len : len to read no of bytes
* @param[out] gyro : Structure pointer to store accel data
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t get_gyro_data(uint8_t len, struct bmi160_sensor_data *gyro, const struct bmi160_dev *dev);
/*!
* @brief This API reads accel and gyro data along with sensor time
* if time is requested by user.
* Kindly refer the user guide(README.md) for more info.
*
* @param[in] len : len to read no of bytes
* @param[out] accel : Structure pointer to store accel data
* @param[out] gyro : Structure pointer to store accel data
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t get_accel_gyro_data(uint8_t len, struct bmi160_sensor_data *accel, struct bmi160_sensor_data *gyro,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the any-motion interrupt for accel.
*
* @param[in] any_motion_int_cfg : Structure instance of
* bmi160_acc_any_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_accel_any_motion_int(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
struct bmi160_dev *dev);
/*!
* @brief This API disable the sig-motion interrupt.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t disable_sig_motion_int(const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to any-motion or
* sig-motion interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_sig_any_motion(
const struct bmi160_int_settg *int_config,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for any-motion interrupt.
*
* @param[in] any_motion_int_cfg : Structure instance of
* bmi160_acc_any_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_any_motion_src(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the duration and threshold of
* any-motion interrupt.
*
* @param[in] any_motion_int_cfg : Structure instance of
* bmi160_acc_any_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_any_dur_threshold(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure necessary setting of any-motion interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] any_motion_int_cfg : Structure instance of
* bmi160_acc_any_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_any_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enable the data ready interrupt.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_data_ready_int(const struct bmi160_dev *dev);
/*!
* @brief This API maps the data ready interrupt to INT pin as per selection.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_data_ready_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API enables the no motion/slow motion interrupt.
*
* @param[in] no_mot_int_cfg : Structure instance of
* bmi160_acc_no_motion_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_no_motion_int(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the interrupt PIN setting for
* no motion/slow motion interrupt.
*
* @param[in] int_config : structure instance of bmi160_int_settg.
* @param[in] no_mot_int_cfg : Structure instance of
* bmi160_acc_no_motion_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_no_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to no motion/slow interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_no_motion(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of interrupt for no motion.
*
* @param[in] no_mot_int_cfg : Structure instance of
* bmi160_acc_no_motion_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_no_motion_data_src(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the duration and threshold of
* no motion/slow motion interrupt along with selection of no/slow motion.
*
* @param[in] no_mot_int_cfg : Structure instance of
* bmi160_acc_no_motion_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_no_motion_dur_thr(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the sig-motion motion interrupt.
*
* @param[in] sig_mot_int_cfg : Structure instance of
* bmi160_acc_sig_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_sig_motion_int(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, struct bmi160_dev *dev);
/*!
* @brief This API configure the interrupt PIN setting for
* significant motion interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] sig_mot_int_cfg : Structure instance of
* bmi160_acc_sig_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_sig_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for sig motion interrupt.
*
* @param[in] sig_mot_int_cfg : Structure instance of
* bmi160_acc_sig_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_sig_motion_data_src(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the threshold, skip and proof time of
* sig motion interrupt.
*
* @param[in] sig_mot_int_cfg : Structure instance of
* bmi160_acc_sig_mot_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_sig_dur_threshold(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the step detector interrupt.
*
* @param[in] step_detect_int_cfg : Structure instance of
* bmi160_acc_step_detect_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_step_detect_int(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to low-g or step detector interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_low_step_detect(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the step detector parameter.
*
* @param[in] step_detect_int_cfg : Structure instance of
* bmi160_acc_step_detect_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_step_detect(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the single/double tap interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_tap_int(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the interrupt PIN setting for
* tap interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_tap_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to single or double tap interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_tap(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for tap interrupt.
*
* @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_tap_data_src(const struct bmi160_acc_tap_int_cfg *tap_int_cfg, const struct bmi160_dev *dev);
/*!
* @brief This API configure the parameters of tap interrupt.
* Threshold, quite, shock, and duration.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_tap_param(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enable the external mode configuration.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_sec_if(const struct bmi160_dev *dev);
/*!
* @brief This API configure the ODR of the auxiliary sensor.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_aux_odr(const struct bmi160_dev *dev);
/*!
* @brief This API maps the actual burst read length set by user.
*
* @param[in] len : Pointer to store the read length.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_read_len(uint16_t *len, const struct bmi160_dev *dev);
/*!
* @brief This API configure the settings of auxiliary sensor.
*
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_aux_settg(const struct bmi160_dev *dev);
/*!
* @brief This API extract the read data from auxiliary sensor.
*
* @param[in] map_len : burst read value.
* @param[in] reg_addr : Address of register to read.
* @param[in] aux_data : Pointer to store the read data.
* @param[in] len : length to read the data.
* @param[in] dev : Structure instance of bmi160_dev.
* @note : Refer user guide for detailed info.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t extract_aux_read(uint16_t map_len, uint8_t reg_addr, uint8_t *aux_data, uint16_t len,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the orient interrupt.
*
* @param[in] orient_int_cfg : Structure instance of bmi160_acc_orient_int_cfg.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_orient_int(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to orientation interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_orient(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the necessary setting of orientation interrupt.
*
* @param[in] orient_int_cfg : Structure instance of bmi160_acc_orient_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_orient_int_settg(const struct bmi160_acc_orient_int_cfg *orient_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the flat interrupt.
*
* @param[in] flat_int : Structure instance of bmi160_acc_flat_detect_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_flat_int(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to flat interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_flat(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the necessary setting of flat interrupt.
*
* @param[in] flat_int : Structure instance of bmi160_acc_flat_detect_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_flat_int_settg(const struct bmi160_acc_flat_detect_int_cfg *flat_int,
const struct bmi160_dev *dev);
/*!
* @brief This API enables the Low-g interrupt.
*
* @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_low_g_int(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of data(filter & pre-filter) for low-g interrupt.
*
* @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_low_g_data_src(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev);
/*!
* @brief This API configure the necessary setting of low-g interrupt.
*
* @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_low_g_int_settg(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev);
/*!
* @brief This API enables the high-g interrupt.
*
* @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_high_g_int(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to High-g interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_high_g(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for high-g interrupt.
*
* @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_high_g_data_src(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the necessary setting of high-g interrupt.
*
* @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_high_g_int_settg(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg,
const struct bmi160_dev *dev);
/*!
* @brief This API configure the behavioural setting of interrupt pin.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_int_out_ctrl(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API configure the mode(input enable, latch or non-latch) of interrupt pin.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t config_int_latch(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets FIFO full interrupt of the sensor.This interrupt
* occurs when the FIFO is full and the next full data sample would cause
* a FIFO overflow, which may delete the old samples.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t set_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This enable the FIFO full interrupt engine.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to FIFO FULL interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_fifo_full(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API sets FIFO watermark interrupt of the sensor.The FIFO
* watermark interrupt is fired, when the FIFO fill level is above a fifo
* watermark.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t set_fifo_watermark_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This enable the FIFO watermark interrupt engine.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t enable_fifo_wtm_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API maps the INT pin to FIFO watermark interrupt.
*
* @param[in] int_config : Structure instance of bmi160_int_settg.
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static int8_t map_int_pin_to_fifo_wtm(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev);
/*!
* @brief This API is used to reset the FIFO related configurations
* in the fifo_frame structure.
*
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void reset_fifo_data_structure(const struct bmi160_dev *dev);
/*!
* @brief This API is used to read number of bytes filled
* currently in FIFO buffer.
*
* @param[in] bytes_to_read : Number of bytes available in FIFO at the
* instant which is obtained from FIFO counter.
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error.
* @retval Any non zero value -> Fail
*
*/
static int8_t get_fifo_byte_counter(uint16_t *bytes_to_read, struct bmi160_dev const *dev);
/*!
* @brief This API is used to compute the number of bytes of accel FIFO data
* which is to be parsed in header-less mode
*
* @param[out] data_index : The start index for parsing data
* @param[out] data_read_length : Number of bytes to be parsed
* @param[in] acc_frame_count : Number of accelerometer frames to be read
* @param[in] dev : Structure instance of bmi160_dev.
*
*/
static void get_accel_len_to_parse(uint16_t *data_index, uint16_t *data_read_length, const uint8_t *acc_frame_count,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data in both header mode and header-less mode.
* It updates the idx value which is used to store the index of
* the current data byte which is parsed.
*
* @param[in,out] acc : structure instance of sensor data
* @param[in,out] idx : Index value of number of bytes parsed
* @param[in,out] acc_idx : Index value of accelerometer data
* (x,y,z axes) frames parsed
* @param[in] frame_info : It consists of either fifo_data_enable
* parameter in header-less mode or
* frame header data in header mode
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_accel_frame(struct bmi160_sensor_data *acc, uint16_t *idx, uint8_t *acc_idx, uint8_t frame_info,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data and store it in the instance of the structure bmi160_sensor_data.
*
* @param[in,out] accel_data : structure instance of sensor data
* @param[in,out] data_start_index : Index value of number of bytes parsed
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_accel_data(struct bmi160_sensor_data *accel_data, uint16_t data_start_index,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data in header mode.
*
* @param[in,out] accel_data : Structure instance of sensor data
* @param[in,out] accel_length : Number of accelerometer frames
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void extract_accel_header_mode(struct bmi160_sensor_data *accel_data, uint8_t *accel_length,
const struct bmi160_dev *dev);
/*!
* @brief This API computes the number of bytes of gyro FIFO data
* which is to be parsed in header-less mode
*
* @param[out] data_index : The start index for parsing data
* @param[out] data_read_length : No of bytes to be parsed from FIFO buffer
* @param[in] gyro_frame_count : Number of Gyro data frames to be read
* @param[in] dev : Structure instance of bmi160_dev.
*/
static void get_gyro_len_to_parse(uint16_t *data_index, uint16_t *data_read_length, const uint8_t *gyro_frame_count,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the gyroscope's data from the
* FIFO data in both header mode and header-less mode.
* It updates the idx value which is used to store the index of
* the current data byte which is parsed.
*
* @param[in,out] gyro : structure instance of sensor data
* @param[in,out] idx : Index value of number of bytes parsed
* @param[in,out] gyro_idx : Index value of gyro data
* (x,y,z axes) frames parsed
* @param[in] frame_info : It consists of either fifo_data_enable
* parameter in header-less mode or
* frame header data in header mode
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_gyro_frame(struct bmi160_sensor_data *gyro, uint16_t *idx, uint8_t *gyro_idx, uint8_t frame_info,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the gyro data from the
* FIFO data and store it in the instance of the structure bmi160_sensor_data.
*
* @param[in,out] gyro_data : structure instance of sensor data
* @param[in,out] data_start_index : Index value of number of bytes parsed
* @param[in] dev : structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_gyro_data(struct bmi160_sensor_data *gyro_data, uint16_t data_start_index,
const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse the gyro data from the
* FIFO data in header mode.
*
* @param[in,out] gyro_data : Structure instance of sensor data
* @param[in,out] gyro_length : Number of gyro frames
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void extract_gyro_header_mode(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length,
const struct bmi160_dev *dev);
/*!
* @brief This API checks the presence of non-valid frames in the read fifo data.
*
* @param[in,out] data_index : The index of the current data to
* be parsed from fifo data
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void check_frame_validity(uint16_t *data_index, const struct bmi160_dev *dev);
/*!
* @brief This API is used to move the data index ahead of the
* current_frame_length parameter when unnecessary FIFO data appears while
* extracting the user specified data.
*
* @param[in,out] data_index : Index of the FIFO data which
* is to be moved ahead of the
* current_frame_length
* @param[in] current_frame_length : Number of bytes in a particular frame
* @param[in] dev : Structure instance of bmi160_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse and store the sensor time from the
* FIFO data in the structure instance dev.
*
* @param[in,out] data_index : Index of the FIFO data which
* has the sensor time.
* @param[in] dev : Structure instance of bma4_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_sensortime_frame(uint16_t *data_index, const struct bmi160_dev *dev);
/*!
* @brief This API is used to parse and store the skipped_frame_count from
* the FIFO data in the structure instance dev.
*
* @param[in,out] data_index : Index of the FIFO data which
* has the skipped frame count.
* @param[in] dev : Structure instance of bma4_dev.
*
* @return Result of API execution status
* @retval zero -> Success / -ve value -> Error
*/
static void unpack_skipped_frame(uint16_t *data_index, const struct bmi160_dev *dev);
/*********************** User function definitions ****************************/
/*!
* @brief This API reads the data from the given register address
* of sensor.
*/
int8_t bmi160_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
/* Null-pointer check */
if ((dev == NULL) || (dev->read == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Configuring reg_addr for SPI Interface */
if (dev->interface == BMI160_SPI_INTF)
reg_addr = (reg_addr | BMI160_SPI_RD_MASK);
rslt = dev->read(dev->id, reg_addr, data, len);
/* Kindly refer section 3.2.4 of data-sheet*/
dev->delay_ms(1);
if (rslt != BMI160_OK)
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
/*!
* @brief This API writes the given data to the register address
* of sensor.
*/
int8_t bmi160_set_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t count = 0;
/* Null-pointer check */
if ((dev == NULL) || (dev->write == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Configuring reg_addr for SPI Interface */
if (dev->interface == BMI160_SPI_INTF)
reg_addr = (reg_addr & BMI160_SPI_WR_MASK);
if ((dev->prev_accel_cfg.power == BMI160_ACCEL_NORMAL_MODE) ||
(dev->prev_gyro_cfg.power == BMI160_GYRO_NORMAL_MODE)) {
rslt = dev->write(dev->id, reg_addr, data, len);
/* Kindly refer section 3.2.4 of data-sheet*/
dev->delay_ms(1);
} else {
/*Burst write is not allowed in
suspend & low power mode */
for (; count < len; count++) {
rslt = dev->write(dev->id, reg_addr, &data[count], 1);
reg_addr++;
/* Kindly refer section 3.2.4 of data-sheet*/
dev->delay_ms(1);
}
}
if (rslt != BMI160_OK)
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
/*!
* @brief This API is the entry point for sensor.It performs
* the selection of I2C/SPI read mechanism according to the
* selected interface and reads the chip-id of bmi160 sensor.
*/
int8_t bmi160_init(struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data;
uint8_t chip_id;
/* Null-pointer check */
rslt = null_ptr_check(dev);
/* Dummy read of 0x7F register to enable SPI Interface
if SPI is used */
if ((rslt == BMI160_OK) && (dev->interface == BMI160_SPI_INTF))
rslt = bmi160_get_regs(BMI160_SPI_COMM_TEST_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
/* Read chip_id */
rslt = bmi160_get_regs(BMI160_CHIP_ID_ADDR, &chip_id, 1, dev);
if ((rslt == BMI160_OK) && (chip_id == BMI160_CHIP_ID)) {
dev->chip_id = chip_id;
dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED;
/*Soft reset*/
rslt = bmi160_soft_reset(dev);
if (rslt == BMI160_OK)
default_param_settg(dev);
} else {
rslt = BMI160_E_DEV_NOT_FOUND;
}
}
return rslt;
}
/*!
* @brief This API resets and restarts the device.
* All register values are overwritten with default parameters.
*/
int8_t bmi160_soft_reset(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = BMI160_SOFT_RESET_CMD;
/* Null-pointer check */
if ((dev == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Reset the device */
rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &data, 1, dev);
dev->delay_ms(BMI160_SOFT_RESET_DELAY_MS);
if ((rslt == BMI160_OK) && (dev->interface == BMI160_SPI_INTF)) {
/* Dummy read of 0x7F register to enable SPI Interface
if SPI is used */
rslt = bmi160_get_regs(BMI160_SPI_COMM_TEST_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configures the power mode, range and bandwidth
* of sensor.
*/
int8_t bmi160_set_sens_conf(struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
/* Null-pointer check */
if ((dev == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = set_accel_conf(dev);
if (rslt == BMI160_OK) {
rslt = set_gyro_conf(dev);
if (rslt == BMI160_OK) {
/* write power mode for accel and gyro */
rslt = bmi160_set_power_mode(dev);
if (rslt == BMI160_OK)
rslt = check_invalid_settg(dev);
}
}
}
return rslt;
}
/*!
* @brief This API sets the power mode of the sensor.
*/
int8_t bmi160_set_power_mode(struct bmi160_dev *dev)
{
int8_t rslt = 0;
/* Null-pointer check */
if ((dev == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = set_accel_pwr(dev);
if (rslt == BMI160_OK)
rslt = set_gyro_pwr(dev);
}
return rslt;
}
/*!
* @brief This API reads sensor data, stores it in
* the bmi160_sensor_data structure pointer passed by the user.
*/
int8_t bmi160_get_sensor_data(uint8_t select_sensor, struct bmi160_sensor_data *accel, struct bmi160_sensor_data *gyro,
const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t time_sel;
uint8_t sen_sel;
uint8_t len = 0;
/*Extract the sensor and time select information*/
sen_sel = select_sensor & BMI160_SEN_SEL_MASK;
time_sel = ((sen_sel & BMI160_TIME_SEL) >> 2);
sen_sel = sen_sel & (BMI160_ACCEL_SEL | BMI160_GYRO_SEL);
if (time_sel == 1)
len = 3;
/* Null-pointer check */
if (dev != NULL) {
switch (sen_sel) {
case BMI160_ACCEL_ONLY:
/* Null-pointer check */
if (accel == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = get_accel_data(len, accel, dev);
break;
case BMI160_GYRO_ONLY:
/* Null-pointer check */
if (gyro == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = get_gyro_data(len, gyro, dev);
break;
case BMI160_BOTH_ACCEL_AND_GYRO:
/* Null-pointer check */
if ((gyro == NULL) || (accel == NULL))
rslt = BMI160_E_NULL_PTR;
else
rslt = get_accel_gyro_data(len, accel, gyro, dev);
break;
default:
rslt = BMI160_E_INVALID_INPUT;
break;
}
} else {
rslt = BMI160_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API configures the necessary interrupt based on
* the user settings in the bmi160_int_settg structure instance.
*/
int8_t bmi160_set_int_config(struct bmi160_int_settg *int_config, struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
switch (int_config->int_type) {
case BMI160_ACC_ANY_MOTION_INT:
/*Any-motion interrupt*/
rslt = set_accel_any_motion_int(int_config, dev);
break;
case BMI160_ACC_SIG_MOTION_INT:
/* Significant motion interrupt */
rslt = set_accel_sig_motion_int(int_config, dev);
break;
case BMI160_ACC_SLOW_NO_MOTION_INT:
/* Slow or no motion interrupt */
rslt = set_accel_no_motion_int(int_config, dev);
break;
case BMI160_ACC_DOUBLE_TAP_INT:
case BMI160_ACC_SINGLE_TAP_INT:
/* Double tap and single tap Interrupt */
rslt = set_accel_tap_int(int_config, dev);
break;
case BMI160_STEP_DETECT_INT:
/* Step detector interrupt */
rslt = set_accel_step_detect_int(int_config, dev);
break;
case BMI160_ACC_ORIENT_INT:
/* Orientation interrupt */
rslt = set_accel_orientation_int(int_config, dev);
break;
case BMI160_ACC_FLAT_INT:
/* Flat detection interrupt */
rslt = set_accel_flat_detect_int(int_config, dev);
break;
case BMI160_ACC_LOW_G_INT:
/* Low-g interrupt */
rslt = set_accel_low_g_int(int_config, dev);
break;
case BMI160_ACC_HIGH_G_INT:
/* High-g interrupt */
rslt = set_accel_high_g_int(int_config, dev);
break;
case BMI160_ACC_GYRO_DATA_RDY_INT:
/* Data ready interrupt */
rslt = set_accel_gyro_data_ready_int(int_config, dev);
break;
case BMI160_ACC_GYRO_FIFO_FULL_INT:
/* Fifo full interrupt */
rslt = set_fifo_full_int(int_config, dev);
break;
case BMI160_ACC_GYRO_FIFO_WATERMARK_INT:
/* Fifo water-mark interrupt */
rslt = set_fifo_watermark_int(int_config, dev);
break;
default:
break;
}
return rslt;
}
/*!
* @brief This API enables or disable the step counter feature.
* 1 - enable step counter (0 - disable)
*/
int8_t bmi160_set_step_counter(uint8_t step_cnt_enable, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt != BMI160_OK) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = bmi160_get_regs(BMI160_INT_STEP_CONFIG_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (step_cnt_enable == BMI160_ENABLE)
data |= (uint8_t)(step_cnt_enable << 3);
else
data &= ~BMI160_STEP_COUNT_EN_BIT_MASK;
rslt = bmi160_set_regs(BMI160_INT_STEP_CONFIG_1_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API reads the step counter value.
*/
int8_t bmi160_read_step_counter(uint16_t *step_val, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data[2] = {0, 0};
uint16_t msb = 0;
uint8_t lsb = 0;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt != BMI160_OK) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = bmi160_get_regs(BMI160_INT_STEP_CNT_0_ADDR, data, 2, dev);
if (rslt == BMI160_OK) {
lsb = data[0];
msb = data[1] << 8;
*step_val = msb | lsb;
}
}
return rslt;
}
/*!
* @brief This API reads the mention no of byte of data from the given
* register address of auxiliary sensor.
*/
int8_t bmi160_aux_read(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
uint16_t map_len = 0;
/* Null-pointer check */
if ((dev == NULL) || (dev->read == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) {
rslt = map_read_len(&map_len, dev);
if (rslt == BMI160_OK)
rslt = extract_aux_read(map_len, reg_addr, aux_data, len, dev);
} else {
rslt = BMI160_E_INVALID_INPUT;
}
}
return rslt;
}
/*!
* @brief This API writes the mention no of byte of data to the given
* register address of auxiliary sensor.
*/
int8_t bmi160_aux_write(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t count = 0;
/* Null-pointer check */
if ((dev == NULL) || (dev->write == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
for (; count < len; count++) {
/* set data to write */
rslt = bmi160_set_regs(BMI160_AUX_IF_4_ADDR, aux_data, 1, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
if (rslt == BMI160_OK) {
/* set address to write */
rslt = bmi160_set_regs(BMI160_AUX_IF_3_ADDR, &reg_addr, 1, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
if (rslt == BMI160_OK && (count < len - 1)) {
aux_data++;
reg_addr++;
}
}
}
}
return rslt;
}
/*!
* @brief This API initialize the auxiliary sensor
* in order to access it.
*/
int8_t bmi160_aux_init(const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt != BMI160_OK) {
rslt = BMI160_E_NULL_PTR;
} else {
if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) {
/* Configures the auxiliary sensor interface settings */
rslt = config_aux_settg(dev);
} else {
rslt = BMI160_E_INVALID_INPUT;
}
}
return rslt;
}
/*!
* @brief This API is used to setup the auxiliary sensor of bmi160 in auto mode
* Thus enabling the auto update of 8 bytes of data from auxiliary sensor
* to BMI160 register address 0x04 to 0x0B
*/
int8_t bmi160_set_aux_auto_mode(uint8_t* data_addr, struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt != BMI160_OK) {
rslt = BMI160_E_NULL_PTR;
} else {
if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) {
/* Write the aux. address to read in 0x4D of BMI160*/
rslt = bmi160_set_regs(BMI160_AUX_IF_2_ADDR, data_addr, 1, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
if (rslt == BMI160_OK) {
/* Disable the aux. manual mode, i.e aux.
sensor is in auto-mode (data-mode) */
dev->aux_cfg.manual_enable = BMI160_DISABLE;
rslt = bmi160_config_aux_mode(dev);
/* Auxiliary sensor data is obtained
in auto mode from this point */
if (rslt == BMI160_OK) {
/* Configure the polling ODR for
auxiliary sensor */
rslt = config_aux_odr(dev);
}
}
} else {
rslt = BMI160_E_INVALID_INPUT;
}
}
return rslt;
}
/*!
* @brief This API configures the 0x4C register and settings like
* Auxiliary sensor manual enable/ disable and aux burst read length.
*/
int8_t bmi160_config_aux_mode(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t aux_if[2] = {(uint8_t)(dev->aux_cfg.aux_i2c_addr * 2), 0};
rslt = bmi160_get_regs(BMI160_AUX_IF_1_ADDR, &aux_if[1], 1, dev);
if (rslt == BMI160_OK) {
/* update the Auxiliary interface to manual/auto mode */
aux_if[1] = BMI160_SET_BITS(aux_if[1], BMI160_MANUAL_MODE_EN , dev->aux_cfg.manual_enable);
/* update the burst read length defined by user */
aux_if[1] = BMI160_SET_BITS_POS_0(aux_if[1], BMI160_AUX_READ_BURST , dev->aux_cfg.aux_rd_burst_len);
/* Set the secondary interface address and manual mode
* along with burst read length */
rslt = bmi160_set_regs(BMI160_AUX_IF_0_ADDR, &aux_if[0], 2, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
}
return rslt;
}
/*!
* @brief This API is used to read the raw uncompensated auxiliary sensor
* data of 8 bytes from BMI160 register address 0x04 to 0x0B
*/
int8_t bmi160_read_aux_data_auto_mode(uint8_t *aux_data, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt != BMI160_OK) {
rslt = BMI160_E_NULL_PTR;
} else {
if ((dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) &&
(dev->aux_cfg.manual_enable == BMI160_DISABLE)) {
/* Read the aux. sensor's raw data */
rslt = bmi160_get_regs(BMI160_AUX_DATA_ADDR, aux_data, 8, dev);
} else {
rslt = BMI160_E_INVALID_INPUT;
}
}
return rslt;
}
/*!
* @brief This API reads the data from fifo buffer.
*/
int8_t bmi160_get_fifo_data(struct bmi160_dev const *dev)
{
int8_t rslt = 0;
uint16_t bytes_to_read = 0;
uint16_t user_fifo_len = 0;
uint8_t addr = BMI160_FIFO_DATA_ADDR;
/* check the bmi160 structure as NULL*/
if (dev == NULL || dev->fifo->data == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
reset_fifo_data_structure(dev);
/* get current FIFO fill-level*/
rslt = get_fifo_byte_counter(&bytes_to_read, dev);
if (rslt == BMI160_OK) {
user_fifo_len = dev->fifo->length;
if (dev->fifo->length > bytes_to_read) {
/* Handling the case where user requests
more data than available in FIFO */
dev->fifo->length = bytes_to_read;
}
if ((dev->fifo->fifo_time_enable == BMI160_FIFO_TIME_ENABLE) && (bytes_to_read + 4 <= user_fifo_len)) {
/* Handling case of sensor time availability */
dev->fifo->length = dev->fifo->length + 4;
}
/* read only the filled bytes in the FIFO Buffer */
rslt = dev->read(dev->id, addr, dev->fifo->data, dev->fifo->length);
}
}
return rslt;
}
/*!
* @brief This API writes fifo_flush command to command register.This
* action clears all data in the Fifo without changing fifo configuration
* settings
*/
int8_t bmi160_set_fifo_flush(const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t data = BMI160_FIFO_FLUSH_VALUE;
uint8_t reg_addr = BMI160_COMMAND_REG_ADDR;
/* Check the bmi160_dev structure for NULL address*/
if (dev == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev);
return rslt;
}
/*! @brief This API sets the FIFO configuration in the sensor.
*
*/
int8_t bmi160_set_fifo_config(uint8_t config, uint8_t enable, struct bmi160_dev const *dev)
{
int8_t rslt = 0;
uint8_t data = 0;
uint8_t reg_addr = BMI160_FIFO_CONFIG_1_ADDR;
uint8_t fifo_config = config & BMI160_FIFO_CONFIG_1_MASK;
/* Check the bmi160_dev structure for NULL address*/
if (dev == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev);
if (rslt == BMI160_OK) {
if (fifo_config > 0) {
if (enable == BMI160_ENABLE)
data = data | fifo_config;
else
data = data & (~fifo_config);
}
/* write fifo frame content configuration*/
rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev);
if (rslt == BMI160_OK) {
/* read fifo frame content configuration*/
rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev);
if (rslt == BMI160_OK) {
/* extract fifo header enabled status */
dev->fifo->fifo_header_enable = data & BMI160_FIFO_HEAD_ENABLE;
/* extract accel/gyr/aux. data enabled status */
dev->fifo->fifo_data_enable = data & BMI160_FIFO_M_G_A_ENABLE;
/* extract fifo sensor time enabled status */
dev->fifo->fifo_time_enable = data & BMI160_FIFO_TIME_ENABLE;
}
}
}
}
return rslt;
}
/*! @brief This API is used to configure the down sampling ratios of
* the accel and gyro data for FIFO.Also, it configures filtered or
* pre-filtered data for accel and gyro.
*
*/
int8_t bmi160_set_fifo_down(uint8_t fifo_down, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t data = 0;
uint8_t reg_addr = BMI160_FIFO_DOWN_ADDR;
/* Check the bmi160_dev structure for NULL address*/
if (dev == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev);
if (rslt == BMI160_OK) {
data = data | fifo_down;
rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev);
}
}
return rslt;
}
/*!
* @brief This API sets the FIFO watermark level in the sensor.
*
*/
int8_t bmi160_set_fifo_wm(uint8_t fifo_wm, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t data = fifo_wm;
uint8_t reg_addr = BMI160_FIFO_CONFIG_0_ADDR;
/* Check the bmi160_dev structure for NULL address*/
if (dev == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev);
return rslt;
}
/*!
* @brief This API parses and extracts the accelerometer frames from
* FIFO data read by the "bmi160_get_fifo_data" API and stores it in
* the "accel_data" structure instance.
*/
int8_t bmi160_extract_accel(struct bmi160_sensor_data *accel_data, uint8_t *accel_length, struct bmi160_dev const *dev)
{
int8_t rslt = 0;
uint16_t data_index = 0;
uint16_t data_read_length = 0;
uint8_t accel_index = 0;
uint8_t fifo_data_enable = 0;
if (dev == NULL || dev->fifo == NULL || dev->fifo->data == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Parsing the FIFO data in header-less mode */
if (dev->fifo->fifo_header_enable == 0) {
/* Number of bytes to be parsed from FIFO */
get_accel_len_to_parse(&data_index, &data_read_length, accel_length, dev);
for (; data_index < data_read_length; ) {
/*Check for the availability of next two bytes of FIFO data */
check_frame_validity(&data_index, dev);
fifo_data_enable = dev->fifo->fifo_data_enable;
unpack_accel_frame(accel_data, &data_index, &accel_index, fifo_data_enable, dev);
}
/* update number of accel data read*/
*accel_length = accel_index;
/*update the accel byte index*/
dev->fifo->accel_byte_start_idx = data_index;
} else {
/* Parsing the FIFO data in header mode */
extract_accel_header_mode(accel_data, &accel_index, dev);
*accel_length = accel_index;
}
}
return rslt;
}
/*!
* @brief This API parses and extracts the gyro frames from
* FIFO data read by the "bmi160_get_fifo_data" API and stores it in
* the "gyro_data" structure instance.
*/
int8_t bmi160_extract_gyro(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length, struct bmi160_dev const *dev)
{
int8_t rslt = 0;
uint16_t data_index = 0;
uint16_t data_read_length = 0;
uint8_t gyro_index = 0;
uint8_t fifo_data_enable = 0;
if (dev == NULL || dev->fifo->data == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Parsing the FIFO data in header-less mode */
if (dev->fifo->fifo_header_enable == 0) {
/* Number of bytes to be parsed from FIFO */
get_gyro_len_to_parse(&data_index, &data_read_length, gyro_length, dev);
for (; data_index < data_read_length ;) {
/*Check for the availability of next two bytes of FIFO data */
check_frame_validity(&data_index, dev);
fifo_data_enable = dev->fifo->fifo_data_enable;
unpack_gyro_frame(gyro_data, &data_index, &gyro_index, fifo_data_enable, dev);
}
/* update number of gyro data read */
*gyro_length = gyro_index;
/* update the gyro byte index */
dev->fifo->gyro_byte_start_idx = data_index;
} else {
/* Parsing the FIFO data in header mode */
extract_gyro_header_mode(gyro_data, &gyro_index, dev);
*gyro_length = gyro_index;
}
}
return rslt;
}
/*********************** Local function definitions ***************************/
/*!
* @brief This API sets the any-motion interrupt of the sensor.
* This interrupt occurs when accel values exceeds preset threshold
* for a certain period of time.
*/
static int8_t set_accel_any_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg = &(int_config->int_type_cfg.acc_any_motion_int);
rslt = enable_accel_any_motion_int(any_motion_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_any_motion_int_settg(int_config, any_motion_int_cfg, dev);
}
return rslt;
}
/*!
* @brief This API sets tap interrupts.Interrupt is fired when
* tap movements happen.
*/
static int8_t set_accel_tap_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_tap_int_cfg *tap_int_cfg = &(int_config->int_type_cfg.acc_tap_int);
rslt = enable_tap_int(int_config, tap_int_cfg, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK)
rslt = config_tap_int_settg(int_config, tap_int_cfg, dev);
}
}
return rslt;
}
/*!
* @brief This API sets the data ready interrupt for both accel and gyro.
* This interrupt occurs when new accel and gyro data comes.
*/
static int8_t set_accel_gyro_data_ready_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
rslt = enable_data_ready_int(dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK)
rslt = map_data_ready_int(int_config, dev);
}
}
return rslt;
}
/*!
* @brief This API sets the significant motion interrupt of the sensor.This
* interrupt occurs when there is change in user location.
*/
static int8_t set_accel_sig_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg = &(int_config->int_type_cfg.acc_sig_motion_int);
rslt = enable_sig_motion_int(sig_mot_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_sig_motion_int_settg(int_config, sig_mot_int_cfg, dev);
}
return rslt;
}
/*!
* @brief This API sets the no motion/slow motion interrupt of the sensor.
* Slow motion is similar to any motion interrupt.No motion interrupt
* occurs when slope bet. two accel values falls below preset threshold
* for preset duration.
*/
static int8_t set_accel_no_motion_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg = &(int_config->int_type_cfg.acc_no_motion_int);
rslt = enable_no_motion_int(no_mot_int_cfg, dev);
if (rslt == BMI160_OK)
/* Configure the INT PIN settings*/
rslt = config_no_motion_int_settg(int_config, no_mot_int_cfg, dev);
}
return rslt;
}
/*!
* @brief This API sets the step detection interrupt.This interrupt
* occurs when the single step causes accel values to go above
* preset threshold.
*/
static int8_t set_accel_step_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg =
&(int_config->int_type_cfg.acc_step_detect_int);
rslt = enable_step_detect_int(step_detect_int_cfg, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
rslt = map_int_pin_to_low_step_detect(int_config, dev);
if (rslt == BMI160_OK)
rslt = config_step_detect(step_detect_int_cfg, dev);
}
}
}
return rslt;
}
/*!
* @brief This API sets the orientation interrupt of the sensor.This
* interrupt occurs when there is orientation change in the sensor
* with respect to gravitational field vector g.
*/
static int8_t set_accel_orientation_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_orient_int_cfg *orient_int_cfg = &(int_config->int_type_cfg.acc_orient_int);
rslt = enable_orient_int(orient_int_cfg, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
/* map INT pin to orient interrupt */
rslt = map_int_pin_to_orient(int_config, dev);
if (rslt == BMI160_OK)
/* configure the
* orientation setting*/
rslt = config_orient_int_settg(orient_int_cfg, dev);
}
}
}
return rslt;
}
/*!
* @brief This API sets the flat interrupt of the sensor.This interrupt
* occurs in case of flat orientation
*/
static int8_t set_accel_flat_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_flat_detect_int_cfg *flat_detect_int = &(int_config->int_type_cfg.acc_flat_int);
/* enable the flat interrupt */
rslt = enable_flat_int(flat_detect_int, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
/* map INT pin to flat interrupt */
rslt = map_int_pin_to_flat(int_config, dev);
if (rslt == BMI160_OK)
/* configure the flat setting*/
rslt = config_flat_int_settg(flat_detect_int, dev);
}
}
}
return rslt;
}
/*!
* @brief This API sets the low-g interrupt of the sensor.This interrupt
* occurs during free-fall.
*/
static int8_t set_accel_low_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_low_g_int_cfg *low_g_int = &(int_config->int_type_cfg.acc_low_g_int);
/* Enable the low-g interrupt*/
rslt = enable_low_g_int (low_g_int, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
/* Map INT pin to low-g interrupt */
rslt = map_int_pin_to_low_step_detect(int_config, dev);
if (rslt == BMI160_OK) {
/* configure the data source
* for low-g interrupt*/
rslt = config_low_g_data_src(low_g_int, dev);
if (rslt == BMI160_OK)
rslt = config_low_g_int_settg(low_g_int, dev);
}
}
}
}
return rslt;
}
/*!
* @brief This API sets the high-g interrupt of the sensor.The interrupt
* occurs if the absolute value of acceleration data of any enabled axis
* exceeds the programmed threshold and the sign of the value does not
* change for a preset duration.
*/
static int8_t set_accel_high_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt != BMI160_OK) || (int_config == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160_acc_high_g_int_cfg *high_g_int_cfg = &(int_config->int_type_cfg.acc_high_g_int);
/* Enable the high-g interrupt */
rslt = enable_high_g_int(high_g_int_cfg, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
/* Map INT pin to high-g interrupt */
rslt = map_int_pin_to_high_g(int_config, dev);
if (rslt == BMI160_OK) {
/* configure the data source
* for high-g interrupt*/
rslt = config_high_g_data_src(high_g_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_high_g_int_settg(high_g_int_cfg, dev);
}
}
}
}
return rslt;
}
/*!
* @brief This API configures the pins to fire the
* interrupt signal when it occurs.
*/
static int8_t set_intr_pin_config(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
/* configure the behavioural settings of interrupt pin */
rslt = config_int_out_ctrl(int_config, dev);
if (rslt == BMI160_OK)
rslt = config_int_latch(int_config, dev);
return rslt;
}
/*!
* @brief This internal API is used to validate the device structure pointer for
* null conditions.
*/
static int8_t null_ptr_check(const struct bmi160_dev *dev)
{
int8_t rslt;
if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Device structure is fine */
rslt = BMI160_OK;
}
return rslt;
}
/*!
* @brief This API sets the default configuration parameters of accel & gyro.
* Also maintain the previous state of configurations.
*/
static void default_param_settg(struct bmi160_dev *dev)
{
/* Initializing accel and gyro params with
* default values */
dev->accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
dev->accel_cfg.odr = BMI160_ACCEL_ODR_100HZ;
dev->accel_cfg.power = BMI160_ACCEL_SUSPEND_MODE;
dev->accel_cfg.range = BMI160_ACCEL_RANGE_2G;
dev->gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
dev->gyro_cfg.odr = BMI160_GYRO_ODR_100HZ;
dev->gyro_cfg.power = BMI160_GYRO_SUSPEND_MODE;
dev->gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS;
/* To maintain the previous state of accel configuration */
dev->prev_accel_cfg = dev->accel_cfg;
/* To maintain the previous state of gyro configuration */
dev->prev_gyro_cfg = dev->gyro_cfg;
}
/*!
* @brief This API set the accel configuration.
*/
static int8_t set_accel_conf(struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data[2] = {0};
rslt = check_accel_config(data, dev);
if (rslt == BMI160_OK) {
/* Write output data rate and bandwidth */
rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, &data[0], 1, dev);
if (rslt == BMI160_OK) {
dev->prev_accel_cfg.odr = dev->accel_cfg.odr;
dev->prev_accel_cfg.bw = dev->accel_cfg.bw;
dev->delay_ms(BMI160_ONE_MS_DELAY);
/* write accel range */
rslt = bmi160_set_regs(BMI160_ACCEL_RANGE_ADDR, &data[1], 1, dev);
if (rslt == BMI160_OK)
dev->prev_accel_cfg.range = dev->accel_cfg.range;
}
}
return rslt;
}
/*!
* @brief This API check the accel configuration.
*/
static int8_t check_accel_config(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt;
/* read accel Output data rate and bandwidth */
rslt = bmi160_get_regs(BMI160_ACCEL_CONFIG_ADDR, data, 2, dev);
if (rslt == BMI160_OK) {
rslt = process_accel_odr(&data[0], dev);
if (rslt == BMI160_OK) {
rslt = process_accel_bw(&data[0], dev);
if (rslt == BMI160_OK)
rslt = process_accel_range(&data[1], dev);
}
}
return rslt;
}
/*!
* @brief This API process the accel odr.
*/
static int8_t process_accel_odr(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t odr = 0;
if (dev->accel_cfg.odr <= BMI160_ACCEL_ODR_MAX) {
if (dev->accel_cfg.odr != dev->prev_accel_cfg.odr) {
odr = (uint8_t)dev->accel_cfg.odr;
temp = *data & ~BMI160_ACCEL_ODR_MASK;
/* Adding output data rate */
*data = temp | (odr & BMI160_ACCEL_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API process the accel bandwidth.
*/
static int8_t process_accel_bw(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t bw = 0;
if (dev->accel_cfg.bw <= BMI160_ACCEL_BW_MAX) {
if (dev->accel_cfg.bw != dev->prev_accel_cfg.bw) {
bw = (uint8_t)dev->accel_cfg.bw;
temp = *data & ~BMI160_ACCEL_BW_MASK;
/* Adding bandwidth */
*data = temp | ((bw << 4) & BMI160_ACCEL_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API process the accel range.
*/
static int8_t process_accel_range(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t range = 0;
if (dev->accel_cfg.range <= BMI160_ACCEL_RANGE_MAX) {
if (dev->accel_cfg.range != dev->prev_accel_cfg.range) {
range = (uint8_t)dev->accel_cfg.range;
temp = *data & ~BMI160_ACCEL_RANGE_MASK;
/* Adding range */
*data = temp | (range & BMI160_ACCEL_RANGE_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API checks the invalid settings for ODR & Bw for
* Accel and Gyro.
*/
static int8_t check_invalid_settg(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
/* read the error reg */
rslt = bmi160_get_regs(BMI160_ERROR_REG_ADDR, &data, 1, dev);
data = data >> 1;
data = data & BMI160_ERR_REG_MASK;
if (data == 1)
rslt = BMI160_E_ACCEL_ODR_BW_INVALID;
else if (data == 2)
rslt = BMI160_E_GYRO_ODR_BW_INVALID;
else if (data == 3)
rslt = BMI160_E_LWP_PRE_FLTR_INT_INVALID;
else if (data == 7)
rslt = BMI160_E_LWP_PRE_FLTR_INVALID;
return rslt;
}
static int8_t set_gyro_conf(struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data[2] = {0};
rslt = check_gyro_config(data, dev);
if (rslt == BMI160_OK) {
/* Write output data rate and bandwidth */
rslt = bmi160_set_regs(BMI160_GYRO_CONFIG_ADDR, &data[0], 1, dev);
if (rslt == BMI160_OK) {
dev->prev_gyro_cfg.odr = dev->gyro_cfg.odr;
dev->prev_gyro_cfg.bw = dev->gyro_cfg.bw;
dev->delay_ms(BMI160_ONE_MS_DELAY);
/* Write gyro range */
rslt = bmi160_set_regs(BMI160_GYRO_RANGE_ADDR, &data[1], 1, dev);
if (rslt == BMI160_OK)
dev->prev_gyro_cfg.range = dev->gyro_cfg.range;
}
}
return rslt;
}
/*!
* @brief This API check the gyro configuration.
*/
static int8_t check_gyro_config(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt;
/* read gyro Output data rate and bandwidth */
rslt = bmi160_get_regs(BMI160_GYRO_CONFIG_ADDR, data, 2, dev);
if (rslt == BMI160_OK) {
rslt = process_gyro_odr(&data[0], dev);
if (rslt == BMI160_OK) {
rslt = process_gyro_bw(&data[0], dev);
if (rslt == BMI160_OK)
rslt = process_gyro_range(&data[1], dev);
}
}
return rslt;
}
/*!
* @brief This API process the gyro odr.
*/
static int8_t process_gyro_odr(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t odr = 0;
if (dev->gyro_cfg.odr <= BMI160_GYRO_ODR_MAX) {
if (dev->gyro_cfg.odr != dev->prev_gyro_cfg.odr) {
odr = (uint8_t)dev->gyro_cfg.odr;
temp = (*data & ~BMI160_GYRO_ODR_MASK);
/* Adding output data rate */
*data = temp | (odr & BMI160_GYRO_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API process the gyro bandwidth.
*/
static int8_t process_gyro_bw(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t bw = 0;
if (dev->gyro_cfg.bw <= BMI160_GYRO_BW_MAX) {
bw = (uint8_t)dev->gyro_cfg.bw;
temp = *data & ~BMI160_GYRO_BW_MASK;
/* Adding bandwidth */
*data = temp | ((bw << 4) & BMI160_GYRO_BW_MASK);
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API process the gyro range.
*/
static int8_t process_gyro_range(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t range = 0;
if (dev->gyro_cfg.range <= BMI160_GYRO_RANGE_MAX) {
if (dev->gyro_cfg.range != dev->prev_gyro_cfg.range) {
range = (uint8_t)dev->gyro_cfg.range;
temp = *data & ~BMI160_GYRO_RANGE_MSK;
/* Adding range */
*data = temp | (range & BMI160_GYRO_RANGE_MSK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API sets the accel power.
*/
static int8_t set_accel_pwr(struct bmi160_dev *dev)
{
int8_t rslt = 0;
uint8_t data = 0;
if ((dev->accel_cfg.power >= BMI160_ACCEL_SUSPEND_MODE) &&
(dev->accel_cfg.power <= BMI160_ACCEL_LOWPOWER_MODE)) {
if (dev->accel_cfg.power != dev->prev_accel_cfg.power) {
rslt = process_under_sampling(&data, dev);
if (rslt == BMI160_OK) {
/* Write accel power */
rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &dev->accel_cfg.power, 1, dev);
/* Add delay of 5 ms */
if (dev->prev_accel_cfg.power == BMI160_ACCEL_SUSPEND_MODE)
dev->delay_ms(BMI160_ACCEL_DELAY_MS);
dev->prev_accel_cfg.power = dev->accel_cfg.power;
}
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API process the undersampling setting of Accel.
*/
static int8_t process_under_sampling(uint8_t *data, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t pre_filter = 0;
rslt = bmi160_get_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
if (rslt == BMI160_OK) {
if (dev->accel_cfg.power == BMI160_ACCEL_LOWPOWER_MODE) {
temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK;
/* Set under-sampling parameter */
*data = temp | ((1 << 7) & BMI160_ACCEL_UNDERSAMPLING_MASK);
/* Write data */
rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
/* disable the pre-filter data in
* low power mode */
if (rslt == BMI160_OK)
/* Disable the Pre-filter data*/
rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &pre_filter, 2, dev);
} else {
if (*data & BMI160_ACCEL_UNDERSAMPLING_MASK) {
temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK;
/* disable under-sampling parameter
if already enabled */
*data = temp | 0x7F;
/* Write data */
rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
}
}
}
return rslt;
}
/*!
* @brief This API sets the gyro power mode.
*/
static int8_t set_gyro_pwr(struct bmi160_dev *dev)
{
int8_t rslt = 0;
if ((dev->gyro_cfg.power == BMI160_GYRO_SUSPEND_MODE) || (dev->gyro_cfg.power == BMI160_GYRO_NORMAL_MODE)
|| (dev->gyro_cfg.power == BMI160_GYRO_FASTSTARTUP_MODE)) {
if (dev->gyro_cfg.power != dev->prev_gyro_cfg.power) {
/* Write gyro power */
rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &dev->gyro_cfg.power, 1, dev);
if (dev->prev_gyro_cfg.power ==
BMI160_GYRO_SUSPEND_MODE) {
/* Delay of 81 ms */
dev->delay_ms(BMI160_GYRO_DELAY_MS);
} else if ((dev->prev_gyro_cfg.power == BMI160_GYRO_FASTSTARTUP_MODE)
&& (dev->accel_cfg.power == BMI160_GYRO_NORMAL_MODE)) {
/* This delay is required for transition from
fast-startup mode to normal mode */
dev->delay_ms(10);
} else {
/* do nothing */
}
dev->prev_gyro_cfg.power = dev->gyro_cfg.power;
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
/*!
* @brief This API reads accel data along with sensor time if time is requested
* by user. Kindly refer the user guide(README.md) for more info.
*/
static int8_t get_accel_data(uint8_t len, struct bmi160_sensor_data *accel, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[9] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
int16_t msblsb;
/* read accel sensor data along with time if requested */
rslt = bmi160_get_regs(BMI160_ACCEL_DATA_ADDR, data_array, 6 + len, dev);
if (rslt == BMI160_OK) {
/* Accel Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->x = msblsb; /* Data in X axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->y = msblsb; /* Data in Y axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->z = msblsb; /* Data in Z axis */
if (len == 3) {
time_0 = data_array[idx++];
time_1 = (uint16_t)(data_array[idx++] << 8);
time_2 = (uint32_t)(data_array[idx++] << 16);
accel->sensortime = (uint32_t)(time_2 | time_1 | time_0);
} else {
accel->sensortime = 0;
}
} else {
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
/*!
* @brief This API reads accel data along with sensor time if time is requested
* by user. Kindly refer the user guide(README.md) for more info.
*/
static int8_t get_gyro_data(uint8_t len, struct bmi160_sensor_data *gyro, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[15] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
int16_t msblsb;
if (len == 0) {
/* read gyro data only */
rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 6, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* Data in X axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* Data in Y axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* Data in Z axis */
gyro->sensortime = 0;
} else {
rslt = BMI160_E_COM_FAIL;
}
} else {
/* read gyro sensor data along with time */
rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* gyro X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* gyro Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* gyro Z axis data */
idx = idx + 6;
time_0 = data_array[idx++];
time_1 = (uint16_t)(data_array[idx++] << 8);
time_2 = (uint32_t)(data_array[idx++] << 16);
gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0);
} else {
rslt = BMI160_E_COM_FAIL;
}
}
return rslt;
}
/*!
* @brief This API reads accel and gyro data along with sensor time
* if time is requested by user.
* Kindly refer the user guide(README.md) for more info.
*/
static int8_t get_accel_gyro_data(uint8_t len, struct bmi160_sensor_data *accel, struct bmi160_sensor_data *gyro,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[15] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
int16_t msblsb;
/* read both accel and gyro sensor data
* along with time if requested */
rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* gyro X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* gyro Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* gyro Z axis data */
/* Accel Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->x = (int16_t)msblsb; /* accel X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->y = (int16_t)msblsb; /* accel Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->z = (int16_t)msblsb; /* accel Z axis data */
if (len == 3) {
time_0 = data_array[idx++];
time_1 = (uint16_t)(data_array[idx++] << 8);
time_2 = (uint32_t)(data_array[idx++] << 16);
accel->sensortime = (uint32_t)(time_2 | time_1 | time_0);
gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0);
} else {
accel->sensortime = 0;
gyro->sensortime = 0;
}
} else {
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
/*!
* @brief This API enables the any-motion interrupt for accel.
*/
static int8_t enable_accel_any_motion_int(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable any motion x, any motion y, any motion z
in Int Enable 0 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (any_motion_int_cfg->anymotion_en == BMI160_ENABLE) {
temp = data & ~BMI160_ANY_MOTION_X_INT_EN_MASK;
/* Adding Any_motion x axis */
data = temp | (any_motion_int_cfg->anymotion_x & BMI160_ANY_MOTION_X_INT_EN_MASK);
temp = data & ~BMI160_ANY_MOTION_Y_INT_EN_MASK;
/* Adding Any_motion y axis */
data = temp | ((any_motion_int_cfg->anymotion_y << 1) & BMI160_ANY_MOTION_Y_INT_EN_MASK);
temp = data & ~BMI160_ANY_MOTION_Z_INT_EN_MASK;
/* Adding Any_motion z axis */
data = temp | ((any_motion_int_cfg->anymotion_z << 2) & BMI160_ANY_MOTION_Z_INT_EN_MASK);
/* any-motion feature selected*/
dev->any_sig_sel = BMI160_ANY_MOTION_ENABLED;
} else {
data = data & ~BMI160_ANY_MOTION_ALL_INT_EN_MASK;
/* neither any-motion feature nor sig-motion selected */
dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED;
}
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API disable the sig-motion interrupt.
*/
static int8_t disable_sig_motion_int(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Disabling Significant motion interrupt if enabled */
rslt = bmi160_get_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = (data & BMI160_SIG_MOTION_SEL_MASK);
if (temp) {
temp = data & ~BMI160_SIG_MOTION_SEL_MASK;
data = temp;
/* Write data to register */
rslt = bmi160_set_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API maps the INT pin to any-motion or
* sig-motion interrupt.
*/
static int8_t map_int_pin_to_sig_any_motion(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int Map register to map interrupt pin to
Slope/Any motion interrupt */
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_SLOPE_MASK;
data = temp | ((1 << 2) & BMI160_INT1_SLOPE_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_SLOPE_MASK;
data = temp | ((1 << 2) & BMI160_INT2_SLOPE_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for any-motion interrupt.
*/
static int8_t config_any_motion_src(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 1 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_MOTION_SRC_INT_MASK;
data = temp | ((any_motion_int_cfg->anymotion_data_src << 7) & BMI160_MOTION_SRC_INT_MASK);
/* Write data to DATA 1 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the duration and threshold of
* any-motion interrupt.
*/
static int8_t config_any_dur_threshold(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
uint8_t data_array[2] = {0};
uint8_t dur;
/* Configure Int Motion 0 register */
rslt = bmi160_get_regs(BMI160_INT_MOTION_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
/* slope duration */
dur = (uint8_t)any_motion_int_cfg->anymotion_dur;
temp = data & ~BMI160_SLOPE_INT_DUR_MASK;
data = temp | (dur & BMI160_MOTION_SRC_INT_MASK);
data_array[0] = data;
/* add slope threshold */
data_array[1] = any_motion_int_cfg->anymotion_thr;
/* INT MOTION 0 and INT MOTION 1 address lie consecutively,
hence writing data to respective registers at one go */
/* Writing to Int_motion 0 and
Int_motion 1 Address simultaneously */
rslt = bmi160_set_regs(BMI160_INT_MOTION_0_ADDR, data_array, 2, dev);
}
return rslt;
}
/*!
* @brief This API configure necessary setting of any-motion interrupt.
*/
static int8_t config_any_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
rslt = disable_sig_motion_int(dev);
if (rslt == BMI160_OK) {
rslt = map_int_pin_to_sig_any_motion(int_config, dev);
if (rslt == BMI160_OK) {
rslt = config_any_motion_src(any_motion_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_any_dur_threshold(any_motion_int_cfg, dev);
}
}
}
return rslt;
}
/*!
* @brief This API enable the data ready interrupt.
*/
static int8_t enable_data_ready_int(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable data ready interrupt in Int Enable 1 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_DATA_RDY_INT_EN_MASK;
data = temp | ((1 << 4) & BMI160_DATA_RDY_INT_EN_MASK);
/* Writing data to INT ENABLE 1 Address */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the data ready interrupt to INT pin as per selection.
*/
static int8_t map_data_ready_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Map register to map interrupt pin to data ready interrupt*/
rslt = bmi160_get_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
temp = data & ~BMI160_INT1_DATA_READY_MASK;
data = temp | ((1 << 7) & BMI160_INT1_DATA_READY_MASK);
} else {
temp = data & ~BMI160_INT2_DATA_READY_MASK;
data = temp | ((1 << 3) & BMI160_INT2_DATA_READY_MASK);
}
/* Writing data to Map 1 address */
rslt = bmi160_set_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API enables the no motion/slow motion interrupt.
*/
static int8_t enable_no_motion_int(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable no motion x, no motion y, no motion z
in Int Enable 2 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (no_mot_int_cfg->no_motion_x == 1) {
temp = data & ~BMI160_NO_MOTION_X_INT_EN_MASK;
/* Adding No_motion x axis */
data = temp | (1 & BMI160_NO_MOTION_X_INT_EN_MASK);
}
if (no_mot_int_cfg->no_motion_y == 1) {
temp = data & ~BMI160_NO_MOTION_Y_INT_EN_MASK;
/* Adding No_motion x axis */
data = temp | ((1 << 1) & BMI160_NO_MOTION_Y_INT_EN_MASK);
}
if (no_mot_int_cfg->no_motion_z == 1) {
temp = data & ~BMI160_NO_MOTION_Z_INT_EN_MASK;
/* Adding No_motion x axis */
data = temp | ((1 << 2) & BMI160_NO_MOTION_Z_INT_EN_MASK);
}
/* write data to Int Enable 2 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the interrupt PIN setting for
* no motion/slow motion interrupt.
*/
static int8_t config_no_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
rslt = map_int_pin_to_no_motion(int_config, dev);
if (rslt == BMI160_OK) {
rslt = config_no_motion_data_src(no_mot_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_no_motion_dur_thr(no_mot_int_cfg, dev);
}
}
return rslt;
}
/*!
* @brief This API maps the INT pin to no motion/slow interrupt.
*/
static int8_t map_int_pin_to_no_motion(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data = 0;
/* Configure Int Map register to map interrupt pin
* to No motion interrupt */
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_NO_MOTION_MASK;
data = temp | ((1 << 3) & BMI160_INT1_NO_MOTION_MASK);
/* Write data to appropriate MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_NO_MOTION_MASK;
data = temp | ((1 << 3) & BMI160_INT2_NO_MOTION_MASK);
/* Write data to appropriate MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the source of interrupt for no motion.
*/
static int8_t config_no_motion_data_src(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 1 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_MOTION_SRC_INT_MASK;
data = temp | ((no_mot_int_cfg->no_motion_src << 7) & BMI160_MOTION_SRC_INT_MASK);
/* Write data to DATA 1 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the duration and threshold of
* no motion/slow motion interrupt along with selection of no/slow motion.
*/
static int8_t config_no_motion_dur_thr(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
uint8_t temp_1 = 0;
uint8_t reg_addr;
uint8_t data_array[2] = {0};
/* Configuring INT_MOTION register */
reg_addr = BMI160_INT_MOTION_0_ADDR;
rslt = bmi160_get_regs(reg_addr, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_NO_MOTION_INT_DUR_MASK;
/* Adding no_motion duration */
data = temp | ((no_mot_int_cfg->no_motion_dur << 2) & BMI160_NO_MOTION_INT_DUR_MASK);
/* Write data to NO_MOTION 0 address */
rslt = bmi160_set_regs(reg_addr, &data, 1, dev);
if (rslt == BMI160_OK) {
reg_addr = BMI160_INT_MOTION_3_ADDR;
rslt = bmi160_get_regs(reg_addr, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_NO_MOTION_SEL_BIT_MASK;
/* Adding no_motion_sel bit */
temp_1 = (no_mot_int_cfg->no_motion_sel & BMI160_NO_MOTION_SEL_BIT_MASK);
data = (temp | temp_1);
data_array[1] = data;
/* Adding no motion threshold */
data_array[0] = no_mot_int_cfg->no_motion_thres;
reg_addr = BMI160_INT_MOTION_2_ADDR;
/* writing data to INT_MOTION 2 and INT_MOTION 3
* address simultaneously */
rslt = bmi160_set_regs(reg_addr, data_array, 2, dev);
}
}
}
return rslt;
}
/*!
* @brief This API enables the sig-motion motion interrupt.
*/
static int8_t enable_sig_motion_int(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* For significant motion,enable any motion x,any motion y,
* any motion z in Int Enable 0 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (sig_mot_int_cfg->sig_en == BMI160_ENABLE) {
temp = data & ~BMI160_SIG_MOTION_INT_EN_MASK;
data = temp | (7 & BMI160_SIG_MOTION_INT_EN_MASK);
/* sig-motion feature selected*/
dev->any_sig_sel = BMI160_SIG_MOTION_ENABLED;
} else {
data = data & ~BMI160_SIG_MOTION_INT_EN_MASK;
/* neither any-motion feature nor sig-motion selected */
dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED;
}
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the interrupt PIN setting for
* significant motion interrupt.
*/
static int8_t config_sig_motion_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
rslt = map_int_pin_to_sig_any_motion(int_config, dev);
if (rslt == BMI160_OK) {
rslt = config_sig_motion_data_src(sig_mot_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_sig_dur_threshold(sig_mot_int_cfg, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for sig motion interrupt.
*/
static int8_t config_sig_motion_data_src(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 1 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_MOTION_SRC_INT_MASK;
data = temp | ((sig_mot_int_cfg->sig_data_src << 7) & BMI160_MOTION_SRC_INT_MASK);
/* Write data to DATA 1 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the threshold, skip and proof time of
* sig motion interrupt.
*/
static int8_t config_sig_dur_threshold(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data;
uint8_t temp = 0;
/* Configuring INT_MOTION registers */
/* Write significant motion threshold.
* This threshold is same as any motion threshold */
data = sig_mot_int_cfg->sig_mot_thres;
/* Write data to INT_MOTION 1 address */
rslt = bmi160_set_regs(BMI160_INT_MOTION_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
rslt = bmi160_get_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_SIG_MOTION_SKIP_MASK;
/* adding skip time of sig_motion interrupt*/
data = temp | ((sig_mot_int_cfg->sig_mot_skip << 2) & BMI160_SIG_MOTION_SKIP_MASK);
temp = data & ~BMI160_SIG_MOTION_PROOF_MASK;
/* adding proof time of sig_motion interrupt */
data = temp | ((sig_mot_int_cfg->sig_mot_proof << 4) & BMI160_SIG_MOTION_PROOF_MASK);
/* configure the int_sig_mot_sel bit to select
* significant motion interrupt */
temp = data & ~BMI160_SIG_MOTION_SEL_MASK;
data = temp | ((sig_mot_int_cfg->sig_en << 1) & BMI160_SIG_MOTION_SEL_MASK);
rslt = bmi160_set_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API enables the step detector interrupt.
*/
static int8_t enable_step_detect_int(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable data ready interrupt in Int Enable 2 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_STEP_DETECT_INT_EN_MASK;
data = temp | ((step_detect_int_cfg->step_detector_en << 3) & BMI160_STEP_DETECT_INT_EN_MASK);
/* Writing data to INT ENABLE 2 Address */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to low-g or step detector interrupt.
*/
static int8_t map_int_pin_to_low_step_detect(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int Map register to map interrupt pin to step detector */
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_LOW_STEP_DETECT_MASK;
data = temp | (1 & BMI160_INT1_LOW_STEP_DETECT_MASK);
/* Write data to MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_LOW_STEP_DETECT_MASK;
data = temp | (1 & BMI160_INT2_LOW_STEP_DETECT_MASK);
/* Write data to MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the step detector parameter.
*/
static int8_t config_step_detect(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data_array[2] = {0};
if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_NORMAL) {
/* Normal mode setting */
data_array[0] = 0x15;
data_array[1] = 0x03;
} else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_SENSITIVE) {
/* Sensitive mode setting */
data_array[0] = 0x2D;
data_array[1] = 0x00;
} else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_ROBUST) {
/* Robust mode setting */
data_array[0] = 0x1D;
data_array[1] = 0x07;
} else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_USER_DEFINE) {
/* Non recommended User defined setting */
/* Configuring STEP_CONFIG register */
rslt = bmi160_get_regs(BMI160_INT_STEP_CONFIG_0_ADDR, &data_array[0], 2, dev);
if (rslt == BMI160_OK) {
temp = data_array[0] & ~BMI160_STEP_DETECT_MIN_THRES_MASK;
/* Adding min_threshold */
data_array[0] = temp | ((step_detect_int_cfg->min_threshold << 3)
& BMI160_STEP_DETECT_MIN_THRES_MASK);
temp = data_array[0] & ~BMI160_STEP_DETECT_STEPTIME_MIN_MASK;
/* Adding steptime_min */
data_array[0] = temp | ((step_detect_int_cfg->steptime_min)
& BMI160_STEP_DETECT_STEPTIME_MIN_MASK);
temp = data_array[1] & ~BMI160_STEP_MIN_BUF_MASK;
/* Adding steptime_min */
data_array[1] = temp | ((step_detect_int_cfg->step_min_buf) & BMI160_STEP_MIN_BUF_MASK);
}
}
/* Write data to STEP_CONFIG register */
rslt = bmi160_set_regs(BMI160_INT_STEP_CONFIG_0_ADDR, data_array, 2, dev);
return rslt;
}
/*!
* @brief This API enables the single/double tap interrupt.
*/
static int8_t enable_tap_int(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable single tap or double tap interrupt in Int Enable 0 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_type == BMI160_ACC_SINGLE_TAP_INT) {
temp = data & ~BMI160_SINGLE_TAP_INT_EN_MASK;
data = temp | ((tap_int_cfg->tap_en << 5) & BMI160_SINGLE_TAP_INT_EN_MASK);
} else {
temp = data & ~BMI160_DOUBLE_TAP_INT_EN_MASK;
data = temp | ((tap_int_cfg->tap_en << 4) & BMI160_DOUBLE_TAP_INT_EN_MASK);
}
/* Write to Enable 0 Address */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the interrupt PIN setting for
* tap interrupt.
*/
static int8_t config_tap_int_settg(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK) {
rslt = map_int_pin_to_tap(int_config, dev);
if (rslt == BMI160_OK) {
rslt = config_tap_data_src(tap_int_cfg, dev);
if (rslt == BMI160_OK)
rslt = config_tap_param(int_config, tap_int_cfg, dev);
}
}
return rslt;
}
/*!
* @brief This API maps the INT pin to single or double tap interrupt.
*/
static int8_t map_int_pin_to_tap(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Map register to map interrupt pin to
single or double tap interrupt*/
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_type == BMI160_ACC_SINGLE_TAP_INT) {
temp = data & ~BMI160_INT1_SINGLE_TAP_MASK;
data = temp | ((1 << 5) & BMI160_INT1_SINGLE_TAP_MASK);
} else {
temp = data & ~BMI160_INT1_DOUBLE_TAP_MASK;
data = temp | ((1 << 4) & BMI160_INT1_DOUBLE_TAP_MASK);
}
}
/* Write data to MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_type == BMI160_ACC_SINGLE_TAP_INT) {
temp = data & ~BMI160_INT2_SINGLE_TAP_MASK;
data = temp | ((1 << 5) & BMI160_INT2_SINGLE_TAP_MASK);
} else {
temp = data & ~BMI160_INT2_DOUBLE_TAP_MASK;
data = temp | ((1 << 4) & BMI160_INT2_DOUBLE_TAP_MASK);
}
}
/* Write data to MAP address */
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for tap interrupt.
*/
static int8_t config_tap_data_src(const struct bmi160_acc_tap_int_cfg *tap_int_cfg, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 0 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_TAP_SRC_INT_MASK;
data = temp | ((tap_int_cfg->tap_data_src << 3) & BMI160_TAP_SRC_INT_MASK);
/* Write data to Data 0 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the parameters of tap interrupt.
* Threshold, quite, shock, and duration.
*/
static int8_t config_tap_param(const struct bmi160_int_settg *int_config,
const struct bmi160_acc_tap_int_cfg *tap_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data = 0;
uint8_t data_array[2] = {0};
uint8_t count = 0;
uint8_t dur, shock, quiet, thres;
/* Configure tap 0 register for tap shock,tap quiet duration
* in case of single tap interrupt */
rslt = bmi160_get_regs(BMI160_INT_TAP_0_ADDR, data_array, 2, dev);
if (rslt == BMI160_OK) {
data = data_array[count];
if (int_config->int_type == BMI160_ACC_DOUBLE_TAP_INT) {
dur = (uint8_t)tap_int_cfg->tap_dur;
temp = (data & ~BMI160_TAP_DUR_MASK);
/* Add tap duration data in case of
* double tap interrupt */
data = temp | (dur & BMI160_TAP_DUR_MASK);
}
shock = (uint8_t)tap_int_cfg->tap_shock;
temp = data & ~BMI160_TAP_SHOCK_DUR_MASK;
data = temp | ((shock << 6) & BMI160_TAP_SHOCK_DUR_MASK);
quiet = (uint8_t)tap_int_cfg->tap_quiet;
temp = data & ~BMI160_TAP_QUIET_DUR_MASK;
data = temp | ((quiet << 7) & BMI160_TAP_QUIET_DUR_MASK);
data_array[count++] = data;
data = data_array[count];
thres = (uint8_t)tap_int_cfg->tap_thr;
temp = data & ~BMI160_TAP_THRES_MASK;
data = temp | (thres & BMI160_TAP_THRES_MASK);
data_array[count++] = data;
/* TAP 0 and TAP 1 address lie consecutively,
hence writing data to respective registers at one go */
/* Writing to Tap 0 and Tap 1 Address simultaneously */
rslt = bmi160_set_regs(BMI160_INT_TAP_0_ADDR, data_array, count, dev);
}
return rslt;
}
/*!
* @brief This API configure the secondary interface.
*/
static int8_t config_sec_if(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t if_conf = 0;
uint8_t cmd = BMI160_AUX_NORMAL_MODE;
/* set the aux power mode to normal*/
rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &cmd, 1, dev);
if (rslt == BMI160_OK) {
rslt = bmi160_get_regs(BMI160_IF_CONF_ADDR, &if_conf, 1, dev);
if_conf |= (uint8_t)(1 << 5);
if (rslt == BMI160_OK)
/*enable the secondary interface also*/
rslt = bmi160_set_regs(BMI160_IF_CONF_ADDR, &if_conf, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the ODR of the auxiliary sensor.
*/
static int8_t config_aux_odr(const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t aux_odr;
rslt = bmi160_get_regs(BMI160_AUX_ODR_ADDR, &aux_odr, 1, dev);
if (rslt == BMI160_OK) {
aux_odr = (uint8_t)(dev->aux_cfg.aux_odr);
/* Set the secondary interface ODR
i.e polling rate of secondary sensor */
rslt = bmi160_set_regs(BMI160_AUX_ODR_ADDR, &aux_odr, 1, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
}
return rslt;
}
/*!
* @brief This API maps the actual burst read length set by user.
*/
static int8_t map_read_len(uint16_t *len, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
switch (dev->aux_cfg.aux_rd_burst_len) {
case BMI160_AUX_READ_LEN_0:
*len = 1;
break;
case BMI160_AUX_READ_LEN_1:
*len = 2;
break;
case BMI160_AUX_READ_LEN_2:
*len = 6;
break;
case BMI160_AUX_READ_LEN_3:
*len = 8;
break;
default:
rslt = BMI160_E_INVALID_INPUT;
break;
}
return rslt;
}
/*!
* @brief This API configure the settings of auxiliary sensor.
*/
static int8_t config_aux_settg(const struct bmi160_dev *dev)
{
int8_t rslt;
rslt = config_sec_if(dev);
if (rslt == BMI160_OK) {
/* Configures the auxiliary interface settings */
rslt = bmi160_config_aux_mode(dev);
}
return rslt;
}
/*!
* @brief This API extract the read data from auxiliary sensor.
*/
static int8_t extract_aux_read(uint16_t map_len, uint8_t reg_addr, uint8_t *aux_data, uint16_t len,
const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t data[8] = {0,};
uint8_t read_addr = BMI160_AUX_DATA_ADDR;
uint8_t count = 0;
uint8_t read_count;
uint8_t read_len = (uint8_t)map_len;
for (; count < len;) {
/* set address to read */
rslt = bmi160_set_regs(BMI160_AUX_IF_2_ADDR, &reg_addr, 1, dev);
dev->delay_ms(BMI160_AUX_COM_DELAY);
if (rslt == BMI160_OK) {
rslt = bmi160_get_regs(read_addr, data, map_len, dev);
if (rslt == BMI160_OK) {
read_count = 0;
/* if read len is less the burst read len
* mention by user*/
if (len < map_len) {
read_len = (uint8_t)len;
} else {
if ((len - count) < map_len)
read_len = (uint8_t)(len - count);
}
for (; read_count < read_len; read_count++)
aux_data[count + read_count] = data[read_count];
reg_addr += (uint8_t)map_len;
count += (uint8_t)map_len;
} else {
rslt = BMI160_E_COM_FAIL;
break;
}
}
}
return rslt;
}
/*!
* @brief This API enables the orient interrupt.
*/
static int8_t enable_orient_int(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable data ready interrupt in Int Enable 0 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_ORIENT_INT_EN_MASK;
data = temp | ((orient_int_cfg->orient_en << 6) & BMI160_ORIENT_INT_EN_MASK);
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to orientation interrupt.
*/
static int8_t map_int_pin_to_orient(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int Map register to map interrupt pin
* to orientation interrupt */
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_ORIENT_MASK;
data = temp | ((1 << 6) & BMI160_INT1_ORIENT_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_ORIENT_MASK;
data = temp | ((1 << 6) & BMI160_INT2_ORIENT_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the necessary setting of orientation interrupt.
*/
static int8_t config_orient_int_settg(const struct bmi160_acc_orient_int_cfg *orient_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
uint8_t data_array[2] = {0, 0};
/* Configuring INT_ORIENT registers */
rslt = bmi160_get_regs(BMI160_INT_ORIENT_0_ADDR, data_array, 2, dev);
if (rslt == BMI160_OK) {
data = data_array[0];
temp = data & ~BMI160_ORIENT_MODE_MASK;
/* Adding Orientation mode */
data = temp | ((orient_int_cfg->orient_mode) & BMI160_ORIENT_MODE_MASK);
temp = data & ~BMI160_ORIENT_BLOCK_MASK;
/* Adding Orientation blocking */
data = temp | ((orient_int_cfg->orient_blocking << 2) & BMI160_ORIENT_BLOCK_MASK);
temp = data & ~BMI160_ORIENT_HYST_MASK;
/* Adding Orientation hysteresis */
data = temp | ((orient_int_cfg->orient_hyst << 4) & BMI160_ORIENT_HYST_MASK);
data_array[0] = data;
data = data_array[1];
temp = data & ~BMI160_ORIENT_THETA_MASK;
/* Adding Orientation threshold */
data = temp | ((orient_int_cfg->orient_theta) & BMI160_ORIENT_THETA_MASK);
temp = data & ~BMI160_ORIENT_UD_ENABLE;
/* Adding Orient_ud_en */
data = temp | ((orient_int_cfg->orient_ud_en << 6) & BMI160_ORIENT_UD_ENABLE);
temp = data & ~BMI160_AXES_EN_MASK;
/* Adding axes_en */
data = temp | ((orient_int_cfg->axes_ex << 7) & BMI160_AXES_EN_MASK);
data_array[1] = data;
/* Writing data to INT_ORIENT 0 and INT_ORIENT 1
* registers simultaneously */
rslt = bmi160_set_regs(BMI160_INT_ORIENT_0_ADDR, data_array, 2, dev);
}
return rslt;
}
/*!
* @brief This API enables the flat interrupt.
*/
static int8_t enable_flat_int(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable flat interrupt in Int Enable 0 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_FLAT_INT_EN_MASK;
data = temp | ((flat_int->flat_en << 7) & BMI160_FLAT_INT_EN_MASK);
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to flat interrupt.
*/
static int8_t map_int_pin_to_flat(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Map register to map interrupt pin to flat interrupt*/
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_FLAT_MASK;
data = temp | ((1 << 7) & BMI160_INT1_FLAT_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_FLAT_MASK;
data = temp | ((1 << 7) & BMI160_INT2_FLAT_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the necessary setting of flat interrupt.
*/
static int8_t config_flat_int_settg(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
uint8_t data_array[2] = {0, 0};
/* Configuring INT_FLAT register */
rslt = bmi160_get_regs(BMI160_INT_FLAT_0_ADDR, data_array, 2, dev);
if (rslt == BMI160_OK) {
data = data_array[0];
temp = data & ~BMI160_FLAT_THRES_MASK;
/* Adding flat theta */
data = temp | ((flat_int->flat_theta) & BMI160_FLAT_THRES_MASK);
data_array[0] = data;
data = data_array[1];
temp = data & ~BMI160_FLAT_HOLD_TIME_MASK;
/* Adding flat hold time */
data = temp | ((flat_int->flat_hold_time << 4) & BMI160_FLAT_HOLD_TIME_MASK);
temp = data & ~BMI160_FLAT_HYST_MASK;
/* Adding flat hysteresis */
data = temp | ((flat_int->flat_hy) & BMI160_FLAT_HYST_MASK);
data_array[1] = data;
/* Writing data to INT_FLAT 0 and INT_FLAT 1
* registers simultaneously */
rslt = bmi160_set_regs(BMI160_INT_FLAT_0_ADDR, data_array, 2, dev);
}
return rslt;
}
/*!
* @brief This API enables the Low-g interrupt.
*/
static int8_t enable_low_g_int(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable low-g interrupt in Int Enable 1 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_LOW_G_INT_EN_MASK;
data = temp | ((low_g_int->low_en << 3) & BMI160_LOW_G_INT_EN_MASK);
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for low-g interrupt.
*/
static int8_t config_low_g_data_src(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 0 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_LOW_HIGH_SRC_INT_MASK;
data = temp | ((low_g_int->low_data_src << 7) & BMI160_LOW_HIGH_SRC_INT_MASK);
/* Write data to Data 0 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the necessary setting of low-g interrupt.
*/
static int8_t config_low_g_int_settg(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data_array[3] = {0, 0, 0};
/* Configuring INT_LOWHIGH register for low-g interrupt */
rslt = bmi160_get_regs(BMI160_INT_LOWHIGH_2_ADDR, &data_array[2], 1, dev);
if (rslt == BMI160_OK) {
temp = data_array[2] & ~BMI160_LOW_G_HYST_MASK;
/* Adding low-g hysteresis */
data_array[2] = temp | (low_g_int->low_hyst & BMI160_LOW_G_HYST_MASK);
temp = data_array[2] & ~BMI160_LOW_G_LOW_MODE_MASK;
/* Adding low-mode */
data_array[2] = temp | ((low_g_int->low_mode << 2) & BMI160_LOW_G_LOW_MODE_MASK);
/* Adding low-g threshold */
data_array[1] = low_g_int->low_thres;
/* Adding low-g interrupt delay */
data_array[0] = low_g_int->low_dur;
/* Writing data to INT_LOWHIGH 0,1,2 registers simultaneously*/
rslt = bmi160_set_regs(BMI160_INT_LOWHIGH_0_ADDR, data_array, 3, dev);
}
return rslt;
}
/*!
* @brief This API enables the high-g interrupt.
*/
static int8_t enable_high_g_int(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Enable low-g interrupt in Int Enable 1 register */
rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
/* Adding high-g X-axis */
temp = data & ~BMI160_HIGH_G_X_INT_EN_MASK;
data = temp | (high_g_int_cfg->high_g_x & BMI160_HIGH_G_X_INT_EN_MASK);
/* Adding high-g Y-axis */
temp = data & ~BMI160_HIGH_G_Y_INT_EN_MASK;
data = temp | ((high_g_int_cfg->high_g_y << 1) & BMI160_HIGH_G_Y_INT_EN_MASK);
/* Adding high-g Z-axis */
temp = data & ~BMI160_HIGH_G_Z_INT_EN_MASK;
data = temp | ((high_g_int_cfg->high_g_z << 2) & BMI160_HIGH_G_Z_INT_EN_MASK);
/* write data to Int Enable 0 register */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to High-g interrupt.
*/
static int8_t map_int_pin_to_high_g(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Map register to map interrupt pin to high-g interrupt*/
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT1_HIGH_G_MASK;
data = temp | ((1 << 1) & BMI160_INT1_HIGH_G_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, &data, 1, dev);
}
} else {
rslt = bmi160_get_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_INT2_HIGH_G_MASK;
data = temp | ((1 << 1) & BMI160_INT2_HIGH_G_MASK);
rslt = bmi160_set_regs(BMI160_INT_MAP_2_ADDR, &data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This API configure the source of data(filter & pre-filter)
* for high-g interrupt.
*/
static int8_t config_high_g_data_src(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
uint8_t temp = 0;
/* Configure Int data 0 register to add source of interrupt */
rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
temp = data & ~BMI160_LOW_HIGH_SRC_INT_MASK;
data = temp | ((high_g_int_cfg->high_data_src << 7) & BMI160_LOW_HIGH_SRC_INT_MASK);
/* Write data to Data 0 address */
rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the necessary setting of high-g interrupt.
*/
static int8_t config_high_g_int_settg(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg,
const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data_array[3] = {0, 0, 0};
rslt = bmi160_get_regs(BMI160_INT_LOWHIGH_2_ADDR, &data_array[0], 1, dev);
if (rslt == BMI160_OK) {
temp = data_array[0] & ~BMI160_HIGH_G_HYST_MASK;
/* Adding high-g hysteresis */
data_array[0] = temp | ((high_g_int_cfg->high_hy << 6) & BMI160_HIGH_G_HYST_MASK);
/* Adding high-g duration */
data_array[1] = high_g_int_cfg->high_dur;
/* Adding high-g threshold */
data_array[2] = high_g_int_cfg->high_thres;
rslt = bmi160_set_regs(BMI160_INT_LOWHIGH_2_ADDR, data_array, 3, dev);
}
return rslt;
}
/*!
* @brief This API configure the behavioural setting of interrupt pin.
*/
static int8_t config_int_out_ctrl(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data = 0;
/* Configuration of output interrupt signals on pins INT1 and INT2 are
* done in BMI160_INT_OUT_CTRL_ADDR register*/
rslt = bmi160_get_regs(BMI160_INT_OUT_CTRL_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
/* updating the interrupt pin structure to local structure */
const struct bmi160_int_pin_settg *intr_pin_sett = &(int_config->int_pin_settg);
/* Configuring channel 1 */
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
/* Output enable */
temp = data & ~BMI160_INT1_OUTPUT_EN_MASK;
data = temp | ((intr_pin_sett->output_en << 3) & BMI160_INT1_OUTPUT_EN_MASK);
/* Output mode */
temp = data & ~BMI160_INT1_OUTPUT_MODE_MASK;
data = temp | ((intr_pin_sett->output_mode << 2) & BMI160_INT1_OUTPUT_MODE_MASK);
/* Output type */
temp = data & ~BMI160_INT1_OUTPUT_TYPE_MASK;
data = temp | ((intr_pin_sett->output_type << 1) & BMI160_INT1_OUTPUT_TYPE_MASK);
/* edge control */
temp = data & ~BMI160_INT1_EDGE_CTRL_MASK;
data = temp | ((intr_pin_sett->edge_ctrl) & BMI160_INT1_EDGE_CTRL_MASK);
} else {
/* Configuring channel 2 */
/* Output enable */
temp = data & ~BMI160_INT2_OUTPUT_EN_MASK;
data = temp | ((intr_pin_sett->output_en << 7) & BMI160_INT2_OUTPUT_EN_MASK);
/* Output mode */
temp = data & ~BMI160_INT2_OUTPUT_MODE_MASK;
data = temp | ((intr_pin_sett->output_mode << 6) & BMI160_INT2_OUTPUT_MODE_MASK);
/* Output type */
temp = data & ~BMI160_INT2_OUTPUT_TYPE_MASK;
data = temp | ((intr_pin_sett->output_type << 5) & BMI160_INT2_OUTPUT_TYPE_MASK);
/* edge control */
temp = data & ~BMI160_INT2_EDGE_CTRL_MASK;
data = temp | ((intr_pin_sett->edge_ctrl << 4) & BMI160_INT2_EDGE_CTRL_MASK);
}
rslt = bmi160_set_regs(BMI160_INT_OUT_CTRL_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API configure the mode(input enable, latch or non-latch) of interrupt pin.
*/
static int8_t config_int_latch(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t data = 0;
/* Configuration of latch on pins INT1 and INT2 are done in
* BMI160_INT_LATCH_ADDR register*/
rslt = bmi160_get_regs(BMI160_INT_LATCH_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
/* updating the interrupt pin structure to local structure */
const struct bmi160_int_pin_settg *intr_pin_sett = &(int_config->int_pin_settg);
if (int_config->int_channel == BMI160_INT_CHANNEL_1) {
/* Configuring channel 1 */
/* Input enable */
temp = data & ~BMI160_INT1_INPUT_EN_MASK;
data = temp | ((intr_pin_sett->input_en << 4) & BMI160_INT1_INPUT_EN_MASK);
} else {
/* Configuring channel 2 */
/* Input enable */
temp = data & ~BMI160_INT2_INPUT_EN_MASK;
data = temp | ((intr_pin_sett->input_en << 5) & BMI160_INT2_INPUT_EN_MASK);
}
/* In case of latch interrupt,update the latch duration */
/* Latching holds the interrupt for the amount of latch
* duration time */
temp = data & ~BMI160_INT_LATCH_MASK;
data = temp | (intr_pin_sett->latch_dur & BMI160_INT_LATCH_MASK);
/* OUT_CTRL_INT and LATCH_INT address lie consecutively,
* hence writing data to respective registers at one go */
rslt = bmi160_set_regs(BMI160_INT_LATCH_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API sets FIFO full interrupt of the sensor.This interrupt
* occurs when the FIFO is full and the next full data sample would cause
* a FIFO overflow, which may delete the old samples.
*/
static int8_t set_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
/* Null-pointer check */
if ((dev == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/*enable the fifo full interrupt */
rslt = enable_fifo_full_int(int_config, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK)
rslt = map_int_pin_to_fifo_full(int_config, dev);
}
}
return rslt;
}
/*!
* @brief This enable the FIFO full interrupt engine.
*/
static int8_t enable_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
data = BMI160_SET_BITS(data, BMI160_FIFO_FULL_INT, int_config->fifo_full_int_en);
/* Writing data to INT ENABLE 1 Address */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to FIFO FULL interrupt.
*/
static int8_t map_int_pin_to_fifo_full(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
/* Configure Map register to map interrupt pin
* to fifo-full interrupt*/
rslt = bmi160_get_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_channel == BMI160_INT_CHANNEL_1)
data = BMI160_SET_BITS(data, BMI160_FIFO_FULL_INT_PIN1, 1);
else
data = BMI160_SET_BITS(data, BMI160_FIFO_FULL_INT_PIN2, 1);
/* Writing data to Map 1 address */
rslt = bmi160_set_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API sets FIFO watermark interrupt of the sensor.The FIFO
* watermark interrupt is fired, when the FIFO fill level is above a fifo
* watermark.
*/
static int8_t set_fifo_watermark_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt = BMI160_OK;
if ((dev == NULL) || (dev->delay_ms == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* Enable fifo-watermark interrupt in Int Enable 1 register */
rslt = enable_fifo_wtm_int(int_config, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = set_intr_pin_config(int_config, dev);
if (rslt == BMI160_OK)
rslt = map_int_pin_to_fifo_wtm(int_config, dev);
}
}
return rslt;
}
/*!
* @brief This enable the FIFO watermark interrupt engine.
*/
static int8_t enable_fifo_wtm_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
data = BMI160_SET_BITS(data, BMI160_FIFO_WTM_INT, int_config->fifo_WTM_int_en);
/* Writing data to INT ENABLE 1 Address */
rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API maps the INT pin to FIFO watermark interrupt.
*/
static int8_t map_int_pin_to_fifo_wtm(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev)
{
int8_t rslt;
uint8_t data = 0;
/* Configure Map register to map interrupt pin
* to fifo-full interrupt*/
rslt = bmi160_get_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
if (rslt == BMI160_OK) {
if (int_config->int_channel == BMI160_INT_CHANNEL_1)
data = BMI160_SET_BITS(data, BMI160_FIFO_WTM_INT_PIN1, 1);
else
data = BMI160_SET_BITS(data, BMI160_FIFO_WTM_INT_PIN2, 1);
/* Writing data to Map 1 address */
rslt = bmi160_set_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev);
}
return rslt;
}
/*!
* @brief This API is used to reset the FIFO related configurations
* in the fifo_frame structure.
*/
static void reset_fifo_data_structure(const struct bmi160_dev *dev)
{
/*Prepare for next FIFO read by resetting FIFO's
internal data structures*/
dev->fifo->accel_byte_start_idx = 0;
dev->fifo->gyro_byte_start_idx = 0;
dev->fifo->sensor_time = 0;
dev->fifo->skipped_frame_count = 0;
}
/*!
* @brief This API is used to read fifo_byte_counter value (i.e)
* current fill-level in Fifo buffer.
*/
static int8_t get_fifo_byte_counter(uint16_t *bytes_to_read, struct bmi160_dev const *dev)
{
int8_t rslt = 0;
uint8_t data[2];
uint8_t addr = BMI160_FIFO_LENGTH_ADDR;
rslt |= bmi160_get_regs(addr, data, 2, dev);
data[1] = data[1] & BMI160_FIFO_BYTE_COUNTER_MASK;
/* Available data in FIFO is stored in bytes_to_read*/
*bytes_to_read = (((uint16_t)data[1] << 8) | ((uint16_t)data[0]));
return rslt;
}
/*!
* @brief This API is used to compute the number of bytes of accel FIFO data
* which is to be parsed in header-less mode
*/
static void get_accel_len_to_parse(uint16_t *data_index, uint16_t *data_read_length, const uint8_t *acc_frame_count,
const struct bmi160_dev *dev)
{
/* Data start index */
*data_index = dev->fifo->accel_byte_start_idx;
if (dev->fifo->fifo_data_enable == BMI160_FIFO_A_ENABLE) {
*data_read_length = (*acc_frame_count) * BMI160_FIFO_A_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_A_ENABLE) {
*data_read_length = (*acc_frame_count) * BMI160_FIFO_GA_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_A_ENABLE) {
*data_read_length = (*acc_frame_count) * BMI160_FIFO_MA_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_A_ENABLE) {
*data_read_length = (*acc_frame_count) * BMI160_FIFO_MGA_LENGTH;
} else {
/* When accel is not enabled ,there will be no accel data.
so we update the data index as complete */
*data_index = dev->fifo->length;
}
if (*data_read_length > dev->fifo->length) {
/* Handling the case where more data is requested
than that is available*/
*data_read_length = dev->fifo->length;
}
}
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data in both header mode and header-less mode.
* It updates the idx value which is used to store the index of
* the current data byte which is parsed.
*/
static void unpack_accel_frame(struct bmi160_sensor_data *acc, uint16_t *idx, uint8_t *acc_idx, uint8_t frame_info,
const struct bmi160_dev *dev)
{
switch (frame_info) {
case BMI160_FIFO_HEAD_A:
case BMI160_FIFO_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_A_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into the structure instance "acc" */
unpack_accel_data(&acc[*acc_idx], *idx, dev);
/*Move the data index*/
*idx = *idx + BMI160_FIFO_A_LENGTH;
(*acc_idx)++;
break;
case BMI160_FIFO_HEAD_G_A:
case BMI160_FIFO_G_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_GA_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "acc"*/
unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_G_LENGTH, dev);
/*Move the data index*/
*idx = *idx + BMI160_FIFO_GA_LENGTH;
(*acc_idx)++;
break;
case BMI160_FIFO_HEAD_M_A:
case BMI160_FIFO_M_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_MA_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "acc"*/
unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_M_LENGTH, dev);
/*Move the data index*/
*idx = *idx + BMI160_FIFO_MA_LENGTH;
(*acc_idx)++;
break;
case BMI160_FIFO_HEAD_M_G_A:
case BMI160_FIFO_M_G_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_MGA_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "acc"*/
unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_MG_LENGTH, dev);
/*Move the data index*/
*idx = *idx + BMI160_FIFO_MGA_LENGTH;
(*acc_idx)++;
break;
case BMI160_FIFO_HEAD_M:
case BMI160_FIFO_M_ENABLE:
(*idx) = (*idx) + BMI160_FIFO_M_LENGTH;
break;
case BMI160_FIFO_HEAD_G:
case BMI160_FIFO_G_ENABLE:
(*idx) = (*idx) + BMI160_FIFO_G_LENGTH;
break;
case BMI160_FIFO_HEAD_M_G:
case BMI160_FIFO_M_G_ENABLE:
(*idx) = (*idx) + BMI160_FIFO_MG_LENGTH;
break;
default:
break;
}
}
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data and store it in the instance of the structure bmi160_sensor_data.
*/
static void unpack_accel_data(struct bmi160_sensor_data *accel_data, uint16_t data_start_index,
const struct bmi160_dev *dev)
{
uint16_t data_lsb;
uint16_t data_msb;
/* Accel raw x data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
accel_data->x = (int16_t)((data_msb << 8) | data_lsb);
/* Accel raw y data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
accel_data->y = (int16_t)((data_msb << 8) | data_lsb);
/* Accel raw z data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
accel_data->z = (int16_t)((data_msb << 8) | data_lsb);
}
/*!
* @brief This API is used to parse the accelerometer data from the
* FIFO data in header mode.
*/
static void extract_accel_header_mode(struct bmi160_sensor_data *accel_data, uint8_t *accel_length,
const struct bmi160_dev *dev)
{
uint8_t frame_header = 0;
uint16_t data_index;
uint8_t accel_index = 0;
for (data_index = dev->fifo->accel_byte_start_idx; data_index < dev->fifo->length;) {
/* extracting Frame header */
frame_header = (dev->fifo->data[data_index] & BMI160_FIFO_TAG_INTR_MASK);
/*Index is moved to next byte where the data is starting*/
data_index++;
switch (frame_header) {
/* Accel frame */
case BMI160_FIFO_HEAD_A:
case BMI160_FIFO_HEAD_M_A:
case BMI160_FIFO_HEAD_G_A:
case BMI160_FIFO_HEAD_M_G_A:
unpack_accel_frame(accel_data, &data_index, &accel_index, frame_header, dev);
break;
case BMI160_FIFO_HEAD_M:
move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev);
break;
case BMI160_FIFO_HEAD_G:
move_next_frame(&data_index, BMI160_FIFO_G_LENGTH, dev);
break;
case BMI160_FIFO_HEAD_M_G:
move_next_frame(&data_index, BMI160_FIFO_MG_LENGTH, dev);
break;
/* Sensor time frame */
case BMI160_FIFO_HEAD_SENSOR_TIME:
unpack_sensortime_frame(&data_index, dev);
break;
/* Skip frame */
case BMI160_FIFO_HEAD_SKIP_FRAME:
unpack_skipped_frame(&data_index, dev);
break;
/* Input config frame */
case BMI160_FIFO_HEAD_INPUT_CONFIG:
move_next_frame(&data_index, 1, dev);
break;
case BMI160_FIFO_HEAD_OVER_READ:
/* Update the data index as complete in case of Over read */
data_index = dev->fifo->length;
break;
default:
break;
}
}
/*Update number of accel data read*/
*accel_length = accel_index;
/*Update the accel frame index*/
dev->fifo->accel_byte_start_idx = data_index;
}
/*!
* @brief This API computes the number of bytes of gyro FIFO data
* which is to be parsed in header-less mode
*/
static void get_gyro_len_to_parse(uint16_t *data_index, uint16_t *data_read_length, const uint8_t *gyro_frame_count,
const struct bmi160_dev *dev)
{
/* Data start index */
*data_index = dev->fifo->gyro_byte_start_idx;
if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_ENABLE) {
*data_read_length = (*gyro_frame_count) * BMI160_FIFO_G_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_A_ENABLE) {
*data_read_length = (*gyro_frame_count) * BMI160_FIFO_GA_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_ENABLE) {
*data_read_length = (*gyro_frame_count) * BMI160_FIFO_MG_LENGTH;
} else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_A_ENABLE) {
*data_read_length = (*gyro_frame_count) * BMI160_FIFO_MGA_LENGTH;
} else {
/* When gyro is not enabled ,there will be no gyro data.
so we update the data index as complete */
*data_index = dev->fifo->length;
}
if (*data_read_length > dev->fifo->length) {
/* Handling the case where more data is requested
than that is available*/
*data_read_length = dev->fifo->length;
}
}
/*!
* @brief This API is used to parse the gyroscope's data from the
* FIFO data in both header mode and header-less mode.
* It updates the idx value which is used to store the index of
* the current data byte which is parsed.
*/
static void unpack_gyro_frame(struct bmi160_sensor_data *gyro, uint16_t *idx, uint8_t *gyro_idx, uint8_t frame_info,
const struct bmi160_dev *dev)
{
switch (frame_info) {
case BMI160_FIFO_HEAD_G:
case BMI160_FIFO_G_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_G_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "gyro"*/
unpack_gyro_data(&gyro[*gyro_idx], *idx, dev);
/*Move the data index*/
(*idx) = (*idx) + BMI160_FIFO_G_LENGTH;
(*gyro_idx)++;
break;
case BMI160_FIFO_HEAD_G_A:
case BMI160_FIFO_G_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_GA_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/* Unpack the data array into structure instance "gyro" */
unpack_gyro_data(&gyro[*gyro_idx], *idx, dev);
/* Move the data index */
*idx = *idx + BMI160_FIFO_GA_LENGTH;
(*gyro_idx)++;
break;
case BMI160_FIFO_HEAD_M_G_A:
case BMI160_FIFO_M_G_A_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_MGA_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "gyro"*/
unpack_gyro_data(&gyro[*gyro_idx], *idx + BMI160_FIFO_M_LENGTH, dev);
/*Move the data index*/
*idx = *idx + BMI160_FIFO_MGA_LENGTH;
(*gyro_idx)++;
break;
case BMI160_FIFO_HEAD_M_A:
case BMI160_FIFO_M_A_ENABLE:
/* Move the data index */
*idx = *idx + BMI160_FIFO_MA_LENGTH;
break;
case BMI160_FIFO_HEAD_M:
case BMI160_FIFO_M_ENABLE:
(*idx) = (*idx) + BMI160_FIFO_M_LENGTH;
break;
case BMI160_FIFO_HEAD_M_G:
case BMI160_FIFO_M_G_ENABLE:
/*Partial read, then skip the data*/
if ((*idx + BMI160_FIFO_MG_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*idx = dev->fifo->length;
break;
}
/*Unpack the data array into structure instance "gyro"*/
unpack_gyro_data(&gyro[*gyro_idx], *idx + BMI160_FIFO_M_LENGTH, dev);
/*Move the data index*/
(*idx) = (*idx) + BMI160_FIFO_MG_LENGTH;
(*gyro_idx)++;
break;
case BMI160_FIFO_HEAD_A:
case BMI160_FIFO_A_ENABLE:
/*Move the data index*/
*idx = *idx + BMI160_FIFO_A_LENGTH;
break;
default:
break;
}
}
/*!
* @brief This API is used to parse the gyro data from the
* FIFO data and store it in the instance of the structure bmi160_sensor_data.
*/
static void unpack_gyro_data(struct bmi160_sensor_data *gyro_data, uint16_t data_start_index,
const struct bmi160_dev *dev)
{
uint16_t data_lsb;
uint16_t data_msb;
/* Gyro raw x data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
gyro_data->x = (int16_t)((data_msb << 8) | data_lsb);
/* Gyro raw y data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
gyro_data->y = (int16_t)((data_msb << 8) | data_lsb);
/* Gyro raw z data */
data_lsb = dev->fifo->data[data_start_index++];
data_msb = dev->fifo->data[data_start_index++];
gyro_data->z = (int16_t)((data_msb << 8) | data_lsb);
}
/*!
* @brief This API is used to parse the gyro data from the
* FIFO data in header mode.
*/
static void extract_gyro_header_mode(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length,
const struct bmi160_dev *dev)
{
uint8_t frame_header = 0;
uint16_t data_index;
uint8_t gyro_index = 0;
for (data_index = dev->fifo->gyro_byte_start_idx; data_index < dev->fifo->length;) {
/* extracting Frame header */
frame_header = (dev->fifo->data[data_index] & BMI160_FIFO_TAG_INTR_MASK);
/*Index is moved to next byte where the data is starting*/
data_index++;
switch (frame_header) {
/* GYRO frame */
case BMI160_FIFO_HEAD_G:
case BMI160_FIFO_HEAD_G_A:
case BMI160_FIFO_HEAD_M_G:
case BMI160_FIFO_HEAD_M_G_A:
unpack_gyro_frame(gyro_data, &data_index, &gyro_index, frame_header, dev);
break;
case BMI160_FIFO_HEAD_A:
move_next_frame(&data_index, BMI160_FIFO_A_LENGTH, dev);
break;
case BMI160_FIFO_HEAD_M:
move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev);
break;
case BMI160_FIFO_HEAD_M_A:
move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev);
break;
/* Sensor time frame */
case BMI160_FIFO_HEAD_SENSOR_TIME:
unpack_sensortime_frame(&data_index, dev);
break;
/* Skip frame */
case BMI160_FIFO_HEAD_SKIP_FRAME:
unpack_skipped_frame(&data_index, dev);
break;
/* Input config frame */
case BMI160_FIFO_HEAD_INPUT_CONFIG:
move_next_frame(&data_index, 1, dev);
break;
case BMI160_FIFO_HEAD_OVER_READ:
/* Update the data index as complete in case of over read */
data_index = dev->fifo->length;
break;
default:
break;
}
}
/*Update number of gyro data read*/
*gyro_length = gyro_index;
/*Update the gyro frame index*/
dev->fifo->gyro_byte_start_idx = data_index;
}
/*!
* @brief This API checks the presence of non-valid frames in the read fifo data.
*/
static void check_frame_validity(uint16_t *data_index, const struct bmi160_dev *dev)
{
if ((*data_index + 2) < dev->fifo->length) {
/* Check if FIFO is empty */
if ((dev->fifo->data[*data_index] == FIFO_CONFIG_MSB_CHECK)
&& (dev->fifo->data[*data_index + 1] == FIFO_CONFIG_LSB_CHECK)) {
/*Update the data index as complete*/
*data_index = dev->fifo->length;
}
}
}
/*!
* @brief This API is used to move the data index ahead of the
* current_frame_length parameter when unnecessary FIFO data appears while
* extracting the user specified data.
*/
static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi160_dev *dev)
{
/*Partial read, then move the data index to last data*/
if ((*data_index + current_frame_length) > dev->fifo->length) {
/*Update the data index as complete*/
*data_index = dev->fifo->length;
} else {
/*Move the data index to next frame*/
*data_index = *data_index + current_frame_length;
}
}
/*!
* @brief This API is used to parse and store the sensor time from the
* FIFO data in the structure instance dev.
*/
static void unpack_sensortime_frame(uint16_t *data_index, const struct bmi160_dev *dev)
{
uint32_t sensor_time_byte3 = 0;
uint16_t sensor_time_byte2 = 0;
uint8_t sensor_time_byte1 = 0;
/*Partial read, then move the data index to last data*/
if ((*data_index + BMI160_SENSOR_TIME_LENGTH) > dev->fifo->length) {
/*Update the data index as complete*/
*data_index = dev->fifo->length;
} else {
sensor_time_byte3 = dev->fifo->data[(*data_index) + BMI160_SENSOR_TIME_MSB_BYTE] << 16;
sensor_time_byte2 = dev->fifo->data[(*data_index) + BMI160_SENSOR_TIME_XLSB_BYTE] << 8;
sensor_time_byte1 = dev->fifo->data[(*data_index)];
/* Sensor time */
dev->fifo->sensor_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1);
*data_index = (*data_index) + BMI160_SENSOR_TIME_LENGTH;
}
}
/*!
* @brief This API is used to parse and store the skipped_frame_count from
* the FIFO data in the structure instance dev.
*/
static void unpack_skipped_frame(uint16_t *data_index, const struct bmi160_dev *dev)
{
/*Partial read, then move the data index to last data*/
if (*data_index >= dev->fifo->length) {
/*Update the data index as complete*/
*data_index = dev->fifo->length;
} else {
dev->fifo->skipped_frame_count = dev->fifo->data[*data_index];
/*Move the data index*/
*data_index = (*data_index) + 1;
}
}
/** @}*/
/**\mainpage
* Copyright (C) 2015 - 2016 Bosch Sensortec GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility
* for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*
* File bmm150.c
* Date 1 Mar 2017
* Version 0.8.0
*
*/
/*! @file bmm150.c
@brief Sensor driver for BMM150 sensor */
#include "bmm150.h"
/************************** Internal macros *******************************/
/* Sensor ODR, Repetition and axes enable/disable settings */
#define MODE_SETTING_SEL UINT16_C(0x000F)
/* Interrupt pin settings like polarity,latch and int_pin enable */
#define INTERRUPT_PIN_SETTING_SEL UINT16_C(0x01F0)
/* Settings to enable/disable interrupts */
#define INTERRUPT_CONFIG_SEL UINT16_C(0x1E00)
/* Interrupt settings for configuring threshold values */
#define INTERRUPT_THRESHOLD_CONFIG_SEL UINT16_C(0x6000)
/********************** Static function declarations ************************/
/*!
* @brief This internal API is used to validate the device pointer for
* null conditions.
*
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t null_ptr_check(const struct bmm150_dev *dev);
/*!
* @brief This internal API sets/resets the power control bit of 0x4B register.
*
* @param[in] pwrcntrl_bit : Variable used to select/deselect the suspend mode.
* @param[in,out] dev : Structure instance of bmm150_dev
*
* pwrcntrl_bit | power mode
* -----------------|-------------------------
* 0x00 | Suspend mode
* 0x01 | Sleep/Active modes
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t set_power_control_bit(uint8_t pwrcntrl_bit, struct bmm150_dev *dev);
/*!
* @brief This internal API reads the trim registers of the sensor and stores
* the trim values in the "trim_data" of device structure.
*
* @param[in,out] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t read_trim_registers(struct bmm150_dev *dev);
/*!
* @brief This internal API writes the op_mode value in the Opmode bits
* (bits 1 and 2) of 0x4C register.
*
* op_mode | Power mode
* ------------|-----------------------
* 0x00 | BMM150_NORMAL_MODE
* 0x01 | BMM150_FORCED_MODE
* 0x03 | BMM150_SLEEP_MODE
*
* @param[in,out] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t write_op_mode(uint8_t op_mode, const struct bmm150_dev *dev);
/*!
* @brief This internal API sets the device from suspend to sleep mode
* by setting the power control bit to '1' of 0x4B register
*
* @param[in,out] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t suspend_to_sleep_mode(struct bmm150_dev *dev);
/*!
* @brief This internal API sets the xy repetition value in the 0x51 register.
*
* @param[in,out] dev : Structure instance of bmm150_dev
*
* dev->settings.xy_rep | nXY(XY Repetitions)
* -------------------------|-----------------------
* 0x00 | 1
* 0x01 | 3
* 0x02 | 5
* . | .
* . | .
* 0xFF | 511
*
* @note number of XY Repetitions nXY = 1+2(dev->settings.xy_rep)
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t set_xy_rep(const struct bmm150_dev *dev);
/*!
* @brief This internal API sets the z repetition value in the 0x52 register.
*
* @param[in,out] dev : Structure instance of bmm150_dev
*
* dev->settings.z_rep | nZ(Z Repetitions)
* -------------------------|-----------------------
* 0x00 | 1
* 0x01 | 2
* 0x02 | 3
* . | .
* . | .
* 0xFF | 256
*
* @note number of Z Repetitions nZ = 1+(dev->settings.z_rep)
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t set_z_rep(const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to set the output data rate of the sensor
*
* @param[in] dev : Structure instance of bmm150_dev.
*
* dev->settings.data_rate | Data rate (ODR)
* -------------------------|-----------------------
* 0x00 | BMM150_DATA_RATE_10HZ
* 0x01 | BMM150_DATA_RATE_02HZ
* 0x02 | BMM150_DATA_RATE_06HZ
* 0x03 | BMM150_DATA_RATE_08HZ
* 0x04 | BMM150_DATA_RATE_15HZ
* 0x05 | BMM150_DATA_RATE_20HZ
* 0x06 | BMM150_DATA_RATE_25HZ
* 0x07 | BMM150_DATA_RATE_30HZ
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_odr(const struct bmm150_dev *dev);
/*!
* @brief This internal API sets the preset mode ODR and repetition settings.
* @param[in] dev : Structure instance of bmm150_dev
*
* API settings | Representation
* -------------------------|------------------------------
* dev->settings.data_rate | Output Data Rate (ODR)
* dev->settings.xy_rep | XY repetition value
* dev->settings.z_rep | Z-repetition value
*
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
*/
static int8_t set_odr_xyz_rep(const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to enable or disable the magnetic
* measurement of x,y,z axes based on the value of xyz_axes_control.
*
* @param[in] dev : Structure instance of bmm150_dev.
*
* dev->settings.xyz_axes_control | Measurement axes/channel
* -------------------------------|--------------------------
* Bit 0 | X - Channel
* Bit 1 | Y - Channel
* Bit 2 | Z - Channel
*
* @note Setting 1 - Disables Channel measurement
* @note Setting 0 - Enables Channel measurement
*
* dev->settings.xyz_axes_control | Measurement axes Enabled/disabled
* -------------------------------|------------------------------------
* 0x01 | Disables X axis (Y,Z axes enabled)
* 0x02 | Disables Y axis (X,Z axes enabled)
* 0x04 | Disables Z axis (X,Y axes enabled)
* 0x07 | Disables all X,Y,Z axes measurement
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_control_measurement_xyz(const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to identify the settings which the user
* wants to modify in the sensor.
*
* @param[in] sub_settings : Contains the settings subset to identify particular
* group of settings which the user is interested to change.
* @param[in] settings : Contains the user specified settings.
*
* @return Indicates whether user is interested to modify the settings which
* are related to sub_settings.
* @retval True -> User wants to modify this group of settings
* @retval False -> User does not want to modify this group of settings
*/
static uint8_t are_settings_changed(uint16_t sub_settings, uint16_t settings);
/*!
* @brief This API sets the ODR , measurement axes control ,
* repetition values of xy,z.
*
* @param[in] desired_settings : Contains the settings which user wants to
* change.
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t mode_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to parse and store the sensor
* settings in the device structure
*
* @param[in] reg_data : Pointer of an array consisting all sensor
* setting data from 0x4B to 0x52 registers.
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static void parse_setting(const uint8_t *reg_data, struct bmm150_dev *dev);
/*!
* @brief This API is used to enable the interrupts and map them to the
* corresponding interrupt pins and specify the pin characteristics like the
* polarity , latch settings for the interrupt pins.
*
* @note The other interrupts can be latched or non-latched but,
* Data ready interrupt is always cleared after reading out the data
*
* @param[in] desired_settings : Contains the settings which user wants to
* change.
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t interrupt_pin_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
/*!
* @brief This API is used to enable data overrun , overflow interrupts and
* enable/disable high/low threshold interrupts for x,y,z axis based on the
* threshold values set by the user in the High threshold (0x50) and
* Low threshold (0x4F) registers.
*
* @param[in] desired_settings : Contains the settings which user wants to
* change.
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t interrupt_config(uint16_t desired_settings, const struct bmm150_dev *dev);
/*!
* @brief This API is used to write the user specified High/Low threshold value
* as a reference to generate the high/low threshold interrupt.
*
* @param[in] desired_settings : Contains the settings which user wants to
* change.
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t interrupt_threshold_settings(uint16_t desired_settings, const struct bmm150_dev *dev);
#ifdef BMM150_USE_FLOATING_POINT
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer X axis data in float.
*
* @param[in] mag_data_x : The value of raw X data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated X data value in float
*/
static float compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Y axis data in float.
*
* @param[in] mag_data_y : The value of raw Y data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated Y data value in float
*/
static float compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Z axis data in float.
*
* @param[in] mag_data_z : The value of raw Z data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated Z data value in float
*/
static float compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev);
#else
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer X axis data in int16_t.
*
* @param[in] mag_data_x : The value of raw X data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated X data value in int16_t format
*/
static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Y axis data in int16_t.
*
* @param[in] mag_data_y : The value of raw Y data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated Y data value in int16_t format
*/
static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Z axis data in int16_t.
*
* @param[in] mag_data_z : The value of raw Z data
* @param[in] data_rhall : The value of raw RHALL data
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of compensated Z data value in int16_t format
*/
static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev);
#endif
/*!
* @brief This internal API is used to perform the normal self test
* of the sensor and return the self test result as return value
*
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t perform_normal_self_test(const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to enable the normal self test by setting
* the Self Test bit (bit0) of the 0x4C register,
* which triggers the start of self test
*
* @param[out] self_test_enable : The value of self test bit0 in 0x4C register
* @param[in] dev : Structure instance of bmm150_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t enable_normal_self_test(uint8_t *self_test_enable, const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to validate the results of normal self test
* by using the self test status available in the bit0 of registers 0x42,0x44
* and 0x46.
*
* @param[in] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t validate_normal_self_test(const struct bmm150_dev *dev);
/*!
* @brief This internal API is used to perform advanced self test for Z axis
*
* @param[in] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*
* Return value | Status of self-test
*----------------------|---------------------------
* 0 | BMM150_OK
* 8 | BMM150_W_ADV_SELF_TEST_FAIL
*/
static int8_t perform_adv_self_test(struct bmm150_dev *dev);
/*!
* @brief This internal API is used to set the desired power mode ,
* axes control and repetition settings for advanced self test
*
* @param[in] dev : Structure instance of bmm150_dev
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t adv_self_test_settings(struct bmm150_dev *dev);
/*!
* @brief This internal API is used to set the positive or negative value of
* self-test current and obtain the corresponding magnetometer z axis data
*
* @param[in] self_test_current : Self test current either positive/negative
* @param[out] data_z : Z-axis Magnetometer data
* @param[in] dev : Structure instance of bmm150_dev
*
* self_test_current | Self-test current Direction
*-------------------------|------------------------------
* 0x03 | BMM150_ENABLE_POSITIVE_CURRENT
* 0x02 | BMM150_ENABLE_NEGATIVE_CURRENT
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t adv_self_test_measurement(uint8_t self_test_current, int16_t *data_z, struct bmm150_dev *dev);
/*!
* @brief This internal API is used to get the difference between the
* Z axis mag data obtained by positive and negative self-test current
* and validate whether the advanced self test is done successfully or not.
*
* @param[in] positive_data_z : Z-axis Mag data by positive self-test current
* @param[in] negative_data_z : Z-axis Mag data by negative self-test current
*
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*
* Return value | Status of self-test
*----------------------|---------------------------
* 0 | BMM150_OK
* 8 | BMM150_W_ADV_SELF_TEST_FAIL
*/
static int8_t validate_adv_self_test(int16_t positive_data_z, int16_t negative_data_z);
/*!
* @brief This internal API is used to set the self test current value in
* the Adv. ST bits (bit6 and bit7) of 0x4C register
*
* @param[in] self_test_current : Self test current value (+ve/-ve)
* @param[in] dev : Structure instance of bmm150_dev
*
* self_test_current | Self-test current Direction
*-------------------------|------------------------------
* 0x00 | BMM150_DISABLE_SELF_TEST_CURRENT
* 0x02 | BMM150_ENABLE_NEGATIVE_CURRENT
* 0x03 | BMM150_ENABLE_POSITIVE_CURRENT
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_adv_self_test_current(uint8_t self_test_current, const struct bmm150_dev *dev);
/********************** Global function definitions ************************/
/*!
* @brief This API is the entry point, Call this API before using other APIs.
* This API reads the chip-id of the sensor which is the first step to
* verify the sensor and updates the trim parameters of the sensor.
*/
int8_t bmm150_init(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t chip_id = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* Power up the sensor from suspend to sleep mode */
rslt = set_power_control_bit(BMM150_POWER_CNTRL_ENABLE, dev);
/* Start-up time delay of 3ms*/
dev->delay_ms(BMM150_START_UP_TIME);
if (rslt == BMM150_OK) {
/* Chip ID of the sensor is read */
rslt = bmm150_get_regs(BMM150_CHIP_ID_ADDR, &chip_id, 1, dev);
/* Proceed if everything is fine until now */
if (rslt == BMM150_OK) {
/* Check for chip id validity */
if (chip_id == BMM150_CHIP_ID) {
dev->chip_id = chip_id;
/* Function to update trim values */
rslt = read_trim_registers(dev);
} else {
rslt = BMM150_E_DEV_NOT_FOUND;
}
}
}
}
return rslt;
}
/*!
* @brief This API writes the given data to the register address
* of the sensor.
*/
int8_t bmm150_set_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bmm150_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMM150_OK) && (reg_data != NULL) && (len != 0)) {
/* Write the data to the reg_addr */
/* SPI write requires to set The MSB of reg_addr as 0
but in default the MSB is always 0 */
rslt = dev->write(dev->id, reg_addr, reg_data, len);
} else {
rslt = BMM150_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API reads the data from the given register address of the sensor.
*/
int8_t bmm150_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bmm150_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMM150_OK) && (reg_data != NULL)) {
if (dev->interface != BMM150_I2C_INTF) {
/* If interface selected is SPI */
reg_addr = reg_addr | 0x80;
}
/* Read the data from the reg_addr */
rslt = dev->read(dev->id, reg_addr, reg_data, len);
} else {
rslt = BMM150_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API is used to perform soft-reset of the sensor
* where all the registers are reset to their default values except 0x4B.
*/
int8_t bmm150_soft_reset(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
reg_data = reg_data | BMM150_SET_SOFT_RESET;
rslt = bmm150_set_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
dev->delay_ms(BMM150_SOFT_RESET_DELAY);
}
}
return rslt;
}
/*!
* @brief This API is used to set the power mode of the sensor.
*/
int8_t bmm150_set_op_mode(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t pwr_mode = dev->settings.pwr_mode;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* Select the power mode to set */
switch (pwr_mode) {
case BMM150_NORMAL_MODE:
/* If the sensor is in suspend mode
put the device to sleep mode */
rslt = suspend_to_sleep_mode(dev);
if (rslt == BMM150_OK) {
/* write the op mode */
rslt = write_op_mode(pwr_mode, dev);
}
break;
case BMM150_FORCED_MODE:
/* If the sensor is in suspend mode
put the device to sleep mode */
rslt = suspend_to_sleep_mode(dev);
if (rslt == BMM150_OK) {
/* write the op mode */
rslt = write_op_mode(pwr_mode, dev);
}
break;
case BMM150_SLEEP_MODE:
/* If the sensor is in suspend mode
put the device to sleep mode */
rslt = suspend_to_sleep_mode(dev);
if (rslt == BMM150_OK) {
/* write the op mode */
rslt = write_op_mode(pwr_mode, dev);
}
break;
case BMM150_SUSPEND_MODE:
/* Set the power control bit to zero */
rslt = set_power_control_bit(BMM150_POWER_CNTRL_DISABLE, dev);
break;
default:
rslt = BMM150_E_INVALID_CONFIG;
break;
}
}
return rslt;
}
/*!
* @brief This API is used to get the power mode of the sensor.
*/
int8_t bmm150_get_op_mode(uint8_t *op_mode, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
if (dev->settings.pwr_cntrl_bit == BMM150_POWER_CNTRL_DISABLE) {
/* Power mode set is suspend mode*/
*op_mode = BMM150_SUSPEND_MODE;
} else {
/*Power mode set is stored in the op_mode */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
*op_mode = BMM150_GET_BITS(reg_data, BMM150_OP_MODE);
}
}
return rslt;
}
/*!
* @brief This API is used to set the preset mode of the sensor.
*/
int8_t bmm150_set_presetmode(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t preset_mode;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
preset_mode = dev->settings.preset_mode;
switch (preset_mode) {
case BMM150_PRESETMODE_LOWPOWER:
/* Set the data rate x,y,z repetition
for Low Power mode */
dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
dev->settings.xy_rep = BMM150_LOWPOWER_REPXY;
dev->settings.z_rep = BMM150_LOWPOWER_REPZ;
rslt = set_odr_xyz_rep(dev);
break;
case BMM150_PRESETMODE_REGULAR:
/* Set the data rate x,y,z repetition
for Regular mode */
dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
dev->settings.xy_rep = BMM150_REGULAR_REPXY;
dev->settings.z_rep = BMM150_REGULAR_REPZ;
rslt = set_odr_xyz_rep(dev);
break;
case BMM150_PRESETMODE_HIGHACCURACY:
/* Set the data rate x,y,z repetition
for High Accuracy mode */
dev->settings.data_rate = BMM150_DATA_RATE_20HZ;
dev->settings.xy_rep = BMM150_HIGHACCURACY_REPXY;
dev->settings.z_rep = BMM150_HIGHACCURACY_REPZ;
rslt = set_odr_xyz_rep(dev);
break;
case BMM150_PRESETMODE_ENHANCED:
/* Set the data rate x,y,z repetition
for Enhanced Accuracy mode */
dev->settings.data_rate = BMM150_DATA_RATE_10HZ;
dev->settings.xy_rep = BMM150_ENHANCED_REPXY;
dev->settings.z_rep = BMM150_ENHANCED_REPZ;
rslt = set_odr_xyz_rep(dev);
break;
default:
rslt = BMM150_E_INVALID_CONFIG;
break;
}
}
return rslt;
}
/*!
* @brief This API sets the sensor settings based on the desired_settings
* and the dev structure configuration
*/
int8_t bmm150_set_sensor_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
if (are_settings_changed(MODE_SETTING_SEL, desired_settings)) {
/* ODR, Control measurement, XY,Z repetition values*/
rslt = mode_settings(desired_settings, dev);
}
if ((!rslt) && are_settings_changed(INTERRUPT_PIN_SETTING_SEL, desired_settings)) {
/* Interrupt pin settings */
rslt = interrupt_pin_settings(desired_settings, dev);
}
if ((!rslt) && are_settings_changed(INTERRUPT_CONFIG_SEL, desired_settings)) {
/* Interrupt configuration settings */
rslt = interrupt_config(desired_settings, dev);
}
if ((!rslt) && are_settings_changed(INTERRUPT_THRESHOLD_CONFIG_SEL, desired_settings)) {
/* Interrupt threshold settings */
rslt = interrupt_threshold_settings(desired_settings, dev);
}
}
return rslt;
}
/*!
* @brief This API gets the sensor settings and updates the dev structure
*/
int8_t bmm150_get_sensor_settings(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t setting[BMM150_SETTING_DATA_LEN] = {0};
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/*Read the entire sensor settings */
rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, setting, BMM150_SETTING_DATA_LEN, dev);
if (rslt == BMM150_OK) {
/*Parse and store the settings */
parse_setting(setting, dev);
}
}
return rslt;
}
/*!
* @brief This API is used to read the magnetometer data from registers
* 0x42 to 0x49 and update the dev structure with the
* compensated mag data in micro-tesla.
*/
int8_t bmm150_read_mag_data(struct bmm150_dev *dev)
{
int8_t rslt;
int16_t msb_data;
uint8_t reg_data[BMM150_XYZR_DATA_LEN] = {0};
struct bmm150_raw_mag_data raw_mag_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/*Read the mag data registers */
rslt = bmm150_get_regs(BMM150_DATA_X_LSB, reg_data, BMM150_XYZR_DATA_LEN, dev);
if (rslt == BMM150_OK) {
/* Mag X axis data */
reg_data[0] = BMM150_GET_BITS(reg_data[0], BMM150_DATA_X);
/* Shift the MSB data to left by 5 bits */
/* Multiply by 32 to get the shift left by 5 value */
msb_data = ((int16_t)((int8_t)reg_data[1])) * 32;
/* Raw mag X axis data */
raw_mag_data.raw_datax = (int16_t)(msb_data | reg_data[0]);
/* Mag Y axis data */
reg_data[2] = BMM150_GET_BITS(reg_data[2], BMM150_DATA_Y);
/* Shift the MSB data to left by 5 bits */
/* Multiply by 32 to get the shift left by 5 value */
msb_data = ((int16_t)((int8_t)reg_data[3])) * 32;
/* Raw mag Y axis data */
raw_mag_data.raw_datay = (int16_t)(msb_data | reg_data[2]);
/* Mag Z axis data */
reg_data[4] = BMM150_GET_BITS(reg_data[4], BMM150_DATA_Z);
/* Shift the MSB data to left by 7 bits */
/* Multiply by 128 to get the shift left by 7 value */
msb_data = ((int16_t)((int8_t)reg_data[5])) * 128;
/* Raw mag Z axis data */
raw_mag_data.raw_dataz = (int16_t)(msb_data | reg_data[4]);
/* Mag R-HALL data */
reg_data[6] = BMM150_GET_BITS(reg_data[6], BMM150_DATA_RHALL);
raw_mag_data.raw_data_r = (uint16_t)(((uint16_t)reg_data[7] << 6) | reg_data[6]);
/* Compensated Mag X data in int16_t format */
dev->data.x = compensate_x(raw_mag_data.raw_datax, raw_mag_data.raw_data_r, dev);
/* Compensated Mag Y data in int16_t format */
dev->data.y = compensate_y(raw_mag_data.raw_datay, raw_mag_data.raw_data_r, dev);
/* Compensated Mag Z data in int16_t format */
dev->data.z = compensate_z(raw_mag_data.raw_dataz, raw_mag_data.raw_data_r, dev);
}
}
return rslt;
}
/*!
* @brief This API is used to perform the complete self test
* (both normal and advanced) for the BMM150 sensor
*/
int8_t bmm150_perform_self_test(uint8_t self_test_mode, struct bmm150_dev *dev)
{
int8_t rslt;
int8_t self_test_rslt = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
switch (self_test_mode) {
case BMM150_NORMAL_SELF_TEST:
/* Set the sensor in sleep mode */
dev->settings.pwr_mode = BMM150_SLEEP_MODE;
rslt = bmm150_set_op_mode(dev);
if (rslt == BMM150_OK) {
/* Perform the normal self test */
rslt = perform_normal_self_test(dev);
}
break;
case BMM150_ADVANCED_SELF_TEST:
/* Perform the advanced self test */
rslt = perform_adv_self_test(dev);
/* Check to ensure bus error does not occur */
if (rslt >= BMM150_OK) {
/* Store the status of self test result */
self_test_rslt = rslt;
/* Perform soft reset */
rslt = bmm150_soft_reset(dev);
}
/* Check to ensure bus operations are success */
if (rslt == BMM150_OK) {
/* Restore self_test_rslt as return value */
rslt = self_test_rslt;
}
break;
default:
rslt = BMM150_E_INVALID_CONFIG;
break;
}
}
return rslt;
}
/*!
* @brief This API is used to get the status flags of all interrupt
* which is used to check for the assertion of interrupts
*/
int8_t bmm150_get_interrupt_status(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t interrupt_status;
uint8_t data_ready_status;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* Read the data ready status from the register 0x48 */
rslt = bmm150_get_regs(BMM150_DATA_READY_STATUS, &data_ready_status, 1, dev);
if (rslt == BMM150_OK) {
/* Read the interrupt status from the register 0x50 */
rslt = bmm150_get_regs(BMM150_INTERRUPT_STATUS, &interrupt_status, 1, dev);
if (rslt == BMM150_OK) {
/* Mask and store the data ready status bit*/
data_ready_status = BMM150_GET_BITS(data_ready_status, BMM150_DRDY_STATUS);
/* store the entire interrupt status in dev */
dev->int_status = (data_ready_status << 8) | interrupt_status;
}
}
}
return rslt;
}
/****************************************************************************/
/**\name INTERNAL APIs */
/*!
* @brief This internal API is used to validate the device structure pointer for
* null conditions.
*/
static int8_t null_ptr_check(const struct bmm150_dev *dev)
{
int8_t rslt;
if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) {
/* Device structure pointer is not valid */
rslt = BMM150_E_NULL_PTR;
} else {
/* Device structure is fine */
rslt = BMM150_OK;
}
return rslt;
}
/*!
* @brief This internal API sets/resets the power control bit of 0x4B register.
*/
static int8_t set_power_control_bit(uint8_t pwrcntrl_bit, struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* Power control register 0x4B is read */
rslt = bmm150_get_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
/* Proceed if everything is fine until now */
if (rslt == BMM150_OK) {
/* Sets the value of power control bit */
reg_data = BMM150_SET_BITS(reg_data, BMM150_PWR_CNTRL, pwrcntrl_bit);
rslt = bmm150_set_regs(BMM150_POWER_CONTROL_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/*Store the power control bit
value in dev structure*/
dev->settings.pwr_cntrl_bit = pwrcntrl_bit;
}
}
}
return rslt;
}
/*!
* @brief This internal API reads the trim registers of the sensor and stores
* the trim values in the "trim_data" of device structure.
*/
static int8_t read_trim_registers(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t trim_x1y1[2] = {0};
uint8_t trim_xyz_data[4] = {0};
uint8_t trim_xy1xy2[10] = {0};
uint16_t temp_msb = 0;
/* Trim register value is read */
rslt = bmm150_get_regs(BMM150_DIG_X1, trim_x1y1, 2, dev);
if (rslt == BMM150_OK) {
rslt = bmm150_get_regs(BMM150_DIG_Z4_LSB, trim_xyz_data, 4, dev);
if (rslt == BMM150_OK) {
rslt = bmm150_get_regs(BMM150_DIG_Z2_LSB, trim_xy1xy2, 10, dev);
if (rslt == BMM150_OK) {
/* Trim data which is read is updated
in the device structure */
dev->trim_data.dig_x1 = (int8_t)trim_x1y1[0];
dev->trim_data.dig_y1 = (int8_t)trim_x1y1[1];
dev->trim_data.dig_x2 = (int8_t)trim_xyz_data[2];
dev->trim_data.dig_y2 = (int8_t)trim_xyz_data[3];
temp_msb = ((uint16_t)trim_xy1xy2[3]) << 8;
dev->trim_data.dig_z1 = (uint16_t)(temp_msb | trim_xy1xy2[2]);
temp_msb = ((uint16_t)trim_xy1xy2[1]) << 8;
dev->trim_data.dig_z2 = (int16_t)(temp_msb | trim_xy1xy2[0]);
temp_msb = ((uint16_t)trim_xy1xy2[7]) << 8;
dev->trim_data.dig_z3 = (int16_t)(temp_msb | trim_xy1xy2[6]);
temp_msb = ((uint16_t)trim_xyz_data[1]) << 8;
dev->trim_data.dig_z4 = (int16_t)(temp_msb | trim_xyz_data[0]);
dev->trim_data.dig_xy1 = trim_xy1xy2[9];
dev->trim_data.dig_xy2 = (int8_t)trim_xy1xy2[8];
temp_msb = ((uint16_t)(trim_xy1xy2[5] & 0x7F)) << 8;
dev->trim_data.dig_xyz1 = (uint16_t)(temp_msb | trim_xy1xy2[4]);
}
}
}
return rslt;
}
/*!
* @brief This internal API writes the op_mode value in the Opmode bits
* (bits 1 and 2) of 0x4C register.
*/
static int8_t write_op_mode(uint8_t op_mode, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* Read the 0x4C register */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/* Set the op_mode value in Opmode bits of 0x4C */
reg_data = BMM150_SET_BITS(reg_data, BMM150_OP_MODE, op_mode);
rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This internal API sets the device from suspend to sleep mode
* by setting the power control bit to '1' of 0x4B register
*/
static int8_t suspend_to_sleep_mode(struct bmm150_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
if (dev->settings.pwr_cntrl_bit == BMM150_POWER_CNTRL_DISABLE) {
rslt = set_power_control_bit(BMM150_POWER_CNTRL_ENABLE, dev);
/* Start-up time delay of 3ms*/
dev->delay_ms(BMM150_START_UP_TIME);
}
}
return rslt;
}
/*!
* @brief This internal API sets the xy repetition value in the 0x51 register.
*/
static int8_t set_xy_rep(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t rep_xy;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* set the xy repetition */
rep_xy = dev->settings.xy_rep;
rslt = bmm150_set_regs(BMM150_REP_XY_ADDR, &rep_xy, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API sets the z repetition value in the 0x52 register.
*/
static int8_t set_z_rep(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t rep_z;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/* set the z repetition */
rep_z = dev->settings.z_rep;
rslt = bmm150_set_regs(BMM150_REP_Z_ADDR, &rep_z, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API is used to set the output data rate of the sensor.
*/
static int8_t set_odr(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
/*Read the 0x4C register */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/*Set the ODR value */
reg_data = BMM150_SET_BITS(reg_data, BMM150_ODR, dev->settings.data_rate);
rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This internal API sets the preset mode ODR and repetition settings.
*/
static int8_t set_odr_xyz_rep(const struct bmm150_dev *dev)
{
int8_t rslt;
/* Set the ODR */
rslt = set_odr(dev);
if (rslt == BMM150_OK) {
/* Set the XY-repetitions number */
rslt = set_xy_rep(dev);
if (rslt == BMM150_OK) {
/* Set the Z-repetitions number */
rslt = set_z_rep(dev);
}
}
return rslt;
}
/*!
* @brief This internal API is used to enable or disable the magnetic
* measurement of x,y,z axes based on the value of xyz_axes_control.
*/
static int8_t set_control_measurement_xyz(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMM150_OK) {
rslt = bmm150_get_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/* Set the axes to be enabled/disabled*/
reg_data = BMM150_SET_BITS(reg_data, BMM150_CONTROL_MEASURE, dev->settings.xyz_axes_control);
rslt = bmm150_set_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
}
}
return rslt;
}
/*!
* @brief This internal API is used to identify the settings which the user
* wants to modify in the sensor.
*/
static uint8_t are_settings_changed(uint16_t sub_settings, uint16_t desired_settings)
{
uint8_t settings_changed = FALSE;
if (sub_settings & desired_settings) {
/* User wants to modify this particular settings */
settings_changed = TRUE;
} else {
/* User don't want to modify this particular settings */
settings_changed = FALSE;
}
return settings_changed;
}
/*!
* @brief This API sets the ODR , measurement axes control ,
* repetition values of xy,z.
*/
static int8_t mode_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
{
int8_t rslt = BMM150_E_INVALID_CONFIG;
if (desired_settings & BMM150_DATA_RATE_SEL) {
/* Sets the ODR */
rslt = set_odr(dev);
}
if (desired_settings & BMM150_CONTROL_MEASURE_SEL) {
/* Enables/Disables the control measurement axes */
rslt = set_control_measurement_xyz(dev);
}
if (desired_settings & BMM150_XY_REP_SEL) {
/* Sets the XY repetition */
rslt = set_xy_rep(dev);
}
if (desired_settings & BMM150_Z_REP_SEL) {
/* Sets the Z repetition */
rslt = set_z_rep(dev);
}
return rslt;
}
/*!
* @brief This internal API is used to parse and store the sensor
* settings in the device structure
*/
static void parse_setting(const uint8_t *reg_data, struct bmm150_dev *dev)
{
/* Parse all the w/r registers and update the
current sensor settings in the dev structure*/
dev->settings.z_rep = reg_data[7];
dev->settings.xy_rep = reg_data[6];
dev->settings.int_settings.high_threshold = reg_data[5];
dev->settings.int_settings.low_threshold = reg_data[4];
dev->settings.xyz_axes_control = BMM150_GET_BITS(reg_data[3], BMM150_CONTROL_MEASURE);
dev->settings.int_settings.drdy_pin_en = BMM150_GET_BITS(reg_data[3], BMM150_DRDY_EN);
dev->settings.int_settings.int_pin_en = BMM150_GET_BITS(reg_data[3], BMM150_INT_PIN_EN);
dev->settings.int_settings.drdy_polarity = BMM150_GET_BITS(reg_data[3], BMM150_DRDY_POLARITY);
dev->settings.int_settings.int_latch = BMM150_GET_BITS(reg_data[3], BMM150_INT_LATCH);
dev->settings.int_settings.int_polarity = BMM150_GET_BITS(reg_data[3], BMM150_INT_POLARITY);
dev->settings.int_settings.data_overrun_en = BMM150_GET_BITS(reg_data[2], BMM150_DATA_OVERRUN_INT);
dev->settings.int_settings.overflow_int_en = BMM150_GET_BITS(reg_data[2], BMM150_OVERFLOW_INT);
dev->settings.int_settings.high_int_en = BMM150_GET_BITS(reg_data[2], BMM150_HIGH_THRESHOLD_INT);
dev->settings.int_settings.low_int_en = BMM150_GET_BITS(reg_data[2], BMM150_LOW_THRESHOLD_INT);
dev->settings.data_rate = BMM150_GET_BITS(reg_data[1], BMM150_ODR);
}
/*!
* @brief This API is used to enable the interrupts and map them to the
* corresponding interrupt pins and specify the pin characteristics like the
* polarity , latch settings for the interrupt pins.
*/
static int8_t interrupt_pin_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
struct bmm150_int_ctrl_settings int_settings;
rslt = bmm150_get_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
int_settings = dev->settings.int_settings;
if (desired_settings & BMM150_DRDY_PIN_EN_SEL) {
/* Enables the Data ready interrupt and
maps it to the DRDY pin of the sensor */
reg_data = BMM150_SET_BITS(reg_data, BMM150_DRDY_EN, int_settings.drdy_pin_en);
}
if (desired_settings & BMM150_INT_PIN_EN_SEL) {
/* Sets interrupt pin enable */
reg_data = BMM150_SET_BITS(reg_data, BMM150_INT_PIN_EN, int_settings.int_pin_en);
}
if (desired_settings & BMM150_DRDY_POLARITY_SEL) {
/* Sets Data ready pin's polarity */
reg_data = BMM150_SET_BITS(reg_data, BMM150_DRDY_POLARITY, int_settings.drdy_polarity);
}
if (desired_settings & BMM150_INT_LATCH_SEL) {
/* Sets Interrupt in latched or non-latched mode */
reg_data = BMM150_SET_BITS(reg_data, BMM150_INT_LATCH, int_settings.int_latch);
}
if (desired_settings & BMM150_INT_POLARITY_SEL) {
/* Sets Interrupt pin's polarity */
reg_data = BMM150_SET_BITS(reg_data, BMM150_INT_POLARITY, int_settings.int_polarity);
}
/* Set the interrupt configurations in the 0x4E register */
rslt = bmm150_set_regs(BMM150_AXES_ENABLE_ADDR, &reg_data, 1, dev);
}
return rslt;
}
/*!
* @brief This API is used to enable data overrun , overflow interrupts and
* enable/disable high/low threshold interrupts for x,y,z axis based on the
* threshold values set by the user in the High threshold (0x50) and
* Low threshold (0x4F) registers.
*/
static int8_t interrupt_config(uint16_t desired_settings, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
struct bmm150_int_ctrl_settings int_settings;
rslt = bmm150_get_regs(BMM150_INT_CONFIG_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
int_settings = dev->settings.int_settings;
if (desired_settings & BMM150_DATA_OVERRUN_INT_SEL) {
/* Sets Data overrun interrupt */
reg_data = BMM150_SET_BITS(reg_data, BMM150_DATA_OVERRUN_INT, int_settings.data_overrun_en);
}
if (desired_settings & BMM150_OVERFLOW_INT_SEL) {
/* Sets Data overflow interrupt */
reg_data = BMM150_SET_BITS(reg_data, BMM150_OVERFLOW_INT, int_settings.overflow_int_en);
}
if (desired_settings & BMM150_HIGH_THRESHOLD_INT_SEL) {
/* Sets high threshold interrupt */
reg_data = BMM150_SET_BITS(reg_data, BMM150_HIGH_THRESHOLD_INT, int_settings.high_int_en);
}
if (desired_settings & BMM150_LOW_THRESHOLD_INT_SEL) {
/* Sets low threshold interrupt */
reg_data = BMM150_SET_BITS(reg_data, BMM150_LOW_THRESHOLD_INT, int_settings.low_int_en);
}
/* Set the interrupt configurations in the 0x4D register */
rslt = bmm150_set_regs(BMM150_INT_CONFIG_ADDR, &reg_data, 1, dev);
}
return rslt;
}
/*!
* @brief This API is used to write the user specified High/Low threshold value
* as a reference to generate the high/low threshold interrupt.
*/
static int8_t interrupt_threshold_settings(uint16_t desired_settings, const struct bmm150_dev *dev)
{
int8_t rslt = BMM150_E_INVALID_CONFIG;
uint8_t reg_data;
if (desired_settings & BMM150_LOW_THRESHOLD_SETTING_SEL) {
/* Sets the Low threshold value to trigger interrupt */
reg_data = dev->settings.int_settings.low_threshold;
rslt = bmm150_set_regs(BMM150_LOW_THRESHOLD_ADDR, &reg_data, 1, dev);
}
if (desired_settings & BMM150_HIGH_THRESHOLD_SETTING_SEL) {
/* Sets the High threshold value to trigger interrupt */
reg_data = dev->settings.int_settings.high_threshold;
rslt = bmm150_set_regs(BMM150_HIGH_THRESHOLD_ADDR, &reg_data, 1, dev);
}
return rslt;
}
#ifdef BMM150_USE_FLOATING_POINT
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer x axis data(micro-tesla) in float.
*/
static float compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev)
{
float retval = 0;
float process_comp_x0;
float process_comp_x1;
float process_comp_x2;
float process_comp_x3;
float process_comp_x4;
/* Overflow condition check */
if ((mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) &&
(data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
/*Processing compensation equations*/
process_comp_x0 = (((float)dev->trim_data.dig_xyz1) * 16384.0f / data_rhall);
retval = (process_comp_x0 - 16384.0f);
process_comp_x1 = ((float)dev->trim_data.dig_xy2) * (retval * retval / 268435456.0f);
process_comp_x2 = process_comp_x1 + retval * ((float)dev->trim_data.dig_xy1) / 16384.0f;
process_comp_x3 = ((float)dev->trim_data.dig_x2) + 160.0f;
process_comp_x4 = mag_data_x * ((process_comp_x2 + 256.0f) * process_comp_x3);
retval = ((process_comp_x4 / 8192.0f) + (((float)dev->trim_data.dig_x1) * 8.0f)) / 16.0f;
} else {
/* overflow, set output to 0.0f */
retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
}
return retval;
}
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer y axis data(micro-tesla) in float.
*/
static float compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev)
{
float retval = 0;
float process_comp_y0;
float process_comp_y1;
float process_comp_y2;
float process_comp_y3;
float process_comp_y4;
/* Overflow condition check */
if ((mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
&& (data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
/*Processing compensation equations*/
process_comp_y0 = ((float)dev->trim_data.dig_xyz1) * 16384.0f / data_rhall;
retval = process_comp_y0 - 16384.0f;
process_comp_y1 = ((float)dev->trim_data.dig_xy2) * (retval * retval / 268435456.0f);
process_comp_y2 = process_comp_y1 + retval * ((float)dev->trim_data.dig_xy1) / 16384.0f;
process_comp_y3 = ((float)dev->trim_data.dig_y2) + 160.0f;
process_comp_y4 = mag_data_y * (((process_comp_y2) + 256.0f) * process_comp_y3);
retval = ((process_comp_y4 / 8192.0f) + (((float)dev->trim_data.dig_y1) * 8.0f)) / 16.0f;
} else {
/* overflow, set output to 0.0f */
retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
}
return retval;
}
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer z axis data(micro-tesla) in float.
*/
static float compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev)
{
float retval = 0;
float process_comp_z0;
float process_comp_z1;
float process_comp_z2;
float process_comp_z3;
float process_comp_z4;
float process_comp_z5;
/* Overflow condition check */
if ((mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL) &&
(dev->trim_data.dig_z2 != 0) && (dev->trim_data.dig_z1 != 0)
&& (dev->trim_data.dig_xyz1 != 0) && (data_rhall != 0)) {
/* Processing compensation equations */
process_comp_z0 = ((float)mag_data_z) - ((float)dev->trim_data.dig_z4);
process_comp_z1 = ((float)data_rhall) - ((float)dev->trim_data.dig_xyz1);
process_comp_z2 = (((float)dev->trim_data.dig_z3) * process_comp_z1);
process_comp_z3 = ((float)dev->trim_data.dig_z1) * ((float)data_rhall) / 32768.0f;
process_comp_z4 = ((float)dev->trim_data.dig_z2) + process_comp_z3;
process_comp_z5 = (process_comp_z0 * 131072.0f) - process_comp_z2;
retval = (process_comp_z5 / ((process_comp_z4) * 4.0f)) / 16.0f;
} else {
/* overflow, set output to 0.0f */
retval = BMM150_OVERFLOW_OUTPUT_FLOAT;
}
return retval;
}
#else
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer X axis data(micro-tesla) in int16_t.
*/
static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall, const struct bmm150_dev *dev)
{
int16_t retval;
uint16_t process_comp_x0 = 0;
int32_t process_comp_x1;
uint16_t process_comp_x2;
int32_t process_comp_x3;
int32_t process_comp_x4;
int32_t process_comp_x5;
int32_t process_comp_x6;
int32_t process_comp_x7;
int32_t process_comp_x8;
int32_t process_comp_x9;
int32_t process_comp_x10;
/* Overflow condition check */
if (mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) {
if (data_rhall != 0) {
/* Availability of valid data*/
process_comp_x0 = data_rhall;
} else if (dev->trim_data.dig_xyz1 != 0) {
process_comp_x0 = dev->trim_data.dig_xyz1;
} else {
process_comp_x0 = 0;
}
if (process_comp_x0 != 0) {
/* Processing compensation equations*/
process_comp_x1 = ((int32_t)dev->trim_data.dig_xyz1) * 16384;
process_comp_x2 = ((uint16_t)(process_comp_x1 / process_comp_x0)) - ((uint16_t)0x4000);
retval = ((int16_t)process_comp_x2);
process_comp_x3 = (((int32_t)retval) * ((int32_t)retval));
process_comp_x4 = (((int32_t)dev->trim_data.dig_xy2) * (process_comp_x3 / 128));
process_comp_x5 = (int32_t)(((int16_t)dev->trim_data.dig_xy1) * 128);
process_comp_x6 = ((int32_t)retval) * process_comp_x5;
process_comp_x7 = (((process_comp_x4 + process_comp_x6) / 512) + ((int32_t)0x100000));
process_comp_x8 = ((int32_t)(((int16_t)dev->trim_data.dig_x2) + ((int16_t)0xA0)));
process_comp_x9 = ((process_comp_x7 * process_comp_x8) / 4096);
process_comp_x10 = ((int32_t)mag_data_x) * process_comp_x9;
retval = ((int16_t)(process_comp_x10 / 8192));
retval = (retval + (((int16_t)dev->trim_data.dig_x1) * 8)) / 16;
} else {
retval = BMM150_OVERFLOW_OUTPUT;
}
} else {
/* Overflow condition */
retval = BMM150_OVERFLOW_OUTPUT;
}
return retval;
}
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Y axis data(micro-tesla) in int16_t.
*/
static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall, const struct bmm150_dev *dev)
{
int16_t retval;
uint16_t process_comp_y0 = 0;
int32_t process_comp_y1;
uint16_t process_comp_y2;
int32_t process_comp_y3;
int32_t process_comp_y4;
int32_t process_comp_y5;
int32_t process_comp_y6;
int32_t process_comp_y7;
int32_t process_comp_y8;
int32_t process_comp_y9;
/* Overflow condition check */
if (mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL) {
if (data_rhall != 0) {
/* Availability of valid data*/
process_comp_y0 = data_rhall;
} else if (dev->trim_data.dig_xyz1 != 0) {
process_comp_y0 = dev->trim_data.dig_xyz1;
} else {
process_comp_y0 = 0;
}
if (process_comp_y0 != 0) {
/*Processing compensation equations*/
process_comp_y1 = (((int32_t)dev->trim_data.dig_xyz1) * 16384) / process_comp_y0;
process_comp_y2 = ((uint16_t)process_comp_y1) - ((uint16_t)0x4000);
retval = ((int16_t)process_comp_y2);
process_comp_y3 = ((int32_t) retval) * ((int32_t)retval);
process_comp_y4 = ((int32_t)dev->trim_data.dig_xy2) * (process_comp_y3 / 128);
process_comp_y5 = ((int32_t)(((int16_t)dev->trim_data.dig_xy1) * 128));
process_comp_y6 = ((process_comp_y4 + (((int32_t)retval) * process_comp_y5)) / 512);
process_comp_y7 = ((int32_t)(((int16_t)dev->trim_data.dig_y2) + ((int16_t)0xA0)));
process_comp_y8 = (((process_comp_y6 + ((int32_t)0x100000)) * process_comp_y7) / 4096);
process_comp_y9 = (((int32_t)mag_data_y) * process_comp_y8);
retval = (int16_t)(process_comp_y9 / 8192);
retval = (retval + (((int16_t)dev->trim_data.dig_y1) * 8)) / 16;
} else {
retval = BMM150_OVERFLOW_OUTPUT;
}
} else {
/* Overflow condition*/
retval = BMM150_OVERFLOW_OUTPUT;
}
return retval;
}
/*!
* @brief This internal API is used to obtain the compensated
* magnetometer Z axis data(micro-tesla) in int16_t.
*/
static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall, const struct bmm150_dev *dev)
{
int32_t retval;
int16_t process_comp_z0;
int32_t process_comp_z1;
int32_t process_comp_z2;
int32_t process_comp_z3;
int16_t process_comp_z4;
if (mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL) {
if ((dev->trim_data.dig_z2 != 0) && (dev->trim_data.dig_z1 != 0)
&& (data_rhall != 0) && (dev->trim_data.dig_xyz1 != 0)) {
/*Processing compensation equations*/
process_comp_z0 = ((int16_t)data_rhall) - ((int16_t) dev->trim_data.dig_xyz1);
process_comp_z1 = (((int32_t)dev->trim_data.dig_z3) * ((int32_t)(process_comp_z0))) / 4;
process_comp_z2 = (((int32_t)(mag_data_z - dev->trim_data.dig_z4)) * 32768);
process_comp_z3 = ((int32_t)dev->trim_data.dig_z1) * (((int16_t)data_rhall) * 2);
process_comp_z4 = (int16_t)((process_comp_z3 + (32768)) / 65536);
retval = ((process_comp_z2 - process_comp_z1) / (dev->trim_data.dig_z2 + process_comp_z4));
/* saturate result to +/- 2 micro-tesla */
if (retval > BMM150_POSITIVE_SATURATION_Z) {
retval = BMM150_POSITIVE_SATURATION_Z;
} else {
if (retval < BMM150_NEGATIVE_SATURATION_Z)
retval = BMM150_NEGATIVE_SATURATION_Z;
}
/* Conversion of LSB to micro-tesla*/
retval = retval / 16;
} else {
retval = BMM150_OVERFLOW_OUTPUT;
}
} else {
/* Overflow condition*/
retval = BMM150_OVERFLOW_OUTPUT;
}
return (int16_t)retval;
}
#endif
/*!
* @brief This internal API is used to perform the normal self test
* of the sensor and return the self test result as return value
*/
static int8_t perform_normal_self_test(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t self_test_bit = 0;
/* Triggers the start of normal self test */
rslt = enable_normal_self_test(&self_test_bit, dev);
/* Check for self test completion status */
if ((rslt == BMM150_OK) && (self_test_bit == 0)) {
/* Validates the self test results for all 3 axes */
rslt = validate_normal_self_test(dev);
}
return rslt;
}
/*!
* @brief This internal API is used to enable the normal self test by setting
* the Self Test bit (bit0) of the 0x4C register,
* which triggers the start of self test
*/
static int8_t enable_normal_self_test(uint8_t *self_test_enable, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
uint8_t self_test_val;
/* Read the data from register 0x4C */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/* Set the Self Test bit(bit0) of the 0x4C register */
self_test_val = 1;
reg_data = BMM150_SET_BITS(reg_data, BMM150_SELF_TEST, self_test_val);
/* Write the data to 0x4C register to trigger self test */
rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
dev->delay_ms(BMM150_NORMAL_SELF_TEST_DELAY);
if (rslt == BMM150_OK) {
/* Read the data from register 0x4C */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
/* Self Test bit(bit0) is stored in self_test_enable,
It will be reset to zero after the self test is over */
*self_test_enable = BMM150_GET_BITS(reg_data, BMM150_SELF_TEST);
}
}
return rslt;
}
/*!
* @brief This internal API is used to validate the results of normal self test
* by using the self test status available in the bit0 of registers 0x42,0x44
* and 0x46.
*/
static int8_t validate_normal_self_test(const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t status;
uint8_t self_test_rslt[5];
/* Read the data from register 0x42 to 0x46 */
rslt = bmm150_get_regs(BMM150_DATA_X_LSB, self_test_rslt, BMM150_SELF_TEST_LEN, dev);
if (rslt == BMM150_OK) {
/* Parse and get the self test status bits */
/* X-Self-Test (bit0) of 0x42 register is stored*/
self_test_rslt[0] = BMM150_GET_BITS(self_test_rslt[0], BMM150_SELF_TEST);
/* Y-Self-Test (bit0) of 0x44 register is stored */
self_test_rslt[2] = BMM150_GET_BITS(self_test_rslt[2], BMM150_SELF_TEST);
/* Z-Self-Test (bit0) of 0x46 register is stored */
self_test_rslt[4] = BMM150_GET_BITS(self_test_rslt[4], BMM150_SELF_TEST);
/* Combine the self test status and store it in the first
3 bits of the status variable for processing*/
status = (uint8_t)((self_test_rslt[4] << 2) | (self_test_rslt[2] << 1) | self_test_rslt[0]);
/* Validate status and store Self test result in "rslt" */
if (status == BMM150_SELF_TEST_STATUS_SUCCESS) {
/* Self test is success when all status bits are set */
rslt = BMM150_OK;
} else {
if (status == BMM150_SELF_TEST_STATUS_XYZ_FAIL) {
/* Self test - all axis fail condition */
rslt = BMM150_W_NORMAL_SELF_TEST_XYZ_FAIL;
} else {
/* Self test - some axis fail condition */
rslt = (int8_t)status;
}
}
}
return rslt;
}
/*!
* @brief This internal API is used to perform advanced self test for Z axis
*/
static int8_t perform_adv_self_test(struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t self_test_current;
int16_t positive_data_z;
int16_t negative_data_z;
/* Set the desired power mode ,axes control and repetition settings */
rslt = adv_self_test_settings(dev);
if (rslt == BMM150_OK) {
/* Measure the Z axes data with positive self-test current */
self_test_current = BMM150_ENABLE_POSITIVE_CURRENT;
rslt = adv_self_test_measurement(self_test_current, &positive_data_z, dev);
if (rslt == BMM150_OK) {
/* Measure the Z axes data with
negative self-test current */
self_test_current = BMM150_ENABLE_NEGATIVE_CURRENT;
rslt = adv_self_test_measurement(self_test_current, &negative_data_z, dev);
if (rslt == BMM150_OK) {
/* Disable self-test current */
self_test_current = BMM150_DISABLE_SELF_TEST_CURRENT;
rslt = set_adv_self_test_current(self_test_current, dev);
if (rslt == BMM150_OK) {
/* Validate the advanced self test */
rslt = validate_adv_self_test(positive_data_z, negative_data_z);
}
}
}
}
return rslt;
}
/*!
* @brief This internal API is used to set the desired power mode ,
* axes control and repetition settings for advanced self test
*/
static int8_t adv_self_test_settings(struct bmm150_dev *dev)
{
int8_t rslt;
/* Set the power mode as sleep mode */
dev->settings.pwr_mode = BMM150_SLEEP_MODE;
rslt = bmm150_set_op_mode(dev);
if (rslt == BMM150_OK) {
/* Disable XY-axis measurement */
dev->settings.xyz_axes_control = BMM150_DISABLE_XY_AXIS;
rslt = set_control_measurement_xyz(dev);
if (rslt == BMM150_OK) {
/* Repetition value is set as 0x04 */
dev->settings.z_rep = BMM150_SELF_TEST_REP_Z;
rslt = set_z_rep(dev);
}
}
return rslt;
}
/*!
* @brief This internal API is used to set the positive or negative value of
* self-test current and obtain the corresponding magnetometer z axis data
*/
static int8_t adv_self_test_measurement(uint8_t self_test_current, int16_t *data_z, struct bmm150_dev *dev)
{
int8_t rslt;
/* Set the advanced self test current as positive or
negative based on the value of parameter "self_test_current" */
rslt = set_adv_self_test_current(self_test_current, dev);
if (rslt == BMM150_OK) {
/* Set the device in forced mode*/
dev->settings.pwr_mode = BMM150_FORCED_MODE;
rslt = bmm150_set_op_mode(dev);
/* Delay to ensure measurement is complete */
dev->delay_ms(BMM150_ADV_SELF_TEST_DELAY);
if (rslt == BMM150_OK) {
/* Read Mag data and store the value of Z axis data */
rslt = bmm150_read_mag_data(dev);
if (rslt == BMM150_OK) {
/* Mag Z axis data is stored */
*data_z = dev->data.z;
}
}
}
return rslt;
}
/*!
* @brief This internal API is used to get the difference between the
* Z axis mag data obtained by positive and negative self-test current
* and validate whether the advanced self test is done successfully or not.
*/
static int8_t validate_adv_self_test(int16_t positive_data_z, int16_t negative_data_z)
{
int32_t adv_self_test_rslt;
int8_t rslt;
/* Advanced self test difference between the Z axis mag data
obtained by the positive and negative self-test current */
adv_self_test_rslt = positive_data_z - negative_data_z;
/* Advanced self test validation */
/*Value of adv_self_test_rslt should be in between 180-240 micro-tesla*/
if ((adv_self_test_rslt > 180) && (adv_self_test_rslt < 240)) {
/* Advanced self test success */
rslt = BMM150_OK;
} else {
/* Advanced self test fail */
rslt = BMM150_W_ADV_SELF_TEST_FAIL;
}
return rslt;
}
/*!
* @brief This internal API is used to set the self test current value in
* the Adv. ST bits (bit6 and bit7) of 0x4C register
*/
static int8_t set_adv_self_test_current(uint8_t self_test_current, const struct bmm150_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
/* Read the 0x4C register */
rslt = bmm150_get_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
if (rslt == BMM150_OK) {
/* Set the self test current value in the Adv. ST bits
(bit6 and bit7) of 0x4c register */
reg_data = BMM150_SET_BITS(reg_data, BMM150_ADV_SELF_TEST, self_test_current);
rslt = bmm150_set_regs(BMM150_OP_MODE_ADDR, &reg_data, 1, dev);
}
return rslt;
}
/*
****************************************************************************
* Copyright (C) 2012 - 2015 Bosch Sensortec GmbH
*
* File : bmp280.c
*
* Date : 2016/06/30
*
* Revision : 2.0.9(Pressure and Temperature compensation code revision is 1.1)
*
* Usage: Sensor Driver for BMP280 sensor
*
****************************************************************************
*
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry.
* They may only be used within the parameters of the respective valid
* product data sheet. Bosch Sensortec products are provided with the
* express understanding that there is no warranty of fitness for a
* particular purpose.They are not fit for use in life-sustaining,
* safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system
* or device malfunctions. In addition,Bosch Sensortec products are
* not fit for use in products which interact with motor vehicle systems.
* The resale and or use of products are at the purchasers own risk and
* his own responsibility. The examination of fitness for the intended use
* is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party
* claims, including any claims for incidental, or consequential damages,
* arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by
* Bosch Sensortec and reimburse Bosch Sensortec for all costs in
* connection with such claims.
*
* The purchaser must monitor the market for the purchased products,
* particularly with regard to product safety and inform Bosch Sensortec
* without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e).
* Samples may vary from the valid technical specifications of the product
* series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal
* client testing. The testing of an engineering sample may in no way
* replace the testing of a product series. Bosch Sensortec assumes
* no liability for the use of engineering samples.
* By accepting the engineering samples, the Purchaser agrees to indemnify
* Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information
* on application-sheets (hereinafter called "Information") is provided
* free of charge for the sole purpose to support your application work.
* The Software and Information is subject to the following
* terms and conditions:
*
* The Software is specifically designed for the exclusive use for
* Bosch Sensortec products by personnel who have special experience
* and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed
* or implied warranties,including without limitation, the implied warranties
* of merchantability and fitness for a particular purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability
* for the functional impairment
* of this Software in terms of fitness, performance and safety.
* Bosch Sensortec and their representatives and agents shall not be liable
* for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable.
* Bosch Sensortec assumes no responsibility for the consequences of use
* of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*
**************************************************************************/
#include "../interface/bmp280.h"
static struct bmp280_t *p_bmp280; /**< pointer to BMP280 */
/*!
* @brief This function is used for initialize
* the bus read and bus write functions
* and assign the chip id and I2C address of the BMP280 sensor
* chip id is read in the register 0xD0 bit from 0 to 7
*
* @param *bmp280 structure pointer.
*
* @note While changing the parameter of the p_bmp280
* @note consider the following point:
* Changing the reference value of the parameter
* will changes the local copy or local reference
* make sure your changes will not
* affect the reference value of the parameter
* (Better case don't change the reference value of the parameter)
*
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_init(struct bmp280_t *bmp280)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
p_bmp280 = bmp280;/* assign BMP280 ptr */
/* read chip id */
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CHIP_ID_REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);/* read Chip Id */
p_bmp280->chip_id = v_data_u8;
/* readout bmp280 calibparam structure */
com_rslt += bmp280_get_calib_param();
return com_rslt;
}
/*!
* @brief This API is used to read uncompensated temperature
* in the registers 0xFA, 0xFB and 0xFC
* @note 0xFA -> MSB -> bit from 0 to 7
* @note 0xFB -> LSB -> bit from 0 to 7
* @note 0xFC -> LSB -> bit from 4 to 7
*
* @param v_uncomp_temperature_s32 : The uncompensated temperature.
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_read_uncomp_temperature(
int32_t *v_uncomp_temperature_s32)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
/* Array holding the MSB and LSb value
a_data_u8r[0] - Temperature MSB
a_data_u8r[1] - Temperature LSB
a_data_u8r[2] - Temperature LSB
*/
uint8_t a_data_u8r[BMP280_TEMPERATURE_DATA_SIZE] = {BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE};
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read temperature data */
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_TEMPERATURE_MSB_REG, a_data_u8r,
BMP280_TEMPERATURE_DATA_LENGTH);
*v_uncomp_temperature_s32 = (int32_t)((((uint32_t)(
a_data_u8r[BMP280_TEMPERATURE_MSB_DATA]))
<< BMP280_SHIFT_BIT_POSITION_BY_12_BITS)
| (((uint32_t)(
a_data_u8r[BMP280_TEMPERATURE_LSB_DATA]))
<< BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
| ((uint32_t)a_data_u8r[BMP280_TEMPERATURE_XLSB_DATA]
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
}
return com_rslt;
}
/*!
* @brief Reads actual temperature
* from uncompensated temperature
* @note Returns the value in 0.01 degree Centigrade
* @note Output value of "5123" equals 51.23 DegC.
*
*
*
* @param v_uncomp_temperature_s32 : value of uncompensated temperature
*
*
*
* @return Actual temperature output as int32_t
*
*/
int32_t bmp280_compensate_temperature_s32(int32_t v_uncomp_temperature_s32)
{
int32_t v_x1_u32r = BMP280_INIT_VALUE;
int32_t v_x2_u32r = BMP280_INIT_VALUE;
int32_t temperature = BMP280_INIT_VALUE;
/* calculate true temperature*/
/*calculate x1*/
v_x1_u32r = ((((v_uncomp_temperature_s32
>> BMP280_SHIFT_BIT_POSITION_BY_03_BITS)
- ((int32_t)p_bmp280->calib_param.dig_T1
<< BMP280_SHIFT_BIT_POSITION_BY_01_BIT)))
* ((int32_t)p_bmp280->calib_param.dig_T2))
>> BMP280_SHIFT_BIT_POSITION_BY_11_BITS;
/*calculate x2*/
v_x2_u32r = (((((v_uncomp_temperature_s32
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
- ((int32_t)p_bmp280->calib_param.dig_T1))
* ((v_uncomp_temperature_s32
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
- ((int32_t)p_bmp280->calib_param.dig_T1)))
>> BMP280_SHIFT_BIT_POSITION_BY_12_BITS)
* ((int32_t)p_bmp280->calib_param.dig_T3))
>> BMP280_SHIFT_BIT_POSITION_BY_14_BITS;
/*calculate t_fine*/
p_bmp280->calib_param.t_fine = v_x1_u32r + v_x2_u32r;
/*calculate temperature*/
temperature = (p_bmp280->calib_param.t_fine * 5 + 128)
>> BMP280_SHIFT_BIT_POSITION_BY_08_BITS;
return temperature;
}
/*!
* @brief This API is used to read uncompensated pressure.
* in the registers 0xF7, 0xF8 and 0xF9
* @note 0xF7 -> MSB -> bit from 0 to 7
* @note 0xF8 -> LSB -> bit from 0 to 7
* @note 0xF9 -> LSB -> bit from 4 to 7
*
*
*
* @param v_uncomp_pressure_s32 : The value of uncompensated pressure
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_read_uncomp_pressure(
int32_t *v_uncomp_pressure_s32)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
/* Array holding the MSB and LSb value
a_data_u8[0] - Pressure MSB
a_data_u8[1] - Pressure LSB
a_data_u8[2] - Pressure LSB
*/
uint8_t a_data_u8[BMP280_PRESSURE_DATA_SIZE] = {BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE};
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_PRESSURE_MSB_REG, a_data_u8,
BMP280_PRESSURE_DATA_LENGTH);
*v_uncomp_pressure_s32 = (int32_t)((((uint32_t)(
a_data_u8[BMP280_PRESSURE_MSB_DATA]))
<< BMP280_SHIFT_BIT_POSITION_BY_12_BITS)
| (((uint32_t)(a_data_u8[BMP280_PRESSURE_LSB_DATA]))
<< BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
| ((uint32_t)a_data_u8[BMP280_PRESSURE_XLSB_DATA]
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
}
return com_rslt;
}
/*!
* @brief Reads actual pressure from uncompensated pressure
* and returns the value in Pascal(Pa)
* @note Output value of "96386" equals 96386 Pa =
* 963.86 hPa = 963.86 millibar
*
*
*
*
* @param v_uncomp_pressure_s32: value of uncompensated pressure
*
*
*
* @return Returns the Actual pressure out put as int32_t
*
*/
uint32_t bmp280_compensate_pressure_s32(int32_t v_uncomp_pressure_s32)
{
int32_t v_x1_u32r = BMP280_INIT_VALUE;
int32_t v_x2_u32r = BMP280_INIT_VALUE;
int32_t v_x3_u32r = BMP280_INIT_VALUE;
uint32_t v_pressure_u32 = BMP280_INIT_VALUE;
/* calculate x1*/
v_x1_u32r = (((int32_t)p_bmp280->calib_param.t_fine)
>> BMP280_SHIFT_BIT_POSITION_BY_01_BIT) - (int32_t)64000;
/* calculate x2*/
v_x2_u32r = (((v_x1_u32r >> BMP280_SHIFT_BIT_POSITION_BY_02_BITS)
* (v_x1_u32r >> BMP280_SHIFT_BIT_POSITION_BY_02_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_11_BITS)
* ((int32_t)p_bmp280->calib_param.dig_P6);
v_x2_u32r = v_x2_u32r + ((v_x1_u32r *
((int32_t)p_bmp280->calib_param.dig_P5))
<< BMP280_SHIFT_BIT_POSITION_BY_01_BIT);
v_x2_u32r = (v_x2_u32r >> BMP280_SHIFT_BIT_POSITION_BY_02_BITS)
+ (((int32_t)p_bmp280->calib_param.dig_P4)
<< BMP280_SHIFT_BIT_POSITION_BY_16_BITS);
/* calculate x1*/
v_x1_u32r = (((p_bmp280->calib_param.dig_P3
* (((v_x1_u32r
>> BMP280_SHIFT_BIT_POSITION_BY_02_BITS) * (v_x1_u32r
>> BMP280_SHIFT_BIT_POSITION_BY_02_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_13_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_03_BITS)
+ ((((int32_t)p_bmp280->calib_param.dig_P2)
* v_x1_u32r)
>> BMP280_SHIFT_BIT_POSITION_BY_01_BIT))
>> BMP280_SHIFT_BIT_POSITION_BY_18_BITS;
v_x1_u32r = ((((32768 + v_x1_u32r))
* ((int32_t)p_bmp280->calib_param.dig_P1))
>> BMP280_SHIFT_BIT_POSITION_BY_15_BITS);
/* calculate pressure*/
v_pressure_u32 = (((uint32_t)(((int32_t)1048576) - v_uncomp_pressure_s32)
- (v_x2_u32r >> BMP280_SHIFT_BIT_POSITION_BY_12_BITS)))
* 3125;
/* check overflow*/
if (v_pressure_u32 < 0x80000000)
/* Avoid exception caused by division by zero */
if (v_x1_u32r != BMP280_INIT_VALUE)
v_pressure_u32 = (v_pressure_u32
<< BMP280_SHIFT_BIT_POSITION_BY_01_BIT)
/ ((uint32_t)v_x1_u32r);
else
return BMP280_INVALID_DATA;
else
/* Avoid exception caused by division by zero */
if (v_x1_u32r != BMP280_INIT_VALUE)
v_pressure_u32 = (v_pressure_u32 / (uint32_t)v_x1_u32r) * 2;
else
return BMP280_INVALID_DATA;
/* calculate x1*/
v_x1_u32r = (((int32_t)p_bmp280->calib_param.dig_P9) * ((int32_t)(
((v_pressure_u32
>> BMP280_SHIFT_BIT_POSITION_BY_03_BITS)
* (v_pressure_u32
>> BMP280_SHIFT_BIT_POSITION_BY_03_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_13_BITS)))
>> BMP280_SHIFT_BIT_POSITION_BY_12_BITS;
/* calculate x2*/
v_x2_u32r = (((int32_t)(v_pressure_u32 >>
BMP280_SHIFT_BIT_POSITION_BY_02_BITS))
* ((int32_t)p_bmp280->calib_param.dig_P8))
>> BMP280_SHIFT_BIT_POSITION_BY_13_BITS;
/* calculate x3*/
v_x3_u32r = (int32_t)(((int32_t)(((v_pressure_u32
>> BMP280_SHIFT_BIT_POSITION_BY_03_BITS) *
(v_pressure_u32 >> BMP280_SHIFT_BIT_POSITION_BY_03_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_08_BITS) *
((int32_t)((((int32_t)p_bmp280->calib_param.dig_P10)
* (int32_t)v_pressure_u32)
>> BMP280_SHIFT_BIT_POSITION_BY_14_BITS)))
>> BMP280_SHIFT_BIT_POSITION_BY_13_BITS);
/* calculate true pressure*/
v_pressure_u32 = (uint32_t)((int32_t)v_pressure_u32 +
((v_x1_u32r + v_x2_u32r + v_x3_u32r
+ p_bmp280->calib_param.dig_P7)
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
return v_pressure_u32;
}
/*!
* @brief reads uncompensated pressure and temperature
*
*
* @param v_uncomp_pressure_s32: The value of uncompensated pressure.
* @param v_uncomp_temperature_s32: The value of uncompensated temperature.
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_read_uncomp_pressure_temperature(
int32_t *v_uncomp_pressure_s32, int32_t *v_uncomp_temperature_s32)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
/* Array holding the temperature and pressure data
a_data_u8[0] - Pressure MSB
a_data_u8[1] - Pressure LSB
a_data_u8[2] - Pressure LSB
a_data_u8[3] - Temperature MSB
a_data_u8[4] - Temperature LSB
a_data_u8[5] - Temperature LSB
*/
uint8_t a_data_u8[BMP280_ALL_DATA_FRAME_LENGTH] = {BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE};
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_PRESSURE_MSB_REG, a_data_u8,
BMP280_DATA_FRAME_SIZE);
/*Pressure*/
*v_uncomp_pressure_s32 = (int32_t)((((uint32_t)(
a_data_u8[BMP280_DATA_FRAME_PRESSURE_MSB_BYTE]))
<< BMP280_SHIFT_BIT_POSITION_BY_12_BITS)
| (((uint32_t)(
a_data_u8[BMP280_DATA_FRAME_PRESSURE_LSB_BYTE]))
<< BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
| ((uint32_t)a_data_u8[
BMP280_DATA_FRAME_PRESSURE_XLSB_BYTE]
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
/* Temperature */
*v_uncomp_temperature_s32 = (int32_t)((((uint32_t)(a_data_u8[
BMP280_DATA_FRAME_TEMPERATURE_MSB_BYTE]))
<< BMP280_SHIFT_BIT_POSITION_BY_12_BITS)
| (((uint32_t)(a_data_u8[
BMP280_DATA_FRAME_TEMPERATURE_LSB_BYTE]))
<< BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
| ((uint32_t)a_data_u8[
BMP280_DATA_FRAME_TEMPERATURE_XLSB_BYTE]
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS));
}
return com_rslt;
}
/*!
* @brief This API reads the true pressure and temperature
*
*
* @param v_pressure_u32 : The value of compensated pressure.
* @param v_temperature_s32 : The value of compensated temperature.
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_read_pressure_temperature(
uint32_t *v_pressure_u32,int32_t *v_temperature_s32)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
int32_t v_uncomp_pressure_s32 = BMP280_INIT_VALUE;
int32_t v_uncomp_temperature_s32 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read uncompensated pressure and temperature*/
com_rslt = bmp280_read_uncomp_pressure_temperature(
&v_uncomp_pressure_s32,
&v_uncomp_temperature_s32);
/* read true pressure and temperature*/
*v_temperature_s32 = bmp280_compensate_temperature_s32(
v_uncomp_temperature_s32);
*v_pressure_u32 = bmp280_compensate_pressure_s32(
v_uncomp_pressure_s32);
}
return com_rslt;
}
/*!
* @brief This API is used to
* calibration parameters used for calculation in the registers
*
* parameter | Register address | bit
*------------|------------------|----------------
* dig_T1 | 0x88 and 0x89 | from 0 : 7 to 8: 15
* dig_T2 | 0x8A and 0x8B | from 0 : 7 to 8: 15
* dig_T3 | 0x8C and 0x8D | from 0 : 7 to 8: 15
* dig_P1 | 0x8E and 0x8F | from 0 : 7 to 8: 15
* dig_P2 | 0x90 and 0x91 | from 0 : 7 to 8: 15
* dig_P3 | 0x92 and 0x93 | from 0 : 7 to 8: 15
* dig_P4 | 0x94 and 0x95 | from 0 : 7 to 8: 15
* dig_P5 | 0x96 and 0x97 | from 0 : 7 to 8: 15
* dig_P6 | 0x98 and 0x99 | from 0 : 7 to 8: 15
* dig_P7 | 0x9A and 0x9B | from 0 : 7 to 8: 15
* dig_P8 | 0x9C and 0x9D | from 0 : 7 to 8: 15
* dig_P9 | 0x9E and 0x9F | from 0 : 7 to 8: 15
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_calib_param(void)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t a_data_u8[BMP280_CALIB_DATA_SIZE] = {
BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE,
BMP280_INIT_VALUE, BMP280_INIT_VALUE, BMP280_INIT_VALUE};
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG,
a_data_u8,
BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH);
/* read calibration values*/
p_bmp280->calib_param.dig_T1 = (uint16_t)((((uint16_t)((uint8_t)a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T1_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T1_LSB]);
p_bmp280->calib_param.dig_T2 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T2_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T2_LSB]);
p_bmp280->calib_param.dig_T3 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T3_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_TEMPERATURE_CALIB_DIG_T3_LSB]);
p_bmp280->calib_param.dig_P1 = (uint16_t)((((uint16_t)((uint8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P1_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P1_LSB]);
p_bmp280->calib_param.dig_P2 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P2_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P2_LSB]);
p_bmp280->calib_param.dig_P3 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P3_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P3_LSB]);
p_bmp280->calib_param.dig_P4 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P4_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P4_LSB]);
p_bmp280->calib_param.dig_P5 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P5_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P5_LSB]);
p_bmp280->calib_param.dig_P6 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P6_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P6_LSB]);
p_bmp280->calib_param.dig_P7 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P7_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P7_LSB]);
p_bmp280->calib_param.dig_P8 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P8_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P8_LSB]);
p_bmp280->calib_param.dig_P9 = (int16_t)((((int16_t)((int8_t)a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P9_MSB]))
<< BMP280_SHIFT_BIT_POSITION_BY_08_BITS)
| a_data_u8[
BMP280_PRESSURE_CALIB_DIG_P9_LSB]);
p_bmp280->calib_param.dig_P10 =
(int8_t)(a_data_u8[BMP280_PRESSURE_CALIB_DIG_P10]);
}
return com_rslt;
}
/*!
* @brief This API is used to get
* the temperature oversampling setting in the register 0xF4
* bits from 5 to 7
*
* value | Temperature oversampling
* ------------------------|------------------------------
* 0x00 | BMP280_OVERSAMP_SKIPPED
* 0x01 | BMP280_OVERSAMP_1X
* 0x02 | BMP280_OVERSAMP_2X
* 0x03 | BMP280_OVERSAMP_4X
* 0x04 | BMP280_OVERSAMP_8X
* 0x05,0x06 and 0x07 | BMP280_OVERSAMP_16X
*
*
* @param v_value_u8 :The value of temperature over sampling
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_oversamp_temperature(uint8_t *v_value_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read temperature over sampling*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__REG,
&v_data_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_value_u8 = BMP280_GET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE);
/* assign temperature oversampling*/
p_bmp280->oversamp_temperature = *v_value_u8;
}
return com_rslt;
}
/*!
* @brief This API is used to set
* the temperature oversampling setting in the register 0xF4
* bits from 5 to 7
*
* value | Temperature oversampling
* ------------------------|------------------------------
* 0x00 | BMP280_OVERSAMP_SKIPPED
* 0x01 | BMP280_OVERSAMP_1X
* 0x02 | BMP280_OVERSAMP_2X
* 0x03 | BMP280_OVERSAMP_4X
* 0x04 | BMP280_OVERSAMP_8X
* 0x05,0x06 and 0x07 | BMP280_OVERSAMP_16X
*
*
* @param v_value_u8 :The value of temperature over sampling
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_oversamp_temperature(uint8_t v_value_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__REG,
&v_data_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
/* write over sampling*/
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE,
v_value_u8);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__REG,
&v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
p_bmp280->oversamp_temperature = v_value_u8;
}
}
return com_rslt;
}
/*!
* @brief This API is used to get
* the pressure oversampling setting in the register 0xF4
* bits from 2 to 4
*
* value | Pressure oversampling
* ------------------------|------------------------------
* 0x00 | BMP280_OVERSAMP_SKIPPED
* 0x01 | BMP280_OVERSAMP_1X
* 0x02 | BMP280_OVERSAMP_2X
* 0x03 | BMP280_OVERSAMP_4X
* 0x04 | BMP280_OVERSAMP_8X
* 0x05,0x06 and 0x07 | BMP280_OVERSAMP_16X
*
*
* @param v_value_u8 : The value of pressure over sampling
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_oversamp_pressure(uint8_t *v_value_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read pressure over sampling */
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__REG,
&v_data_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_value_u8 = BMP280_GET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE);
p_bmp280->oversamp_pressure = *v_value_u8;
}
return com_rslt;
}
/*!
* @brief This API is used to set
* the pressure oversampling setting in the register 0xF4
* bits from 2 to 4
*
* value | Pressure oversampling
* ------------------------|------------------------------
* 0x00 | BMP280_OVERSAMP_SKIPPED
* 0x01 | BMP280_OVERSAMP_1X
* 0x02 | BMP280_OVERSAMP_2X
* 0x03 | BMP280_OVERSAMP_4X
* 0x04 | BMP280_OVERSAMP_8X
* 0x05,0x06 and 0x07 | BMP280_OVERSAMP_16X
*
*
* @param v_value_u8 : The value of pressure over sampling
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_oversamp_pressure(uint8_t v_value_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__REG,
&v_data_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
/* write pressure over sampling */
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE,
v_value_u8);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__REG,
&v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
p_bmp280->oversamp_pressure = v_value_u8;
}
}
return com_rslt;
}
/*!
* @brief This API used to get the
* Operational Mode from the sensor in the register 0xF4 bit 0 and 1
*
*
*
* @param v_power_mode_u8 : The value of power mode value
* value | Power mode
* ------------------|------------------
* 0x00 | BMP280_SLEEP_MODE
* 0x01 and 0x02 | BMP280_FORCED_MODE
* 0x03 | BMP280_NORMAL_MODE
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_power_mode(uint8_t *v_power_mode_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_mode_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read the power mode*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_POWER_MODE__REG,
&v_mode_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_power_mode_u8 = BMP280_GET_BITSLICE(v_mode_u8,
BMP280_CTRL_MEAS_REG_POWER_MODE);
}
return com_rslt;
}
/*!
* @brief This API used to set the
* Operational Mode from the sensor in the register 0xF4 bit 0 and 1
*
*
*
* @param v_power_mode_u8 : The value of power mode value
* value | Power mode
* ------------------|------------------
* 0x00 | BMP280_SLEEP_MODE
* 0x01 and 0x02 | BMP280_FORCED_MODE
* 0x03 | BMP280_NORMAL_MODE
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_power_mode(uint8_t v_power_mode_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_mode_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
if (v_power_mode_u8 <= BMP280_NORMAL_MODE) {
/* write the power mode*/
v_mode_u8 = (p_bmp280->oversamp_temperature
<< BMP280_SHIFT_BIT_POSITION_BY_05_BITS)
+ (p_bmp280->oversamp_pressure
<< BMP280_SHIFT_BIT_POSITION_BY_02_BITS)
+ v_power_mode_u8;
com_rslt = p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG_POWER_MODE__REG,
&v_mode_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
} else {
com_rslt = E_BMP280_OUT_OF_RANGE;
}
}
return com_rslt;
}
/*!
* @brief Used to reset the sensor
* The value 0xB6 is written to the 0xE0 register
* the device is reset using the
* complete power-on-reset procedure.
* Soft reset can be easily set using bmp280_set_softreset().
*
* @note Usage Hint : bmp280_set_softreset()
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_soft_rst(void)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_SOFT_RESET_CODE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* write soft reset */
com_rslt = p_bmp280->bus_write(p_bmp280->dev_addr,
BMP280_RST_REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
}
return com_rslt;
}
/*!
* @brief This API used to get the sensor
* SPI mode(communication type) in the register 0xF5 bit 0
*
*
*
* @param v_enable_disable_u8 : The spi3 enable or disable state
* value | Description
* -----------|---------------
* 0 | Disable
* 1 | Enable
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_spi3(uint8_t *v_enable_disable_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_SPI3_ENABLE__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_enable_disable_u8 = BMP280_GET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_SPI3_ENABLE);
}
return com_rslt;
}
/*!
* @brief This API used to set the sensor
* SPI mode(communication type) in the register 0xF5 bit 0
*
*
*
* @param v_enable_disable_u8 : The spi3 enable or disable state
* value | Description
* -----------|---------------
* 0 | Disable
* 1 | Enable
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_spi3(uint8_t v_enable_disable_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_SPI3_ENABLE__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_SPI3_ENABLE,
v_enable_disable_u8);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CONFIG_REG_SPI3_ENABLE__REG,
&v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
}
}
return com_rslt;
}
/*!
* @brief This API is used to reads filter setting
* in the register 0xF5 bit 3 and 4
*
*
*
* @param v_value_u8 : The value of filter coefficient
* value | Filter coefficient
* -------------|-------------------------
* 0x00 | BMP280_FILTER_COEFF_OFF
* 0x01 | BMP280_FILTER_COEFF_2
* 0x02 | BMP280_FILTER_COEFF_4
* 0x03 | BMP280_FILTER_COEFF_8
* 0x04 | BMP280_FILTER_COEFF_16
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_filter(uint8_t *v_value_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read filter*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_FILTER__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_value_u8 = BMP280_GET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_FILTER);
}
return com_rslt;
}
/*!
* @brief This API is used to write filter setting
* in the register 0xF5 bit 3 and 4
*
*
*
* @param v_value_u8 : The value of filter coefficient
* value | Filter coefficient
* -------------|-------------------------
* 0x00 | BMP280_FILTER_COEFF_OFF
* 0x01 | BMP280_FILTER_COEFF_2
* 0x02 | BMP280_FILTER_COEFF_4
* 0x03 | BMP280_FILTER_COEFF_8
* 0x04 | BMP280_FILTER_COEFF_16
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_filter(uint8_t v_value_u8)
{
BMP280_RETURN_FUNCTION_TYPE com_rslt = SUCCESS;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* write filter*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_FILTER__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_FILTER, v_value_u8);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CONFIG_REG_FILTER__REG,
&v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
}
}
return com_rslt;
}
/*!
* @brief This API used to Read the
* standby duration time from the sensor in the register 0xF5 bit 5 to 7
*
* @param v_standby_durn_u8 : The standby duration time value.
* value | standby duration
* -----------|--------------------
* 0x00 | BMP280_STANDBYTIME_1_MS
* 0x01 | BMP280_STANDBYTIME_63_MS
* 0x02 | BMP280_STANDBYTIME_125_MS
* 0x03 | BMP280_STANDBYTIME_250_MS
* 0x04 | BMP280_STANDBYTIME_500_MS
* 0x05 | BMP280_STANDBYTIME_1000_MS
* 0x06 | BMP280_STANDBYTIME_2000_MS
* 0x07 | BMP280_STANDBYTIME_4000_MS
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_standby_durn(uint8_t *v_standby_durn_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read the standby duration*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_STANDBY_DURN__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
*v_standby_durn_u8 = BMP280_GET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_STANDBY_DURN);
}
return com_rslt;
}
/*!
* @brief This API used to Read the
* standby duration time from the sensor
* in the register 0xF5 bit 5 to 7
* @note Normal mode comprises an
* automated perpetual cycling between an (active)
* Measurement period and an (inactive) standby period.
* @note The standby time is determined
* by the contents of the register t_sb.
* Standby time can be set using BMP280_STANDBYTIME_125_MS.
*
* @note bmp280_set_standby_durn(BMP280_STANDBYTIME_125_MS)
*
*
*
* @param v_standby_durn_u8 : The standby duration time value.
* value | standby duration
* -----------|--------------------
* 0x00 | BMP280_STANDBYTIME_1_MS
* 0x01 | BMP280_STANDBYTIME_63_MS
* 0x02 | BMP280_STANDBYTIME_125_MS
* 0x03 | BMP280_STANDBYTIME_250_MS
* 0x04 | BMP280_STANDBYTIME_500_MS
* 0x05 | BMP280_STANDBYTIME_1000_MS
* 0x06 | BMP280_STANDBYTIME_2000_MS
* 0x07 | BMP280_STANDBYTIME_4000_MS
*
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_standby_durn(uint8_t v_standby_durn_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* write the standby duration*/
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
BMP280_CONFIG_REG_STANDBY_DURN__REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CONFIG_REG_STANDBY_DURN,
v_standby_durn_u8);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr,
BMP280_CONFIG_REG_STANDBY_DURN__REG,
&v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
}
}
return com_rslt;
}
/*!
* @brief This API is used to write
* the working mode of the sensor
*
*
* @param v_work_mode_u8 : The value of work mode
* value | mode
* -------------|-------------
* 0 | BMP280_ULTRA_LOW_POWER_MODE
* 1 | BMP280_LOW_POWER_MODE
* 2 | BMP280_STANDARD_RESOLUTION_MODE
* 3 | BMP280_HIGH_RESOLUTION_MODE
* 4 | BMP280_ULTRA_HIGH_RESOLUTION_MODE
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_set_work_mode(uint8_t v_work_mode_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
if (v_work_mode_u8 <= BMP280_ULTRA_HIGH_RESOLUTION_MODE) {
com_rslt = p_bmp280->bus_read(
p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
if (com_rslt == SUCCESS) {
switch (v_work_mode_u8) {
/* write work mode*/
case BMP280_ULTRA_LOW_POWER_MODE:
p_bmp280->oversamp_temperature =
BMP280_ULTRALOWPOWER_OVERSAMP_TEMPERATURE;
p_bmp280->oversamp_pressure =
BMP280_ULTRALOWPOWER_OVERSAMP_PRESSURE;
break;
case BMP280_LOW_POWER_MODE:
p_bmp280->oversamp_temperature =
BMP280_LOWPOWER_OVERSAMP_TEMPERATURE;
p_bmp280->oversamp_pressure =
BMP280_LOWPOWER_OVERSAMP_PRESSURE;
break;
case BMP280_STANDARD_RESOLUTION_MODE:
p_bmp280->oversamp_temperature =
BMP280_STANDARDRESOLUTION_OVERSAMP_TEMPERATURE;
p_bmp280->oversamp_pressure =
BMP280_STANDARDRESOLUTION_OVERSAMP_PRESSURE;
break;
case BMP280_HIGH_RESOLUTION_MODE:
p_bmp280->oversamp_temperature =
BMP280_HIGHRESOLUTION_OVERSAMP_TEMPERATURE;
p_bmp280->oversamp_pressure =
BMP280_HIGHRESOLUTION_OVERSAMP_PRESSURE;
break;
case BMP280_ULTRA_HIGH_RESOLUTION_MODE:
p_bmp280->oversamp_temperature =
BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE;
p_bmp280->oversamp_pressure =
BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE;
break;
}
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE,
p_bmp280->oversamp_temperature);
v_data_u8 = BMP280_SET_BITSLICE(v_data_u8,
BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE,
p_bmp280->oversamp_pressure);
com_rslt += p_bmp280->bus_write(
p_bmp280->dev_addr, BMP280_CTRL_MEAS_REG,
&v_data_u8, BMP280_GEN_READ_WRITE_DATA_LENGTH);
}
} else {
com_rslt = E_BMP280_OUT_OF_RANGE;
}
}
return com_rslt;
}
/*!
* @brief This API used to read both
* uncompensated pressure and temperature in forced mode
*
*
* @param v_uncomp_pressure_s32: The value of uncompensated pressure.
* @param v_uncomp_temperature_s32: The value of uncompensated temperature
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_get_forced_uncomp_pressure_temperature(
int32_t *v_uncomp_pressure_s32, int32_t *v_uncomp_temperature_s32)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
uint8_t v_data_u8 = BMP280_INIT_VALUE;
uint8_t v_waittime_u8 = BMP280_INIT_VALUE;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
/* read pressure and temperature*/
v_data_u8 = (p_bmp280->oversamp_temperature
<< BMP280_SHIFT_BIT_POSITION_BY_05_BITS)
+ (p_bmp280->oversamp_pressure
<< BMP280_SHIFT_BIT_POSITION_BY_02_BITS)
+ BMP280_FORCED_MODE;
com_rslt = p_bmp280->bus_write(p_bmp280->dev_addr,
BMP280_CTRL_MEAS_REG, &v_data_u8,
BMP280_GEN_READ_WRITE_DATA_LENGTH);
bmp280_compute_wait_time(&v_waittime_u8);
p_bmp280->delay_ms(v_waittime_u8);
com_rslt += bmp280_read_uncomp_pressure_temperature(
v_uncomp_pressure_s32,
v_uncomp_temperature_s32);
}
return com_rslt;
}
/*!
* @brief
* This API write the data to
* the given register
*
*
* @param v_addr_u8 -> Address of the register
* @param v_data_u8 -> The data from the register
* @param v_len_u8 -> no of bytes to read
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_write_register(uint8_t v_addr_u8, uint8_t *v_data_u8,
uint8_t v_len_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_write(p_bmp280->dev_addr,
v_addr_u8, v_data_u8, v_len_u8);
}
return com_rslt;
}
/*!
* @brief
* This API reads the data from
* the given register
*
*
* @param v_addr_u8 -> Address of the register
* @param v_data_u8 -> The data from the register
* @param v_len_u8 -> no of bytes to read
*
*
* @return results of bus communication function
* @retval 0 -> Success
* @retval -1 -> Error
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_read_register(uint8_t v_addr_u8, uint8_t *v_data_u8,
uint8_t v_len_u8)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = ERROR;
/* check the p_bmp280 structure pointer as NULL*/
if (p_bmp280 == BMP280_NULL) {
return E_BMP280_NULL_PTR;
} else {
com_rslt = p_bmp280->bus_read(p_bmp280->dev_addr,
v_addr_u8, v_data_u8, v_len_u8);
}
return com_rslt;
}
#ifdef BMP280_ENABLE_FLOAT
/*!
* @brief This API used to read
* actual temperature from uncompensated temperature
* @note Returns the value in Degree centigrade
* @note Output value of "51.23" equals 51.23 DegC.
*
*
*
* @param v_uncomp_temperature_s32 : value of uncompensated temperature
*
*
*
* @return
* Actual temperature in floating point
*
*/
float bmp280_compensate_temperature_float(int32_t v_uncomp_temperature_s32)
{
float v_x1_u32r = BMP280_INIT_VALUE;
float v_x2_u32r = BMP280_INIT_VALUE;
float temperature = BMP280_INIT_VALUE;
/* calculate x1*/
v_x1_u32r = (((float)v_uncomp_temperature_s32) / 16384.0f -
((float)p_bmp280->calib_param.dig_T1) / 1024.0f) *
((float)p_bmp280->calib_param.dig_T2);
/* calculate x2*/
v_x2_u32r = ((((float)v_uncomp_temperature_s32) / 131072.0f -
((float)p_bmp280->calib_param.dig_T1) / 8192.0f) *
(((float)v_uncomp_temperature_s32) / 131072.0f -
((float)p_bmp280->calib_param.dig_T1) / 8192.0f)) *
((float)p_bmp280->calib_param.dig_T3);
/* calculate t_fine*/
p_bmp280->calib_param.t_fine = (int32_t)(v_x1_u32r + v_x2_u32r);
/* calculate true pressure*/
temperature = (v_x1_u32r + v_x2_u32r) / 5120.0f;
return temperature;
}
/*!
* @brief Reads actual pressure from uncompensated pressure
* and returns pressure in Pa as float.
* @note Output value of "96386.2"
* equals 96386.2 Pa = 963.862 hPa.
*
*
*
* @param v_uncomp_pressure_s32 : value of uncompensated pressure
*
*
*
* @return
* Actual pressure in floating point
*
*/
float bmp280_compensate_pressure_float(int32_t v_uncomp_pressure_s32)
{
float v_x1_u32r = BMP280_INIT_VALUE;
float v_x2_u32r = BMP280_INIT_VALUE;
float pressure = BMP280_INIT_VALUE;
float v_pressure_diff_dbl = BMP280_INIT_VALUE;
float v_x3_u32r = BMP280_INIT_VALUE;
v_x1_u32r = ((float)p_bmp280->calib_param.t_fine/2.0f) - 64000.0f;
v_x2_u32r = v_x1_u32r * v_x1_u32r *
((float)p_bmp280->calib_param.dig_P6) / 32768.0f;
v_x2_u32r = v_x2_u32r + v_x1_u32r *
((float)p_bmp280->calib_param.dig_P5) * 2.0f;
v_x2_u32r = (v_x2_u32r / 4.0f) +
(((float)p_bmp280->calib_param.dig_P4) * 65536.0f);
v_x1_u32r = (((float)p_bmp280->calib_param.dig_P3) *
v_x1_u32r * v_x1_u32r / 524288.0f +
((float)p_bmp280->calib_param.dig_P2) * v_x1_u32r) / 524288.0f;
v_x1_u32r = (1.0f + v_x1_u32r / 32768.0f) *
((float)p_bmp280->calib_param.dig_P1);
pressure = 1048576.0f - (float)v_uncomp_pressure_s32;
/* Avoid exception caused by division by zero */
if ((v_x1_u32r > 0) || (v_x1_u32r < 0))
pressure = (pressure - (v_x2_u32r / 4096.0f)) *
6250.0f / v_x1_u32r;
else
return BMP280_INVALID_DATA;
v_x1_u32r = ((float)p_bmp280->calib_param.dig_P9) *
pressure * pressure / 2147483648.0f;
v_x2_u32r = pressure * ((float)p_bmp280->calib_param.dig_P8) / 32768.0f;
/* calculate different pressure*/
v_pressure_diff_dbl = pressure / 256.0f;
/* calculate x3*/
v_x3_u32r = ((v_pressure_diff_dbl *
v_pressure_diff_dbl * v_pressure_diff_dbl
* (float)p_bmp280->calib_param.dig_P10)
/ 131072.0f);
/* calculate true pressure*/
pressure = pressure + (v_x1_u32r + v_x2_u32r + v_x3_u32r +
((float)p_bmp280->calib_param.dig_P7))
/ 16.0f;
return pressure;
}
#endif
#if defined(BMP280_ENABLE_INT64) && defined(BMP280_64BITSUPPORT_PRESENT)
/*!
* @brief This API used to read actual pressure from uncompensated pressure
* @note returns the value in Pa as unsigned 32 bit
* integer in Q24.8 format (24 integer bits and
* 8 fractional bits). Output value of "24674867"
* represents 24674867 / 256 = 96386.2 Pa = 963.862 hPa
*
*
*
* @param v_uncomp_pressure_s32 : value of uncompensated pressure
*
*
*
* @return actual pressure as 64bit output
*
*/
uint32_t bmp280_compensate_pressure_int64(int32_t v_uncomp_pressure_s32)
{
int64_t v_x1_s64r = BMP280_INIT_VALUE;
int64_t v_x2_s64r = BMP280_INIT_VALUE;
int64_t v_x3_s64r = BMP280_INIT_VALUE;
int64_t pressure = BMP280_INIT_VALUE;
/* calculate x1*/
v_x1_s64r = ((int64_t)p_bmp280->calib_param.t_fine) - 128000;
v_x2_s64r = v_x1_s64r * v_x1_s64r *
(int64_t)p_bmp280->calib_param.dig_P6;
/* calculate x2*/
v_x2_s64r = v_x2_s64r + ((v_x1_s64r *
(int64_t)p_bmp280->calib_param.dig_P5)
<< BMP280_SHIFT_BIT_POSITION_BY_17_BITS);
v_x2_s64r = v_x2_s64r +
(((int64_t)p_bmp280->calib_param.dig_P4)
<< BMP280_SHIFT_BIT_POSITION_BY_35_BITS);
v_x1_s64r = ((v_x1_s64r * v_x1_s64r *
(int64_t)p_bmp280->calib_param.dig_P3)
>> BMP280_SHIFT_BIT_POSITION_BY_08_BITS) +
((v_x1_s64r * (int64_t)p_bmp280->calib_param.dig_P2)
<< BMP280_SHIFT_BIT_POSITION_BY_12_BITS);
v_x1_s64r = (((((int64_t)1)
<< BMP280_SHIFT_BIT_POSITION_BY_47_BITS) + v_x1_s64r)) *
((int64_t)p_bmp280->calib_param.dig_P1)
>> BMP280_SHIFT_BIT_POSITION_BY_33_BITS;
pressure = 1048576 - v_uncomp_pressure_s32;
if (v_x1_s64r != BMP280_INIT_VALUE)
#if defined __KERNEL__
pressure = div64_s64((((pressure
<< BMP280_SHIFT_BIT_POSITION_BY_31_BITS) - v_x2_s64r)
* 3125), v_x1_s64r);
#else
pressure = (((pressure
<< BMP280_SHIFT_BIT_POSITION_BY_31_BITS) - v_x2_s64r)
* 3125) / v_x1_s64r;
#endif
else
return BMP280_INVALID_DATA;
v_x1_s64r = (((int64_t)p_bmp280->calib_param.dig_P9) *
(pressure >> BMP280_SHIFT_BIT_POSITION_BY_13_BITS) * (pressure
>> BMP280_SHIFT_BIT_POSITION_BY_13_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_25_BITS;
v_x2_s64r = (((int64_t)p_bmp280->calib_param.dig_P8) *
pressure) >> BMP280_SHIFT_BIT_POSITION_BY_19_BITS;
/* calculate x3*/
v_x3_s64r = (int64_t)(((int64_t)(((pressure
>> BMP280_SHIFT_BIT_POSITION_BY_04_BITS)
* (pressure >> BMP280_SHIFT_BIT_POSITION_BY_04_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_30_BITS) * (int64_t)((pressure
* (int64_t)p_bmp280->calib_param.dig_P10)
>> BMP280_SHIFT_BIT_POSITION_BY_10_BITS))
>> BMP280_SHIFT_BIT_POSITION_BY_29_BITS);
/* calculate true pressure*/
pressure = ((pressure + v_x1_s64r + v_x2_s64r + v_x3_s64r)
>> BMP280_SHIFT_BIT_POSITION_BY_08_BITS) +
(((int64_t)p_bmp280->calib_param.dig_P7)
<< BMP280_SHIFT_BIT_POSITION_BY_04_BITS);
return (uint32_t)pressure;
}
#endif
/*!
* @brief Computing waiting time for sensor data read
*
*
*
*
* @param v_delaytime_u8r: The value of delay time
*
*
* @return 0
*
*
*/
BMP280_RETURN_FUNCTION_TYPE bmp280_compute_wait_time(uint8_t *v_delaytime_u8r)
{
/* variable used to return communication result*/
BMP280_RETURN_FUNCTION_TYPE com_rslt = SUCCESS;
*v_delaytime_u8r = (T_INIT_MAX + T_MEASURE_PER_OSRS_MAX * (((1
<< p_bmp280->oversamp_temperature)
>> BMP280_SHIFT_BIT_POSITION_BY_01_BIT)
+ ((1 << p_bmp280->oversamp_pressure)
>> BMP280_SHIFT_BIT_POSITION_BY_01_BIT))
+ ((p_bmp280->oversamp_pressure > 0) ?
T_SETUP_PRESSURE_MAX : 0) + 15) / 16;
return com_rslt;
}
/**\mainpage
* Copyright (C) 2016 - 2017 Bosch Sensortec GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*
* The information provided is believed to be accurate and reliable.
* The copyright holder assumes no responsibility
* for the consequences of use
* of such information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of the copyright holder.
*
* File bmp3.c
* Date 04 Dec 2017
* Version 1.0.0
*
*/
/*! @file bmp3.c
@brief Sensor driver for BMP3 sensor */
#include "bmp3.h"
/***************** Internal macros ******************************/
/*! Power control settings */
#define POWER_CNTL UINT16_C(0x0006)
/*! Odr and filter settings */
#define ODR_FILTER UINT16_C(0x00F0)
/*! Interrupt control settings */
#define INT_CTRL UINT16_C(0x0708)
/*! Advance settings */
#define ADV_SETT UINT16_C(0x1800)
/*! FIFO settings */
/*! Mask for fifo_mode, fifo_stop_on_full, fifo_time_en, fifo_press_en and
fifo_temp_en settings */
#define FIFO_CONFIG_1 UINT16_C(0x003E)
/*! Mask for fifo_sub_sampling and data_select settings */
#define FIFO_CONFIG_2 UINT16_C(0x00C0)
/*! Mask for fwtm_en and ffull_en settings */
#define FIFO_INT_CTRL UINT16_C(0x0300)
/*! FIFO Header */
/*! FIFO temperature pressure header frame */
#define FIFO_TEMP_PRESS_FRAME UINT8_C(0x94)
/*! FIFO temperature header frame */
#define FIFO_TEMP_FRAME UINT8_C(0x90)
/*! FIFO pressure header frame */
#define FIFO_PRESS_FRAME UINT8_C(0x84)
/*! FIFO time header frame */
#define FIFO_TIME_FRAME UINT8_C(0xA0)
/*! FIFO error header frame */
#define FIFO_ERROR_FRAME UINT8_C(0x44)
/*! FIFO configuration change header frame */
#define FIFO_CONFIG_CHANGE UINT8_C(0x48)
/***************** Static function declarations ******************************/
/*!
* @brief This internal API reads the calibration data from the sensor, parse
* it then compensates it and store in the device structure.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t get_calib_data(struct bmp3_dev *dev);
/*!
* @brief This internal API is used to parse the calibration data, compensates
* it and store it in device structure.
*
* @param[in] dev : Structure instance of bmp3_dev.
* @param[out] reg_data : Contains calibration data to be parsed.
*
*/
static void parse_calib_data(const uint8_t *reg_data, struct bmp3_dev *dev);
/*!
* @brief This internal API gets the over sampling, odr and filter settings
* from the sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t get_odr_filter_settings(struct bmp3_dev *dev);
/*!
* @brief This internal API is used to parse the pressure and temperature data
* and store it in the bmp3_uncomp_data structure instance.
*
* @param[in] reg_data : Contains the register data which needs to be parsed.
* @param[out] uncomp_data : Contains the uncompensated press and temp data.
*
*/
static void parse_sensor_data(const uint8_t *reg_data, struct bmp3_uncomp_data *uncomp_data);
/*!
* @brief This internal API is used to compensate the pressure or temperature
* or both the data according to the component selected by the user.
*
* @param[in] sensor_comp : Used to select pressure or temperature.
* @param[in] uncomp_data : Contains the uncompensated pressure and
* temperature data.
* @param[out] comp_data : Contains the compensated pressure and
* temperature data.
* @param[in] calib_data : Pointer to the calibration data structure.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t compensate_data(uint8_t sensor_comp, const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_data *comp_data, struct bmp3_calib_data *calib_data);
#ifdef FLOATING_POINT_COMPENSATION
/*!
* @brief This internal API is used to compensate the raw temperature data and
* return the compensated temperature data.
*
* @param[in] uncomp_data : Contains the uncompensated temperature data.
* @param[in] calib_data : Pointer to calibration data structure.
*
* @return Compensated temperature data.
* @retval Compensated temperature data in float.
*/
static float compensate_temperature(const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_calib_data *calib_data);
/*!
* @brief This internal API is used to compensate the pressure data and return
* the compensated pressure data.
*
* @param[in] uncomp_data : Contains the uncompensated pressure data.
* @param[in] calib_data : Pointer to the calibration data structure.
*
* @return Compensated pressure data.
* @retval Compensated pressure data in float.
*/
static float compensate_pressure(const struct bmp3_uncomp_data *uncomp_data,
const struct bmp3_calib_data *calib_data);
/*!
* @brief This internal API is used to calculate the power functionality for
* floating point values.
*
* @param[in] base : Contains the base value.
* @param[in] power : Contains the power value.
*
* @return Output of power function.
* @retval Calculated power function output in float.
*/
static float bmp3_pow(float base, uint8_t power);
#else
/*!
* @brief This internal API is used to compensate the raw temperature data and
* return the compensated temperature data in integer data type.
*
* @param[in] uncomp_data : Contains the uncompensated temperature data.
* @param[in] calib_data : Pointer to calibration data structure.
*
* @return Compensated temperature data.
* @retval Compensated temperature data in integer.
*/
static int64_t compensate_temperature(const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_calib_data *calib_data);
/*!
* @brief This internal API is used to compensate the pressure data and return
* the compensated pressure data in integer data type.
*
* @param[in] uncomp_data : Contains the uncompensated pressure data.
* @param[in] calib_data : Pointer to the calibration data structure.
*
* @return Compensated pressure data.
* @retval Compensated pressure data in integer.
*/
static uint64_t compensate_pressure(const struct bmp3_uncomp_data *uncomp_data,
const struct bmp3_calib_data *calib_data);
/*!
* @brief This internal API is used to calculate the power functionality.
*
* @param[in] base : Contains the base value.
* @param[in] power : Contains the power value.
*
* @return Output of power function.
* @retval Calculated power function output in integer.
*/
static uint32_t bmp3_pow(uint8_t base, uint8_t power);
#endif
/*!
* @brief This internal API is used to identify the settings which the user
* wants to modify in the sensor.
*
* @param[in] sub_settings : Contains the settings subset to identify particular
* group of settings which the user is interested to change.
* @param[in] settings : Contains the user specified settings.
*
* @return Indicates whether user is interested to modify the settings which
* are related to sub_settings.
* @retval True -> User wants to modify this group of settings
* @retval False -> User does not want to modify this group of settings
*/
static uint8_t are_settings_changed(uint32_t sub_settings, uint32_t settings);
/*!
* @brief This internal API interleaves the register address between the
* register data buffer for burst write operation.
*
* @param[in] reg_addr : Contains the register address array.
* @param[out] temp_buff : Contains the temporary buffer to store the
* register data and register address.
* @param[in] reg_data : Contains the register data to be written in the
* temporary buffer.
* @param[in] len : No of bytes of data to be written for burst write.
*
*/
static void interleave_reg_addr(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint8_t len);
/*!
* @brief This internal API sets the pressure enable and
* temperature enable settings of the sensor.
*
* @param[in] desired_settings : Contains the settings which user wants to
* change.
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_pwr_ctrl_settings(uint32_t desired_settings, const struct bmp3_dev *dev);
/*!
* @brief This internal API sets the over sampling, odr and filter settings of
* the sensor based on the settings selected by the user.
*
* @param[in] desired_settings : Variable used to select the settings which
* are to be set.
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_odr_filter_settings(uint32_t desired_settings, struct bmp3_dev *dev);
/*!
* @brief This internal API sets the interrupt control (output mode, level,
* latch and data ready) settings of the sensor based on the settings
* selected by the user.
*
* @param[in] desired_settings : Variable used to select the settings which
* are to be set.
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_int_ctrl_settings(uint32_t desired_settings, const struct bmp3_dev *dev);
/*!
* @brief This internal API sets the advance (i2c_wdt_en, i2c_wdt_sel)
* settings of the sensor based on the settings selected by the user.
*
* @param[in] desired_settings : Variable used to select the settings which
* are to be set.
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_advance_settings(uint32_t desired_settings, const struct bmp3_dev *dev);
/*!
* @brief This internal API fills the register address and register data of the
* the over sampling settings for burst write operation.
*
* @param[in] desired_settings : Variable which specifies the settings which
* are to be set in the sensor.
* @param[out] addr : To store the address to fill in register buffer.
* @param[out] reg_data : To store the osr register data.
* @param[out] len : To store the len for burst write.
* @param[in] dev : Structure instance of bmp3_dev.
*
*/
static void fill_osr_data(uint32_t desired_settings, uint8_t *addr, uint8_t *reg_data, uint8_t *len,
const struct bmp3_dev *dev);
/*!
* @brief This internal API fills the register address and register data of the
* the odr settings for burst write operation.
*
* @param[out] addr : To store the address to fill in register buffer.
* @param[out] reg_data : To store the register data to set the odr data.
* @param[out] len : To store the len for burst write.
* @param[in] dev : Structure instance of bmp3_dev.
*
*/
static void fill_odr_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, struct bmp3_dev *dev);
/*!
* @brief This internal API fills the register address and register data of the
* the filter settings for burst write operation.
*
* @param[out] addr : To store the address to fill in register buffer.
* @param[out] reg_data : To store the register data to set the filter.
* @param[out] len : To store the len for burst write.
* @param[in] dev : Structure instance of bmp3_dev.
*
*/
static void fill_filter_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, const struct bmp3_dev *dev);
/*!
* @brief This internal API is used to validate the device pointer for
* null conditions.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t null_ptr_check(const struct bmp3_dev *dev);
/*!
* @brief This internal API parse the power control(power mode, pressure enable
* and temperature enable), over sampling, odr, filter and interrupt control
* settings and store in the device structure.
*
* @param[in] reg_data : Register data to be parsed.
* @param[out] dev : Structure instance of bmp3_dev.
*/
static void parse_sett_data(const uint8_t *reg_data, struct bmp3_dev *dev);
/*!
* @brief This internal API parse the power control(power mode, pressure enable
* and temperature enable) settings and store in the device structure.
*
* @param[in] reg_data : Pointer variable which stores the register data to
* parse.
* @param[out] settings : Structure instance of bmp3_settings.
*/
static void parse_pwr_ctrl_settings(const uint8_t *reg_data, struct bmp3_settings *settings);
/*!
* @brief This internal API parse the over sampling, odr and filter
* settings and store in the device structure.
*
* @param[in] reg_data : Pointer variable which stores the register data to
* parse.
* @param[out] settings : Structure instance of bmp3_odr_filter_settings.
*/
static void parse_odr_filter_settings(const uint8_t *reg_data, struct bmp3_odr_filter_settings *settings);
/*!
* @brief This internal API parse the interrupt control(output mode, level,
* latch and data ready) settings and store in the device structure.
*
* @param[in] reg_data : Pointer variable which stores the register data to
* parse.
* @param[out] settings : Structure instance of bmp3_int_ctrl_settings.
*/
static void parse_int_ctrl_settings(const uint8_t *reg_data, struct bmp3_int_ctrl_settings *settings);
/*!
* @brief This internal API parse the advance (i2c_wdt_en, i2c_wdt_sel)
* settings and store in the device structure.
*
* @param[in] reg_data : Pointer variable which stores the register data to
* parse.
* @param[out] settings : Structure instance of bmp3_adv_settings.
*/
static void parse_advance_settings(const uint8_t *reg_data, struct bmp3_adv_settings *settings);
/*!
* @brief This internal API validate the normal mode settings of the sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t validate_normal_mode_settings(struct bmp3_dev *dev);
/*!
* @brief This internal API validate the over sampling, odr settings of the
* sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Indicates whether odr and osr settings are valid or not.
* @retval zero -> Success / -ve value -> Error
*/
static int8_t validate_osr_and_odr_settings(const struct bmp3_dev *dev);
/*!
* @brief This internal API calculates the pressure measurement duration of the
* sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Pressure measurement time
* @retval Pressure measurement time in milli secs
*/
static uint16_t calculate_press_meas_time(const struct bmp3_dev *dev);
/*!
* @brief This internal API calculates the temperature measurement duration of
* the sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Temperature measurement time
* @retval Temperature measurement time in millisecs
*/
static uint16_t calculate_temp_meas_time(const struct bmp3_dev *dev);
/*!
* @brief This internal API checks whether the measurement time and odr duration
* of the sensor are proper.
*
* @param[in] meas_t : Pressure and temperature measurement time in millisecs.
* @param[in] odr_duration : Duration in millisecs corresponding to the odr
* value.
*
* @return Indicates whether odr and osr settings are valid or not.
* @retval zero -> Success / +ve value -> Warning
*/
static int8_t verify_meas_time_and_odr_duration(uint16_t meas_t, uint32_t odr_duration);
/*!
* @brief This internal API puts the device to sleep mode.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status.
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t put_device_to_sleep(const struct bmp3_dev *dev);
/*!
* @brief This internal API sets the normal mode in the sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status.
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t set_normal_mode(struct bmp3_dev *dev);
/*!
* @brief This internal API writes the power mode in the sensor.
*
* @param[in] dev : Structure instance of bmp3_dev.
*
* @return Result of API execution status.
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
*/
static int8_t write_power_mode(const struct bmp3_dev *dev);
/*!
* @brief This internal API fills the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en) settings in the
* reg_data variable so as to burst write in the sensor.
*
* @param[in] desired_settings : Variable which specifies the settings which
* are to be set in the sensor.
* @param[out] reg_data : Pointer variable where the fifo_config_1 register
* data will be stored so as to burst write in the register.
* @param[in] dev_fifo : Structure instance of bmp3_fifo_settings which
* contains the fifo_config_1 values set by the user.
*/
static void fill_fifo_config_1(uint16_t desired_settings, uint8_t *reg_data,
struct bmp3_fifo_settings *dev_fifo);
/*!
* @brief This internal API fills the fifo_config_2(fifo_sub_sampling,
* data_select) settings in the reg_data variable so as to burst write
* in the sensor.
*
* @param[in] desired_settings : Variable which specifies the settings which
* are to be set in the sensor.
* @param[out] reg_data : Pointer variable where the fifo_config_2 register
* data will be stored so as to burst write in the register.
* @param[in] dev_fifo : Structure instance of bmp3_fifo_settings which
* contains the fifo_config_2 values set by the user.
*/
static void fill_fifo_config_2(uint16_t desired_settings, uint8_t *reg_data,
const struct bmp3_fifo_settings *dev_fifo);
/*!
* @brief This internal API fills the fifo interrupt control(fwtm_en, ffull_en)
* settings in the reg_data variable so as to burst write in the sensor.
*
* @param[in] desired_settings : Variable which specifies the settings which
* are to be set in the sensor.
* @param[out] reg_data : Pointer variable where the fifo interrupt control
* register data will be stored so as to burst write in the register.
* @param[in] dev_fifo : Structure instance of bmp3_fifo_settings which
* contains the fifo interrupt control values set by the user.
*/
static void fill_fifo_int_ctrl(uint16_t desired_settings, uint8_t *reg_data,
const struct bmp3_fifo_settings *dev_fifo);
/*!
* @brief This internal API is used to parse the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en),
* fifo_config_2(fifo_subsampling, data_select) and int_ctrl(fwtm_en, ffull_en)
* settings and store it in device structure
*
* @param[in] reg_data : Pointer variable which stores the fifo settings data
* read from the sensor.
* @param[out] dev_fifo : Structure instance of bmp3_fifo_settings which
* contains the fifo settings after parsing.
*/
static void parse_fifo_settings(const uint8_t *reg_data, struct bmp3_fifo_settings *dev_fifo);
/*!
* @brief This internal API parse the FIFO data frame from the fifo buffer and
* fills the byte count, uncompensated pressure and/or temperature data and no
* of parsed frames.
*
* @param[in] header : Pointer variable which stores the fifo settings data
* read from the sensor.
* @param[in,out] fifo : Structure instance of bmp3_fifo which stores the
* read fifo data.
* @param[out] byte_index : Byte count which is incremented according to the
* of data.
* @param[out] uncomp_data : Uncompensated pressure and/or temperature data
* which is stored after parsing fifo buffer data.
* @param[out] parsed_frames : Total number of parsed frames.
*
* @return Result of API execution status.
* @retval zero -> Success / -ve value -> Error
*/
static uint8_t parse_fifo_data_frame(uint8_t header, struct bmp3_fifo *fifo, uint16_t *byte_index,
struct bmp3_uncomp_data *uncomp_data, uint8_t *parsed_frames);
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count, uncompensated pressure and/or temperature data.
*
* @param[out] byte_index : Byte count of fifo buffer.
* @param[in] fifo_buffer : FIFO buffer from where the temperature and pressure
* frames are unpacked.
* @param[out] uncomp_data : Uncompensated temperature and pressure data after
* unpacking from fifo buffer.
*/
static void unpack_temp_press_frame(uint16_t *byte_index, const uint8_t *fifo_buffer,
struct bmp3_uncomp_data *uncomp_data);
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count and uncompensated pressure data.
*
* @param[out] byte_index : Byte count of fifo buffer.
* @param[in] fifo_buffer : FIFO buffer from where the pressure frames are
* unpacked.
* @param[out] uncomp_data : Uncompensated pressure data after unpacking from
* fifo buffer.
*/
static void unpack_press_frame(uint16_t *byte_index, const uint8_t *fifo_buffer,
struct bmp3_uncomp_data *uncomp_data);
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count and uncompensated temperature data.
*
* @param[out] byte_index : Byte count of fifo buffer.
* @param[in] fifo_buffer : FIFO buffer from where the temperature frames
* are unpacked.
* @param[out] uncomp_data : Uncompensated temperature data after unpacking from
* fifo buffer.
*/
static void unpack_temp_frame(uint16_t *byte_index, const uint8_t *fifo_buffer, struct bmp3_uncomp_data *uncomp_data);
/*!
* @brief This internal API unpacks the time frame from the fifo data buffer and
* fills the byte count and update the sensor time variable.
*
* @param[out] byte_index : Byte count of fifo buffer.
* @param[in] fifo_buffer : FIFO buffer from where the sensor time frames
* are unpacked.
* @param[out] sensor_time : Variable used to store the sensor time.
*/
static void unpack_time_frame(uint16_t *byte_index, const uint8_t *fifo_buffer, uint32_t *sensor_time);
/*!
* @brief This internal API parses the FIFO buffer and gets the header info.
*
* @param[out] header : Variable used to store the fifo header data.
* @param[in] fifo_buffer : FIFO buffer from where the header data is retrieved.
* @param[out] byte_index : Byte count of fifo buffer.
*/
static void get_header_info(uint8_t *header, const uint8_t *fifo_buffer, uint16_t *byte_index);
/*!
* @brief This internal API parses the FIFO data frame from the fifo buffer and
* fills uncompensated temperature and/or pressure data.
*
* @param[in] sensor_comp : Variable used to select either temperature or
* pressure or both while parsing the fifo frames.
* @param[in] fifo_buffer : FIFO buffer where the temperature or pressure or
* both the data to be parsed.
* @param[out] uncomp_data : Uncompensated temperature or pressure or both the
* data after unpacking from fifo buffer.
*/
static void parse_fifo_sensor_data(uint8_t sensor_comp, const uint8_t *fifo_buffer,
struct bmp3_uncomp_data *uncomp_data);
/*!
* @brief This internal API resets the FIFO buffer, start index,
* parsed frame count, configuration change, configuration error and
* frame_not_available variables.
*
* @param[out] fifo : FIFO structure instance where the fifo related variables
* are reset.
*/
static void reset_fifo_index(struct bmp3_fifo *fifo);
/*!
* @brief This API gets the command ready, data ready for pressure and
* temperature, power on reset status from the sensor.
*
* @param[in,out] dev : Structure instance of bmp3_dev
*
* @return Result of API execution status.
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t get_sensor_status(struct bmp3_dev *dev);
/*!
* @brief This API gets the interrupt (fifo watermark, fifo full, data ready)
* status from the sensor.
*
* @param[in,out] dev : Structure instance of bmp3_dev
*
* @return Result of API execution status.
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t get_int_status(struct bmp3_dev *dev);
/*!
* @brief This API gets the fatal, command and configuration error
* from the sensor.
*
* @param[in,out] dev : Structure instance of bmp3_dev
*
* @return Result of API execution status.
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t get_err_status(struct bmp3_dev *dev);
/*!
* @brief This internal API converts the no. of frames required by the user to
* bytes so as to write in the watermark length register.
*
* @param[in] dev : Structure instance of bmp3_dev
* @param[out] watermark_len : Pointer variable which contains the watermark
* length.
*
* @return Result of API execution status.
* @retval zero -> Success / -ve value -> Error.
*/
static int8_t convert_frames_to_bytes(uint16_t *watermark_len, const struct bmp3_dev *dev);
/****************** Global Function Definitions *******************************/
/*!
* @brief This API is the entry point.
* It performs the selection of I2C/SPI read mechanism according to the
* selected interface and reads the chip-id and calibration data of the sensor.
*/
int8_t bmp3_init(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t chip_id = 0;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMP3_OK) {
/* Read mechanism according to selected interface */
if (dev->intf != BMP3_I2C_INTF) {
/* If SPI interface is selected, read extra byte */
dev->dummy_byte = 1;
} else {
/* If I2C interface is selected, no need to read
extra byte */
dev->dummy_byte = 0;
}
/* Read the chip-id of bmp3 sensor */
rslt = bmp3_get_regs(BMP3_CHIP_ID_ADDR, &chip_id, 1, dev);
/* Proceed if everything is fine until now */
if (rslt == BMP3_OK) {
/* Check for chip id validity */
if (chip_id == BMP3_CHIP_ID) {
dev->chip_id = chip_id;
/* Reset the sensor */
rslt = bmp3_soft_reset(dev);
if (rslt == BMP3_OK) {
/* Read the calibration data */
rslt = get_calib_data(dev);
}
} else {
rslt = BMP3_E_DEV_NOT_FOUND;
}
}
}
return rslt;
}
/*!
* @brief This API reads the data from the given register address of the sensor.
*/
int8_t bmp3_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, const struct bmp3_dev *dev)
{
int8_t rslt;
uint16_t temp_len = len + dev->dummy_byte;
uint16_t i;
uint8_t temp_buff[len + dev->dummy_byte];
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMP3_OK) {
/* If interface selected is SPI */
if (dev->intf != BMP3_I2C_INTF) {
reg_addr = reg_addr | 0x80;
/* Read the data from the register */
rslt = dev->read(dev->dev_id, reg_addr, temp_buff, temp_len);
for (i = 0; i < len; i++)
reg_data[i] = temp_buff[i + dev->dummy_byte];
} else {
/* Read the data using I2C */
rslt = dev->read(dev->dev_id, reg_addr, reg_data, len);
}
/* Check for communication error */
if (rslt != BMP3_OK)
rslt = BMP3_E_COMM_FAIL;
}
return rslt;
}
/*!
* @brief This API writes the given data to the register address
* of the sensor.
*/
int8_t bmp3_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t temp_buff[len * 2];
uint16_t temp_len;
uint8_t reg_addr_cnt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Check for arguments validity */
if ((rslt == BMP3_OK) && (reg_addr != NULL) && (reg_data != NULL)) {
if (len != 0) {
temp_buff[0] = reg_data[0];
/* If interface selected is SPI */
if (dev->intf == BMP3_SPI_INTF) {
for (reg_addr_cnt = 0; reg_addr_cnt < len; reg_addr_cnt++)
reg_addr[reg_addr_cnt] = reg_addr[reg_addr_cnt] & 0x7F;
}
/* Burst write mode */
if (len > 1) {
/* Interleave register address w.r.t data for
burst write*/
interleave_reg_addr(reg_addr, temp_buff, reg_data, len);
temp_len = len * 2;
} else {
temp_len = len;
}
rslt = dev->write(dev->dev_id, reg_addr[0], temp_buff, temp_len);
/* Check for communication error */
if (rslt != BMP3_OK)
rslt = BMP3_E_COMM_FAIL;
} else {
rslt = BMP3_E_INVALID_LEN;
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API sets the power control(pressure enable and
* temperature enable), over sampling, odr and filter
* settings in the sensor.
*/
int8_t bmp3_set_sensor_settings(uint32_t desired_settings, struct bmp3_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMP3_OK) {
if (are_settings_changed(POWER_CNTL, desired_settings)) {
/* Set the power control settings */
rslt = set_pwr_ctrl_settings(desired_settings, dev);
}
if (are_settings_changed(ODR_FILTER, desired_settings) && (!rslt)) {
/* Set the over sampling, odr and filter settings*/
rslt = set_odr_filter_settings(desired_settings, dev);
}
if (are_settings_changed(INT_CTRL, desired_settings) && (!rslt)) {
/* Set the interrupt control settings */
rslt = set_int_ctrl_settings(desired_settings, dev);
}
if (are_settings_changed(ADV_SETT, desired_settings) && (!rslt)) {
/* Set the advance settings */
rslt = set_advance_settings(desired_settings, dev);
}
}
return rslt;
}
/*!
* @brief This API gets the power control(power mode, pressure enable and
* temperature enable), over sampling, odr, filter, interrupt control and
* advance settings from the sensor.
*/
int8_t bmp3_get_sensor_settings(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t settings_data[BMP3_GEN_SETT_LEN];
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMP3_OK) {
rslt = bmp3_get_regs(BMP3_INT_CTRL_ADDR, settings_data, BMP3_GEN_SETT_LEN, dev);
if (rslt == BMP3_OK) {
/* Parse the settings data */
parse_sett_data(settings_data, dev);
}
}
return rslt;
}
/*!
* @brief This API sets the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en),
* fifo_config_2(fifo_subsampling, data_select) and int_ctrl(fwtm_en, ffull_en)
* settings in the sensor.
*/
int8_t bmp3_set_fifo_settings(uint16_t desired_settings, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t fifo_sett[5];
uint8_t len = 3;
uint8_t reg_addr[3] = {BMP3_FIFO_CONFIG_1_ADDR, BMP3_FIFO_CONFIG_1_ADDR+1, BMP3_FIFO_CONFIG_1_ADDR+2};
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMP3_OK) && (dev->fifo != NULL)) {
rslt = bmp3_get_regs(reg_addr[0], fifo_sett, len, dev);
if (rslt == BMP3_OK) {
if (are_settings_changed(FIFO_CONFIG_1, desired_settings)) {
/* Fill the FIFO config 1 register data */
fill_fifo_config_1(desired_settings, &fifo_sett[0], &dev->fifo->settings);
}
if (are_settings_changed(desired_settings, FIFO_CONFIG_2)) {
/* Fill the FIFO config 2 register data */
fill_fifo_config_2(desired_settings, &fifo_sett[1], &dev->fifo->settings);
}
if (are_settings_changed(desired_settings, FIFO_INT_CTRL)) {
/* Fill the FIFO interrupt ctrl register data */
fill_fifo_int_ctrl(desired_settings, &fifo_sett[2], &dev->fifo->settings);
}
/* Write the FIFO settings in the sensor */
rslt = bmp3_set_regs(reg_addr, fifo_sett, len, dev);
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API gets the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en),
* fifo_config_2(fifo_subsampling, data_select) and int_ctrl(fwtm_en, ffull_en)
* settings from the sensor.
*/
int8_t bmp3_get_fifo_settings(const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t fifo_sett[3];
uint8_t len = 3;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if ((rslt == BMP3_OK) && (dev->fifo != NULL)) {
rslt = bmp3_get_regs(BMP3_FIFO_CONFIG_1_ADDR, fifo_sett, len, dev);
/* Parse the fifo settings */
parse_fifo_settings(fifo_sett, &dev->fifo->settings);
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API gets the fifo data from the sensor.
*/
int8_t bmp3_get_fifo_data(const struct bmp3_dev *dev)
{
int8_t rslt;
uint16_t fifo_len;
struct bmp3_fifo *fifo = dev->fifo;
rslt = null_ptr_check(dev);
if ((rslt == BMP3_OK) && (fifo != NULL)) {
reset_fifo_index(dev->fifo);
/* Get the total no of bytes available in FIFO */
rslt = bmp3_get_fifo_length(&fifo_len, dev);
/* For sensor time frame */
if (dev->fifo->settings.time_en == TRUE)
fifo_len = fifo_len + 4;
/* Update the fifo length in the fifo structure */
dev->fifo->data.byte_count = fifo_len;
if (rslt == BMP3_OK) {
/* Read the fifo data */
rslt = bmp3_get_regs(BMP3_FIFO_DATA_ADDR, fifo->data.buffer, fifo_len, dev);
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API sets the fifo watermark length according to the frames count
* set by the user in the device structure. Refer below for usage.
*/
int8_t bmp3_set_fifo_watermark(const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data[2];
uint8_t reg_addr[2] = {BMP3_FIFO_WM_ADDR, BMP3_FIFO_WM_ADDR+1};
uint16_t watermark_len;
rslt = null_ptr_check(dev);
if ((rslt == BMP3_OK) && (dev->fifo != NULL)) {
rslt = convert_frames_to_bytes(&watermark_len, dev);
if (rslt == BMP3_OK) {
reg_data[0] = BMP3_GET_LSB(watermark_len);
reg_data[1] = BMP3_GET_MSB(watermark_len) & 0x01;
rslt = bmp3_set_regs(reg_addr, reg_data, 2, dev);
}
}
return rslt;
}
/*!
* @brief This API extracts the temperature and/or pressure data from the FIFO
* data which is already read from the fifo.
*/
int8_t bmp3_extract_fifo_data(struct bmp3_data *data, struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t header;
uint16_t byte_index = dev->fifo->data.start_idx;
uint8_t parsed_frames = 0;
uint8_t t_p_frame;
struct bmp3_uncomp_data uncomp_data;
rslt = null_ptr_check(dev);
if ((rslt == BMP3_OK) && (dev->fifo != NULL) && (data != NULL)) {
while ((parsed_frames < (dev->fifo->data.req_frames)) && (byte_index < dev->fifo->data.byte_count)) {
get_header_info(&header, dev->fifo->data.buffer, &byte_index);
t_p_frame = parse_fifo_data_frame(header, dev->fifo, &byte_index, &uncomp_data, &parsed_frames);
/* If the frame is pressure and/or temperature data */
if (t_p_frame != FALSE) {
/* Compensate temperature and pressure data */
rslt = compensate_data(t_p_frame, &uncomp_data, &data[parsed_frames-1],
&dev->calib_data);
}
}
/* Check if any frames are parsed in FIFO */
if (parsed_frames != 0) {
/* Update the bytes parsed in the device structure */
dev->fifo->data.start_idx = byte_index;
dev->fifo->data.parsed_frames += parsed_frames;
} else {
/* No frames are there to parse. It is time to
read the FIFO, if more frames are needed */
dev->fifo->data.frame_not_available = TRUE;
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API gets the command ready, data ready for pressure and
* temperature and interrupt (fifo watermark, fifo full, data ready) and
* error status from the sensor.
*/
int8_t bmp3_get_status(struct bmp3_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
if (rslt == BMP3_OK) {
rslt = get_sensor_status(dev);
/* Proceed further if the earlier operation is fine */
if (rslt == BMP3_OK) {
rslt = get_int_status(dev);
/* Proceed further if the earlier operation is fine */
if (rslt == BMP3_OK) {
/* Get the error status */
rslt = get_err_status(dev);
}
}
}
return rslt;
}
/*!
* @brief This API gets the fifo length from the sensor.
*/
int8_t bmp3_get_fifo_length(uint16_t *fifo_length, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data[2];
rslt = null_ptr_check(dev);
if (rslt == BMP3_OK) {
rslt = bmp3_get_regs(BMP3_FIFO_LENGTH_ADDR, reg_data, 2, dev);
/* Proceed if read from register is fine */
if (rslt == BMP3_OK) {
/* Update the fifo length */
*fifo_length = BMP3_CONCAT_BYTES(reg_data[1], reg_data[0]);
}
}
return rslt;
}
/*!
* @brief This API performs the soft reset of the sensor.
*/
int8_t bmp3_soft_reset(const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr = BMP3_CMD_ADDR;
/* 0xB6 is the soft reset command */
uint8_t soft_rst_cmd = 0xB6;
uint8_t cmd_rdy_status;
uint8_t cmd_err_status;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
/* Proceed if null check is fine */
if (rslt == BMP3_OK) {
/* Check for command ready status */
rslt = bmp3_get_regs(BMP3_SENS_STATUS_REG_ADDR, &cmd_rdy_status, 1, dev);
/* Device is ready to accept new command */
if ((cmd_rdy_status & BMP3_CMD_RDY) && (rslt == BMP3_OK)) {
/* Write the soft reset command in the sensor */
rslt = bmp3_set_regs(&reg_addr, &soft_rst_cmd, 1, dev);
/* Proceed if everything is fine until now */
if (rslt == BMP3_OK) {
/* Wait for 2 ms */
dev->delay_ms(2);
/* Read for command error status */
rslt = bmp3_get_regs(BMP3_ERR_REG_ADDR, &cmd_err_status, 1, dev);
/* check for command error status */
if ((cmd_err_status & BMP3_CMD_ERR) || (rslt != BMP3_OK)) {
/* Command not written hence return
error */
rslt = BMP3_E_CMD_EXEC_FAILED;
}
}
} else {
rslt = BMP3_E_CMD_EXEC_FAILED;
}
}
return rslt;
}
/*!
* @brief This API sets the power mode of the sensor.
*/
int8_t bmp3_set_op_mode(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t last_set_mode;
uint8_t curr_mode = dev->settings.op_mode;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
if (rslt == BMP3_OK) {
rslt = bmp3_get_op_mode(&last_set_mode, dev);
/* If the sensor is not in sleep mode put the device to sleep
mode */
if (last_set_mode != BMP3_SLEEP_MODE) {
/* Device should be put to sleep before transiting to
forced mode or normal mode */
rslt = put_device_to_sleep(dev);
/* Give some time for device to go into sleep mode */
dev->delay_ms(5);
}
/* Set the power mode */
if (rslt == BMP3_OK) {
if (curr_mode == BMP3_NORMAL_MODE) {
/* Set normal mode and validate
necessary settings */
rslt = set_normal_mode(dev);
} else if (curr_mode == BMP3_FORCED_MODE) {
/* Set forced mode */
rslt = write_power_mode(dev);
}
}
}
return rslt;
}
/*!
* @brief This API gets the power mode of the sensor.
*/
int8_t bmp3_get_op_mode(uint8_t *op_mode, const struct bmp3_dev *dev)
{
int8_t rslt;
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
if (rslt == BMP3_OK) {
/* Read the power mode register */
rslt = bmp3_get_regs(BMP3_PWR_CTRL_ADDR, op_mode, 1, dev);
/* Assign the power mode in the device structure */
*op_mode = BMP3_GET_BITS(*op_mode, BMP3_OP_MODE);
}
return rslt;
}
/*!
* @brief This API reads the pressure, temperature or both data from the
* sensor, compensates the data and store it in the bmp3_data structure
* instance passed by the user.
*/
int8_t bmp3_get_sensor_data(uint8_t sensor_comp, struct bmp3_data *comp_data, struct bmp3_dev *dev)
{
int8_t rslt;
/* Array to store the pressure and temperature data read from
the sensor */
uint8_t reg_data[BMP3_P_T_DATA_LEN] = {0};
struct bmp3_uncomp_data uncomp_data = {0};
/* Check for null pointer in the device structure*/
rslt = null_ptr_check(dev);
if ((rslt == BMP3_OK) && (comp_data != NULL)) {
/* Read the pressure and temperature data from the sensor */
rslt = bmp3_get_regs(BMP3_DATA_ADDR, reg_data, BMP3_P_T_DATA_LEN, dev);
if (rslt == BMP3_OK) {
/* Parse the read data from the sensor */
parse_sensor_data(reg_data, &uncomp_data);
/* Compensate the pressure/temperature/both data read
from the sensor */
rslt = compensate_data(sensor_comp, &uncomp_data, comp_data, &dev->calib_data);
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
/****************** Static Function Definitions *******************************/
/*!
* @brief This internal API converts the no. of frames required by the user to
* bytes so as to write in the watermark length register.
*/
static int8_t convert_frames_to_bytes(uint16_t *watermark_len, const struct bmp3_dev *dev)
{
int8_t rslt = BMP3_OK;
if ((dev->fifo->data.req_frames > 0) && (dev->fifo->data.req_frames <= BMP3_FIFO_MAX_FRAMES)) {
if (dev->fifo->settings.press_en && dev->fifo->settings.temp_en) {
/* Multiply with pressure and temperature header len */
*watermark_len = dev->fifo->data.req_frames * BMP3_P_AND_T_HEADER_DATA_LEN;
} else if (dev->fifo->settings.temp_en || dev->fifo->settings.press_en) {
/* Multiply with pressure or temperature header len */
*watermark_len = dev->fifo->data.req_frames * BMP3_P_OR_T_HEADER_DATA_LEN;
} else {
/* No sensor is enabled */
rslt = BMP3_W_SENSOR_NOT_ENABLED;
}
} else {
/* Required frame count is zero, which is invalid */
rslt = BMP3_W_INVALID_FIFO_REQ_FRAME_CNT;
}
return rslt;
}
/*!
* @brief This internal API resets the FIFO buffer, start index,
* parsed frame count, configuration change, configuration error and
* frame_not_available variables.
*/
static void reset_fifo_index(struct bmp3_fifo *fifo)
{
/* Loop variable */
uint16_t i;
for (i = 0; i < 512; i++) {
/* Initialize data buffer to zero */
fifo->data.buffer[i] = 0;
}
fifo->data.byte_count = 0;
fifo->data.start_idx = 0;
fifo->data.parsed_frames = 0;
fifo->data.config_change = 0;
fifo->data.config_err = 0;
fifo->data.frame_not_available = 0;
}
/*!
* @brief This internal API parse the FIFO data frame from the fifo buffer and
* fills the byte count, uncompensated pressure and/or temperature data and no
* of parsed frames.
*/
static uint8_t parse_fifo_data_frame(uint8_t header, struct bmp3_fifo *fifo, uint16_t *byte_index,
struct bmp3_uncomp_data *uncomp_data, uint8_t *parsed_frames)
{
uint8_t t_p_frame = 0;
switch (header) {
case FIFO_TEMP_PRESS_FRAME:
unpack_temp_press_frame(byte_index, fifo->data.buffer, uncomp_data);
*parsed_frames = *parsed_frames + 1;
t_p_frame = BMP3_PRESS | BMP3_TEMP;
break;
case FIFO_TEMP_FRAME:
unpack_temp_frame(byte_index, fifo->data.buffer, uncomp_data);
*parsed_frames = *parsed_frames + 1;
t_p_frame = BMP3_TEMP;
break;
case FIFO_PRESS_FRAME:
unpack_press_frame(byte_index, fifo->data.buffer, uncomp_data);
*parsed_frames = *parsed_frames + 1;
t_p_frame = BMP3_PRESS;
break;
case FIFO_TIME_FRAME:
unpack_time_frame(byte_index, fifo->data.buffer, &fifo->data.sensor_time);
break;
case FIFO_CONFIG_CHANGE:
fifo->data.config_change = 1;
*byte_index = *byte_index + 1;
break;
case FIFO_ERROR_FRAME:
fifo->data.config_err = 1;
*byte_index = *byte_index + 1;
break;
default:
fifo->data.config_err = 1;
*byte_index = *byte_index + 1;
break;
}
return t_p_frame;
}
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count, uncompensated pressure and/or temperature data.
*/
static void unpack_temp_press_frame(uint16_t *byte_index, const uint8_t *fifo_buffer,
struct bmp3_uncomp_data *uncomp_data)
{
parse_fifo_sensor_data((BMP3_PRESS | BMP3_TEMP), &fifo_buffer[*byte_index], uncomp_data);
*byte_index = *byte_index + BMP3_P_T_DATA_LEN;
}
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count and uncompensated temperature data.
*/
static void unpack_temp_frame(uint16_t *byte_index, const uint8_t *fifo_buffer, struct bmp3_uncomp_data *uncomp_data)
{
parse_fifo_sensor_data(BMP3_TEMP, &fifo_buffer[*byte_index], uncomp_data);
*byte_index = *byte_index + BMP3_T_DATA_LEN;
}
/*!
* @brief This internal API unpacks the FIFO data frame from the fifo buffer and
* fills the byte count and uncompensated pressure data.
*/
static void unpack_press_frame(uint16_t *byte_index, const uint8_t *fifo_buffer, struct bmp3_uncomp_data *uncomp_data)
{
parse_fifo_sensor_data(BMP3_PRESS, &fifo_buffer[*byte_index], uncomp_data);
*byte_index = *byte_index + BMP3_P_DATA_LEN;
}
/*!
* @brief This internal API unpacks the time frame from the fifo data buffer and
* fills the byte count and update the sensor time variable.
*/
static void unpack_time_frame(uint16_t *byte_index, const uint8_t *fifo_buffer, uint32_t *sensor_time)
{
uint16_t index = *byte_index;
uint32_t xlsb = fifo_buffer[index];
uint32_t lsb = ((uint32_t)fifo_buffer[index + 1]) << 8;
uint32_t msb = ((uint32_t)fifo_buffer[index + 2]) << 16;
*sensor_time = msb | lsb | xlsb;
*byte_index = *byte_index + BMP3_SENSOR_TIME_LEN;
}
/*!
* @brief This internal API parses the FIFO data frame from the fifo buffer and
* fills uncompensated temperature and/or pressure data.
*/
static void parse_fifo_sensor_data(uint8_t sensor_comp, const uint8_t *fifo_buffer,
struct bmp3_uncomp_data *uncomp_data)
{
/* Temporary variables to store the sensor data */
uint32_t data_xlsb;
uint32_t data_lsb;
uint32_t data_msb;
/* Store the parsed register values for temperature data */
data_xlsb = (uint32_t)fifo_buffer[0];
data_lsb = (uint32_t)fifo_buffer[1] << 8;
data_msb = (uint32_t)fifo_buffer[2] << 16;
if (sensor_comp == BMP3_TEMP) {
/* Update uncompensated temperature */
uncomp_data->temperature = data_msb | data_lsb | data_xlsb;
}
if (sensor_comp == BMP3_PRESS) {
/* Update uncompensated pressure */
uncomp_data->pressure = data_msb | data_lsb | data_xlsb;
}
if (sensor_comp == (BMP3_TEMP | BMP3_PRESS)) {
uncomp_data->temperature = data_msb | data_lsb | data_xlsb;
/* Store the parsed register values for pressure data */
data_xlsb = (uint32_t)fifo_buffer[3];
data_lsb = (uint32_t)fifo_buffer[4] << 8;
data_msb = (uint32_t)fifo_buffer[5] << 16;
uncomp_data->pressure = data_msb | data_lsb | data_xlsb;
}
}
/*!
* @brief This internal API parses the FIFO buffer and gets the header info.
*/
static void get_header_info(uint8_t *header, const uint8_t *fifo_buffer, uint16_t *byte_index)
{
*header = fifo_buffer[*byte_index];
*byte_index = *byte_index + 1;
}
/*!
* @brief This internal API sets the normal mode in the sensor.
*/
static int8_t set_normal_mode(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t conf_err_status;
rslt = validate_normal_mode_settings(dev);
/* If osr and odr settings are proper then write the power mode */
if (rslt == BMP3_OK) {
rslt = write_power_mode(dev);
/* check for configuration error */
if (rslt == BMP3_OK) {
/* Read the configuration error status */
rslt = bmp3_get_regs(BMP3_ERR_REG_ADDR, &conf_err_status, 1, dev);
/* Check if conf. error flag is set */
if (rslt == BMP3_OK) {
if (conf_err_status & BMP3_CONF_ERR) {
/* Osr and odr configuration is
not proper */
rslt = BMP3_E_CONFIGURATION_ERR;
}
}
}
}
return rslt;
}
/*!
* @brief This internal API writes the power mode in the sensor.
*/
static int8_t write_power_mode(const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr = BMP3_PWR_CTRL_ADDR;
uint8_t op_mode = dev->settings.op_mode;
/* Temporary variable to store the value read from op-mode register */
uint8_t op_mode_reg_val;
/* Read the power mode register */
rslt = bmp3_get_regs(reg_addr, &op_mode_reg_val, 1, dev);
/* Set the power mode */
if (rslt == BMP3_OK) {
op_mode_reg_val = BMP3_SET_BITS(op_mode_reg_val, BMP3_OP_MODE, op_mode);
/* Write the power mode in the register */
rslt = bmp3_set_regs(&reg_addr, &op_mode_reg_val, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API puts the device to sleep mode.
*/
static int8_t put_device_to_sleep(const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr = BMP3_PWR_CTRL_ADDR;
/* Temporary variable to store the value read from op-mode register */
uint8_t op_mode_reg_val;
rslt = bmp3_get_regs(BMP3_PWR_CTRL_ADDR, &op_mode_reg_val, 1, dev);
if (rslt == BMP3_OK) {
/* Set the power mode */
op_mode_reg_val = op_mode_reg_val & (~(BMP3_OP_MODE_MSK));
/* Write the power mode in the register */
rslt = bmp3_set_regs(&reg_addr, &op_mode_reg_val, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API validate the normal mode settings of the sensor.
*/
static int8_t validate_normal_mode_settings(struct bmp3_dev *dev)
{
int8_t rslt;
rslt = get_odr_filter_settings(dev);
if (rslt == BMP3_OK)
rslt = validate_osr_and_odr_settings(dev);
return rslt;
}
/*!
* @brief This internal API reads the calibration data from the sensor, parse
* it then compensates it and store in the device structure.
*/
static int8_t get_calib_data(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr = BMP3_CALIB_DATA_ADDR;
/* Array to store calibration data */
uint8_t calib_data[BMP3_CALIB_DATA_LEN] = {0};
/* Read the calibration data from the sensor */
rslt = bmp3_get_regs(reg_addr, calib_data, BMP3_CALIB_DATA_LEN, dev);
/* Parse calibration data and store it in device structure */
parse_calib_data(calib_data, dev);
return rslt;
}
/*!
* @brief This internal API interleaves the register address between the
* register data buffer for burst write operation.
*/
static void interleave_reg_addr(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint8_t len)
{
uint8_t index;
for (index = 1; index < len; index++) {
temp_buff[(index * 2) - 1] = reg_addr[index];
temp_buff[index * 2] = reg_data[index];
}
}
/*!
* @brief This internal API parse the power control(power mode, pressure enable
* and temperature enable), over sampling, odr, filter, interrupt control and
* advance settings and store in the device structure.
*/
static void parse_sett_data(const uint8_t *reg_data, struct bmp3_dev *dev)
{
/* Parse interrupt control settings and store in device structure */
parse_int_ctrl_settings(&reg_data[0], &dev->settings.int_settings);
/* Parse advance settings and store in device structure */
parse_advance_settings(&reg_data[1], &dev->settings.adv_settings);
/* Parse power control settings and store in device structure */
parse_pwr_ctrl_settings(&reg_data[2], &dev->settings);
/* Parse odr and filter settings and store in device structure */
parse_odr_filter_settings(&reg_data[3], &dev->settings.odr_filter);
}
/*!
* @brief This internal API parse the interrupt control(output mode, level,
* latch and data ready) settings and store in the device structure.
*/
static void parse_int_ctrl_settings(const uint8_t *reg_data, struct bmp3_int_ctrl_settings *settings)
{
settings->output_mode = BMP3_GET_BITS_POS_0(*reg_data, BMP3_INT_OUTPUT_MODE);
settings->level = BMP3_GET_BITS(*reg_data, BMP3_INT_LEVEL);
settings->latch = BMP3_GET_BITS(*reg_data, BMP3_INT_LATCH);
settings->drdy_en = BMP3_GET_BITS(*reg_data, BMP3_INT_DRDY_EN);
}
static void parse_advance_settings(const uint8_t *reg_data, struct bmp3_adv_settings *settings)
{
settings->i2c_wdt_en = BMP3_GET_BITS(*reg_data, BMP3_I2C_WDT_EN);
settings->i2c_wdt_sel = BMP3_GET_BITS(*reg_data, BMP3_I2C_WDT_SEL);
}
/*!
* @brief This internal API parse the power control(power mode, pressure enable
* and temperature enable) settings and store in the device structure.
*/
static void parse_pwr_ctrl_settings(const uint8_t *reg_data, struct bmp3_settings *settings)
{
settings->op_mode = BMP3_GET_BITS(*reg_data, BMP3_OP_MODE);
settings->press_en = BMP3_GET_BITS_POS_0(*reg_data, BMP3_PRESS_EN);
settings->temp_en = BMP3_GET_BITS(*reg_data, BMP3_TEMP_EN);
}
/*!
* @brief This internal API parse the over sampling, odr and filter
* settings and store in the device structure.
*/
static void parse_odr_filter_settings(const uint8_t *reg_data, struct bmp3_odr_filter_settings *settings)
{
uint8_t index = 0;
/* Odr and filter settings index starts from one (0x1C register) */
settings->press_os = BMP3_GET_BITS_POS_0(reg_data[index], BMP3_PRESS_OS);
settings->temp_os = BMP3_GET_BITS(reg_data[index], BMP3_TEMP_OS);
/* Move index to 0x1D register */
index++;
settings->odr = BMP3_GET_BITS_POS_0(reg_data[index], BMP3_ODR);
/* Move index to 0x1F register */
index = index + 2;
settings->iir_filter = BMP3_GET_BITS(reg_data[index], BMP3_IIR_FILTER);
}
/*!
* @brief This API sets the pressure enable and temperature enable
* settings of the sensor.
*/
static int8_t set_pwr_ctrl_settings(uint32_t desired_settings, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr = BMP3_PWR_CTRL_ADDR;
uint8_t reg_data;
rslt = bmp3_get_regs(reg_addr, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
if (desired_settings & BMP3_PRESS_EN_SEL) {
/* Set the pressure enable settings in the
register variable */
reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_PRESS_EN, dev->settings.press_en);
}
if (desired_settings & BMP3_TEMP_EN_SEL) {
/* Set the temperature enable settings in the
register variable */
reg_data = BMP3_SET_BITS(reg_data, BMP3_TEMP_EN, dev->settings.temp_en);
}
/* Write the power control settings in the register */
rslt = bmp3_set_regs(&reg_addr, &reg_data, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API sets the over sampling, odr and filter settings
* of the sensor based on the settings selected by the user.
*/
static int8_t set_odr_filter_settings(uint32_t desired_settings, struct bmp3_dev *dev)
{
int8_t rslt;
/* No of registers to be configured is 3*/
uint8_t reg_addr[3] = {0};
/* No of register data to be read is 4 */
uint8_t reg_data[4];
uint8_t len = 0;
rslt = bmp3_get_regs(BMP3_OSR_ADDR, reg_data, 4, dev);
if (rslt == BMP3_OK) {
if (are_settings_changed((BMP3_PRESS_OS_SEL | BMP3_TEMP_OS_SEL), desired_settings)) {
/* Fill the over sampling register address and
register data to be written in the sensor */
fill_osr_data(desired_settings, reg_addr, reg_data, &len, dev);
}
if (are_settings_changed(BMP3_ODR_SEL, desired_settings)) {
/* Fill the output data rate register address and
register data to be written in the sensor */
fill_odr_data(reg_addr, reg_data, &len, dev);
}
if (are_settings_changed(BMP3_IIR_FILTER_SEL, desired_settings)) {
/* Fill the iir filter register address and
register data to be written in the sensor */
fill_filter_data(reg_addr, reg_data, &len, dev);
}
if (dev->settings.op_mode == BMP3_NORMAL_MODE) {
/* For normal mode, osr and odr settings should
be proper */
rslt = validate_osr_and_odr_settings(dev);
}
if (rslt == BMP3_OK) {
/* Burst write the over sampling, odr and filter
settings in the register */
rslt = bmp3_set_regs(reg_addr, reg_data, len, dev);
}
}
return rslt;
}
/*!
* @brief This internal API sets the interrupt control (output mode, level,
* latch and data ready) settings of the sensor based on the settings
* selected by the user.
*/
static int8_t set_int_ctrl_settings(uint32_t desired_settings, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
uint8_t reg_addr;
struct bmp3_int_ctrl_settings int_settings;
reg_addr = BMP3_INT_CTRL_ADDR;
rslt = bmp3_get_regs(reg_addr, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
int_settings = dev->settings.int_settings;
if (desired_settings & BMP3_OUTPUT_MODE_SEL) {
/* Set the interrupt output mode bits */
reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_INT_OUTPUT_MODE, int_settings.output_mode);
}
if (desired_settings & BMP3_LEVEL_SEL) {
/* Set the interrupt level bits */
reg_data = BMP3_SET_BITS(reg_data, BMP3_INT_LEVEL, int_settings.level);
}
if (desired_settings & BMP3_LATCH_SEL) {
/* Set the interrupt latch bits */
reg_data = BMP3_SET_BITS(reg_data, BMP3_INT_LATCH, int_settings.latch);
}
if (desired_settings & BMP3_DRDY_EN_SEL) {
/* Set the interrupt data ready bits */
reg_data = BMP3_SET_BITS(reg_data, BMP3_INT_DRDY_EN, int_settings.drdy_en);
}
rslt = bmp3_set_regs(&reg_addr, &reg_data, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API sets the advance (i2c_wdt_en, i2c_wdt_sel)
* settings of the sensor based on the settings selected by the user.
*/
static int8_t set_advance_settings(uint32_t desired_settings, const struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr;
uint8_t reg_data;
struct bmp3_adv_settings adv_settings = dev->settings.adv_settings;
reg_addr = BMP3_IF_CONF_ADDR;
rslt = bmp3_get_regs(reg_addr, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
if (desired_settings & BMP3_I2C_WDT_EN_SEL) {
/* Set the i2c watch dog enable bits */
reg_data = BMP3_SET_BITS(reg_data, BMP3_I2C_WDT_EN, adv_settings.i2c_wdt_en);
}
if (desired_settings & BMP3_I2C_WDT_SEL_SEL) {
/* Set the i2c watch dog select bits */
reg_data = BMP3_SET_BITS(reg_data, BMP3_I2C_WDT_SEL, adv_settings.i2c_wdt_sel);
}
rslt = bmp3_set_regs(&reg_addr, &reg_data, 1, dev);
}
return rslt;
}
/*!
* @brief This internal API gets the over sampling, odr and filter settings
* of the sensor.
*/
static int8_t get_odr_filter_settings(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data[4];
/* Read data beginning from 0x1C register */
rslt = bmp3_get_regs(BMP3_OSR_ADDR, reg_data, 4, dev);
/* Parse the read data and store it in dev structure */
parse_odr_filter_settings(reg_data, &dev->settings.odr_filter);
return rslt;
}
/*!
* @brief This internal API validate the over sampling, odr settings of the
* sensor.
*/
static int8_t validate_osr_and_odr_settings(const struct bmp3_dev *dev)
{
int8_t rslt;
uint16_t meas_t = 0;
/* Odr values in milli secs */
uint32_t odr[18] = {5, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120, 10240,
20480, 40960, 81920, 163840, 327680, 655360};
if (dev->settings.press_en) {
/* Calculate the pressure measurement duration */
meas_t = calculate_press_meas_time(dev);
}
if (dev->settings.temp_en) {
/* Calculate the temperature measurement duration */
meas_t += calculate_temp_meas_time(dev);
}
rslt = verify_meas_time_and_odr_duration(meas_t, odr[dev->settings.odr_filter.odr]);
return rslt;
}
/*!
* @brief This internal API checks whether the measurement time and odr duration
* of the sensor are proper.
*/
static int8_t verify_meas_time_and_odr_duration(uint16_t meas_t, uint32_t odr_duration)
{
int8_t rslt;
if (meas_t < odr_duration) {
/* If measurement duration is less than odr duration
then osr and odr settings are fine */
rslt = BMP3_OK;
} else {
/* Osr and odr settings are not proper */
rslt = BMP3_E_INVALID_ODR_OSR_SETTINGS;
}
return rslt;
}
/*!
* @brief This internal API calculates the pressure measurement duration of the
* sensor.
*/
static uint16_t calculate_press_meas_time(const struct bmp3_dev *dev)
{
uint16_t press_meas_t;
struct bmp3_odr_filter_settings odr_filter = dev->settings.odr_filter;
#ifdef FLOATING_POINT_COMPENSATION
float base = 2.0;
float partial_out;
#else
uint8_t base = 2;
uint32_t partial_out;
#endif
partial_out = bmp3_pow(base, odr_filter.press_os);
press_meas_t = (uint16_t)(BMP3_PRESS_SETTLE_TIME + partial_out * BMP3_ADC_CONV_TIME);
/* convert into mill seconds */
press_meas_t = press_meas_t / 1000;
return press_meas_t;
}
/*!
* @brief This internal API calculates the temperature measurement duration of
* the sensor.
*/
static uint16_t calculate_temp_meas_time(const struct bmp3_dev *dev)
{
uint16_t temp_meas_t;
struct bmp3_odr_filter_settings odr_filter = dev->settings.odr_filter;
#ifdef FLOATING_POINT_COMPENSATION
float base = 2.0;
float partial_out;
#else
uint8_t base = 2;
uint32_t partial_out;
#endif
partial_out = bmp3_pow(base, odr_filter.temp_os);
temp_meas_t = (uint16_t)(BMP3_TEMP_SETTLE_TIME + partial_out * BMP3_ADC_CONV_TIME);
/* convert into mill seconds */
temp_meas_t = temp_meas_t / 1000;
return temp_meas_t;
}
/*!
* @brief This internal API fills the register address and register data of
* the over sampling settings for burst write operation.
*/
static void fill_osr_data(uint32_t settings, uint8_t *addr, uint8_t *reg_data, uint8_t *len,
const struct bmp3_dev *dev)
{
struct bmp3_odr_filter_settings osr_settings = dev->settings.odr_filter;
if (settings & (BMP3_PRESS_OS_SEL | BMP3_TEMP_OS_SEL)) {
/* Pressure over sampling settings check */
if (settings & BMP3_PRESS_OS_SEL) {
/* Set the pressure over sampling settings in the
register variable */
reg_data[*len] = BMP3_SET_BITS_POS_0(reg_data[0], BMP3_PRESS_OS, osr_settings.press_os);
}
/* Temperature over sampling settings check */
if (settings & BMP3_TEMP_OS_SEL) {
/* Set the temperature over sampling settings in the
register variable */
reg_data[*len] = BMP3_SET_BITS(reg_data[0], BMP3_TEMP_OS, osr_settings.temp_os);
}
/* 0x1C is the register address of over sampling register */
addr[*len] = BMP3_OSR_ADDR;
(*len)++;
}
}
/*!
* @brief This internal API fills the register address and register data of
* the odr settings for burst write operation.
*/
static void fill_odr_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, struct bmp3_dev *dev)
{
struct bmp3_odr_filter_settings *osr_settings = &dev->settings.odr_filter;
/* Limit the ODR to 0.001525879 Hz*/
if (osr_settings->odr > BMP3_ODR_0_001_HZ)
osr_settings->odr = BMP3_ODR_0_001_HZ;
/* Set the odr settings in the register variable */
reg_data[*len] = BMP3_SET_BITS_POS_0(reg_data[1], BMP3_ODR, osr_settings->odr);
/* 0x1D is the register address of output data rate register */
addr[*len] = 0x1D;
(*len)++;
}
/*!
* @brief This internal API fills the register address and register data of
* the filter settings for burst write operation.
*/
static void fill_filter_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, const struct bmp3_dev *dev)
{
struct bmp3_odr_filter_settings osr_settings = dev->settings.odr_filter;
/* Set the iir settings in the register variable */
reg_data[*len] = BMP3_SET_BITS(reg_data[3], BMP3_IIR_FILTER, osr_settings.iir_filter);
/* 0x1F is the register address of iir filter register */
addr[*len] = 0x1F;
(*len)++;
}
/*!
* @brief This internal API is used to parse the pressure or temperature or
* both the data and store it in the bmp3_uncomp_data structure instance.
*/
static void parse_sensor_data(const uint8_t *reg_data, struct bmp3_uncomp_data *uncomp_data)
{
/* Temporary variables to store the sensor data */
uint32_t data_xlsb;
uint32_t data_lsb;
uint32_t data_msb;
/* Store the parsed register values for pressure data */
data_xlsb = (uint32_t)reg_data[0];
data_lsb = (uint32_t)reg_data[1] << 8;
data_msb = (uint32_t)reg_data[2] << 16;
uncomp_data->pressure = data_msb | data_lsb | data_xlsb;
/* Store the parsed register values for temperature data */
data_xlsb = (uint32_t)reg_data[3];
data_lsb = (uint32_t)reg_data[4] << 8;
data_msb = (uint32_t)reg_data[5] << 16;
uncomp_data->temperature = data_msb | data_lsb | data_xlsb;
}
/*!
* @brief This internal API is used to compensate the pressure or temperature
* or both the data according to the component selected by the user.
*/
static int8_t compensate_data(uint8_t sensor_comp, const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_data *comp_data, struct bmp3_calib_data *calib_data)
{
int8_t rslt = BMP3_OK;
if ((uncomp_data != NULL) && (comp_data != NULL) && (calib_data != NULL)) {
/* If pressure or temperature component is selected */
if (sensor_comp & (BMP3_PRESS | BMP3_TEMP)) {
/* Compensate the temperature data */
comp_data->temperature = compensate_temperature(uncomp_data, calib_data);
}
if (sensor_comp & BMP3_PRESS) {
/* Compensate the pressure data */
comp_data->pressure = compensate_pressure(uncomp_data, calib_data);
}
} else {
rslt = BMP3_E_NULL_PTR;
}
return rslt;
}
#ifdef FLOATING_POINT_COMPENSATION
/*!
* @brief This internal API is used to parse the calibration data, compensates
* it and store it in device structure
*/
static void parse_calib_data(const uint8_t *reg_data, struct bmp3_dev *dev)
{
/* Temporary variable to store the aligned trim data */
struct bmp3_reg_calib_data *reg_calib_data = &dev->calib_data.reg_calib_data;
struct bmp3_quantized_calib_data *quantized_calib_data = &dev->calib_data.quantized_calib_data;
/* Temporary variable */
float temp_var;
/* 1 / 2^8 */
temp_var = 0.00390625f;
reg_calib_data->par_t1 = BMP3_CONCAT_BYTES(reg_data[1], reg_data[0]);
quantized_calib_data->par_t1 = ((float)reg_calib_data->par_t1 / temp_var);
reg_calib_data->par_t2 = BMP3_CONCAT_BYTES(reg_data[3], reg_data[2]);
temp_var = 1073741824.0f;
quantized_calib_data->par_t2 = ((float)reg_calib_data->par_t2 / temp_var);
reg_calib_data->par_t3 = (int8_t)reg_data[4];
temp_var = 281474976710656.0f;
quantized_calib_data->par_t3 = ((float)reg_calib_data->par_t3 / temp_var);
reg_calib_data->par_p1 = (int16_t)BMP3_CONCAT_BYTES(reg_data[6], reg_data[5]);
temp_var = 1048576.0f;
quantized_calib_data->par_p1 = ((float)(reg_calib_data->par_p1 - (16384)) / temp_var);
reg_calib_data->par_p2 = (int16_t)BMP3_CONCAT_BYTES(reg_data[8], reg_data[7]);
temp_var = 536870912.0f;
quantized_calib_data->par_p2 = ((float)(reg_calib_data->par_p2 - (16384)) / temp_var);
reg_calib_data->par_p3 = (int8_t)reg_data[9];
temp_var = 4294967296.0f;
quantized_calib_data->par_p3 = ((float)reg_calib_data->par_p3 / temp_var);
reg_calib_data->par_p4 = (int8_t)reg_data[10];
temp_var = 137438953472.0f;
quantized_calib_data->par_p4 = ((float)reg_calib_data->par_p4 / temp_var);
reg_calib_data->par_p5 = BMP3_CONCAT_BYTES(reg_data[12], reg_data[11]);
/* 1 / 2^3 */
temp_var = 0.125f;
quantized_calib_data->par_p5 = ((float)reg_calib_data->par_p5 / temp_var);
reg_calib_data->par_p6 = BMP3_CONCAT_BYTES(reg_data[14], reg_data[13]);
temp_var = 64.0f;
quantized_calib_data->par_p6 = ((float)reg_calib_data->par_p6 / temp_var);
reg_calib_data->par_p7 = (int8_t)reg_data[15];
temp_var = 256.0f;
quantized_calib_data->par_p7 = ((float)reg_calib_data->par_p7 / temp_var);
reg_calib_data->par_p8 = (int8_t)reg_data[16];
temp_var = 32768.0f;
quantized_calib_data->par_p8 = ((float)reg_calib_data->par_p8 / temp_var);
reg_calib_data->par_p9 = (int16_t)BMP3_CONCAT_BYTES(reg_data[18], reg_data[17]);
temp_var = 281474976710656.0f;
quantized_calib_data->par_p9 = ((float)reg_calib_data->par_p9 / temp_var);
reg_calib_data->par_p10 = (int8_t)reg_data[19];
temp_var = 281474976710656.0f;
quantized_calib_data->par_p10 = ((float)reg_calib_data->par_p10 / temp_var);
reg_calib_data->par_p11 = (int8_t)reg_data[20];
temp_var = 36893488147419103232.0f;
quantized_calib_data->par_p11 = ((float)reg_calib_data->par_p11 / temp_var);
}
/*!
* @brief This internal API is used to compensate the raw temperature data and
* return the compensated temperature data in float data type.
*/
static float compensate_temperature(const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_calib_data *calib_data)
{
uint32_t uncomp_temp = uncomp_data->temperature;
float partial_data1;
float partial_data2;
partial_data1 = (float)(uncomp_temp - calib_data->quantized_calib_data.par_t1);
partial_data2 = (float)(partial_data1 * calib_data->quantized_calib_data.par_t2);
/* Update the compensated temperature in calib structure since this is
needed for pressure calculation */
calib_data->quantized_calib_data.t_lin = partial_data2 + (partial_data1 * partial_data1)
* calib_data->quantized_calib_data.par_t3;
/* Returns compensated temperature */
return calib_data->quantized_calib_data.t_lin;
}
/*!
* @brief This internal API is used to compensate the raw pressure data and
* return the compensated pressure data in float data type.
*/
static float compensate_pressure(const struct bmp3_uncomp_data *uncomp_data,
const struct bmp3_calib_data *calib_data)
{
const struct bmp3_quantized_calib_data *quantized_calib_data = &calib_data->quantized_calib_data;
/* Variable to store the compensated pressure */
float comp_press;
/* Temporary variables used for compensation */
float partial_data1;
float partial_data2;
float partial_data3;
float partial_data4;
float partial_out1;
float partial_out2;
partial_data1 = quantized_calib_data->par_p6 * quantized_calib_data->t_lin;
partial_data2 = quantized_calib_data->par_p7 * bmp3_pow(quantized_calib_data->t_lin, 2);
partial_data3 = quantized_calib_data->par_p8 * bmp3_pow(quantized_calib_data->t_lin, 3);
partial_out1 = quantized_calib_data->par_p5 + partial_data1 + partial_data2 + partial_data3;
partial_data1 = quantized_calib_data->par_p2 * quantized_calib_data->t_lin;
partial_data2 = quantized_calib_data->par_p3 * bmp3_pow(quantized_calib_data->t_lin, 2);
partial_data3 = quantized_calib_data->par_p4 * bmp3_pow(quantized_calib_data->t_lin, 3);
partial_out2 = uncomp_data->pressure *
(quantized_calib_data->par_p1 + partial_data1 + partial_data2 + partial_data3);
partial_data1 = bmp3_pow((float)uncomp_data->pressure, 2);
partial_data2 = quantized_calib_data->par_p9 + quantized_calib_data->par_p10 * quantized_calib_data->t_lin;
partial_data3 = partial_data1 * partial_data2;
partial_data4 = partial_data3 + bmp3_pow((float)uncomp_data->pressure, 3) * quantized_calib_data->par_p11;
comp_press = partial_out1 + partial_out2 + partial_data4;
return comp_press;
}
/*!
* @brief This internal API is used to calculate the power functionality for
* floating point values.
*/
static float bmp3_pow(float base, uint8_t power)
{
float pow_output = 1;
while (power != 0) {
pow_output = base * pow_output;
power--;
}
return pow_output;
}
#else
/*!
* @brief This internal API is used to parse the calibration data, compensates
* it and store it in device structure
*/
static void parse_calib_data(const uint8_t *reg_data, struct bmp3_dev *dev)
{
/* Temporary variable to store the aligned trim data */
struct bmp3_reg_calib_data *reg_calib_data = &dev->calib_data.reg_calib_data;
reg_calib_data->par_t1 = BMP3_CONCAT_BYTES(reg_data[1], reg_data[0]);
reg_calib_data->par_t2 = BMP3_CONCAT_BYTES(reg_data[3], reg_data[2]);
reg_calib_data->par_t3 = (int8_t)reg_data[4];
reg_calib_data->par_p1 = (int16_t)BMP3_CONCAT_BYTES(reg_data[6], reg_data[5]);
reg_calib_data->par_p2 = (int16_t)BMP3_CONCAT_BYTES(reg_data[8], reg_data[7]);
reg_calib_data->par_p3 = (int8_t)reg_data[9];
reg_calib_data->par_p4 = (int8_t)reg_data[10];
reg_calib_data->par_p5 = BMP3_CONCAT_BYTES(reg_data[12], reg_data[11]);
reg_calib_data->par_p6 = BMP3_CONCAT_BYTES(reg_data[14], reg_data[13]);
reg_calib_data->par_p7 = (int8_t)reg_data[15];
reg_calib_data->par_p8 = (int8_t)reg_data[16];
reg_calib_data->par_p9 = (int16_t)BMP3_CONCAT_BYTES(reg_data[18], reg_data[17]);
reg_calib_data->par_p10 = (int8_t)reg_data[19];
reg_calib_data->par_p11 = (int8_t)reg_data[20];
}
/*!
* @brief This internal API is used to compensate the raw temperature data and
* return the compensated temperature data in integer data type.
*/
static int64_t compensate_temperature(const struct bmp3_uncomp_data *uncomp_data,
struct bmp3_calib_data *calib_data)
{
uint64_t partial_data1;
uint64_t partial_data2;
uint64_t partial_data3;
int64_t partial_data4;
int64_t partial_data5;
int64_t partial_data6;
int64_t comp_temp;
partial_data1 = uncomp_data->temperature - (256 * calib_data->reg_calib_data.par_t1);
partial_data2 = calib_data->reg_calib_data.par_t2 * partial_data1;
partial_data3 = partial_data1 * partial_data1;
partial_data4 = (int64_t)partial_data3 * calib_data->reg_calib_data.par_t3;
partial_data5 = ((int64_t)(partial_data2 * 262144) + partial_data4);
partial_data6 = partial_data5 / 4294967296;
/* Store t_lin in dev. structure for pressure calculation */
calib_data->reg_calib_data.t_lin = partial_data6;
comp_temp = (int64_t)((partial_data6 * 25) / 16384);
return comp_temp;
}
/*!
* @brief This internal API is used to compensate the raw pressure data and
* return the compensated pressure data in integer data type.
*/
static uint64_t compensate_pressure(const struct bmp3_uncomp_data *uncomp_data,
const struct bmp3_calib_data *calib_data)
{
const struct bmp3_reg_calib_data *reg_calib_data = &calib_data->reg_calib_data;
int64_t partial_data1;
int64_t partial_data2;
int64_t partial_data3;
int64_t partial_data4;
int64_t partial_data5;
int64_t partial_data6;
int64_t offset;
int64_t sensitivity;
uint64_t comp_press;
partial_data1 = reg_calib_data->t_lin * reg_calib_data->t_lin;
partial_data2 = partial_data1 / 64;
partial_data3 = (partial_data2 * reg_calib_data->t_lin) / 256;
partial_data4 = (reg_calib_data->par_p8 * partial_data3) / 32;
partial_data5 = (reg_calib_data->par_p7 * partial_data1) * 16;
partial_data6 = (reg_calib_data->par_p6 * reg_calib_data->t_lin) * 4194304;
offset = (reg_calib_data->par_p5 * 140737488355328) + partial_data4 + partial_data5 + partial_data6;
partial_data2 = (reg_calib_data->par_p4 * partial_data3) / 32;
partial_data4 = (reg_calib_data->par_p3 * partial_data1) * 4;
partial_data5 = (reg_calib_data->par_p2 - 16384) * reg_calib_data->t_lin * 2097152;
sensitivity = ((reg_calib_data->par_p1 - 16384) * 70368744177664) + partial_data2 + partial_data4
+ partial_data5;
partial_data1 = (sensitivity / 16777216) * uncomp_data->pressure;
partial_data2 = reg_calib_data->par_p10 * reg_calib_data->t_lin;
partial_data3 = partial_data2 + (65536 * reg_calib_data->par_p9);
partial_data4 = (partial_data3 * uncomp_data->pressure) / 8192;
partial_data5 = (partial_data4 * uncomp_data->pressure) / 512;
partial_data6 = (int64_t)((uint64_t)uncomp_data->pressure * (uint64_t)uncomp_data->pressure);
partial_data2 = (reg_calib_data->par_p11 * partial_data6) / 65536;
partial_data3 = (partial_data2 * uncomp_data->pressure) / 128;
partial_data4 = (offset / 4) + partial_data1 + partial_data5 + partial_data3;
comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776);
return comp_press;
}
/*!
* @brief This internal API is used to calculate the power functionality.
*/
static uint32_t bmp3_pow(uint8_t base, uint8_t power)
{
uint32_t pow_output = 1;
while (power != 0) {
pow_output = base * pow_output;
power--;
}
return pow_output;
}
#endif
/*!
* @brief This internal API is used to identify the settings which the user
* wants to modify in the sensor.
*/
static uint8_t are_settings_changed(uint32_t sub_settings, uint32_t desired_settings)
{
uint8_t settings_changed = FALSE;
if (sub_settings & desired_settings) {
/* User wants to modify this particular settings */
settings_changed = TRUE;
} else {
/* User don't want to modify this particular settings */
settings_changed = FALSE;
}
return settings_changed;
}
/*!
* @brief This internal API is used to validate the device structure pointer for
* null conditions.
*/
static int8_t null_ptr_check(const struct bmp3_dev *dev)
{
int8_t rslt;
if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) {
/* Device structure pointer is not valid */
rslt = BMP3_E_NULL_PTR;
} else {
/* Device structure is fine */
rslt = BMP3_OK;
}
return rslt;
}
/*!
* @brief This internal API is used to parse the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en),
* fifo_config_2(fifo_subsampling, data_select) and int_ctrl(fwtm_en, ffull_en)
* settings and store it in device structure
*/
static void parse_fifo_settings(const uint8_t *reg_data, struct bmp3_fifo_settings *dev_fifo)
{
uint8_t fifo_config_1_data = reg_data[0];
uint8_t fifo_config_2_data = reg_data[1];
uint8_t fifo_int_ctrl_data = reg_data[2];
/* Parse fifo config 1 register data */
dev_fifo->mode = BMP3_GET_BITS_POS_0(fifo_config_1_data, BMP3_FIFO_MODE);
dev_fifo->stop_on_full_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_STOP_ON_FULL);
dev_fifo->time_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_TIME_EN);
dev_fifo->press_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_PRESS_EN);
dev_fifo->temp_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_TEMP_EN);
/* Parse fifo config 2 register data */
dev_fifo->down_sampling = BMP3_GET_BITS_POS_0(fifo_config_2_data, BMP3_FIFO_DOWN_SAMPLING);
dev_fifo->filter_en = BMP3_GET_BITS(fifo_config_2_data, BMP3_FIFO_FILTER_EN);
/* Parse fifo related interrupt control data */
dev_fifo->ffull_en = BMP3_GET_BITS(fifo_int_ctrl_data, BMP3_FIFO_FULL_EN);
dev_fifo->fwtm_en = BMP3_GET_BITS(fifo_int_ctrl_data, BMP3_FIFO_FWTM_EN);
}
/*!
* @brief This internal API fills the fifo_config_1(fifo_mode,
* fifo_stop_on_full, fifo_time_en, fifo_press_en, fifo_temp_en) settings in the
* reg_data variable so as to burst write in the sensor.
*/
static void fill_fifo_config_1(uint16_t desired_settings, uint8_t *reg_data,
struct bmp3_fifo_settings *dev_fifo)
{
if (desired_settings & BMP3_FIFO_MODE_SEL) {
/* Fill the FIFO mode register data */
*reg_data = BMP3_SET_BITS_POS_0(*reg_data, BMP3_FIFO_MODE, dev_fifo->mode);
}
if (desired_settings & BMP3_FIFO_STOP_ON_FULL_EN_SEL) {
/* Fill the stop on full data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_STOP_ON_FULL, dev_fifo->stop_on_full_en);
}
if (desired_settings & BMP3_FIFO_TIME_EN_SEL) {
/* Fill the time enable data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_TIME_EN, dev_fifo->time_en);
}
if (desired_settings &
(BMP3_FIFO_PRESS_EN_SEL | BMP3_FIFO_TEMP_EN_SEL)) {
/* Fill the FIFO pressure enable */
if (desired_settings & BMP3_FIFO_PRESS_EN_SEL) {
if ((dev_fifo->temp_en == 0) && (dev_fifo->press_en == 1)) {
/* Set the temperature sensor to be enabled */
dev_fifo->temp_en = 1;
}
/* Fill the pressure enable data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_PRESS_EN, dev_fifo->press_en);
}
/* Temperature should be enabled to get the pressure data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_TEMP_EN, dev_fifo->temp_en);
}
}
/*!
* @brief This internal API fills the fifo_config_2(fifo_subsampling,
* data_select) settings in the reg_data variable so as to burst write
* in the sensor.
*/
static void fill_fifo_config_2(uint16_t desired_settings, uint8_t *reg_data,
const struct bmp3_fifo_settings *dev_fifo)
{
if (desired_settings & BMP3_FIFO_DOWN_SAMPLING_SEL) {
/* To do check Normal mode */
/* Fill the down-sampling data */
*reg_data = BMP3_SET_BITS_POS_0(*reg_data, BMP3_FIFO_DOWN_SAMPLING, dev_fifo->down_sampling);
}
if (desired_settings & BMP3_FIFO_FILTER_EN_SEL) {
/* Fill the filter enable data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_FILTER_EN, dev_fifo->filter_en);
}
}
/*!
* @brief This internal API fills the fifo interrupt control(fwtm_en, ffull_en)
* settings in the reg_data variable so as to burst write in the sensor.
*/
static void fill_fifo_int_ctrl(uint16_t desired_settings, uint8_t *reg_data,
const struct bmp3_fifo_settings *dev_fifo)
{
if (desired_settings & BMP3_FIFO_FWTM_EN_SEL) {
/* Fill the FIFO watermark interrupt enable data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_FWTM_EN, dev_fifo->fwtm_en);
}
if (desired_settings & BMP3_FIFO_FULL_EN_SEL) {
/* Fill the FIFO full interrupt enable data */
*reg_data = BMP3_SET_BITS(*reg_data, BMP3_FIFO_FULL_EN, dev_fifo->ffull_en);
}
}
/*!
* @brief This API gets the command ready, data ready for pressure and
* temperature, power on reset status from the sensor.
*/
static int8_t get_sensor_status(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_addr;
uint8_t reg_data;
reg_addr = BMP3_SENS_STATUS_REG_ADDR;
rslt = bmp3_get_regs(reg_addr, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
dev->status.sensor.cmd_rdy = BMP3_GET_BITS(reg_data, BMP3_STATUS_CMD_RDY);
dev->status.sensor.drdy_press = BMP3_GET_BITS(reg_data, BMP3_STATUS_DRDY_PRESS);
dev->status.sensor.drdy_temp = BMP3_GET_BITS(reg_data, BMP3_STATUS_DRDY_TEMP);
reg_addr = BMP3_EVENT_ADDR;
rslt = bmp3_get_regs(reg_addr, &reg_data, 1, dev);
dev->status.pwr_on_rst = reg_data & 0x01;
}
return rslt;
}
/*!
* @brief This API gets the interrupt (fifo watermark, fifo full, data ready)
* status from the sensor.
*/
static int8_t get_int_status(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
rslt = bmp3_get_regs(BMP3_INT_STATUS_REG_ADDR, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
dev->status.intr.fifo_wm = BMP3_GET_BITS_POS_0(reg_data, BMP3_INT_STATUS_FWTM);
dev->status.intr.fifo_full = BMP3_GET_BITS(reg_data, BMP3_INT_STATUS_FFULL);
dev->status.intr.drdy = BMP3_GET_BITS(reg_data, BMP3_INT_STATUS_DRDY);
}
return rslt;
}
/*!
* @brief This API gets the fatal, command and configuration error
* from the sensor.
*/
static int8_t get_err_status(struct bmp3_dev *dev)
{
int8_t rslt;
uint8_t reg_data;
rslt = bmp3_get_regs(BMP3_ERR_REG_ADDR, &reg_data, 1, dev);
if (rslt == BMP3_OK) {
dev->status.err.cmd = BMP3_GET_BITS_POS_0(reg_data, BMP3_ERR_FATAL);
dev->status.err.conf = BMP3_GET_BITS(reg_data, BMP3_ERR_CMD);
dev->status.err.fatal = BMP3_GET_BITS(reg_data, BMP3_ERR_CONF);
}
return rslt;
}
/*
* Copyright (C) 2014 Bosch Sensortec GmbH
*
* \section Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry.
* They may only be used within the parameters of the respective valid
* product data sheet. Bosch Sensortec products are provided with the
* express understanding that there is no warranty of fitness for a
* particular purpose.They are not fit for use in life-sustaining,
* safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system
* or device malfunctions. In addition,Bosch Sensortec products are
* not fit for use in products which interact with motor vehicle systems.
* The resale and or use of products are at the purchasers own risk and
* his own responsibility. The examination of fitness for the intended use
* is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party
* claims, including any claims for incidental, or consequential damages,
* arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by
* Bosch Sensortec and reimburse Bosch Sensortec for all costs in
* connection with such claims.
*
* The purchaser must monitor the market for the purchased products,
* particularly with regard to product safety and inform Bosch Sensortec
* without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e).
* Samples may vary from the valid technical specifications of the product
* series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal
* client testing. The testing of an engineering sample may in no way
* replace the testing of a product series. Bosch Sensortec assumes
* no liability for the use of engineering samples.
* By accepting the engineering samples, the Purchaser agrees to indemnify
* Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information
* on application-sheets (hereinafter called "Information") is provided
* free of charge for the sole purpose to support your application work.
* The Software and Information is subject to the following
* terms and conditions:
*
* The Software is specifically designed for the exclusive use for
* Bosch Sensortec products by personnel who have special experience
* and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed
* or implied warranties,including without limitation, the implied warranties
* of merchantability and fitness for a particular purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability
* for the functional impairment
* of this Software in terms of fitness, performance and safety.
* Bosch Sensortec and their representatives and agents shall not be liable
* for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable.
* Bosch Sensortec assumes no responsibility for the consequences of use
* of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
*/
/*!
* @file bstdr_comm_support.c
*
* @brief
* Contains the code for the communication wrapper APIs
*
*/
#include "bstdr_comm_support.h"
#include "stm32fxxx.h"
#include "FreeRTOS.h"
#include "task.h"
// TA: Maybe not so good to bring in these dependencies...
#include "debug.h"
#include "eprintf.h"
#include "i2cdev.h"
/*!
* @brief Communication initialization
*
* This is optional. Depends on the system you are using
*
* @return Zero if successful, otherwise an error code
*/
bstdr_ret_t bstdr_comm_init(void)
{
/**< Communication initialization --Optional!*/
return (bstdr_ret_t)0;
}
/*!
* @brief Generic burst read
*
* @param [out] dev_id I2C address, SPI chip select or user desired identifier
*
* @return Zero if successful, otherwise an error code
*/
bstdr_ret_t bstdr_burst_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint32_t len)
{
/**< Burst read code comes here */
if (i2cdevReadReg8(I2C1_DEV, dev_id, reg_addr, (uint16_t) len, reg_data))
{
return BSTDR_OK;
}
else
{
return BSTDR_E_CON_ERROR;
}
}
/*!
* @brief Generic burst write
*
* @param [out] dev_id I2C address, SPI chip select or user desired identifier
*
* @return Zero if successful, otherwise an error code
*/
bstdr_ret_t bstdr_burst_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint32_t len)
{
/**< Burst write code comes here */
if (i2cdevWriteReg8(I2C1_DEV, dev_id,reg_addr,(uint16_t) len, reg_data))
{
return BSTDR_OK;
}
else
{
return BSTDR_E_CON_ERROR;
}
}
/*!
* @brief Generic burst read
*
* @param [in] period Delay period in milliseconds
*
* @return None
*/
void bstdr_ms_delay(uint32_t period)
{
/**< Delay code comes */
vTaskDelay(M2T(period)); // Delay a while to let the device stabilize
}
/**
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2012 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* adc.h - Analog Digital Conversion header file
*/
#ifndef ADC_H_
#define ADC_H_
#include <stdbool.h>
#include <stdint.h>
#include "FreeRTOS.h"
#include "semphr.h"
#include "config.h"
/******** Defines ********/
/**
* \def ADC_MEAN_SIZE
* Number of samples used in the mean value calculation.
* Mean size should be evenly dividable by decimation bits.
*/
#define ADC_DECIMATE_TO_BITS 12
#define ADC_MEAN_SIZE 8
#define ADC_RESOLUTION 12
#define ADC_DECIMATE_DIVEDEND (ADC_MEAN_SIZE / (1 << (ADC_DECIMATE_TO_BITS - ADC_RESOLUTION)))
#if ADC_DECIMATE_TO_BITS < ADC_RESOLUTION
# error "ADC_DECIMATE_TO_BITS must be bigger or equal to ADC_RESOLUTION"
#endif
#define ADC_SAMPLING_FREQ 100
#define ADC_OVERSAMPLING_FREQ (ADC_SAMPLING_FREQ * ADC_MEAN_SIZE)
#define ADC_TRIG_PRESCALE 1
#define ADC_TRIG_PRESCALE_FREQ (72000000 / (ADC_TRIG_PRESCALE + 1))
#define ADC_TRIG_PERIOD (ADC_TRIG_PRESCALE_FREQ / (ADC_OVERSAMPLING_FREQ))
#define ADC_INTERNAL_VREF 1.20
/******** Types ********/
typedef struct __attribute__((packed))
{
uint16_t vref;
uint16_t val;
} AdcPair;
typedef struct __attribute__((packed))
{
AdcPair vbat;
} AdcGroup;
typedef struct
{
uint16_t vbat;
uint16_t vbatVref;
} AdcDeciGroup;
/*** Public interface ***/
/**
* Initialize analog to digital converter. Configures gyro and vref channels.
* Configures DMA to transfer the result.
*/
void adcInit(void);
bool adcTest(void);
/**
* Converts a 12 bit ADC value to battery voltage
* @param vbat 12 bit adc value
* @param vref 12 bit adc value of the internal voltage
* reference, 1.2V
*
* @return The voltage in a float value
*/
float adcConvertToVoltageFloat(uint16_t v, uint16_t vref);
/**
* Starts converting ADC samples by activating the DMA.
*/
void adcDmaStart(void);
/**
* Stop converting ADC samples.
*/
void adcDmaStop(void);
/**
* ADC interrupt handler
*/
void adcInterruptHandler(void);
/**
* ADC task
*/
void adcTask(void *param);
#endif /* ADC_H_ */