Skip to content

Commit

Permalink
* BMP180: changes to allow (custom) intialization of sea level pressu…
Browse files Browse the repository at this point in the history
…re for the component (relying on shared_APS module)

* shared_APS: added files for common code regarding ambient pressure sensing
  • Loading branch information
SMFSW committed Dec 15, 2020
1 parent 39c652e commit 1e4787c
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 82 deletions.
139 changes: 76 additions & 63 deletions BMP180_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
#if defined(HAL_I2C_MODULE_ENABLED)
#if defined(I2C_BMP180)
/****************************************************************/
// std libs
#include <math.h>
/****************************************************************/

//#define BMP180_TST //!< Defined to check calculations with datasheet

Expand All @@ -24,6 +21,22 @@ extern uint8_t BMP180_OSS_time[4];
/****************************************************************/


#if defined(BMP180_TST)
static void BMP180_Test_Result(const char * str, const bool res)
{
printf("BMP180 %s result: TEST %s\r\n", str, res ? "PASS" : "FAIL");
}
#endif


__WEAK FctERR NONNULL__ BMP180_Set_SeaLevel_Pressure(BMP180_t * pCpnt)
{
pCpnt->cfg.SeaLevelPressure = Get_SeaLevel_Pressure();

return ERROR_OK;
}


