STM32 I2C Library for BMP581 Pressure Sensor

STM32 I2C Library for BMP581 Pressure Sensor

Please read Liability Disclaimer and License Agreement CAREFULLY

Before going further please read BMP581 datasheet

In BMP581.h add the following code

#ifndef __BMP581_H
#define __BMP581_H

#ifdef __cplusplus
extern "C" {
#endif

#include "i2c.h"

// ((int32_t)0X7F << 16) | ((int32_t)0X7F << 8) | 0X7F;
#define CHECK_EMPTY 8355711

#define BMP581_GET_BITSLICE(regvar, bitname)						((regvar & bitname##_MSK) >> bitname##_POS)
#define BMP581_SET_BITSLICE(regvar, bitname, val)				((regvar & ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK))

#define BMP581_GET_LSB(var)															(uint8_t)(var & BMP581_SET_LOW_BYTE)
#define BMP581_GET_MSB(var)															(uint8_t)((var & BMP581_SET_HIGH_BYTE) >> 8)

#define BMP581_SET_BIT_VAL_0(reg_data, bitname)					(reg_data & ~(bitname##_MSK))
#define BMP581_SET_BITS_POS_0(reg_data, bitname, data)	((reg_data & ~(bitname##_MSK)) | (data & bitname##_MSK))
#define BMP581_GET_BITS_POS_0(reg_data, bitname)				(reg_data & (bitname##_MSK))

// Define constants
#define ZERO	0
#define ONE		1
#define TWO		2
#define THREE	3
#define FOUR	4
#define FIVE	5
#define SIX		6
#define TEMP_COEFF		65536.0f
#define PRESS_COEFF		64.0f

#define BMP581_RESPONCE_TIME											100
#define BMP581_ADDRESS														0x8C//0x46

// Chip id of BMP5
#define BMP581_CHIP_ID_PRIM                         0x50
#define BMP581_CHIP_ID_SEC                          0x51

#define BMP581_ENABLE                               1
#define BMP581_DISABLE                              0

// Register addresses
#define BMP581_REG_CHIP_ID                          0x01
#define BMP581_REG_REV_ID                           0x02
#define BMP581_REG_CHIP_STATUS                      0x11
#define BMP581_REG_DRIVE_CONFIG                     0x13
#define BMP581_REG_INT_CONFIG                       0x14
#define BMP581_REG_INT_SOURCE                       0x15
#define BMP581_REG_FIFO_CONFIG                      0x16
#define BMP581_REG_FIFO_COUNT                       0x17
#define BMP581_REG_FIFO_SEL                         0x18
#define BMP581_REG_TEMP_DATA_XLSB                   0x1D
#define BMP581_REG_TEMP_DATA_LSB                    0x1E
#define BMP581_REG_TEMP_DATA_MSB                    0x1F
#define BMP581_REG_PRESS_DATA_XLSB                  0x20
#define BMP581_REG_PRESS_DATA_LSB                   0x21
#define BMP581_REG_PRESS_DATA_MSB                   0x22
#define BMP581_REG_INT_STATUS                       0x27
#define BMP581_REG_STATUS                           0x28
#define BMP581_REG_FIFO_DATA                        0x29
#define BMP581_REG_NVM_ADDR                         0x2B
#define BMP581_REG_NVM_DATA_LSB                     0x2C
#define BMP581_REG_NVM_DATA_MSB                     0x2D
#define BMP581_REG_DSP_CONFIG                       0x30
#define BMP581_REG_DSP_IIR                          0x31
#define BMP581_REG_OOR_THR_P_LSB                    0x32
#define BMP581_REG_OOR_THR_P_MSB                    0x33
#define BMP581_REG_OOR_RANGE                        0x34
#define BMP581_REG_OOR_CONFIG                       0x35
#define BMP581_REG_OSR_CONFIG                       0x36
#define BMP581_REG_ODR_CONFIG                       0x37
#define BMP581_REG_OSR_EFF                          0x38
#define BMP581_REG_CMD                              0x7E

// I2C addresses
#define BMP581_I2C_ADDR_PRIM                        0x46
#define BMP581_I2C_ADDR_SEC                         0x47

// NVM addresses
#define BMP581_NVM_START_ADDR                       0x20
#define BMP581_NVM_END_ADDR                         0x22

// Interface settings
#define BMP581_SPI_RD_MASK                          0x80

// Delay definition
#define BMP581_DELAY_US_SOFT_RESET                  2000
#define BMP581_DELAY_US_STANDBY                     2500
#define BMP581_DELAY_US_NVM_READY_READ              800
#define BMP581_DELAY_US_NVM_READY_WRITE             10000

// Soft reset command
#define BMP581_SOFT_RESET_CMD                       0xB6

// NVM command
#define BMP581_NVM_FIRST_CMND                       0x5D
#define BMP581_NVM_READ_ENABLE_CMND                 0xA5
#define BMP581_NVM_WRITE_ENABLE_CMND                0xA0

// Deepstandby enable/disable
#define BMP581_DEEP_ENABLED                         0
#define BMP581_DEEP_DISABLED                        1

// ODR settings
#define BMP581_ODR_240_HZ                           0x00
#define BMP581_ODR_218_5_HZ                         0x01
#define BMP581_ODR_199_1_HZ                         0x02
#define BMP581_ODR_179_2_HZ                         0x03
#define BMP581_ODR_160_HZ                           0x04
#define BMP581_ODR_149_3_HZ                         0x05
#define BMP581_ODR_140_HZ                           0x06
#define BMP581_ODR_129_8_HZ                         0x07
#define BMP581_ODR_120_HZ                           0x08
#define BMP581_ODR_110_1_HZ                         0x09
#define BMP581_ODR_100_2_HZ                         0x0A
#define BMP581_ODR_89_6_HZ                          0x0B
#define BMP581_ODR_80_HZ                            0x0C
#define BMP581_ODR_70_HZ                            0x0D
#define BMP581_ODR_60_HZ                            0x0E
#define BMP581_ODR_50_HZ                            0x0F
#define BMP581_ODR_45_HZ                            0x10
#define BMP581_ODR_40_HZ                            0x11
#define BMP581_ODR_35_HZ                            0x12
#define BMP581_ODR_30_HZ                            0x13
#define BMP581_ODR_25_HZ                            0x14
#define BMP581_ODR_20_HZ                            0x15
#define BMP581_ODR_15_HZ                            0x16
#define BMP581_ODR_10_HZ                            0x17
#define BMP581_ODR_05_HZ                            0x18
#define BMP581_ODR_04_HZ                            0x19
#define BMP581_ODR_03_HZ                            0x1A
#define BMP581_ODR_02_HZ                            0x1B
#define BMP581_ODR_01_HZ                            0x1C
#define BMP581_ODR_0_5_HZ                           0x1D
#define BMP581_ODR_0_250_HZ                         0x1E
#define BMP581_ODR_0_125_HZ                         0x1F

// Oversampling for temperature and pressure
#define BMP581_OVERSAMPLING_1X                      0x00
#define BMP581_OVERSAMPLING_2X                      0x01
#define BMP581_OVERSAMPLING_4X                      0x02
#define BMP581_OVERSAMPLING_8X                      0x03
#define BMP581_OVERSAMPLING_16X                     0x04
#define BMP581_OVERSAMPLING_32X                     0x05
#define BMP581_OVERSAMPLING_64X                     0x06
#define BMP581_OVERSAMPLING_128X                    0x07

// IIR filter for temperature and pressure
#define BMP581_IIR_FILTER_BYPASS                    0x00
#define BMP581_IIR_FILTER_COEFF_1                   0x01
#define BMP581_IIR_FILTER_COEFF_3                   0x02
#define BMP581_IIR_FILTER_COEFF_7                   0x03
#define BMP581_IIR_FILTER_COEFF_15                  0x04
#define BMP581_IIR_FILTER_COEFF_31                  0x05
#define BMP581_IIR_FILTER_COEFF_63                  0x06
#define BMP581_IIR_FILTER_COEFF_127                 0x07

// Fifo frame configuration
#define BMP581_FIFO_EMPTY                           0X7F
#define BMP581_FIFO_MAX_THRESHOLD_P_T_MODE          0x0F
#define BMP581_FIFO_MAX_THRESHOLD_P_MODE            0x1F

// Macro is used to bypass both iir_t and iir_p together
#define BMP581_IIR_BYPASS                           0xC0

// Pressure Out-of-range count limit
#define BMP581_OOR_COUNT_LIMIT_1                    0x00
#define BMP581_OOR_COUNT_LIMIT_3                    0x01
#define BMP581_OOR_COUNT_LIMIT_7                    0x02
#define BMP581_OOR_COUNT_LIMIT_15                   0x03

// Interrupt configurations
#define BMP581_INT_MODE_PULSED                      0
#define BMP581_INT_MODE_LATCHED                     1

#define BMP581_INT_POL_ACTIVE_LOW                   0
#define BMP581_INT_POL_ACTIVE_HIGH                  1

#define BMP581_INT_OD_PUSHPULL                      0
#define BMP581_INT_OD_OPENDRAIN                     1

// NVM and Interrupt status asserted macros
#define BMP581_INT_ASSERTED_DRDY                    0x01
#define BMP581_INT_ASSERTED_FIFO_FULL               0x02
#define BMP581_INT_ASSERTED_FIFO_THRES              0x04
#define BMP581_INT_ASSERTED_PRESSURE_OOR            0x08
#define BMP581_INT_ASSERTED_POR_SOFTRESET_COMPLETE  0x10
#define BMP581_INT_NVM_RDY                          0x02
#define BMP581_INT_NVM_ERR                          0x04
#define BMP581_INT_NVM_CMD_ERR                      0x08

// Interrupt configurations
#define BMP581_INT_MODE_MSK                         0x01

#define BMP581_INT_POL_MSK                          0x02
#define BMP581_INT_POL_POS                          1

#define BMP581_INT_OD_MSK                           0x04
#define BMP581_INT_OD_POS                           2

#define BMP581_INT_EN_MSK                           0x08
#define BMP581_INT_EN_POS                           3

#define BMP581_INT_DRDY_EN_MSK                      0x01

#define BMP581_INT_FIFO_FULL_EN_MSK                 0x02
#define BMP581_INT_FIFO_FULL_EN_POS                 1

#define BMP581_INT_FIFO_THRES_EN_MSK                0x04
#define BMP581_INT_FIFO_THRES_EN_POS                2

#define BMP581_INT_OOR_PRESS_EN_MSK                 0x08
#define BMP581_INT_OOR_PRESS_EN_POS                 3

// ODR configuration
#define BMP581_ODR_MSK                              0x7C
#define BMP581_ODR_POS                              2

// OSR configurations
#define BMP581_TEMP_OS_MSK                          0x07

#define BMP581_PRESS_OS_MSK                         0x38
#define BMP581_PRESS_OS_POS                         3

// Pressure enable
#define BMP581_PRESS_EN_MSK                         0x40
#define BMP581_PRESS_EN_POS                         6

// IIR configurations
#define BMP581_SET_IIR_TEMP_MSK                     0x07

#define BMP581_SET_IIR_PRESS_MSK                    0x38
#define BMP581_SET_IIR_PRESS_POS                    3

#define BMP581_OOR_SEL_IIR_PRESS_MSK                0x80
#define BMP581_OOR_SEL_IIR_PRESS_POS                7

#define BMP581_SHDW_SET_IIR_TEMP_MSK                0x08
#define BMP581_SHDW_SET_IIR_TEMP_POS                3

#define BMP581_SHDW_SET_IIR_PRESS_MSK               0x20
#define BMP581_SHDW_SET_IIR_PRESS_POS               5

#define BMP581_SET_FIFO_IIR_TEMP_MSK                0x10
#define BMP581_SET_FIFO_IIR_TEMP_POS                4

#define BMP581_SET_FIFO_IIR_PRESS_MSK               0x40
#define BMP581_SET_FIFO_IIR_PRESS_POS               6

#define BMP581_IIR_FLUSH_FORCED_EN_MSK              0x04
#define BMP581_IIR_FLUSH_FORCED_EN_POS              2

// Effective OSR configurations and ODR valid status
#define BMP581_OSR_TEMP_EFF_MSK                     0x07

#define BMP581_OSR_PRESS_EFF_MSK                    0x38
#define BMP581_OSR_PRESS_EFF_POS                    3

#define BMP581_ODR_IS_VALID_MSK                     0x80
#define BMP581_ODR_IS_VALID_POS                     7

// Powermode
#define BMP581_POWERMODE_MSK                        0x03

#define BMP581_DEEP_DISABLE_MSK                     0x80
#define BMP581_DEEP_DISABLE_POS                     7

// Fifo configurations
#define BMP581_FIFO_THRESHOLD_MSK                   0x1F

#define BMP581_FIFO_MODE_MSK                        0x20
#define BMP581_FIFO_MODE_POS                        5

#define BMP581_FIFO_DEC_SEL_MSK                     0x1C
#define BMP581_FIFO_DEC_SEL_POS                     2

#define BMP581_FIFO_COUNT_MSK                       0x3F

#define BMP581_FIFO_FRAME_SEL_MSK                   0x03

// Out-of-range configuration
#define BMP581_OOR_THR_P_LSB_MSK                    0x0000FF

#define BMP581_OOR_THR_P_MSB_MSK                    0x00FF00

#define BMP581_OOR_THR_P_XMSB_MSK                   0x010000
#define BMP581_OOR_THR_P_XMSB_POS                   16

// Macro to mask xmsb value of oor threshold from register(0x35) value
#define BMP581_OOR_THR_P_XMSB_REG_MSK               0x01

#define BMP581_OOR_COUNT_LIMIT_MSK                  0xC0
#define BMP581_OOR_COUNT_LIMIT_POS                  6

// NVM configuration
#define BMP581_NVM_ADDR_MSK                         0x3F

#define BMP581_NVM_PROG_EN_MSK                      0x40
#define BMP581_NVM_PROG_EN_POS                      6

#define BMP581_NVM_DATA_LSB_MSK                     0x00FF

#define BMP581_NVM_DATA_MSB_MSK                     0xFF00

// Enumerator for interrupt enable disable
enum BMP581_intr_en_dis {
    // Interrupt diable
    BMP581_INTR_DISABLE = BMP581_DISABLE,
    // Interrupt enable
    BMP581_INTR_ENABLE = BMP581_ENABLE
};

// Enumerator for interrupt mode
enum BMP581_intr_mode {
    // Interrupt mode - pulsed
    BMP581_PULSED = BMP581_INT_MODE_PULSED,
    // Interrupt mode - latched
    BMP581_LATCHED = BMP581_INT_MODE_LATCHED
};

// Enumerator for interrupt polarity
enum BMP581_intr_polarity {
    // Interrupt polarity - active low
    BMP581_ACTIVE_LOW = BMP581_INT_POL_ACTIVE_LOW,
    // Interrupt polarity - active high
    BMP581_ACTIVE_HIGH = BMP581_INT_POL_ACTIVE_HIGH
};

// Enumerator for interrupt drive
enum BMP581_intr_drive {
    // Interrupt drive - push-pull
    BMP581_INTR_PUSH_PULL = BMP581_INT_OD_PUSHPULL,
    // Interrupt drive - open drain
    BMP581_INTR_OPEN_DRAIN = BMP581_INT_OD_OPENDRAIN
};

enum BMP581_fifo_frame_sel {
    // Fifo disabled 
    BMP581_FIFO_NOT_ENABLED,
    // Fifo temperature data only enabled
    BMP581_FIFO_TEMPERATURE_DATA,
    // Fifo pressure data only enabled
    BMP581_FIFO_PRESSURE_DATA,
    // Fifo pressure and temperature data enabled
    BMP581_FIFO_PRESS_TEMP_DATA
};

// Enumerator for fifo decimation factor(downsampling) selection
enum BMP581_fifo_dec_sel {
    BMP581_FIFO_NO_DOWNSAMPLING, //Fifo downsampling disabled
    BMP581_FIFO_DOWNSAMPLING_2X,
    BMP581_FIFO_DOWNSAMPLING_4X,
    BMP581_FIFO_DOWNSAMPLING_8X,
    BMP581_FIFO_DOWNSAMPLING_16X,
    BMP581_FIFO_DOWNSAMPLING_32X,
    BMP581_FIFO_DOWNSAMPLING_64X,
    BMP581_FIFO_DOWNSAMPLING_128X
};

// Enumerator for fifo mode selection
enum BMP581_fifo_mode {
    BMP581_FIFO_MODE_STREAMING,
    BMP581_FIFO_MODE_STOP_ON_FULL
};

// Enumerator for powermode selection
enum BMP581_powermode {
    // Standby powermode
    BMP581_POWERMODE_STANDBY,
    // Normal powermode
    BMP581_POWERMODE_NORMAL,
    // Forced powermode
    BMP581_POWERMODE_FORCED,
    // Continous powermode
    BMP581_POWERMODE_CONTINOUS,
    // Deep standby powermode
    BMP581_POWERMODE_DEEP_STANDBY
};

typedef struct BMP581_osr_odr_eff {
	// Effective temperature OSR
	uint8_t osr_t_eff;
	// Effective pressure OSR
	uint8_t osr_p_eff;
	// If asserted, the ODR parametrization is valid
	uint8_t odr_is_valid;
} BMP581_osr_odr_eff_t;

typedef struct BMP581_oor_press_configuration {
	uint32_t oor_thr_p;
	uint8_t oor_range_p;
	uint8_t cnt_lim;
	uint8_t oor_sel_iir_p;
} BMP581_oor_press_configuration_t;

// SR, ODR and pressure configuration structure
typedef struct BMP581_osr_odr_press_config {
    uint8_t osr_t;		// BMP581_OVERSAMPLING_1X, 2, 4, 8, 16, 32, 64, 128X
    uint8_t osr_p;		// BMP581_OVERSAMPLING_1X, 2, 4, 8, 16, 32, 64, 128X
    uint8_t press_en; // BMP581_ENABLE, BMP581_ENABLE
    uint8_t odr;			// Output Data Rate
} BMP581_osr_odr_press_config_t;

typedef struct BMP581_fifo {
    uint8_t *data;					// Pointer to fifo data
    uint16_t length;				// Length of user defined bytes of fifo to be read
    uint8_t frame_sel;			// BMP581_FIFO_NOT_ENABLED, BMP581_FIFO_TEMPERATURE_DATA, BMP581_FIFO_PRESSURE_DATA, BMP581_FIFO_PRESS_TEMP_DATA
    uint8_t dec_sel;				// BMP581_FIFO_NO_DOWNSAMPLING, 2X, 4X, 8X, 16X, 32X, 64X, 128X
    uint8_t fifo_count;			// Fifo frame count
    uint8_t mode;						// BMP581_FIFO_MODE_STREAMING, BMP581_FIFO_MODE_STOP_ON_FULL
    uint8_t threshold;			// Threshold for fifo
    uint8_t set_fifo_iir_t; //Fifo temperature IIR BMP581_ENABLE, BMP581_DISABLE
    uint8_t set_fifo_iir_p; // Fifo pressure IIR BMP581_ENABLE, BMP581_DISABLE
} BMP581_fifo_t;

// IIR configuration structure
typedef struct BMP581_iir_config {
    uint8_t set_iir_t;						// IIR configuration structure BMP581_IIR_FILTER_BYPASS...BMP581_IIR_FILTER_0_00220
    uint8_t set_iir_p;						// Pressure IIR BMP581_IIR_FILTER_BYPASS...BMP581_IIR_FILTER_0_00220
    uint8_t shdw_set_iir_t;				// Shadow IIR selection for temperature BMP581_ENABLE, BMP581_DISABLE
    uint8_t shdw_set_iir_p;				// Shadow IIR selection for pressure BMP581_ENABLE, BMP581_DISABLE
    uint8_t iir_flush_forced_en;	// IIR flush in forced mode enable BMP581_ENABLE, BMP581_DISABLE
}BMP581_iir_config_t;

// BMP5 interrupt source selection.
typedef struct BMP581_int_source_select {
	uint8_t drdy_en;				// Data ready interrupt enable
	uint8_t fifo_full_en;		// Fifo full interrupt enable
	uint8_t fifo_thres_en;	// Fifo threshold interrupt enable
	uint8_t oor_press_en;		// Pressure out of range interrupt enable
}BMP581_int_source_select_t;

// BMP5 sensor data structure which comprises of temperature and pressure.
// BMP5 sensor data structure which comprises of temperature and pressure in floating point with data type as float for pressure and temperature.
typedef	struct BMP581_sensor_data {
	//Pressure data
	float pressure;
	//Temperature data
	float temperature;
} BMP581_sensor_data_t;

// Used to get the interrupt status (data ready interrupt, fifo full interrupt, fifo threshold interrupt, pressure out of range interrupt and power-on reset/software reset complete interrupt).
HAL_StatusTypeDef BMP581_getInterruptStatus(uint8_t *int_status);
// Used to soft-reset the sensor where all the registers are reset to their default values.
HAL_StatusTypeDef BMP581_SoftReset(void);
// Call this API before using all other APIs
HAL_StatusTypeDef BMP581_Init(void);

HAL_StatusTypeDef BMP581_setHighAccuracy(void);
// Reads the temperature(deg C) and pressure(Pa) data from the sensor and store it in the BMP581_sensor_data_t structure instance passed by the user.
HAL_StatusTypeDef BMP581_getSensorData(BMP581_sensor_data_t *sensor_data);

// Gets the power mode of the sensor
HAL_StatusTypeDef BMP581_getPowerMode(enum BMP581_powermode *powermode);
// Sets the power mode of the sensor
HAL_StatusTypeDef BMP581_setPowerMode(enum BMP581_powermode powermode);

// Gets the configuration for IIR of temperature and pressure
HAL_StatusTypeDef BMP581_getIirConfig(BMP581_iir_config_t *iir_cfg);
// Sets the configuration for IIR of temperature and pressure
HAL_StatusTypeDef BMP581_setIirConfig(const BMP581_iir_config_t *iir_cfg);

// Gets the configuration for oversampling of temperature, oversampling of pressure and ODR configuration along with pressure enable.
HAL_StatusTypeDef BMP581_getOsrOdrPressConfig(BMP581_osr_odr_press_config_t *osr_odr_press_cfg);
// Sets the configuration for oversampling of temperature, oversampling of pressure and ODR configuration along with pressure enable.
HAL_StatusTypeDef BMP581_setOsrOdrPressConfig(const BMP581_osr_odr_press_config_t *osr_odr_press_cfg);

// Used to enable the interrupts(drdy interrupt, fifo full interrupt, fifo threshold enable and pressure data out of range interrupt).
HAL_StatusTypeDef BMP581_InterruptSourceSelect(const BMP581_int_source_select_t *int_source_select);
// Used to configure the interrupt settings
HAL_StatusTypeDef BMP581_ConfigureInterrupt(enum BMP581_intr_mode int_mode, enum BMP581_intr_polarity int_pol, enum BMP581_intr_drive int_od, enum BMP581_intr_en_dis int_en);

// Gets the configuration for effective OSR of temperature, effective OSR of pressure and ODR valid status
HAL_StatusTypeDef BMP581_getOsrOdrEffective(BMP581_osr_odr_eff_t *osr_odr_eff);

// Used to get the configurations of fifo in the sensor
HAL_StatusTypeDef BMP581_getFifoConfiguration(BMP581_fifo_t *fifo);
// Used to set the configurations of fifo in the sensor
HAL_StatusTypeDef BMP581_set_FifoConfiguration(const BMP581_fifo_t *fifo);
// Used to get the length of fifo from the sensor
HAL_StatusTypeDef BMP581_getFifoLength(uint16_t *fifo_len, BMP581_fifo_t *fifo);
// Used to get the fifo data from the sensor
HAL_StatusTypeDef BMP581_get_FifoData(BMP581_fifo_t *fifo);
// Extract the temperature and/or pressure data from the fifo data which is already read from the fifo.
HAL_StatusTypeDef BMP581_ExtractFifoData(const BMP581_fifo_t *fifo, BMP581_sensor_data_t *sensor_data);

// Gets the configuration for out-of-range pressure threshold, range count limit and IIR
HAL_StatusTypeDef BMP581_getOorConfiguration(BMP581_oor_press_configuration_t *oor_press_config);
// Sets the configuration for out-of-range pressure threshold, range count limit and IIR
HAL_StatusTypeDef BMP581_set_OorConfiguration(const BMP581_oor_press_configuration_t *oor_press_config);
// Used to perform NVM read
HAL_StatusTypeDef BMP581_NvmRead(uint8_t nvm_addr, uint16_t *nvm_data);
// Used to perform NVM write
HAL_StatusTypeDef BMP581_NvmWrite(uint8_t nvm_addr, const uint16_t *nvm_data);

#ifdef __cplusplus
}
#endif

