/** * Copyright (c) 2022 Bosch Sensortec GmbH. All rights reserved. * * BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. Neither the name of the copyright holder nor the names of its * 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 THE * 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. * * @file bmp3.c * @date 2022-04-01 * @version v2.0.6 * */ /*! @file bmp3.c * @brief Sensor driver for BMP3 sensor */ #include "bmp3.h" /***************** 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 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ 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] settings : Structure instance of bmp3_settings. * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t get_odr_filter_settings(struct bmp3_settings *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 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ 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 BMP3_FLOAT_COMPENSATION /*! * @brief This internal API is used to compensate the raw temperature data and * return the compensated temperature data. * * @param[out] temperature : Compensated temperature data in double. * @param[in] uncomp_data : Contains the uncompensated temperature data. * @param[in] calib_data : Pointer to calibration data structure. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail * */ static int8_t compensate_temperature(double *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[out] comp_pressure : Compensated pressure data in double. * @param[in] uncomp_data : Contains the uncompensated pressure data. * @param[in] calib_data : Pointer to the calibration data structure. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t compensate_pressure(double *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 * double precision 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 pow_bmp3(double 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[out] temperature : Compensated temperature data in integer. * @param[in] uncomp_data : Contains the uncompensated temperature data. * @param[in] calib_data : Pointer to calibration data structure. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t compensate_temperature(int64_t *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[out] comp_pressure : Compensated pressure data in integer. * @param[in] uncomp_data : Contains the uncompensated pressure data. * @param[in] calib_data : Pointer to the calibration data structure. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t compensate_pressure(uint64_t *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 pow_bmp3(uint8_t base, uint8_t power); #endif /* BMP3_FLOAT_COMPENSATION */ /*! * @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, uint32_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] settings : Structure instance of bmp3_settings * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t set_pwr_ctrl_settings(uint32_t desired_settings, const struct bmp3_settings *settings, 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] settings : Structure instance of bmp3_settings * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t set_odr_filter_settings(uint32_t desired_settings, struct bmp3_settings *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] settings : Structure instance of bmp3_settings * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t set_int_ctrl_settings(uint32_t desired_settings, const struct bmp3_settings *settings, 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] settings : Structure instance of bmp3_settings * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t set_advance_settings(uint32_t desired_settings, const struct bmp3_settings *settings, 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] settings : Structure instance of bmp3_settings * */ static void fill_osr_data(uint32_t desired_settings, uint8_t *addr, uint8_t *reg_data, uint8_t *len, const struct bmp3_settings *settings); /*! * @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] settings : Structure instance of bmp3_settings * */ static void fill_odr_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, struct bmp3_settings *settings); /*! * @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] settings : Structure instance of bmp3_settings * */ static void fill_filter_data(uint8_t *addr, uint8_t *reg_data, uint8_t *len, const struct bmp3_settings *settings); /*! * @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 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ 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[in] settings : Structure instance of bmp3_settings */ static void parse_sett_data(const uint8_t *reg_data, struct bmp3_settings *settings); /*! * @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[out] settings : Structure instance of bmp3_settings. * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t validate_normal_mode_settings(struct bmp3_settings *settings, struct bmp3_dev *dev); /*! * @brief This internal API validate the over sampling, ODR settings of the * sensor. * * @param[out] settings : Structure instance of bmp3_settings. * * @return Indicates whether ODR and OSR settings are valid or not. * @retval 0 -> Success * @retval <0 -> Fail */ static int8_t validate_osr_and_odr_settings(const struct bmp3_settings *settings); /*! * @brief This internal API calculates the pressure measurement duration of the * sensor. * * @param[out] settings : Structure instance of bmp3_settings. * * @return Pressure measurement time * @retval Pressure measurement time in microseconds */ static uint32_t calculate_press_meas_time(const struct bmp3_settings *settings); /*! * @brief This internal API calculates the temperature measurement duration of * the sensor. * * @param[out] settings : Structure instance of bmp3_settings. * * @return Temperature measurement time * @retval Temperature measurement time in microseconds */ static uint32_t calculate_temp_meas_time(const struct bmp3_settings *settings); /*! * @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 microseconds. * @param[in] odr_duration : Duration in microseconds corresponding to the ODR * value. * * @return Indicates whether ODR and OSR settings are valid or not. * @retval 0 -> Success * @retval >0 -> Warning */ static int8_t verify_meas_time_and_odr_duration(uint32_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 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t put_device_to_sleep(struct bmp3_dev *dev); /*! * @brief This internal API sets the normal mode in the sensor. * * @param[in] settings : Structure instance of bmp3_settings. * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status. * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t set_normal_mode(struct bmp3_settings *settings, struct bmp3_dev *dev); /*! * @brief This internal API writes the power mode in the sensor. * * @param[out] settings : Structure instance of bmp3_settings. * @param[in] dev : Structure instance of bmp3_dev. * * @return Result of API execution status. * @retval 0 -> Success * @retval >0 -> Warning * @retval <0 -> Fail */ static int8_t write_power_mode(const struct bmp3_settings *settings, 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[in] fifo_settings : Structure instance of bmp3_fifo_settings * @param[in] dev : Structure instance of bmp3_dev */ static int8_t fill_fifo_config_1(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev); /*! * @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[in] fifo_settings : Structure instance of bmp3_fifo_settings * @param[in] dev : Structure instance of bmp3_dev */ static int8_t fill_fifo_config_2(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev); /*! * @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[in] fifo_settings : Structure instance of bmp3_fifo_settings * @param[in] dev : Structure instance of bmp3_dev */ static int8_t fill_fifo_int_ctrl(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev); /*! * @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] fifo_settings : 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 *fifo_settings); /*! * @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 * @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 0 -> Success * @retval <0 -> Fail */ static uint8_t parse_fifo_data_frame(uint8_t header, struct bmp3_fifo_data *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_data *fifo); /*! * @brief This API gets the command ready, data ready for pressure and * temperature, power on reset status from the sensor. * * @param[out] : Structure instance of bmp3_status * @param[in] dev : Structure instance of bmp3_dev * * @return Result of API execution status. * @retval 0 -> Success * @retval <0 -> Fail */ static int8_t get_sensor_status(struct bmp3_status *status, struct bmp3_dev *dev); /*! * @brief This API gets the interrupt (fifo watermark, fifo full, data ready) * status from the sensor. * * @param[out] : Structure instance of bmp3_status * @param[in] dev : Structure instance of bmp3_dev * * @return Result of API execution status. * @retval 0 -> Success * @retval <0 -> Fail */ static int8_t get_int_status(struct bmp3_status *status, struct bmp3_dev *dev); /*! * @brief This API gets the fatal, command and configuration error * from the sensor. * * @param[out] : Structure instance of bmp3_status * @param[in] dev : Structure instance of bmp3_dev * * @return Result of API execution status. * @retval 0 -> Success * @retval <0 -> Fail */ static int8_t get_err_status(struct bmp3_status *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[out] watermark_len : Pointer variable which contains the watermark * length. * @param[in] fifo : Structure instance of bmp3_fifo_data * @param[in] fifo_settings : Structure instance of bmp3_fifo_settings * * @return Result of API execution status. * @retval 0 -> Success * @retval <0 -> Fail */ static int8_t convert_frames_to_bytes(uint16_t *watermark_len, const struct bmp3_fifo_data *fifo, const struct bmp3_fifo_settings *fifo_settings); /****************** 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_REG_CHIP_ID, &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) || (chip_id == BMP390_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, uint32_t len, struct bmp3_dev *dev) { int8_t rslt; uint32_t idx; /* Check for null pointer in the device structure */ rslt = null_ptr_check(dev); /* Proceed if null check is fine */ if ((rslt == BMP3_OK) && (reg_data != NULL)) { uint32_t temp_len = len + dev->dummy_byte; uint8_t temp_buff[len + dev->dummy_byte]; /* If interface selected is SPI */ if (dev->intf != BMP3_I2C_INTF) { reg_addr = reg_addr | 0x80; /* Read the data from the register */ dev->intf_rslt = dev->read(reg_addr, temp_buff, temp_len, dev->intf_ptr); for (idx = 0; idx < len; idx++) { reg_data[idx] = temp_buff[idx + dev->dummy_byte]; } } else { /* Read the data using I2C */ dev->intf_rslt = dev->read(reg_addr, reg_data, len, dev->intf_ptr); } /* Check for communication error */ if (dev->intf_rslt != BMP3_INTF_RET_SUCCESS) { rslt = BMP3_E_COMM_FAIL; } } else { rslt = BMP3_E_NULL_PTR; } 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, uint32_t len, struct bmp3_dev *dev) { int8_t rslt; uint8_t temp_buff[len * 2]; uint32_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; } dev->intf_rslt = dev->write(reg_addr[0], temp_buff, temp_len, dev->intf_ptr); /* Check for communication error */ if (dev->intf_rslt != BMP3_INTF_RET_SUCCESS) { 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_settings *settings, struct bmp3_dev *dev) { int8_t rslt = BMP3_OK; if (settings != NULL) { if (are_settings_changed(BMP3_POWER_CNTL, desired_settings)) { /* Set the power control settings */ rslt = set_pwr_ctrl_settings(desired_settings, settings, dev); } if (are_settings_changed(BMP3_ODR_FILTER, desired_settings)) { /* Set the over sampling, ODR and filter settings */ rslt = set_odr_filter_settings(desired_settings, settings, dev); } if (are_settings_changed(BMP3_INT_CTRL, desired_settings)) { /* Set the interrupt control settings */ rslt = set_int_ctrl_settings(desired_settings, settings, dev); } if (are_settings_changed(BMP3_ADV_SETT, desired_settings)) { /* Set the advance settings */ rslt = set_advance_settings(desired_settings, settings, dev); } } else { rslt = BMP3_E_NULL_PTR; } 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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t settings_data[BMP3_LEN_GEN_SETT]; if (settings != NULL) { rslt = bmp3_get_regs(BMP3_REG_INT_CTRL, settings_data, BMP3_LEN_GEN_SETT, dev); if (rslt == BMP3_OK) { /* Parse the settings data */ parse_sett_data(settings_data, settings); } } else { rslt = BMP3_E_NULL_PTR; } 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_fifo_settings *fifo_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) && (fifo_settings != NULL)) { if (are_settings_changed(BMP3_FIFO_CONFIG_1, desired_settings)) { /* Fill the FIFO config 1 register data */ rslt = fill_fifo_config_1(desired_settings, fifo_settings, dev); } if (are_settings_changed(desired_settings, BMP3_FIFO_CONFIG_2)) { /* Fill the FIFO config 2 register data */ rslt = fill_fifo_config_2(desired_settings, fifo_settings, dev); } if (are_settings_changed(desired_settings, BMP3_FIFO_INT_CTRL)) { /* Fill the FIFO interrupt ctrl register data */ rslt = fill_fifo_int_ctrl(desired_settings, fifo_settings, 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(struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t fifo_sett[3]; uint8_t len = 3; /* Proceed if null check is fine */ if (fifo_settings != NULL) { rslt = bmp3_get_regs(BMP3_REG_FIFO_CONFIG_1, fifo_sett, len, dev); /* Parse the fifo settings */ parse_fifo_settings(fifo_sett, 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(struct bmp3_fifo_data *fifo, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint16_t fifo_len; if ((fifo != NULL) && (fifo_settings != NULL)) { reset_fifo_index(fifo); /* Get the total number of bytes available in FIFO */ rslt = bmp3_get_fifo_length(&fifo_len, dev); if (rslt == BMP3_OK) { /* For sensor time frame , add additional overhead bytes */ if (fifo_settings->time_en == TRUE) { fifo_len = fifo_len + BMP3_SENSORTIME_OVERHEAD_BYTES; } /* Update the fifo length in the fifo structure */ fifo->byte_count = fifo_len; /* Read the fifo data */ rslt = bmp3_get_regs(BMP3_REG_FIFO_DATA, fifo->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_fifo_data *fifo, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data[2]; uint8_t reg_addr[2] = { BMP3_REG_FIFO_WM, BMP3_REG_FIFO_WM + 1 }; uint16_t watermark_len; if ((fifo != NULL) && (fifo_settings != NULL)) { rslt = convert_frames_to_bytes(&watermark_len, fifo, fifo_settings); 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); } } 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_get_fifo_watermark(uint16_t *watermark_len, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data[2]; uint8_t reg_addr = BMP3_REG_FIFO_WM; if (watermark_len != NULL) { rslt = bmp3_get_regs(reg_addr, reg_data, 2, dev); if (rslt == BMP3_OK) { *watermark_len = (reg_data[0]) + (reg_data[1] << 8); } } else { rslt = BMP3_E_NULL_PTR; } 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_fifo_data *fifo, struct bmp3_dev *dev) { int8_t rslt; uint8_t header; uint8_t parsed_frames = 0; uint8_t t_p_frame; struct bmp3_uncomp_data uncomp_data = { 0 }; rslt = null_ptr_check(dev); if ((rslt == BMP3_OK) && (fifo != NULL) && (data != NULL)) { uint16_t byte_index = fifo->start_idx; while (byte_index < fifo->byte_count) { get_header_info(&header, fifo->buffer, &byte_index); t_p_frame = parse_fifo_data_frame(header, 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 */ fifo->start_idx = byte_index; fifo->parsed_frames += parsed_frames; } else { /* No frames are there to parse. It is time to * read the FIFO, if more frames are needed */ fifo->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_status *status, struct bmp3_dev *dev) { int8_t rslt; if (status != NULL) { rslt = get_sensor_status(status, dev); /* Proceed further if the earlier operation is fine */ if (rslt == BMP3_OK) { rslt = get_int_status(status, dev); /* Proceed further if the earlier operation is fine */ if (rslt == BMP3_OK) { /* Get the error status */ rslt = get_err_status(status, dev); } } } else { rslt = BMP3_E_NULL_PTR; } return rslt; } /*! * @brief This API gets the fifo length from the sensor. */ int8_t bmp3_get_fifo_length(uint16_t *fifo_length, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data[2]; if (fifo_length != NULL) { rslt = bmp3_get_regs(BMP3_REG_FIFO_LENGTH, 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]); } } else { rslt = BMP3_E_NULL_PTR; } return rslt; } /*! * @brief This API performs the soft reset of the sensor. */ int8_t bmp3_soft_reset(struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_CMD; /* 0xB6 is the soft reset command */ uint8_t soft_rst_cmd = BMP3_SOFT_RESET; uint8_t cmd_rdy_status; uint8_t cmd_err_status; /* Check for command ready status */ rslt = bmp3_get_regs(BMP3_REG_SENS_STATUS, &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(®_addr, &soft_rst_cmd, 1, dev); /* Proceed if everything is fine until now */ if (rslt == BMP3_OK) { /* Wait for 2 ms */ dev->delay_us(2000, dev->intf_ptr); /* Read for command error status */ rslt = bmp3_get_regs(BMP3_REG_ERR, &cmd_err_status, 1, dev); /* check for command error status */ if ((cmd_err_status & BMP3_REG_CMD) || (rslt != BMP3_OK)) { /* Command not written hence return * error */ rslt = BMP3_E_CMD_EXEC_FAILED; } } } return rslt; } /*! * @brief This API performs the soft reset of the sensor. */ int8_t bmp3_fifo_flush(struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_CMD; uint8_t fifo_flush_cmd = BMP3_FIFO_FLUSH; uint8_t cmd_rdy_status; uint8_t cmd_err_status; /* Check for command ready status */ rslt = bmp3_get_regs(BMP3_REG_SENS_STATUS, &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(®_addr, &fifo_flush_cmd, 1, dev); /* Proceed if everything is fine until now */ if (rslt == BMP3_OK) { /* Wait for 2 ms */ dev->delay_us(2000, dev->intf_ptr); /* Read for command error status */ rslt = bmp3_get_regs(BMP3_REG_ERR, &cmd_err_status, 1, dev); /* check for command error status */ if ((cmd_err_status & BMP3_REG_CMD) || (rslt != BMP3_OK)) { /* Command not written hence return * error */ 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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t last_set_mode; /* Check for null pointer in the device structure */ rslt = null_ptr_check(dev); if ((rslt == BMP3_OK) && (settings != NULL)) { uint8_t curr_mode = settings->op_mode; 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_MODE_SLEEP) && (rslt == BMP3_OK)) { /* 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_us(5000, dev->intf_ptr); } /* Set the power mode */ if (rslt == BMP3_OK) { if (curr_mode == BMP3_MODE_NORMAL) { /* Set normal mode and validate * necessary settings */ rslt = set_normal_mode(settings, dev); } else if (curr_mode == BMP3_MODE_FORCED) { /* Set forced mode */ rslt = write_power_mode(settings, dev); } } } else { rslt = BMP3_E_NULL_PTR; } return rslt; } /*! * @brief This API gets the power mode of the sensor. */ int8_t bmp3_get_op_mode(uint8_t *op_mode, struct bmp3_dev *dev) { int8_t rslt; if (op_mode != NULL) { /* Read the power mode register */ rslt = bmp3_get_regs(BMP3_REG_PWR_CTRL, op_mode, 1, dev); /* Assign the power mode in the device structure */ *op_mode = BMP3_GET_BITS(*op_mode, BMP3_OP_MODE); } else { rslt = BMP3_E_NULL_PTR; } 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_LEN_P_T_DATA] = { 0 }; struct bmp3_uncomp_data uncomp_data = { 0 }; if (comp_data != NULL) { /* Read the pressure and temperature data from the sensor */ rslt = bmp3_get_regs(BMP3_REG_DATA, reg_data, BMP3_LEN_P_T_DATA, 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_fifo_data *fifo, const struct bmp3_fifo_settings *fifo_settings) { int8_t rslt = BMP3_OK; if ((fifo->req_frames > 0) && (fifo->req_frames <= BMP3_FIFO_MAX_FRAMES)) { if (fifo_settings->press_en && fifo_settings->temp_en) { /* Multiply with pressure and temperature header len */ *watermark_len = fifo->req_frames * BMP3_LEN_P_AND_T_HEADER_DATA; } else if (fifo_settings->temp_en || fifo_settings->press_en) { /* Multiply with pressure or temperature header len */ *watermark_len = fifo->req_frames * BMP3_LEN_P_OR_T_HEADER_DATA; } 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_data *fifo) { /* Loop variable */ uint16_t index; /* Variable for FIFO size */ uint16_t fifo_size = 512; /* The size of FIFO in BMP3 is 512 bytes */ for (index = 0; index < fifo_size; index++) { /* Initialize data buffer to zero */ fifo->buffer[index] = 0; } fifo->byte_count = 0; fifo->start_idx = 0; fifo->parsed_frames = 0; fifo->config_change = 0; fifo->config_err = 0; fifo->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_data *fifo, uint16_t *byte_index, struct bmp3_uncomp_data *uncomp_data, uint8_t *parsed_frames) { uint8_t t_p_frame = FALSE; switch (header) { case BMP3_FIFO_TEMP_PRESS_FRAME: unpack_temp_press_frame(byte_index, fifo->buffer, uncomp_data); *parsed_frames = *parsed_frames + 1; t_p_frame = BMP3_PRESS_TEMP; break; case BMP3_FIFO_TEMP_FRAME: unpack_temp_frame(byte_index, fifo->buffer, uncomp_data); *parsed_frames = *parsed_frames + 1; t_p_frame = BMP3_TEMP; break; case BMP3_FIFO_PRESS_FRAME: unpack_press_frame(byte_index, fifo->buffer, uncomp_data); *parsed_frames = *parsed_frames + 1; t_p_frame = BMP3_PRESS; break; case BMP3_FIFO_TIME_FRAME: unpack_time_frame(byte_index, fifo->buffer, &fifo->sensor_time); break; case BMP3_FIFO_CONFIG_CHANGE: fifo->config_change = 1; *byte_index = *byte_index + 1; break; case BMP3_FIFO_ERROR_FRAME: fifo->config_err = 1; *byte_index = *byte_index + 1; break; case BMP3_FIFO_EMPTY_FRAME: *byte_index = fifo->byte_count; break; default: fifo->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_TEMP), &fifo_buffer[*byte_index], uncomp_data); *byte_index = *byte_index + BMP3_LEN_P_T_DATA; } /*! * @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_LEN_T_DATA; } /*! * @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_LEN_P_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. */ 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_LEN_SENSOR_TIME; } /*! * @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_PRESS_TEMP)) { 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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t conf_err_status; rslt = validate_normal_mode_settings(settings, dev); /* If OSR and ODR settings are proper then write the power mode */ if (rslt == BMP3_OK) { rslt = write_power_mode(settings, dev); /* check for configuration error */ if (rslt == BMP3_OK) { /* Read the configuration error status */ rslt = bmp3_get_regs(BMP3_REG_ERR, &conf_err_status, 1, dev); /* Check if conf. error flag is set */ if (rslt == BMP3_OK) { if (conf_err_status & BMP3_ERR_CONF) { /* 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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_PWR_CTRL; uint8_t op_mode = 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(®_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(struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_PWR_CTRL; /* Temporary variable to store the value read from op-mode register */ uint8_t op_mode_reg_val; rslt = bmp3_get_regs(BMP3_REG_PWR_CTRL, &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(®_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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; rslt = get_odr_filter_settings(settings, dev); if (rslt == BMP3_OK) { rslt = validate_osr_and_odr_settings(settings); } 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_REG_CALIB_DATA; /* Array to store calibration data */ uint8_t calib_data[BMP3_LEN_CALIB_DATA] = { 0 }; /* Read the calibration data from the sensor */ rslt = bmp3_get_regs(reg_addr, calib_data, BMP3_LEN_CALIB_DATA, 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, uint32_t len) { uint32_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_settings *settings) { /* Parse interrupt control settings and store in device structure */ parse_int_ctrl_settings(®_data[0], &settings->int_settings); /* Parse advance settings and store in device structure */ parse_advance_settings(®_data[1], &settings->adv_settings); /* Parse power control settings and store in device structure */ parse_pwr_ctrl_settings(®_data[2], settings); /* Parse ODR and filter settings and store in device structure */ parse_odr_filter_settings(®_data[3], &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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_PWR_CTRL; uint8_t reg_data; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { if (desired_settings & BMP3_SEL_PRESS_EN) { /* Set the pressure enable settings in the * register variable */ reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_PRESS_EN, settings->press_en); } if (desired_settings & BMP3_SEL_TEMP_EN) { /* Set the temperature enable settings in the * register variable */ reg_data = BMP3_SET_BITS(reg_data, BMP3_TEMP_EN, settings->temp_en); } /* Write the power control settings in the register */ rslt = bmp3_set_regs(®_addr, ®_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_settings *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_REG_OSR, reg_data, 4, dev); if (rslt == BMP3_OK) { if (are_settings_changed((BMP3_SEL_PRESS_OS | BMP3_SEL_TEMP_OS), 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, settings); } if (are_settings_changed(BMP3_SEL_ODR, 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, settings); } if (are_settings_changed(BMP3_SEL_IIR_FILTER, 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, settings); } if (settings->op_mode == BMP3_MODE_NORMAL) { /* For normal mode, OSR and ODR settings should * be proper */ rslt = validate_osr_and_odr_settings(settings); } 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_settings *settings, 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_REG_INT_CTRL; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { int_settings = settings->int_settings; if (desired_settings & BMP3_SEL_OUTPUT_MODE) { /* 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_SEL_LEVEL) { /* Set the interrupt level bits */ reg_data = BMP3_SET_BITS(reg_data, BMP3_INT_LEVEL, int_settings.level); } if (desired_settings & BMP3_SEL_LATCH) { /* Set the interrupt latch bits */ reg_data = BMP3_SET_BITS(reg_data, BMP3_INT_LATCH, int_settings.latch); } if (desired_settings & BMP3_SEL_DRDY_EN) { /* 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(®_addr, ®_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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr; uint8_t reg_data; struct bmp3_adv_settings adv_settings = settings->adv_settings; reg_addr = BMP3_REG_IF_CONF; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { if (desired_settings & BMP3_SEL_I2C_WDT_EN) { /* 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_SEL_I2C_WDT) { /* 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(®_addr, ®_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_settings *settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data[4]; /* Read data beginning from 0x1C register */ rslt = bmp3_get_regs(BMP3_REG_OSR, reg_data, 4, dev); /* Parse the read data and store it in dev structure */ parse_odr_filter_settings(reg_data, &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_settings *settings) { int8_t rslt; /* According to BMP388 datasheet at Section 3.9.2. "Measurement rate in * forced mode and normal mode" there is also the constant of 234us also to * be considered in the sum. */ uint32_t meas_t = 234; uint32_t meas_t_p = 0; /* Sampling period corresponding to ODR in microseconds */ uint32_t odr[18] = { 5000, 10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000, 10240000, 20480000, 40960000, 81920000, 163840000, 327680000, 655360000 }; if (settings->press_en) { /* Calculate the pressure measurement duration */ meas_t_p += calculate_press_meas_time(settings); } if (settings->temp_en) { /* Calculate the temperature measurement duration */ meas_t_p += calculate_temp_meas_time(settings); } /* Constant 234us added to the summation of temperature and pressure measurement duration */ meas_t += meas_t_p; rslt = verify_meas_time_and_odr_duration(meas_t, odr[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(uint32_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 uint32_t calculate_press_meas_time(const struct bmp3_settings *settings) { uint32_t press_meas_t; struct bmp3_odr_filter_settings odr_filter = settings->odr_filter; #ifdef BMP3_FLOAT_COMPENSATION double base = 2.0; float partial_out; #else uint8_t base = 2; uint32_t partial_out; #endif /* BMP3_FLOAT_COMPENSATION */ partial_out = pow_bmp3(base, odr_filter.press_os); press_meas_t = (uint32_t)(BMP3_SETTLE_TIME_PRESS + partial_out * BMP3_ADC_CONV_TIME); /* Output in microseconds */ return press_meas_t; } /*! * @brief This internal API calculates the temperature measurement duration of * the sensor. */ static uint32_t calculate_temp_meas_time(const struct bmp3_settings *settings) { uint32_t temp_meas_t; struct bmp3_odr_filter_settings odr_filter = settings->odr_filter; #ifdef BMP3_FLOAT_COMPENSATION double base = 2.0; float partial_out; #else uint8_t base = 2; uint32_t partial_out; #endif /* BMP3_FLOAT_COMPENSATION */ partial_out = pow_bmp3(base, odr_filter.temp_os); temp_meas_t = (uint32_t)(BMP3_SETTLE_TIME_TEMP + partial_out * BMP3_ADC_CONV_TIME); /* Output in uint32_t */ 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 desired_settings, uint8_t *addr, uint8_t *reg_data, uint8_t *len, const struct bmp3_settings *settings) { struct bmp3_odr_filter_settings osr_settings = settings->odr_filter; if (desired_settings & (BMP3_SEL_PRESS_OS | BMP3_SEL_TEMP_OS)) { /* Pressure over sampling settings check */ if (desired_settings & BMP3_SEL_PRESS_OS) { /* 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 (desired_settings & BMP3_SEL_TEMP_OS) { /* 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_REG_OSR; (*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_settings *settings) { struct bmp3_odr_filter_settings *osr_settings = &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] = BMP3_REG_ODR; (*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_settings *settings) { struct bmp3_odr_filter_settings osr_settings = 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] = BMP3_REG_CONFIG; (*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 and temperature component is selected */ if (sensor_comp == BMP3_PRESS_TEMP) { /* * NOTE : Temperature compensation must be done first. * Followed by pressure compensation * Compensated temperature updated in calib structure, * is needed for pressure calculation */ /* Compensate pressure and temperature data */ rslt = compensate_temperature(&comp_data->temperature, uncomp_data, calib_data); if (rslt == BMP3_OK) { rslt = compensate_pressure(&comp_data->pressure, uncomp_data, calib_data); } } else if (sensor_comp == BMP3_PRESS) { /* * NOTE : Temperature compensation must be done first. * Followed by pressure compensation * Compensated temperature updated in calib structure, * is needed for pressure calculation. * As only pressure is enabled in 'sensor_comp', after calculating * compensated temperature, assign it to zero. */ (void)compensate_temperature(&comp_data->temperature, uncomp_data, calib_data); comp_data->temperature = 0; /* Compensate the pressure data */ rslt = compensate_pressure(&comp_data->pressure, uncomp_data, calib_data); } else if (sensor_comp == BMP3_TEMP) { /* Compensate the temperature data */ rslt = compensate_temperature(&comp_data->temperature, uncomp_data, calib_data); /* * As only temperature is enabled in 'sensor_comp' * make compensated pressure as zero */ comp_data->pressure = 0; } else { comp_data->pressure = 0; comp_data->temperature = 0; } } else { rslt = BMP3_E_NULL_PTR; } return rslt; } #ifdef BMP3_FLOAT_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 */ double 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 = ((double)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 = ((double)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 = ((double)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 = ((double)(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 = ((double)(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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 = ((double)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 double data type. * Returns temperature (deg Celsius) in double. * For e.g. Returns temperature 24.26 deg Celsius */ static int8_t compensate_temperature(double *temperature, const struct bmp3_uncomp_data *uncomp_data, struct bmp3_calib_data *calib_data) { int8_t rslt = BMP3_OK; int64_t uncomp_temp = uncomp_data->temperature; double partial_data1; double partial_data2; partial_data1 = (double)(uncomp_temp - calib_data->quantized_calib_data.par_t1); partial_data2 = (double)(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 */ if (calib_data->quantized_calib_data.t_lin < BMP3_MIN_TEMP_DOUBLE) { calib_data->quantized_calib_data.t_lin = BMP3_MIN_TEMP_DOUBLE; rslt = BMP3_W_MIN_TEMP; } if (calib_data->quantized_calib_data.t_lin > BMP3_MAX_TEMP_DOUBLE) { calib_data->quantized_calib_data.t_lin = BMP3_MAX_TEMP_DOUBLE; rslt = BMP3_W_MAX_TEMP; } (*temperature) = calib_data->quantized_calib_data.t_lin; return rslt; } /*! * @brief This internal API is used to compensate the raw pressure data and * return the compensated pressure data in double data type. * For e.g. returns pressure in Pascal p = 95305.295 */ static int8_t compensate_pressure(double *pressure, const struct bmp3_uncomp_data *uncomp_data, const struct bmp3_calib_data *calib_data) { int8_t rslt = BMP3_OK; const struct bmp3_quantized_calib_data *quantized_calib_data = &calib_data->quantized_calib_data; /* Variable to store the compensated pressure */ double comp_press; /* Temporary variables used for compensation */ double partial_data1; double partial_data2; double partial_data3; double partial_data4; double partial_out1; double partial_out2; partial_data1 = quantized_calib_data->par_p6 * quantized_calib_data->t_lin; partial_data2 = quantized_calib_data->par_p7 * pow_bmp3(quantized_calib_data->t_lin, 2); partial_data3 = quantized_calib_data->par_p8 * pow_bmp3(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 * pow_bmp3(quantized_calib_data->t_lin, 2); partial_data3 = quantized_calib_data->par_p4 * pow_bmp3(quantized_calib_data->t_lin, 3); partial_out2 = uncomp_data->pressure * (quantized_calib_data->par_p1 + partial_data1 + partial_data2 + partial_data3); partial_data1 = pow_bmp3((double)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 + pow_bmp3((double)uncomp_data->pressure, 3) * quantized_calib_data->par_p11; comp_press = partial_out1 + partial_out2 + partial_data4; if (comp_press < BMP3_MIN_PRES_DOUBLE) { comp_press = BMP3_MIN_PRES_DOUBLE; rslt = BMP3_W_MIN_PRES; } if (comp_press > BMP3_MAX_PRES_DOUBLE) { comp_press = BMP3_MAX_PRES_DOUBLE; rslt = BMP3_W_MAX_PRES; } (*pressure) = comp_press; return rslt; } /*! * @brief This internal API is used to calculate the power functionality for * floating point values. */ static float pow_bmp3(double base, uint8_t power) { float pow_output = 1; while (power != 0) { pow_output = (float) 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. * Returns temperature in integer. Actual temperature is obtained by dividing by 100 * For eg : If returned temperature is 2426 then it is 2426/100 = 24 deg Celsius */ static int8_t compensate_temperature(int64_t *temperature, const struct bmp3_uncomp_data *uncomp_data, struct bmp3_calib_data *calib_data) { int8_t rslt = BMP3_OK; 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 comp_temp; partial_data1 = (int64_t)(uncomp_data->temperature - ((int64_t)256 * calib_data->reg_calib_data.par_t1)); partial_data2 = (int64_t)(calib_data->reg_calib_data.par_t2 * partial_data1); partial_data3 = (int64_t)(partial_data1 * partial_data1); partial_data4 = (int64_t)partial_data3 * calib_data->reg_calib_data.par_t3; partial_data5 = (int64_t)((int64_t)(partial_data2 * 262144) + partial_data4); partial_data6 = (int64_t)(partial_data5 / 4294967296); /* Store t_lin in dev. structure for pressure calculation */ calib_data->reg_calib_data.t_lin = (int64_t)partial_data6; comp_temp = (int64_t)((partial_data6 * 25) / 16384); if (comp_temp < BMP3_MIN_TEMP_INT) { comp_temp = BMP3_MIN_TEMP_INT; rslt = BMP3_W_MIN_TEMP; } if (comp_temp > BMP3_MAX_TEMP_INT) { comp_temp = BMP3_MAX_TEMP_INT; rslt = BMP3_W_MAX_TEMP; } (*temperature) = comp_temp; return rslt; } /*! * @brief This internal API is used to compensate the raw pressure data and * return the compensated pressure data in integer data type. * for eg return if pressure is 9528709 which is 9528709/100 = 95287.09 Pascal */ static int8_t compensate_pressure(uint64_t *pressure, const struct bmp3_uncomp_data *uncomp_data, const struct bmp3_calib_data *calib_data) { int8_t rslt = BMP3_OK; 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 = (int64_t)(reg_calib_data->t_lin * reg_calib_data->t_lin); partial_data2 = (int64_t)(partial_data1 / 64); partial_data3 = (int64_t)((partial_data2 * reg_calib_data->t_lin) / 256); partial_data4 = (int64_t)((reg_calib_data->par_p8 * partial_data3) / 32); partial_data5 = (int64_t)((reg_calib_data->par_p7 * partial_data1) * 16); partial_data6 = (int64_t)((reg_calib_data->par_p6 * reg_calib_data->t_lin) * 4194304); offset = (int64_t)((reg_calib_data->par_p5 * 140737488355328) + partial_data4 + partial_data5 + partial_data6); partial_data2 = (int64_t)((reg_calib_data->par_p4 * partial_data3) / 32); partial_data4 = (int64_t)((reg_calib_data->par_p3 * partial_data1) * 4); partial_data5 = (int64_t)((reg_calib_data->par_p2 - (int32_t)16384) * reg_calib_data->t_lin * 2097152); sensitivity = (int64_t)(((reg_calib_data->par_p1 - (int32_t)16384) * 70368744177664) + partial_data2 + partial_data4 + partial_data5); partial_data1 = (int64_t)((sensitivity / 16777216) * uncomp_data->pressure); partial_data2 = (int64_t)(reg_calib_data->par_p10 * reg_calib_data->t_lin); partial_data3 = (int64_t)(partial_data2 + ((int32_t)65536 * reg_calib_data->par_p9)); partial_data4 = (int64_t)((partial_data3 * uncomp_data->pressure) / (int32_t)8192); /* dividing by 10 followed by multiplying by 10 * To avoid overflow caused by (uncomp_data->pressure * partial_data4) */ partial_data5 = (int64_t)((uncomp_data->pressure * (partial_data4 / 10)) / (int32_t)512); partial_data5 = (int64_t)(partial_data5 * 10); partial_data6 = (int64_t)(uncomp_data->pressure * uncomp_data->pressure); partial_data2 = (int64_t)((reg_calib_data->par_p11 * partial_data6) / (int32_t)65536); partial_data3 = (int64_t)((int64_t)(partial_data2 * uncomp_data->pressure) / 128); partial_data4 = (int64_t)((offset / 4) + partial_data1 + partial_data5 + partial_data3); comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776); if (comp_press < BMP3_MIN_PRES_INT) { comp_press = BMP3_MIN_PRES_INT; rslt = BMP3_W_MIN_PRES; } if (comp_press > BMP3_MAX_PRES_INT) { comp_press = BMP3_MAX_PRES_INT; rslt = BMP3_W_MAX_PRES; } (*pressure) = comp_press; return rslt; } /*! * @brief This internal API is used to calculate the power functionality. */ static uint32_t pow_bmp3(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_us == NULL) || (dev->intf_ptr == 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 *fifo_settings) { 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 */ fifo_settings->mode = BMP3_GET_BITS_POS_0(fifo_config_1_data, BMP3_FIFO_MODE); fifo_settings->stop_on_full_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_STOP_ON_FULL); fifo_settings->time_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_TIME_EN); fifo_settings->press_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_PRESS_EN); fifo_settings->temp_en = BMP3_GET_BITS(fifo_config_1_data, BMP3_FIFO_TEMP_EN); /* Parse fifo config 2 register data */ fifo_settings->down_sampling = BMP3_GET_BITS_POS_0(fifo_config_2_data, BMP3_FIFO_DOWN_SAMPLING); fifo_settings->filter_en = BMP3_GET_BITS(fifo_config_2_data, BMP3_FIFO_FILTER_EN); /* Parse fifo related interrupt control data */ fifo_settings->ffull_en = BMP3_GET_BITS(fifo_int_ctrl_data, BMP3_FIFO_FULL_EN); fifo_settings->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 int8_t fill_fifo_config_1(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_FIFO_CONFIG_1; uint8_t reg_data; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { if (desired_settings & BMP3_SEL_FIFO_MODE) { /* Fill the FIFO mode register data */ reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_FIFO_MODE, fifo_settings->mode); } if (desired_settings & BMP3_SEL_FIFO_STOP_ON_FULL_EN) { /* Fill the stop on full data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_STOP_ON_FULL, fifo_settings->stop_on_full_en); } if (desired_settings & BMP3_SEL_FIFO_TIME_EN) { /* Fill the time enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_TIME_EN, fifo_settings->time_en); } if (desired_settings & (BMP3_SEL_FIFO_PRESS_EN | BMP3_SEL_FIFO_TEMP_EN)) { /* Fill the pressure enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_PRESS_EN, fifo_settings->press_en); /* Fill the temperature enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_TEMP_EN, fifo_settings->temp_en); } /* Write the power control settings in the register */ rslt = bmp3_set_regs(®_addr, ®_data, 1, dev); } return rslt; } /*! * @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 int8_t fill_fifo_config_2(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_FIFO_CONFIG_2; uint8_t reg_data; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { if (desired_settings & BMP3_SEL_FIFO_DOWN_SAMPLING) { /* To do check Normal mode */ /* Fill the down-sampling data */ reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_FIFO_DOWN_SAMPLING, fifo_settings->down_sampling); } if (desired_settings & BMP3_SEL_FIFO_FILTER_EN) { /* Fill the filter enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_FILTER_EN, fifo_settings->filter_en); } /* Write the power control settings in the register */ rslt = bmp3_set_regs(®_addr, ®_data, 1, dev); } return rslt; } /*! * @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 int8_t fill_fifo_int_ctrl(uint16_t desired_settings, const struct bmp3_fifo_settings *fifo_settings, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr = BMP3_REG_INT_CTRL; uint8_t reg_data; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { if (desired_settings & BMP3_SEL_FIFO_FWTM_EN) { /* Fill the FIFO watermark interrupt enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_FWTM_EN, fifo_settings->fwtm_en); } if (desired_settings & BMP3_SEL_FIFO_FULL_EN) { /* Fill the FIFO full interrupt enable data */ reg_data = BMP3_SET_BITS(reg_data, BMP3_FIFO_FULL_EN, fifo_settings->ffull_en); } /* Write the power control settings in the register */ rslt = bmp3_set_regs(®_addr, ®_data, 1, dev); } return rslt; } /*! * @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_status *status, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_addr; uint8_t reg_data; reg_addr = BMP3_REG_SENS_STATUS; rslt = bmp3_get_regs(reg_addr, ®_data, 1, dev); if (rslt == BMP3_OK) { status->sensor.cmd_rdy = BMP3_GET_BITS(reg_data, BMP3_STATUS_CMD_RDY); status->sensor.drdy_press = BMP3_GET_BITS(reg_data, BMP3_STATUS_DRDY_PRESS); status->sensor.drdy_temp = BMP3_GET_BITS(reg_data, BMP3_STATUS_DRDY_TEMP); reg_addr = BMP3_REG_EVENT; rslt = bmp3_get_regs(reg_addr, ®_data, 1, 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_status *status, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data; rslt = bmp3_get_regs(BMP3_REG_INT_STATUS, ®_data, 1, dev); if (rslt == BMP3_OK) { status->intr.fifo_wm = BMP3_GET_BITS_POS_0(reg_data, BMP3_INT_STATUS_FWTM); status->intr.fifo_full = BMP3_GET_BITS(reg_data, BMP3_INT_STATUS_FFULL); 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_status *status, struct bmp3_dev *dev) { int8_t rslt; uint8_t reg_data; rslt = bmp3_get_regs(BMP3_REG_ERR, ®_data, 1, dev); if (rslt == BMP3_OK) { status->err.fatal = BMP3_GET_BITS_POS_0(reg_data, BMP3_ERR_FATAL); status->err.cmd = BMP3_GET_BITS(reg_data, BMP3_ERR_CMD); status->err.conf = BMP3_GET_BITS(reg_data, BMP3_ERR_CONF); } return rslt; }