__WEAK FctERR NONNULL__ BMP180_Init_Sequence(BMP180_t * pCpnt)
{
FctERR err;
Expand All @@ -34,8 +47,10 @@ __WEAK FctERR NONNULL__ BMP180_Init_Sequence(BMP180_t * pCpnt)
if (err) { return err; }
if (pCpnt->cfg.ID != BMP180_CHIP_ID) { return ERROR_COMMON; } // Unknown device

err = BMP180_Set_SeaLevel_Pressure(pCpnt);

#if !defined(BMP180_TST)
err = BMP180_Get_Calibration(pCpnt, &pCpnt->cfg.Calib);
err |= BMP180_Get_Calibration(pCpnt, &pCpnt->cfg.Calib);
#else
pCpnt->cfg.OSS = BMP180__OSS_1_TIME;
pCpnt->cfg.Calib.AC1 = 408;
Expand All @@ -58,32 +73,6 @@ __WEAK FctERR NONNULL__ BMP180_Init_Sequence(BMP180_t * pCpnt)
/****************************************************************/


/**!\brief Calculates the altitude (in meters) from the specified atmospheric
** pressure (in hPa), and sea-level pressure (in hPa).
** \param[in] pressure - Atmospheric pressure in hPa
**/
__STATIC_INLINE float INLINE__ BMP180_Pressure_To_Altitude(const float pressure)
{
// Equation from BMP180 datasheet from page 16
return (44330.0f * (1.0f - pow(pressure / SEA_LEVEL_PRESSURE, (1.0f / 5.255f))));
}


/**!\brief Calculates the pressure at sea level (in hPa) from the specified altitude
** (in meters), and atmospheric pressure (in hPa).
** \param[in] altitude - Altitude in meters
** \param[in] pressure - Atmospheric pressure in hPa
**/
__STATIC_INLINE float INLINE__ BMP180_seaLevel_Pressure_For_Altitude(const float altitude, const float pressure)
{
// Equation from BMP180 datasheet from page 17
return (pressure / pow(1.0f - (altitude / 44330.0f), 5.255f));
}


/****************************************************************/


FctERR NONNULL__ BMP180_Set_Oversampling(BMP180_t * pCpnt, const BMP180_oversampling oss)
{
if (oss > BMP180__OSS_8_TIME) { return ERROR_VALUE; } // Unknown Oversampling
Expand All @@ -93,9 +82,9 @@ FctERR NONNULL__ BMP180_Set_Oversampling(BMP180_t * pCpnt, const BMP180_oversamp
}


FctERR NONNULL__ BMP180_Get_Calibration(BMP180_t * pCpnt, BMP180_calib * calib)
FctERR NONNULL__ BMP180_Get_Calibration(BMP180_t * pCpnt, BMP180_calib * pCalib)
{
int16_t * addr = (int16_t *) calib;
int16_t * addr = (int16_t *) pCalib;
FctERR err = ERROR_OK;

for (int i = 0 ; i < SZ_OBJ(BMP180_calib, int16_t) ; i++)
Expand All @@ -108,25 +97,37 @@ FctERR NONNULL__ BMP180_Get_Calibration(BMP180_t * pCpnt, BMP180_calib * calib)
}


/**!\brief Compute B5 coefficient used in temperature & pressure calculations.
** \param[in] pCpnt - Pointer to BMP180 component
/**!\brief Determine B5 compensated value used in temperature & pressure calculations.
** \param[in] pCalib - Pointer to BMP180 calibration structure
** \param[in] UT - UT value (temperature data)
** \return B5 value (compensated temperature value)
**/
static int32_t NONNULL__ computeB5(const BMP180_t * pCpnt, const int32_t UT)
static int32_t NONNULL__ UT_To_B5(const BMP180_calib * const pCalib, const int32_t UT)
{
int32_t X1 = (UT - pCpnt->cfg.Calib.AC6) * pCpnt->cfg.Calib.AC5 / 32768;
int32_t X2 = pCpnt->cfg.Calib.MC * 2048 / (X1 + pCpnt->cfg.Calib.MD);
const int32_t X1 = (UT - pCalib->AC6) * pCalib->AC5 / 32768;
const int32_t X2 = pCalib->MC * 2048 / (X1 + pCalib->MD);
return X1 + X2;
}


/**!\brief Convert B5 compensated value to Celsius degrees
** \param[in] B5 - B5 value (compensated temperature value)
** \return Celsius degrees value
**/
static float B5_To_Celcius(const int32_t B5)
{
const int32_t t = (B5 + 8) / 16;
return ((float) t / 10.0f); // temperature given in 0.1°C (thus divide by 10 to get °C)
}


FctERR NONNULLX__(1) BMP180_Get_Pressure(BMP180_t * pCpnt, float * pres)
{
int32_t UT = 0, UP = 0, compp = 0;
int32_t x1, x2, b5, b6, x3, b3, p;
uint32_t b4, b7;
float t;
FctERR err = ERROR_OK;
int32_t UT = 0, UP = 0, compp = 0;
int32_t x1, x2, b6, x3, b3, p;
uint32_t b4, b7;
FctERR err = ERROR_OK;
const BMP180_calib * const pCalib = &pCpnt->cfg.Calib;

/* Get the raw pressure and temperature values */
#if !defined(BMP180_TST)
Expand All @@ -140,18 +141,22 @@ FctERR NONNULLX__(1) BMP180_Get_Pressure(BMP180_t * pCpnt, float * pres)
#endif

/* Temperature compensation */
b5 = computeB5(pCpnt, UT);
const int32_t b5 = UT_To_B5(pCalib, UT);

#if defined(BMP180_TST)
BMP180_Test_Result("B5", binEval(b5 == 2399));
#endif

/* Pressure compensation */
b6 = b5 - 4000;
x1 = (pCpnt->cfg.Calib.B2 * ((b6 * b6) / 4096)) / 2048;
x2 = pCpnt->cfg.Calib.AC2 * b6 / 2048;
x1 = (pCalib->B2 * ((b6 * b6) / 4096)) / 2048;
x2 = pCalib->AC2 * b6 / 2048;
x3 = x1 + x2;
b3 = ((((pCpnt->cfg.Calib.AC1 * 4) + x3) << pCpnt->cfg.OSS) + 2) / 4;
x1 = (pCpnt->cfg.Calib.AC3 * b6) / 8192;
x2 = (pCpnt->cfg.Calib.B1 * ((b6 * b6) / 4096)) / 65536;
b3 = ((((pCalib->AC1 * 4) + x3) << pCpnt->cfg.OSS) + 2) / 4;
x1 = (pCalib->AC3 * b6) / 8192;
x2 = (pCalib->B1 * ((b6 * b6) / 4096)) / 65536;
x3 = ((x1 + x2) + 2) / 4;
b4 = pCpnt->cfg.Calib.AC4 * (x3 + 32768) / 32768;
b4 = pCalib->AC4 * (x3 + 32768) / 32768;
b7 = (UP - b3) * (50000 >> pCpnt->cfg.OSS);

if (b7 < 0x80000000) { p = (b7 * 2) / b4; }
Expand All @@ -163,14 +168,15 @@ FctERR NONNULLX__(1) BMP180_Get_Pressure(BMP180_t * pCpnt, float * pres)
x2 = (-7357 * p) / 65536;
compp = p + ((x1 + x2 + 3791) / 16);

/* Assign compensated pressure value */
pCpnt->Pressure = compp / 100; // From kPa to hPa

t = ((float) b5 + 8) / 16;
pCpnt->Temperature = t / 10; // temperature given in 0.1�C (thus divide by 10 to get �C)
/* Set results */
pCpnt->Pressure = compp / 100; // From Pa to hPa (mbar)
pCpnt->Temperature = B5_To_Celcius(b5);
pCpnt->Altitude = Atmospheric_Pressure_To_Altitude(pCpnt->Pressure, pCpnt->cfg.SeaLevelPressure);

pCpnt->Altitude = BMP180_Pressure_To_Altitude(pCpnt->Pressure);
pCpnt->SeaLevelPressure = BMP180_seaLevel_Pressure_For_Altitude(pCpnt->Altitude, pCpnt->Pressure);
#if defined(BMP180_TST)
BMP180_Test_Result("Pressure", binEval(compp == 69994));
BMP180_Test_Result("Temperature", binEval(pCpnt->Temperature == 15));
#endif

if (pres) { *pres = pCpnt->Pressure; }

Expand All @@ -180,8 +186,7 @@ FctERR NONNULLX__(1) BMP180_Get_Pressure(BMP180_t * pCpnt, float * pres)

FctERR NONNULLX__(1) BMP180_Get_Temperature(BMP180_t * pCpnt, float * temp)
{
int32_t UT = 0, b5;
float t;
int32_t UT = 0;
FctERR err = ERROR_OK;

#if !defined(BMP180_TST)
Expand All @@ -191,10 +196,18 @@ FctERR NONNULLX__(1) BMP180_Get_Temperature(BMP180_t * pCpnt, float * temp)
UT = 27898; //!< For test purposes
#endif

b5 = computeB5(pCpnt, UT);
t = ((float) b5 + 8) / 16;
const int32_t b5 = UT_To_B5(&pCpnt->cfg.Calib, UT);

#if defined(BMP180_TST)
BMP180_Test_Result("B5", binEval(b5 == 2399));
#endif

pCpnt->Temperature = t / 10; // temperature given in 0.1�C (thus divide by 10 to get �C)
/* Set results */
pCpnt->Temperature = B5_To_Celcius(b5);

#if defined(BMP180_TST)
BMP180_Test_Result("Temperature", binEval(pCpnt->Temperature == 15));
#endif

if (temp) { *temp = pCpnt->Temperature; }

Expand All @@ -214,9 +227,9 @@ __WEAK FctERR NONNULL__ BMP180_handler(BMP180_t * pCpnt)

#if defined(VERBOSE)
const uint8_t idx = pCpnt - BMP180;
printf("BMP180 id%d: Pressure %ldhPa, Temperature %d.%02ld°C, Alt %ldm, Pressure at sea level %ldhPa\r\n",
printf("BMP180 id%d: Pressure %ldhPa, Temperature %d.%02ld°C, Alt %ldm, Pressure at sea level %ldhPa (for reference)\r\n",
idx, (int32_t) pCpnt->Pressure, (int16_t) pCpnt->Temperature, get_fp_dec(pCpnt->Temperature, 2),
(int32_t) pCpnt->Altitude, (int32_t) pCpnt->SeaLevelPressure);
(int32_t) pCpnt->Altitude, (int32_t) pCpnt->cfg.SeaLevelPressure);
#endif

return err;
Expand Down
17 changes: 12 additions & 5 deletions BMP180_proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "sarmfsw.h"
#include "BMP180.h"

#include "shared_APS.h"

#if defined(HAL_I2C_MODULE_ENABLED)
/****************************************************************/

Expand All @@ -24,8 +26,6 @@
// *****************************************************************************
#define BMP180_CHIP_ID 0x55 //!< BMP180 Chip ID to check against

#define SEA_LEVEL_PRESSURE 1013.25f //!< Sea pressure level (hPa)


// *****************************************************************************
// Section: Types
Expand Down Expand Up @@ -54,13 +54,13 @@ typedef struct BMP180_t {
float Pressure; //!< Current atmospheric pressure
float Temperature; //!< Current temperature
float Altitude; //!< Current altitude
float SeaLevelPressure; //!< Current atmospheric pressure at sea level
uint32_t hStartConversion; //!< Last conversion start tick
struct {
I2C_slave_t * slave_inst; //!< Slave structure
BMP180_oversampling OSS; //!< Oversampling
BMP180_calib Calib; //!< Calibration values
uint8_t ID; //!< Chip ID
float SeaLevelPressure; //!< Current atmospheric pressure at sea level
} cfg;
} BMP180_t;

Expand All @@ -74,6 +74,13 @@ extern BMP180_t BMP180[I2C_BMP180_NB]; //!< BMP180 User structure
/*** Procedures ***/
/******************/

/*!\brief Setter of Sea Level pressure for BMP180 peripheral
** \weak BMP180 Sea Level pressure setter may be user implemented
** \param[in] pCpnt - Pointer to BMP180 component
** \return FctERR - error code
**/
FctERR NONNULL__ BMP180_Set_SeaLevel_Pressure(BMP180_t * pCpnt);

/*!\brief Initialization Sequence for BMP180 peripheral
** \weak BMP180 Init sequence may be user implemented if custom initialization sequence needed
** \param[in] pCpnt - Pointer to BMP180 component
Expand All @@ -92,10 +99,10 @@ FctERR NONNULL__ BMP180_Set_Oversampling(BMP180_t * pCpnt, const BMP180_oversamp

/*!\brief Get calibration parameters from BMP180 peripheral
** \param[in] pCpnt - Pointer to BMP180 component
** \param[in,out] calib - pointer to calibration structure to read to
** \param[in,out] pCalib - pointer to calibration structure to read to
** \return FctERR - error code
**/
FctERR NONNULL__ BMP180_Get_Calibration(BMP180_t * pCpnt, BMP180_calib * calib);
FctERR NONNULL__ BMP180_Get_Calibration(BMP180_t * pCpnt, BMP180_calib * pCalib);

/*!\brief Gets the compensated pressure level
** \param[in] pCpnt - Pointer to BMP180 component
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ Please keep in mind some components are somewhat custom and needs to be accesses
## Multiple component type on single project (singleton components excluded)

- If multiple component type are used on the same MCU device:
- A for loop can be used passing I2C_$CPNT$ if all components are tied to the same i2C instance (physical bus)
- In case same multiple same component type are used on different physical busses, please pass each instance to $CPNT$_Init
- note: formerly, I2C_$CPNT$ was used to determine device type enabling (and its instance); as long as enabled with former I2C_$CPNT$, init function can be called using other params
- A for loop can be used passing I2C_$CPNT$ if all components are tied to the same i2C instance (physical bus)
- In case same multiple same component type are used on different physical busses, please pass each instance to $CPNT$_Init
- note: formerly, I2C_$CPNT$ was used to determine device type enabling (and its instance); as long as enabled with former I2C_$CPNT$, init function can be called using other params

## Following peripherals (?)

Expand All @@ -135,7 +135,7 @@ You may also:

## TODO

- Any RTOS compatibility (blocking transactions doesn't match with RTOS task timings)
- Any RTOS compatibility (blocking transactions doesn't match with RTOS task timings)
- (FreeRTOS) compatibility using R/W functions using interrupts with callbacks (when possible)

## Misc
Expand Down
14 changes: 8 additions & 6 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ SOFTWARE.
* strict aliasing types in printf statements
* Some informations added in components doxygen documentation for compatibility with other devices
* implementation of multiple peripheral of the same type (for devices that may most likely not being alone in a project)
- needed a few refactoring (inlines becoming functions / some typedefs moved)
- except: DS_GPMS, PCF8523 & DRV2605L
* needed a few refactoring (inlines becoming functions / some typedefs moved)
* except: DS_GPMS, PCF8523 & DRV2605L
* template update (splitted into singleton/multiple device(s))
* more NONNULL__ checks
* possibility to set different device base address than default set in header (at project level or in globals.h)
Expand All @@ -54,14 +54,15 @@ SOFTWARE.
* AT42QT1244: Few delay added between each communication for calibration pending in FHM setup procedure
* AT42QT1244: weak handler & init implementations
* BMP180: fixed temperature and pressure calculation (no use of unsigned LSHIFT or RSHIFT for signed calculations)
* BMP180: changes to allow (custom) intialization of sea level pressure for the component (relying on shared_APS module)
* DRV2605: fixed init following timeout configuration using defaults from structure
* FM24C: added possibility to customize FM24C_SIZE macro if needed
* MCP4725: Fixed general call function (transmit command, not receive), and taking I2C_HandleTypeDef pointer as parameter
* MTCH6102: 1ms delay between each transaction end has been added to ensure proper communication flow
* MTCH6102: As MTCH6102 seems somewhat erratic on first try when it comes to configure it, I often get default RX/TX number values after config performed with custom projects:
- added a while loop to test if parameters are taken into account (it works well the second time if not on the first time)...
- I already encountered a lot of issues with this chip, related to timing between transactions, power on, etc... mostly when it comes to configure chip or store to NV storage
- As the Datasheet is very light about these subjects (and I got no answers from Microchip), here are some workarounds that seems to be working all the time (so far)
* added a while loop to test if parameters are taken into account (it works well the second time if not on the first time)...
* I already encountered a lot of issues with this chip, related to timing between transactions, power on, etc... mostly when it comes to configure chip or store to NV storage
* As the Datasheet is very light about these subjects (and I got no answers from Microchip), here are some workarounds that seems to be working all the time (so far)
* MTCH6102: splitted init function into several functions (to also be able to store settings to Non-volatile storage)
* MTCH6102: period calculation doesn't use floats anymore to save some flash space
* MTCH6102: simplified MTCH6102_Get_MFG_Results
Expand All @@ -80,6 +81,7 @@ SOFTWARE.
* PCA9685: Refactoring and changes to handle PCA9685 outputs shifting (delay on)
* PCA9685: Dedicated functions to compute PWM register values (useful to manually fill an array with registers values to send multiple channels at once in one I2C transaction)
* README.md: updated (and added limitations section)
* shared_APS: added files for common code regarding ambient pressure sensing
* shared_ALS: added files for common code regarding ambient light sensing
* shared_CLS: added files for common code regarding color light sensing (RGB to chromacity CIE1931 xy conversion and CCT calculation)
* shared_CLS: double precision now single precision
Expand All @@ -105,7 +107,7 @@ SOFTWARE.
* rationalization of includes
* init sequence returns with error value if something goes wrong during initialization
* implementation of slave instance (slave_inst) in xxx_proc files (easier debug access to component structure except special cases)
* I2C_component: instance inst becomes bus_inst (new slave_inst implementation in xxx_proc files to avoid name confusions)
* I2C_component: instance inst becomes bus_inst (new slave_inst implementation in xxx_proc files to avoid name confusions)
* FM24C & MB85RC256V: added macros to create simple inlines to read/write values from addresses (to use in some header)
* MTCH6102: added standalone function for commands & inlines for configuration, restore to defaults & tests commands
* MTCH6102: added filtering type configuration function & inlines for configuration
Expand Down
2 changes: 0 additions & 2 deletions shared_ALS.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
/****************************************************************/
#include "shared_ALS.h"

#include "I2C_Component.h"

#if defined(HAL_I2C_MODULE_ENABLED)
#if defined(I2C_APDS9930) || defined(I2C_TSL2591)
/****************************************************************/
Expand Down
2 changes: 2 additions & 0 deletions shared_ALS.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include "sarmfsw.h"

#include "I2C_Component.h"

#if defined(HAL_I2C_MODULE_ENABLED)
/****************************************************************/

Expand Down
Loading

0 comments on commit 1e4787c

Please sign in to comment.