#endif /* __BMP581_H */

In BMP581.c add the following code

#include "BMP581.h"
#include "i2c.h"
#include "gpio.h"

// Place to store OSR/ODR config values
BMP581_osr_odr_press_config_t osrOdrConfig;

// Place to store FIFO config values
BMP581_fifo_t fifo;
BMP581_int_source_select_t interruptSource;
BMP581_iir_config_t iirConfig;
BMP581_osr_odr_eff_t eff;

static inline int32_t get_32bit(const uint8_t *data_ptr) {
    return ((int32_t)data_ptr[2] << 16) | ((int32_t)data_ptr[1] << 8) | data_ptr[0];
}

// I2C write function
static HAL_StatusTypeDef write(const uint8_t regAddress, const uint8_t* dataBuffer, uint8_t numBytes) {
	return HAL_I2C_Mem_Write(&hi2c1, BMP581_ADDRESS, regAddress, ONE, (uint8_t *)dataBuffer, numBytes, BMP581_RESPONCE_TIME);
}

// I2C read function
static HAL_StatusTypeDef read(const uint8_t regAddress, uint8_t* dataBuffer, const uint8_t numBytes) {
	return HAL_I2C_Mem_Read(&hi2c1, BMP581_ADDRESS, regAddress, ONE, dataBuffer, numBytes, BMP581_RESPONCE_TIME);
}

// Power-up check. The reset check is done in the init function
static HAL_StatusTypeDef power_up_check(void) {
	uint8_t nvm_status;
	if(read(BMP581_REG_STATUS, &nvm_status, ONE) == HAL_OK) {
		// Check if nvm_rdy status = 1 and nvm_err status = 0 to proceed
		if((nvm_status & BMP581_INT_NVM_RDY) && (!(nvm_status & BMP581_INT_NVM_ERR))) {
			return HAL_OK;
//			uint8_t por_status;
//			if(BMP581_getInterruptStatus(&por_status) == HAL_OK) {
//				// Check if por/soft-reset complete status = 1 to proceed
//        if(por_status & BMP581_INT_ASSERTED_POR_SOFTRESET_COMPLETE) {
//					return HAL_OK;
//				}
//			}
		}
	}
	return HAL_ERROR;
}

// Set power mode
static HAL_StatusTypeDef set_power_mode(const enum BMP581_powermode powermode) {
	uint8_t reg_data;
	if(read(BMP581_REG_ODR_CONFIG, &reg_data, ONE) == HAL_OK) {
		// Setting deep_dis = 1(BMP581_DEEP_DISABLED) disables the deep standby mode
		reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_DEEP_DISABLE, BMP581_DEEP_DISABLED);
		reg_data = BMP581_SET_BITS_POS_0(reg_data, BMP581_POWERMODE, powermode);
		return write(BMP581_REG_ODR_CONFIG, &reg_data, ONE);
	}
	return HAL_ERROR;
}

// Check deep standby mode
static HAL_StatusTypeDef check_deepstandby_mode(enum BMP581_powermode *powermode) {
	uint8_t fifo_frame_sel;
	BMP581_iir_config_t iir_cfg = {0};
	BMP581_osr_odr_press_config_t osr_odr_press_cfg = {0};
	HAL_StatusTypeDef result = read(BMP581_REG_FIFO_SEL, &fifo_frame_sel, ONE);
	fifo_frame_sel = BMP581_GET_BITS_POS_0(fifo_frame_sel, BMP581_FIFO_FRAME_SEL);
	if(result == HAL_OK) {
		result = BMP581_getOsrOdrPressConfig(&osr_odr_press_cfg);
		if(result == HAL_OK) {
			result = BMP581_getIirConfig(&iir_cfg);
		}
	}
	// As per datasheet odr should be less than 5Hz. But register value for 5Hz is less than 4Hz and so, thus in this below condition odr is checked whether greater than 5Hz macro.
	if((osr_odr_press_cfg.odr > BMP581_ODR_05_HZ) && (fifo_frame_sel == BMP581_DISABLE) && (iir_cfg.set_iir_t == BMP581_IIR_FILTER_BYPASS) && (iir_cfg.set_iir_p == BMP581_IIR_FILTER_BYPASS)) {
		*powermode = BMP581_POWERMODE_DEEP_STANDBY;
	}
	return result;
}

// Set deep standby mode
static HAL_StatusTypeDef set_deep_standby_mode(void) {
	uint8_t reg_data;
	HAL_StatusTypeDef result = read(BMP581_REG_ODR_CONFIG, &reg_data, ONE);
	if(result == HAL_OK) {
		// Setting deep_dis = 0(BMP581_DEEP_ENABLED) enables the deep standby mode
		reg_data = BMP581_SET_BIT_VAL_0(reg_data, BMP581_DEEP_DISABLE);
		// Set ODR less then 5Hz - ODR used is 1Hz
		reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_ODR, BMP581_ODR_01_HZ);
		// Write the value to the odr config register(0x37)
		result = write(BMP581_REG_ODR_CONFIG, &reg_data, ONE);
		if(result == HAL_OK) {
			result = read(BMP581_REG_DSP_IIR, &reg_data, ONE);
			if(result == HAL_OK) {
				// Set iir_t and iir_p as Bypass(0x00).
				// The register holds only iir_t and iir_p and the last 2 bits are reserved.
				// Thus using the macro BMP581_IIR_BYPASS(0xC0) the register value is set as zero.
				reg_data = reg_data & BMP581_IIR_BYPASS;
				// Write the value to the IIR register(0x31)
				result = write(BMP581_REG_DSP_IIR, &reg_data, ONE);
			}
		}
		if(result == HAL_OK) {
			result = read(BMP581_REG_FIFO_SEL, &reg_data, ONE);
			if(result == HAL_OK) {
				// Disable fifo frame selct
				reg_data = BMP581_SET_BIT_VAL_0(reg_data, BMP581_FIFO_FRAME_SEL);
				// Write the value to the fifo select register(0x18)
				result = write(BMP581_REG_FIFO_SEL, &reg_data, ONE);
			}
		}
	}
	return result;
}

// Set standby mode
static HAL_StatusTypeDef set_standby_mode(void) {
	enum BMP581_powermode pwrmode;
	HAL_StatusTypeDef result = BMP581_getPowerMode(&pwrmode);
	if(result == HAL_OK) {
		if(pwrmode == BMP581_POWERMODE_DEEP_STANDBY) {
			result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
		}
	}
	return result;
}

// This internal API is used to set the IIR for temperature and pressure.
static HAL_StatusTypeDef set_iir_config(const BMP581_iir_config_t *iir_cfg) {
	// Variable to set IIR config
	uint8_t reg_data[TWO];
	if(read(BMP581_REG_DSP_CONFIG, reg_data, TWO) == HAL_OK) {
		reg_data[ZERO] = BMP581_SET_BITSLICE(reg_data[ZERO], BMP581_SHDW_SET_IIR_TEMP, iir_cfg->shdw_set_iir_t);
		reg_data[ZERO] = BMP581_SET_BITSLICE(reg_data[ZERO], BMP581_SHDW_SET_IIR_PRESS, iir_cfg->shdw_set_iir_p);
		reg_data[ZERO] = BMP581_SET_BITSLICE(reg_data[ZERO], BMP581_IIR_FLUSH_FORCED_EN, iir_cfg->iir_flush_forced_en);
		reg_data[ONE] = iir_cfg->set_iir_t;
		reg_data[ONE] = BMP581_SET_BITSLICE(reg_data[ONE], BMP581_SET_IIR_PRESS, iir_cfg->set_iir_p);
		// Set IIR configuration
		return write(BMP581_REG_DSP_CONFIG, reg_data, TWO);
	}
	return HAL_ERROR;
}

static HAL_StatusTypeDef set_fifo_iir_config(const uint8_t set_fifo_iir_t, const uint8_t set_fifo_iir_p) {
	// Variable to store the function result
	HAL_StatusTypeDef result;
	// Variable to set fifo IIR config
	uint8_t reg_data = 0;
	// Variable to store existing powermode
	enum BMP581_powermode curr_pwrmode;
	result = BMP581_getPowerMode(&curr_pwrmode);
	if(result == HAL_OK) {
		// Fifo IIR configuration is writable only during STANDBY mode(as per datasheet)
		if(curr_pwrmode != BMP581_POWERMODE_STANDBY) {
			// If sensor is not in standby mode, set sensor in standby mode
			result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
		}
		if(result == HAL_OK) {
			// Get fifo IIR configuration
			result = read(BMP581_REG_DSP_CONFIG, &reg_data, ONE);
			if(result == HAL_OK) {
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_SET_FIFO_IIR_TEMP, set_fifo_iir_t);
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_SET_FIFO_IIR_PRESS, set_fifo_iir_p);
				// Set fifo IIR configuration
				result = write(BMP581_REG_DSP_CONFIG, &reg_data, ONE);
			}
		}
		// If previous mode is not standbymode return sensor to that previous mode after setting fifo iir configuration
		if(result == HAL_OK) {
			// Since fifo IIR works only in standby mode we are not re-writing to deepstandby mode as deep standby mode resets the fifo IIR settings to default
			if((curr_pwrmode != BMP581_POWERMODE_STANDBY) && (curr_pwrmode != BMP581_POWERMODE_DEEP_STANDBY)) {
				result = BMP581_setPowerMode(curr_pwrmode);
			}
		}
	}
	return result;
}

static HAL_StatusTypeDef set_fifo_threshold(uint8_t *reg_data, const BMP581_fifo_t *fifo) {
	if((fifo->frame_sel == BMP581_FIFO_TEMPERATURE_DATA) || (fifo->frame_sel == BMP581_FIFO_PRESSURE_DATA)) {
		// If Pressure or Temperature is selected, maximum 31 frames can be set as threshold
		if(fifo->threshold <= BMP581_FIFO_MAX_THRESHOLD_P_MODE) {
			reg_data[0] = BMP581_SET_BITS_POS_0(reg_data[0], BMP581_FIFO_THRESHOLD, fifo->threshold);
		} else {
			return HAL_ERROR;
		}
	} else if(fifo->frame_sel == BMP581_FIFO_PRESS_TEMP_DATA) {
		// If both pressure and temperature is selected, maximum 15 frames can be set as threshold
		if(fifo->threshold <= BMP581_FIFO_MAX_THRESHOLD_P_T_MODE)        {
			reg_data[0] = BMP581_SET_BITS_POS_0(reg_data[0], BMP581_FIFO_THRESHOLD, fifo->threshold);
		} else {
			return HAL_ERROR;
		}
	}
	return HAL_OK;
}

static HAL_StatusTypeDef unpack_sensor_data(BMP581_sensor_data_t *sensor_data, uint16_t *data_index, const BMP581_fifo_t *fifo) {
	int32_t raw_data_t = get_32bit(&fifo->data[*data_index]);
	uint32_t raw_data_p;
	switch (fifo->frame_sel) {
		case BMP581_FIFO_TEMPERATURE_DATA:
			// Check if fifo frame is empty using get_32bit function
			if(raw_data_t != CHECK_EMPTY){
			//if(!((fifo->data[*data_index] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 1] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 2] == BMP581_FIFO_EMPTY))) {
				//raw_data_t = (int32_t)((uint32_t)fifo->data[*data_index + 2] << 16 | (uint16_t)fifo->data[*data_index + 1] << 8 | fifo->data[*data_index]);
				// Division by 2^16(whose equivalent value is 65536) is performed to get temperature data in deg C
				sensor_data->temperature = ((float)raw_data_t / TEMP_COEFF);
				sensor_data->pressure = 0.0;
				*data_index += 3;
			} else {
				// Move the data index to the last byte to mark completion
				*data_index = fifo->length;
				return HAL_ERROR;
			}
		break;
		case BMP581_FIFO_PRESSURE_DATA:
			// Check if fifo frame is empty
			if(raw_data_t != CHECK_EMPTY){
			//if(!((fifo->data[*data_index] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 1] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 2] == BMP581_FIFO_EMPTY))) {
				// The value was calculated above as int32
				raw_data_p = (uint32_t)raw_data_t;//((uint32_t)fifo->data[(*data_index) + 2] << 16 | (uint16_t)fifo->data[(*data_index) + 1] << 8 | fifo->data[*data_index]);
				// Division by 2^6(whose equivalent value is 64) is performed to get pressure data in Pa
				sensor_data->pressure = ((float)raw_data_p / PRESS_COEFF);
				sensor_data->temperature = 0.0;
				*data_index += 3;
			} else {
				// Move the data index to the last byte to mark completion
				*data_index = fifo->length;
				return HAL_ERROR;
			}
		break;
		case BMP581_FIFO_PRESS_TEMP_DATA:
			raw_data_p = (uint32_t)get_32bit(&fifo->data[*data_index + 3]);
			if((raw_data_t != CHECK_EMPTY) && (raw_data_p != CHECK_EMPTY)){
			//if(!((fifo->data[*data_index] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 1] == BMP581_FIFO_EMPTY) &&
				//(fifo->data[*data_index + 2] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 3] == BMP581_FIFO_EMPTY) &&
				//(fifo->data[*data_index + 4] == BMP581_FIFO_EMPTY) && (fifo->data[*data_index + 5] == BMP581_FIFO_EMPTY))) {
				//raw_data_t = (int32_t)((uint32_t)fifo->data[*data_index + 2] << 16 | (uint16_t)fifo->data[*data_index + 1] << 8 | fifo->data[*data_index]);
				//raw_data_p = (uint32_t)((uint32_t)fifo->data[(*data_index) + 5] << 16 | (uint16_t)fifo->data[(*data_index) + 4] << 8 | fifo->data[*data_index + 3]);
				// Division by 2^16(whose equivalent value is 65536) is performed to get temperature data in deg C
				sensor_data->temperature = (float)(raw_data_t / 65536.0);
				// Division by 2^6(whose equivalent value is 64) is performed to get pressure data in Pa
				sensor_data->pressure = (float)(raw_data_p / 64.0);
				*data_index += 6;
			} else {
				// Move the data index to the last byte to mark completion
				*data_index = fifo->length;
				return HAL_ERROR;
			}
		break;
		default:
			sensor_data->pressure = 0.0;
			sensor_data->temperature = 0.0;
		break;
	}
	return HAL_OK;
}

static HAL_StatusTypeDef set_oor_iir_count_limit(const uint8_t set_oor_iir_p, const uint8_t set_count_limit) {
	HAL_StatusTypeDef result = HAL_OK;
	uint8_t reg_data = 0;
	//Variable to store existing powermode
	enum BMP581_powermode curr_pwrmode;
	result = BMP581_getPowerMode(&curr_pwrmode);
	if(result == HAL_OK) {
		//OOR IIR configuration and count limit is writable only during STANDBY mode(as per datasheet) */
		if(curr_pwrmode != BMP581_POWERMODE_STANDBY) {
			//If sensor is not in standby mode, set sensor in standby mode */
			result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
		}
		if(result == HAL_OK) {
			//Get OOR pressure IIR configuration
			result = read(BMP581_REG_DSP_CONFIG, &reg_data, ONE);
			if(result == HAL_OK) {
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_OOR_SEL_IIR_PRESS, set_oor_iir_p);
				//Set OOR pressure IIR configuration
				result = write(BMP581_REG_DSP_CONFIG, &reg_data, ONE);
			}
			if(result == HAL_OK) {
				//Get OOR pressure count limit
				result = read(BMP581_REG_OOR_CONFIG, &reg_data, ONE);
			}
			if(result == HAL_OK) {
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_OOR_COUNT_LIMIT, set_count_limit);
			}
			if(result == HAL_OK) {
				//Set OOR pressure count limit
				result = write(BMP581_REG_OOR_CONFIG, &reg_data, 1);
			}
		}
		//If previous mode is not standbymode return sensor to that previous mode after setting oor iir configuration and count limit
		if(result == HAL_OK) {
			//Since oor IIR and count limit works only in standby mode we are not re-writing to deepstandby mode as deep standby mode resets the oor iir configuration and count limit to default
			if((curr_pwrmode != BMP581_POWERMODE_STANDBY) && (curr_pwrmode != BMP581_POWERMODE_DEEP_STANDBY)) {
				result = BMP581_setPowerMode(curr_pwrmode);
			}
		}
	}
	return result;
}

static HAL_StatusTypeDef set_nvm_addr(const uint8_t nvm_addr, const uint8_t prog_en) {
	uint8_t nvm_status;
	// Check if NVM ready status = 1
	HAL_StatusTypeDef result = read(BMP581_REG_STATUS, &nvm_status, ONE);
	if(result == HAL_OK) {
		if(nvm_status & BMP581_INT_NVM_RDY) {
			uint8_t reg_data;
			result = read(BMP581_REG_NVM_ADDR, &reg_data, ONE);
			if(result == HAL_OK) {
				// Write the NVM address */
				reg_data = BMP581_SET_BITS_POS_0(reg_data, BMP581_NVM_ADDR, nvm_addr);
				if(prog_en == BMP581_ENABLE) {
				// Set bit nvm_prog_en as 1 if NVM write is selected
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_NVM_PROG_EN, prog_en);
				} else {
					// Set bit nvm_prog_en as 0 if NVM read is selected
					reg_data = BMP581_SET_BIT_VAL_0(reg_data, BMP581_NVM_PROG_EN);
				}
				result = write(BMP581_REG_NVM_ADDR, &reg_data, ONE);
			}
		}	else {
			return HAL_ERROR;
		}
	}
	return result;
}

static HAL_StatusTypeDef nvm_write_addr(const uint8_t nvm_addr, const uint8_t prog_en, enum BMP581_powermode *curr_pwrmode) {
	HAL_StatusTypeDef result = HAL_ERROR;
	if((nvm_addr >= BMP581_NVM_START_ADDR) && (nvm_addr <= BMP581_NVM_END_ADDR)) {
		// Get current powermode
		result = BMP581_getPowerMode(curr_pwrmode);
		if(result == HAL_OK) {
			// NVM write can be performed only during STANDBY mode
			if(*curr_pwrmode != BMP581_POWERMODE_STANDBY) {
				// If sensor is not in standby mode, set sensor in standby mode
				result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
			}
			if(result == HAL_OK) {
				// Write the NVM address and set NVM prog_en with respect to NVM read/write selected.
				result = set_nvm_addr(nvm_addr, prog_en);
			}
		}
	}
	return result;
}

static HAL_StatusTypeDef get_nvm_data(uint16_t *nvm_data) {
	uint8_t nvm_status;
	HAL_StatusTypeDef result = read(BMP581_REG_STATUS, &nvm_status, ONE);
	if(result == HAL_OK) {
		// Check if NVM ready status = 1, NVM error status = 0 and NVM command error status = 0
		if((nvm_status & BMP581_INT_NVM_RDY) && (!(nvm_status & BMP581_INT_NVM_ERR)) &&(!(nvm_status & BMP581_INT_NVM_CMD_ERR))) {
			// Read the NVM data from the register address
			uint8_t nvmdata[2];
			result = read(BMP581_REG_NVM_DATA_LSB, nvmdata, TWO);
			(*nvm_data) = (uint16_t)((nvmdata[1] << 8) | nvmdata[0]);
		} else {
			return HAL_ERROR;
		}
	}
	return result;
}

// This API is used to get interrupt status.
HAL_StatusTypeDef BMP581_getInterruptStatus(uint8_t *int_status) {
	return read(BMP581_REG_INT_STATUS, int_status, ONE);
}

HAL_StatusTypeDef BMP581_SoftReset(void) {
	uint8_t data = BMP581_SOFT_RESET_CMD;
	if(write(BMP581_REG_CMD, &data, ONE) == HAL_OK) {
		// Soft-reset execution takes 2 ms
		HAL_Delay(2);
		uint8_t por_status;
		if(BMP581_getInterruptStatus(&por_status) == HAL_OK) {
			if(por_status & BMP581_INT_ASSERTED_POR_SOFTRESET_COMPLETE) {
				return HAL_OK;
			}
		}
	}
	return HAL_ERROR;
}

HAL_StatusTypeDef BMP581_Init(void) {
	if(BMP581_SoftReset() == HAL_OK) {
		// Read chip_id 
		uint8_t chip_id;
		if(read(BMP581_REG_CHIP_ID, &chip_id, ONE) == HAL_OK) {
			if(chip_id != ZERO) {
				// Validate post power-up procedure
				if(power_up_check() == HAL_OK) {
					return (chip_id == BMP581_CHIP_ID_PRIM || chip_id == BMP581_CHIP_ID_SEC) ? HAL_OK : HAL_ERROR;
				}
			}
		}
	}
	return HAL_ERROR;
}

// Set BMP581 to get out precise data, no speed constraint
HAL_StatusTypeDef BMP581_setHighAccuracy(void) {
	HAL_StatusTypeDef result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
	if(BMP581_setPowerMode(BMP581_POWERMODE_STANDBY) == HAL_OK) {
		osrOdrConfig.odr = BMP581_ODR_05_HZ;
		osrOdrConfig.osr_p = BMP581_OVERSAMPLING_128X;
		osrOdrConfig.osr_t = BMP581_OVERSAMPLING_128X;
		osrOdrConfig.press_en = BMP581_ENABLE; // !!! Enable pressure
		if(BMP581_setOsrOdrPressConfig(&osrOdrConfig) == HAL_OK) {
			iirConfig.set_iir_t = BMP581_IIR_FILTER_COEFF_127;
			iirConfig.set_iir_p = BMP581_IIR_FILTER_COEFF_127;
			iirConfig.shdw_set_iir_p = BMP581_ENABLE;
			iirConfig.shdw_set_iir_t = BMP581_ENABLE;
			if(BMP581_setIirConfig(&iirConfig) == HAL_OK) {
				if(BMP581_ConfigureInterrupt(BMP581_PULSED, BMP581_ACTIVE_HIGH, BMP581_INTR_PUSH_PULL, BMP581_INTR_ENABLE) == HAL_OK) {						
					interruptSource.drdy_en = BMP581_ENABLE;				// Trigger interrupts when data is ready
					interruptSource.fifo_full_en = BMP581_DISABLE;	// Trigger interrupts when FIFO is full
					interruptSource.fifo_thres_en = BMP581_DISABLE;	// Trigger interrupts when FIFO threshold is reached
					interruptSource.oor_press_en = BMP581_DISABLE;	// Trigger interrupts when pressure goes out of range
					// Select INT_SOURCE after configuring interrupt
					if(BMP581_InterruptSourceSelect(&interruptSource) == HAL_OK) {
						result = BMP581_getOsrOdrEffective(&eff);
						if(result){}
						//Set powermode as continous
						return BMP581_setPowerMode(BMP581_POWERMODE_CONTINOUS);
					}
				}
			}
		}
	}
	return result;
}
// This API reads the temperature(deg C) or both pressure(Pa) and temperature(deg C) data from the sensor and store it in the BMP581_sensor_data structure instance passed by the user.
HAL_StatusTypeDef BMP581_getSensorData(BMP581_sensor_data_t *sensor_data) {
	uint8_t reg_data[SIX] = {0};
	if(read(BMP581_REG_TEMP_DATA_XLSB, reg_data, SIX) == HAL_OK) {
		int32_t raw_data_t = (int32_t) ((int32_t) ((uint32_t)(((uint32_t)reg_data[TWO] << 16) | ((uint16_t)reg_data[ONE] << 8) | reg_data[ZERO]) << 8) >> 8);
		// Division by 2^16(whose equivalent value is 65536) is performed to get temperature data in deg C
		sensor_data->temperature = ((float)raw_data_t / TEMP_COEFF);
		// ToDo Decide if I should keep this condition as pressuere will be enabled by default
//		if(osrOdrConfig.press_en) {
			uint32_t raw_data_p = (uint32_t)((uint32_t)(reg_data[FIVE] << 16) | (uint16_t)(reg_data[FOUR] << 8) | reg_data[THREE]);
			// Division by 2^6(whose equivalent value is 64) is performed to get pressure data in Pa
			sensor_data->pressure = ((float)raw_data_p / PRESS_COEFF);
//		} else {
//			sensor_data->pressure = 0.0;
//		}
		return HAL_OK;
	}
	return HAL_ERROR;
}

// This API is used to get powermode of the sensor.
HAL_StatusTypeDef BMP581_getPowerMode(enum BMP581_powermode *powermode) {
	uint8_t reg_data;
	// Read the power mode register
	if(read(BMP581_REG_ODR_CONFIG, &reg_data, ONE) == HAL_OK) {
		uint8_t pwrmode = BMP581_GET_BITS_POS_0(reg_data, BMP581_POWERMODE);
		uint8_t deep_dis;
		switch (pwrmode) {
			case BMP581_POWERMODE_STANDBY:
				// Getting deep disable status
				deep_dis = BMP581_GET_BITSLICE(reg_data, BMP581_DEEP_DISABLE);
				// Checking deepstandby status only when powermode is in standby mode
				// If deep_dis = 0(BMP581_DEEP_ENABLED) then deepstandby mode is enabled.
				// If deep_dis = 1(BMP581_DEEP_DISABLED) then deepstandby mode is disabled
				if(deep_dis == BMP581_DEEP_ENABLED) {
					return check_deepstandby_mode(powermode);
				} else {
					*powermode = BMP581_POWERMODE_STANDBY;
				}
			break;
			case BMP581_POWERMODE_NORMAL:
				*powermode = BMP581_POWERMODE_NORMAL;
			break;
			case BMP581_POWERMODE_FORCED:
				*powermode = BMP581_POWERMODE_FORCED;
			break;
			case BMP581_POWERMODE_CONTINOUS:
				*powermode = BMP581_POWERMODE_CONTINOUS;
			break;
		}
		return HAL_OK;
	}
	return HAL_ERROR;
}

// This API is used to set powermode of the sensor.
HAL_StatusTypeDef BMP581_setPowerMode(const enum BMP581_powermode powermode) {
	HAL_StatusTypeDef result = HAL_ERROR;
	enum BMP581_powermode lst_pwrmode;
	// Existing power mode of the device is received in lst_pwrmode
	result = BMP581_getPowerMode(&lst_pwrmode);
	if(result == HAL_OK) {
		// If the sensor is not in standby mode set the device to standby mode.
		if(lst_pwrmode != BMP581_POWERMODE_STANDBY) {
			// Device should be set to standby before transiting to forced mode or normal mode or continous mode.
			result = set_power_mode(BMP581_POWERMODE_STANDBY);
			if(result == HAL_OK) {
				// Give t_standby(as per data sheet) time for device to go into standby mode
				HAL_Delay(3);
			}
		}
		if(result == HAL_OK) {
			// Set the desired power mode
			switch (powermode) {
				case BMP581_POWERMODE_DEEP_STANDBY:
					result = set_deep_standby_mode();
				break;
				case BMP581_POWERMODE_STANDBY:
					// Since switching between powermodes require sensor to be in standby mode it is performed above. So it is not explicitly performed here.
				break;
				case BMP581_POWERMODE_NORMAL:
				case BMP581_POWERMODE_FORCED:
				case BMP581_POWERMODE_CONTINOUS:
					result = set_power_mode(powermode);
				break;
        default:
					result = HAL_ERROR;
        break;
			}
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_getIirConfig(BMP581_iir_config_t *iir_cfg) {
	// Variable to get IIR config
	uint8_t reg_data[TWO];
	// Get IIR configuration
	if(read(BMP581_REG_DSP_CONFIG, reg_data, TWO) == HAL_OK) {
		iir_cfg->shdw_set_iir_t = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_SHDW_SET_IIR_TEMP);
		iir_cfg->shdw_set_iir_p = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_SHDW_SET_IIR_PRESS);
		iir_cfg->iir_flush_forced_en = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_IIR_FLUSH_FORCED_EN);
		iir_cfg->set_iir_t = BMP581_GET_BITS_POS_0(reg_data[ONE], BMP581_SET_IIR_TEMP);
		iir_cfg->set_iir_p = BMP581_GET_BITSLICE(reg_data[ONE], BMP581_SET_IIR_PRESS);
		return HAL_OK;
	}
	return HAL_ERROR;
}

// This API sets the configuration for IIR of temperature and pressure.
// If IIR value for both temperature and pressure is set a value other than bypass then powermode is set
//  as standby mode, as IIR with value other than bypass without disabling deep-standby mode makes powermode invalid.
HAL_StatusTypeDef BMP581_setIirConfig(const BMP581_iir_config_t *iir_cfg) {
	HAL_StatusTypeDef result = HAL_OK;
	// Variable to store existing powermode
	enum BMP581_powermode curr_pwrmode;
	// If IIR value for both temperature and pressure is set a value other than bypass then powermode is set
	// as standby mode, as IIR with value other than bypass without disabling deep-standby mode makes powermode
	// invalid.
	if((iir_cfg->set_iir_t != BMP581_IIR_FILTER_BYPASS) || (iir_cfg->set_iir_p != BMP581_IIR_FILTER_BYPASS)) {
		result = set_standby_mode();
	}
	if(result == HAL_OK) {
		result = BMP581_getPowerMode(&curr_pwrmode);
		if(result == HAL_OK) {
			// IIR configuration is writable only during STANDBY mode(as per datasheet)
			if(curr_pwrmode != BMP581_POWERMODE_STANDBY) {
				result = BMP581_setPowerMode(BMP581_POWERMODE_STANDBY);
			}
			// If sensor is not in standby mode, set sensor in standby mode
			if(result == HAL_OK) {
				result = set_iir_config(iir_cfg);
			}
			// If previous mode is not standbymode return sensor to that previous mode after setting iir configuration
			if(result == HAL_OK) {
				// Since IIR works only in standby mode we are not re-writing to deepstandby mode	as deep standby mode resets the IIR settings to default
				if((curr_pwrmode != BMP581_POWERMODE_STANDBY) && (curr_pwrmode != BMP581_POWERMODE_DEEP_STANDBY)) {
					result = BMP581_setPowerMode(curr_pwrmode);
				}
			}
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_getOsrOdrPressConfig(BMP581_osr_odr_press_config_t *osr_odr_press_cfg) {
	// Variable to store OSR and ODR config
	uint8_t reg_data[TWO];
	// Get OSR and ODR configuration in burst read
	if(read(BMP581_REG_OSR_CONFIG, reg_data, TWO) == HAL_OK) {
		osr_odr_press_cfg->osr_t = BMP581_GET_BITS_POS_0(reg_data[ZERO], BMP581_TEMP_OS);
		osr_odr_press_cfg->osr_p = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_PRESS_OS);
		osr_odr_press_cfg->press_en = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_PRESS_EN);
		osr_odr_press_cfg->odr = BMP581_GET_BITSLICE(reg_data[ONE], BMP581_ODR);
		return HAL_OK;
	}
	return HAL_ERROR;
}


// This API sets the configuration for oversampling temperature, oversampling of
//  pressure and ODR configuration along with pressure enable.
// If ODR is set to a value higher than 5Hz then powermode is set as standby mode, as ODR value greater than 5HZ
//  without disabling deep-standby mode makes powermode invalid.
HAL_StatusTypeDef BMP581_setOsrOdrPressConfig(const BMP581_osr_odr_press_config_t *osr_odr_press_cfg) {
	HAL_StatusTypeDef result = HAL_OK;
	// Variable to set ODR and OSR config
	uint8_t reg_data[TWO] = {0};
	// If ODR is set to a value higher than 5Hz then powermode is set as standby mode, as ODR value greater than 5HZ
	// without disabling deep-standby mode makes powermode invalid.
	// NOTE: Register value for 5Hz is greater compared to ODRs higher than it. Thus in this below condition odr is checked whether less than 5Hz macro.
	if(osr_odr_press_cfg->odr < BMP581_ODR_05_HZ) {
		result = set_standby_mode();
	}
	if(result == HAL_OK) {
		if(read(BMP581_REG_OSR_CONFIG, reg_data, TWO) == HAL_OK) {
			reg_data[ZERO] = BMP581_SET_BITS_POS_0(reg_data[ZERO], BMP581_TEMP_OS, osr_odr_press_cfg->osr_t);
			reg_data[ZERO] = BMP581_SET_BITSLICE(reg_data[ZERO], BMP581_PRESS_OS, osr_odr_press_cfg->osr_p);
			reg_data[ZERO] = BMP581_SET_BITSLICE(reg_data[ZERO], BMP581_PRESS_EN, osr_odr_press_cfg->press_en);
			reg_data[ONE] = BMP581_SET_BITSLICE(reg_data[ONE], BMP581_ODR, osr_odr_press_cfg->odr);
			// Set ODR and OSR configuration
			result = write(BMP581_REG_OSR_CONFIG, reg_data, TWO);
		}
	}
	return result;
}

// This API is used to enable the interrupts(drdy interrupt, fifo full interrupt, fifo threshold enable and pressure data out of range interrupt).
HAL_StatusTypeDef BMP581_InterruptSourceSelect(const BMP581_int_source_select_t *int_source_select) {
	uint8_t reg_data;
	if(read(BMP581_REG_INT_SOURCE, &reg_data, ONE) == HAL_OK)        {
		reg_data = BMP581_SET_BITS_POS_0(reg_data, BMP581_INT_DRDY_EN, int_source_select->drdy_en);
		reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_FIFO_FULL_EN, int_source_select->fifo_full_en);
		reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_FIFO_THRES_EN, int_source_select->fifo_thres_en);
		reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_OOR_PRESS_EN, int_source_select->oor_press_en);
		return write(BMP581_REG_INT_SOURCE, &reg_data, ONE);
	}
	return HAL_ERROR;
}

// This API is used to configure the interrupt settings.
HAL_StatusTypeDef BMP581_ConfigureInterrupt(const enum BMP581_intr_mode int_mode, const enum BMP581_intr_polarity int_pol, const enum BMP581_intr_drive int_od, const enum BMP581_intr_en_dis int_en) {
	// Variable to get interrupt configuration
	uint8_t reg_data = 0;
	// Get interrupt configuration
	if(read(BMP581_REG_INT_CONFIG, &reg_data, ONE) == HAL_OK)    {
		// Any change between latched/pulsed mode has to be applied while interrupt is disabled
		// Step 1 : Turn off all INT sources (INT_SOURCE -> 0x00)
		uint8_t int_source = 0;
		if(write(BMP581_REG_INT_SOURCE, &int_source, ONE) == HAL_OK) {
			// Step 2 : Read the INT_STATUS register to clear the status
			uint8_t int_status = 0;
			if(read(BMP581_REG_INT_STATUS, &int_status, ONE) == HAL_OK) {
				// Step 3 : Set the desired mode in INT_CONFIG.int_mode
				reg_data = BMP581_SET_BITS_POS_0(reg_data, BMP581_INT_MODE, int_mode);
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_POL, int_pol);
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_OD, int_od);
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_INT_EN, int_en);
				// Finally transfer the interrupt configurations
				return write(BMP581_REG_INT_CONFIG, &reg_data, ONE);
			}
		}
	}
	return HAL_ERROR;
}

HAL_StatusTypeDef BMP581_getOsrOdrEffective(BMP581_osr_odr_eff_t *osr_odr_eff) {
	//Variable to store effective OSR
	uint8_t reg_data;
	//Get effective OSR configuration and ODR valid status
	HAL_StatusTypeDef result = read(BMP581_REG_OSR_EFF, &reg_data, ONE);
	if(result == HAL_OK) {
		osr_odr_eff->osr_t_eff = BMP581_GET_BITS_POS_0(reg_data, BMP581_OSR_TEMP_EFF);
		osr_odr_eff->osr_p_eff = BMP581_GET_BITSLICE(reg_data, BMP581_OSR_PRESS_EFF);
		osr_odr_eff->odr_is_valid = BMP581_GET_BITSLICE(reg_data, BMP581_ODR_IS_VALID);
	}
	return result;
}

HAL_StatusTypeDef BMP581_getFifoConfiguration(BMP581_fifo_t *fifo) {
	uint8_t reg_data;
	//Get the fifo congifurations
	HAL_StatusTypeDef result = read(BMP581_REG_FIFO_CONFIG, &reg_data, ONE);
	if(result == HAL_OK) {
		fifo->threshold = BMP581_GET_BITS_POS_0(reg_data, BMP581_FIFO_THRESHOLD);
		fifo->mode = BMP581_GET_BITSLICE(reg_data, BMP581_FIFO_MODE);
		result = read(BMP581_REG_FIFO_SEL, &reg_data, ONE);
		if(result == HAL_OK) {
			fifo->frame_sel = BMP581_GET_BITS_POS_0(reg_data, BMP581_FIFO_FRAME_SEL);
			fifo->dec_sel = BMP581_GET_BITSLICE(reg_data, BMP581_FIFO_DEC_SEL);
		}
	}
	if(result == HAL_OK) {
		result = read(BMP581_REG_DSP_CONFIG, &reg_data, ONE);
		if(result == HAL_OK) {
			fifo->set_fifo_iir_t = BMP581_GET_BITSLICE(reg_data, BMP581_SET_FIFO_IIR_TEMP);
			fifo->set_fifo_iir_p = BMP581_GET_BITSLICE(reg_data, BMP581_SET_FIFO_IIR_PRESS);
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_set_FifoConfiguration(const BMP581_fifo_t *fifo) {
	HAL_StatusTypeDef result = HAL_OK;
	//If Fifo frame selection is enabled then powermode is set as standby mode, as fifo frame selection enabled without disabling deep-standby mode makes powermode invalid.
	if(fifo->frame_sel != BMP581_DISABLE) {
		result = set_standby_mode();
	}
	if(result == HAL_OK) {
		uint8_t set_fifo_iir_t, set_fifo_iit_p;
		set_fifo_iir_t = fifo->set_fifo_iir_t;
		set_fifo_iit_p = fifo->set_fifo_iir_p;
		result = set_fifo_iir_config(set_fifo_iir_t, set_fifo_iit_p);
		if(result == HAL_OK) {
			uint8_t reg_data;
			//Get the fifo congifurations
			result = read(BMP581_REG_FIFO_CONFIG, &reg_data, ONE);
			if(result == HAL_OK) {
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_FIFO_MODE, fifo->mode);
				result = set_fifo_threshold(&reg_data, fifo);
			}
			if(result == HAL_OK) {
				//Set the fifo congifurations
				result = write(BMP581_REG_FIFO_CONFIG, &reg_data, ONE);
			}
			if(result == HAL_OK) {
				result = read(BMP581_REG_FIFO_SEL, &reg_data, ONE);
			}
			if(result == HAL_OK) {
				reg_data = BMP581_SET_BITS_POS_0(reg_data, BMP581_FIFO_FRAME_SEL, fifo->frame_sel);
				reg_data = BMP581_SET_BITSLICE(reg_data, BMP581_FIFO_DEC_SEL, fifo->dec_sel);
			}
			if(result == HAL_OK) {
				//Set the fifo congifurations
				result = write(BMP581_REG_FIFO_SEL, &reg_data, ONE);
			}
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_getFifoLength(uint16_t *fifo_len, BMP581_fifo_t *fifo) {
	uint8_t reg_data;
	//Get the fifo frame count
	HAL_StatusTypeDef result = read(BMP581_REG_FIFO_COUNT, &reg_data, ONE);
	if(result == HAL_OK) {
		fifo->fifo_count = BMP581_GET_BITS_POS_0(reg_data, BMP581_FIFO_COUNT);
		if((fifo->frame_sel == BMP581_FIFO_TEMPERATURE_DATA) || (fifo->frame_sel == BMP581_FIFO_PRESSURE_DATA)) {
			//Maximum of 32 frames if either one of temperature or pressure is selected and each frame comprises of 3 bytes of data
			*fifo_len = fifo->fifo_count * 3;
		}else if(fifo->frame_sel == BMP581_FIFO_PRESS_TEMP_DATA) {
			//Maximum of 16 frames if both temperature and pressure is selected and each frame comprises of 6 bytes of data
			*fifo_len = fifo->fifo_count * 6;
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_get_FifoData(BMP581_fifo_t *fifo) {
	uint16_t fifo_len;
	//Get the fifo length
	HAL_StatusTypeDef result = BMP581_getFifoLength(&fifo_len, fifo);
	if(result == HAL_OK) {
		if(fifo->length > fifo_len) {
			fifo->length = fifo_len;
		}
		//Read the fifo data
		result = read(BMP581_REG_FIFO_DATA, fifo->data, fifo->length);
	}
	return result;
}

HAL_StatusTypeDef BMP581_ExtractFifoData(const BMP581_fifo_t *fifo, BMP581_sensor_data_t *sensor_data) {
	HAL_StatusTypeDef result = HAL_OK;
	uint8_t idx = 0;
	uint16_t data_indx;
	for (data_indx = 0; (data_indx < fifo->length) && (result != HAL_OK);) {
		//Inside unpack_sensor_data function, data_index is incremented
		result = unpack_sensor_data(&sensor_data[idx], &data_indx, fifo);
		idx++;
	}
	return result;
}

HAL_StatusTypeDef BMP581_getOorConfiguration(BMP581_oor_press_configuration_t *oor_press_config) {
	uint8_t reg_data[4];
	HAL_StatusTypeDef result = read(BMP581_REG_DSP_CONFIG, &reg_data[ZERO], ONE);
	if(result == HAL_OK) {
		oor_press_config->oor_sel_iir_p = BMP581_GET_BITSLICE(reg_data[ZERO], BMP581_OOR_SEL_IIR_PRESS);
		result = read(BMP581_REG_OOR_THR_P_LSB, reg_data, FOUR);
		if(result == HAL_OK) {
			oor_press_config->oor_thr_p = reg_data[ZERO] | (reg_data[ONE] << 8) | ((reg_data[THREE] & BMP581_OOR_THR_P_XMSB_REG_MSK) << 16);
			oor_press_config->oor_range_p = reg_data[TWO];
			oor_press_config->cnt_lim = BMP581_GET_BITSLICE(reg_data[3], BMP581_OOR_COUNT_LIMIT);
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_set_OorConfiguration(const BMP581_oor_press_configuration_t *oor_press_config) {
	uint8_t set_oor_iir_p, set_count_limit;
	HAL_StatusTypeDef result = set_oor_iir_count_limit(set_oor_iir_p, set_count_limit);
	if(result == HAL_OK) {
		uint8_t reg_data[4];
		//Get the OOR configurations
		result = read(BMP581_REG_OOR_THR_P_LSB, reg_data, FOUR);
		if(result == HAL_OK) {
			uint8_t thres_xmsb;
			set_oor_iir_p = oor_press_config->oor_sel_iir_p;
			set_count_limit = oor_press_config->cnt_lim;
			reg_data[ZERO] = BMP581_SET_BITS_POS_0(reg_data[ZERO], BMP581_OOR_THR_P_LSB, oor_press_config->oor_thr_p);
			reg_data[ONE] = (uint8_t)(BMP581_SET_BITS_POS_0(reg_data[ONE], BMP581_OOR_THR_P_MSB, oor_press_config->oor_thr_p) >> 8);
			reg_data[TWO] = oor_press_config->oor_range_p;
			thres_xmsb = BMP581_GET_BITSLICE(oor_press_config->oor_thr_p, BMP581_OOR_THR_P_XMSB);
			reg_data[3] = BMP581_SET_BITS_POS_0(reg_data[3], BMP581_OOR_THR_P_XMSB_REG, thres_xmsb);
			//Set the OOR congifurations
			result = write(BMP581_REG_OOR_THR_P_LSB, reg_data, FOUR);
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_NvmRead(const uint8_t nvm_addr, uint16_t *nvm_data) {
	uint8_t reg_data;
	//Variable to store existing powermode
	enum BMP581_powermode curr_pwrmode;
	//Proceed if null check is fine
	HAL_StatusTypeDef result = nvm_write_addr(nvm_addr, BMP581_DISABLE, &curr_pwrmode);
	if(result == HAL_OK) {
		//First NVM command for user read sequence
		reg_data = BMP581_NVM_FIRST_CMND;
		result = write(BMP581_REG_CMD, &reg_data, ONE);
	}

	if(result == HAL_OK) {
		//Read enable NVM command for user read sequence
		reg_data = BMP581_NVM_READ_ENABLE_CMND;
		result = write(BMP581_REG_CMD, &reg_data, ONE);
		//Delay required for NVM ready status to change to 1 before NVM read
		HAL_Delay(1); // 800us
	}
	if(result == HAL_OK) {
		result = get_nvm_data(nvm_data);
	}
	if(result == HAL_OK) {
		//If previous mode is not standbymode return sensor to that previous mode after performing NVM
		if(curr_pwrmode != BMP581_POWERMODE_STANDBY) {
			result = BMP581_setPowerMode(curr_pwrmode);
		}
	}
	return result;
}

HAL_StatusTypeDef BMP581_NvmWrite(const uint8_t nvm_addr, const uint16_t *nvm_data) {
	uint8_t nvm_status = 0;
	uint8_t reg_data = 0;
	uint8_t nvmdata[2];
	//Variable to store existing powermode
	enum BMP581_powermode curr_pwrmode;
	HAL_StatusTypeDef result = nvm_write_addr(nvm_addr, BMP581_ENABLE, &curr_pwrmode);
	if(result == HAL_OK) {
		//Write data to be written to NVM address
		result = read(BMP581_REG_NVM_DATA_LSB, nvmdata, TWO);
		if(result == HAL_OK) {
			nvmdata[0] = (uint8_t)(*nvm_data & BMP581_NVM_DATA_LSB_MSK);
			nvmdata[1] = (uint8_t)((*nvm_data & BMP581_NVM_DATA_MSB_MSK) >> 8);
			result = write(BMP581_REG_NVM_DATA_LSB, nvmdata, 2);
		}
	}
	if(result == HAL_OK) {
		//First NVM command for user write sequence
		reg_data = BMP581_NVM_FIRST_CMND;
		result = write(BMP581_REG_CMD, &reg_data, ONE);
	}
	if(result == HAL_OK) {
		//Write enable NVM command for user write sequence
		reg_data = BMP581_NVM_WRITE_ENABLE_CMND;
		result = write(BMP581_REG_CMD, &reg_data, ONE);
		//Delay required for NVM ready status to change to 1
		HAL_Delay(10);
	}
	if(result == HAL_OK) {
		//Check if NVM ready status = 1, NVM error status = 0 and NVM command error status = 0
		result = read(BMP581_REG_STATUS, &nvm_status, ONE);
		if((nvm_status & BMP581_INT_NVM_RDY) && (!(nvm_status & BMP581_INT_NVM_ERR)) &&(!(nvm_status & BMP581_INT_NVM_CMD_ERR))) {
			//Reset NVM prog_en
			reg_data = BMP581_SET_BIT_VAL_0(reg_data, BMP581_NVM_PROG_EN);
			result = write(BMP581_REG_NVM_ADDR, &reg_data, ONE);
		} else {
		result = HAL_ERROR;
		}
	}
	if(result == HAL_OK) {
		//If previous mode is not standbymode return sensor to that previous mode after performing NVM
		if(curr_pwrmode != BMP581_POWERMODE_STANDBY) {
			result = BMP581_setPowerMode(curr_pwrmode);
		}
	}
	return result;
}

Comments powered by CComment

Who’s online

We have 47 guests and no members online