Skip to content

Instantly share code, notes, and snippets.

@ggirjau
Last active February 23, 2021 22:10
Show Gist options
  • Select an option

  • Save ggirjau/369d1520a21c7cf41413b00352446d61 to your computer and use it in GitHub Desktop.

Select an option

Save ggirjau/369d1520a21c7cf41413b00352446d61 to your computer and use it in GitHub Desktop.
BMP180 C library using STM32 I2C HAL driver
/*
* bmp180.c
*
* Created on: 27 feb. 2019
* Author: gheorghe.ghirjev
*/
#include <string.h>
#include <math.h>
#include "bmp180.h"
#include "stm32f7xx_hal.h"
// global struct to store all BMP180 main data.
bmp_t bmp;
extern I2C_HandleTypeDef hi2c1;
/*!
* @brief: - Read and check bmp chip ID.This value is fixed to 0x55,
* and can be used to check whether communication is functioning.
* @param[in] - NONE.
* @return - NO_ERR if chip_id is equal to 0x55, otherwise CHIP_ID_INVALID_ERR.
*/
static bmp_err_t read_chip_id (void)
{
uint8_t out_buff = 0;
uint8_t ret_val = NO_ERR;
HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_CHIP_ID_REG, 1, &out_buff, 1, BMP_I2C_TIMEOUT);
if (BMP_CHIP_ID_VAL != out_buff)
{
ret_val = CHIP_ID_INVALID_ERR;
}
return ret_val;
}
/*!
* @brief: - Write oversampling settings to the Control register.
* @param[in] - struct of type oss_t
* @param[in] - enum of type oss_ratio_t
* @return - None
*/
static void set_oss (oss_t * oss, oss_ratio_t ratio)
{
uint8_t in_buff[2] = {0};
switch (ratio)
{
case ULTRA_LOW_PWR_MODE:
{
oss->wait_time = BMP_OSS0_CONV_TIME;
break;
}
case STANDARD_MODE:
{
oss->wait_time = BMP_OSS1_CONV_TIME;
break;
}
case HIGH:
{
oss->wait_time = BMP_OSS2_CONV_TIME;
break;
}
case ULTRA_HIGH_RESOLUTION:
{
oss->wait_time = BMP_OSS3_CONV_TIME;
break;
}
default:
{
oss->wait_time = BMP_OSS1_CONV_TIME;
break;
}
}
oss->ratio = ratio;
BMP_SET_I2CRW_REG (in_buff[1], BMP_CTRL_OSS_MASK(ratio));
HAL_I2C_Mem_Write( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, in_buff, 2, BMP_I2C_TIMEOUT );
}
/*!
* @brief: - Read calibration BMP data. The E2PROM has stored 176 bit of individual calibration data.
* This is used to compensate offset, temperature dependence and other parameters of the sensor.
* @param[in] - struct of type bmp_calib_param_t
* @return - NO_ERR if read calibration data are valid otherwise READ_CALIB_ERR.
*/
static bmp_err_t read_calib_data (short * calib_data)
{
bmp_err_t ret_val = NO_ERR;
uint8_t out_buff[BMP_CALIB_DATA_SIZE] = {0};
uint8_t i = 0;
uint8_t j = 1;
HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_CALIB_ADDR, 1, out_buff, BMP_CALIB_DATA_SIZE, BMP_I2C_TIMEOUT);
// Store read calib data to bmp_calib struct.
for (i = 0; i <= BMP_CALIB_DATA_SIZE / 2; i++, j+2)
{
calib_data[i] = (out_buff[i * 2] << 8) | out_buff[j];
// checking that none of the words has the value 0 or 0xFFFF.
if ((0 == calib_data[i]) | (-1 == calib_data[i]))
{
ret_val = GET_CALIB_ERR;
}
}
return ret_val;
}
/*!
* @brief: - Performe initial sequence of BMP sensor
* @param[in] - pointer to struct of type bmp_calib_param_t
* @return - None.
*/
void bmp_init (bmp_t * bmp)
{
memset(bmp, 0x00, sizeof(&bmp)); // clear bmp strut;
bmp->err = read_chip_id (); // check chip validity and I2C communication.
bmp->err = read_calib_data ((short *)&bmp->calib);
set_oss (&bmp->oss, HIGH); // set oversampling settings
}
/*!
* @brief: - Get uncompensated temperature value. UT = temperature data (16 bit)
* @param[in] - None.
* @return - uncompensated temp.
*/
int32_t get_ut (void)
{
uint8_t out_buff[2];
BMP_SET_I2CRW_REG (out_buff[0], BMP_SET_TEMP_CONV);
HAL_I2C_Mem_Write( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, out_buff, 1, BMP_I2C_TIMEOUT );
HAL_Delay (BMP_TEMP_CONV_TIME);
HAL_I2C_Mem_Read ( &hi2c1, BMP_READ_ADDR, BMP_DATA_MSB_ADDR, 1, out_buff, 2, BMP_I2C_TIMEOUT );
return (out_buff[0] << BYTE_SHIFT) | out_buff[1];
}
/*!
* @brief: - Calc true temperature.
* @param[in] - pointer to struct of type bmp_t
* @return - true temp.
*/
float get_temp(bmp_t * bmp)
{
int32_t X1 = 0;
int32_t X2 = 0;
float temp = 0;
X1 = (((int32_t)bmp->uncomp.temp - bmp->calib.AC6) * bmp->calib.AC5) >> 15;
X2 = (bmp->calib.MC << 11) / (X1 + bmp->calib.MD);
bmp->data.B5 = X1 + X2;
temp = ((bmp->data.B5 + 8) >> 4) * 0.1f;
if ((temp <= BMP_MIN_TEMP_THRESHOLD) || (temp >= BMP_MAX_TEMP_THRESHOLD))
{
bmp->err = GET_TEMP_ERR;
}
return temp;
}
/*!
* @brief: - Get uncompensated pressure value. UP = pressure data (16 to 19 bit)
* @param[in] - struct of type oss_t
* @return - uncompensated pressure.
*/
int32_t get_up (oss_t oss)
{
uint8_t out_buff[3] = {0};
long up = 0;
BMP_SET_I2CRW_REG (out_buff[0], BMP_SET_PRESS_CONV);
HAL_I2C_Mem_Write ( &hi2c1, BMP_WRITE_ADDR, BMP_CTRL_REG, 1, out_buff, 1, BMP_I2C_TIMEOUT );
HAL_Delay (oss.wait_time);
HAL_I2C_Mem_Read(&hi2c1, BMP_READ_ADDR, BMP_DATA_MSB_ADDR, 1, out_buff, 3, BMP_I2C_TIMEOUT);
up = ((out_buff[0] << SHORT_SHIFT) + (out_buff[1] << BYTE_SHIFT) + out_buff[2]) >> (8 - oss.ratio);
return up;
}
/*!
* @brief: - Calc true pressure.
* @param[in] - struct of type bmp_t
* @return - true pressure in Pa.
*/
int32_t get_pressure(bmp_t bmp)
{
int32_t X1, X2, X3, B3, B6, p = 0;
uint32_t B4, B7 = 0;
B6 = bmp.data.B5 - 4000;
X1 = (bmp.calib.B2 * (B6 * B6 / 0x1000)) / 0x800;
X2 = bmp.calib.AC2 * B6 / 0x800;
X3 = X1 + X2;
B3 = (((bmp.calib.AC1 * 4 + X3) << bmp.oss.ratio) +2) / 4;
X1 = bmp.calib.AC3 * B6 / 0x2000;
X2 = (bmp.calib.B1 * (B6 * B6 / 0x1000)) / 0x10000;
X3 = ((X1 + X2) + 2) / 0x4;
B4 = bmp.calib.AC4 * (unsigned long)(X3 + 32768) / 0x8000;
B7 = ((unsigned long)bmp.uncomp.press - B3) * (50000 >> bmp.oss.ratio);
if (B7 < 0x80000000)
{
p = (B7 * 2) / B4;
}
else
{
p = (B7 / B4) * 2;
}
X1 = (p / 0x100 * (p / 0x100));
X1 = (X1 * 3038) / 0x10000;
X2 = (-7357 * p) / 0x10000;
p = p + (X1 + X2 + 3791) / 0x10;
return p;
}
/*!
* @brief: - Calc true altitude.
* @param[in] - struct of type bmp_t
* @return - true pressure.
*/
float get_altitude (bmp_t * bmp)
{
float altitude = 0;
altitude = BMP_PRESS_CONST_COEFICIENT * (1.0f - pow((bmp->data.press / BMP_PRESS_CONST_SEA_LEVEL), (1/5.255)));
if ((altitude <= BMP_MIN_ALT_THRESHOLD) || (altitude >= BMP_MAX_ALT_THRESHOLD))
{
bmp->err = GET_ALTITUDE_ERR;
}
return altitude;
}
/*
* bmp180.h
*
* Created on: 27 feb. 2019
* Author: gheorghe.ghirjev
*/
#ifndef BMP180_H_
#define BMP180_H_
#include "stdint.h"
// Data type definitions:
#define BYTE_SHIFT (8U)
#define SHORT_SHIFT (16U)
/* Chip-id [R/O] (register D0h): This value is fixed to 0x55,
* and can be used to check whether communication is functioning. */
#define BMP_CHIP_ID_REG (0xD0)
#define BMP_CHIP_ID_VAL (0x55)
/* Measurement control [R/W] (register F4h):
* <4:0> - Controls measurements.
* <5> - SCO : Start of conversion. The value of this bit stays “1” during conversion,
* and is reset to “0” after conversion is complete
* <7:6> - OSS : Controls the oversampling ratio of the pressure measurement
*/
#define BMP_CTRL_REG (0xF4)
#define BMP_CTRL_SCO_BIT(reg) ((reg & 0x20) >> 5)
#define BMP_CTRL_OSS_MASK(oss) (oss = (oss & 0x3) << 6)
#define BMP_OSS0_CONV_TIME (5U)
#define BMP_OSS1_CONV_TIME (8U)
#define BMP_OSS2_CONV_TIME (14U)
#define BMP_OSS3_CONV_TIME (26U)
/* Soft reset [W/O] (register E0h):
* If set to 0xB6, will perform the same sequence as power on reset. */
#define BMP_SOFT_RST_REG (0xE0)
#define BMP_SOFT_RST_VAL (0xB6)
// Calibration data [R/O] (register AAh up to BFh):
#define BMP_CALIB_ADDR (0xAA)
#define BMP_CALIB_DATA_SIZE (22U)
// Device I2C addr register [R/O]: write EEh, read EFh:
#define BMP_READ_ADDR (0xEF)
#define BMP_WRITE_ADDR (0xEE)
#define BMP_I2C_TIMEOUT (50U)
#define BMP_SET_I2CRW_REG(i2c_buff, reg) (i2c_buff = reg)
// BMP measurmenet regs
#define BMP_DATA_MSB_ADDR (0xF6)
#define BMP_DATA_LSB_ADDR (0xF7)
#define BMP_DATA_XLSB_ADDR (0xF8)
// Temp. measurement :
#define BMP_SET_TEMP_CONV (0x2E)
#define BMP_TEMP_CONV_TIME (5U)
#define BMP_MIN_TEMP_THRESHOLD (-40)
#define BMP_MAX_TEMP_THRESHOLD (85U)
// Pressure measurment :
#define BMP_SET_PRESS_CONV (0x34)
#define BMP_PRESS_CONST_SEA_LEVEL (101325.0f) // pressure in Pa
#define BMP_PRESS_CONST_COEFICIENT (44330.0f)
// Altitude measurment :
#define BMP_MIN_ALT_THRESHOLD (-500) // m. relating to sea level)
#define BMP_MAX_ALT_THRESHOLD (9000U) // m. relating to sea level)
struct bmp_calib_param_t
{
int16_t AC1;
int16_t AC2;
int16_t AC3;
uint16_t AC4;
uint16_t AC5;
uint16_t AC6;
int16_t B1;
int16_t B2;
int16_t MB;
int16_t MC;
int16_t MD;
};
struct measure_data_t
{
float temp;
int32_t press;
/* for uncompensated values do not use below fields: */
int32_t B5;
float altitude;
};
typedef enum
{
ULTRA_LOW_PWR_MODE = 0,
STANDARD_MODE,
HIGH,
ULTRA_HIGH_RESOLUTION
} oss_ratio_t;
typedef struct
{
oss_ratio_t ratio;
uint8_t wait_time;
}oss_t;
typedef enum
{
NO_ERR = 0,
CHIP_ID_INVALID_ERR,
GET_CALIB_ERR,
GET_TEMP_ERR,
GET_PRESSURE_ERR,
GET_ALTITUDE_ERR
} bmp_err_t;
typedef struct
{
struct bmp_calib_param_t calib;
struct measure_data_t uncomp; // uncompensated values
struct measure_data_t data;
oss_t oss;
bmp_err_t err;
}bmp_t;
/*!
* @brief: - Performe initial sequence of BMP180 sensor.
* @param[in] - pointer to struct of type bmp_calib_param_t
* @return - None.
*/
void bmp_init (bmp_t * bmp);
/*!
* @brief: - Read oversampling settings from CTRL reg F4h.
* Oss (register F4h <7:6>): controls the oversampling ratio of the pressure measurement
* (00b: single, 01b: 2 times, 10b: 4 times, 11b: 8 times).
* @param[in] - None.
* @return - None.
*/
static void set_oss (oss_t * oss, oss_ratio_t ratio);
/*!
* @brief: - Get uncompensated temperature value.
* @param[in] - None.
* @return - uncompensated temp.
*/
int32_t get_ut (void);
/*!
* @brief: - Calc true temperature.
* @param[in] - pointer to struct of type bmp_t
* @return - true temp.
*/
float get_temp(bmp_t * bmp);
/*!
* @brief: - Get uncompensated pressure value.
* @param[in] - oss - conversion time.
* @return - uncompensated pressure.
*/
int32_t get_up (oss_t oss);
/*!
* @brief: - Calc true pressure.
* @param[in] - struct of type bmp_t
* @return - true pressure in Pa.
*/
int32_t get_pressure(bmp_t bmp);
/*!
* @brief: - Calc true altitude.
* @param[in] - struct of type bmp_t
* @return - altitude in meters.
*/
float get_altitude (bmp_t * bmp);
#endif /* BMP180_H_ */
@ggirjau
Copy link
Author

ggirjau commented Mar 21, 2019

C library for BMP180 digital pressure sensor, link
Tis library is destinated for Cortex M7 MCU Hardware, to use it on another ARM Cortex board change the inclusion
#include "stm32f7xx_hal.h" in bmp180.c to needed stm32fX header.

The following code is the API calling in your main function :
bmp_t bmp;

main () {
bmp_init (&bmp);
while (1) {
bmp.uncomp.temp = get_ut ();
bmp.data.temp = get_temp (&bmp);
bmp.uncomp.press = get_up (bmp.oss);
bmp.data.press = get_pressure (bmp);
bmp.data.altitude = get_altitude (&bmp);
}

@Novalanugrah
Copy link

Hello, I'm grateful for the library that was created,
but after I compailer an error occurred.

error lies when I initialize
bmp_init (& bmp);
'bmp' undeclared (first use in this function); did you mean 'bmp_t'?

@OmarAgundis
Copy link

Hello.
First of all, thank you very much for all the material you provided.
I have been trying to make it work on a STM32H747 board, which is double core.
I download the program on the CM4 core which is suitable for my application. The problem is that when I try to read the values, temperature stands on 0 °C and Pressure on 236.
It is very strange becouse when I make the reading of uncompensated values I can see the oscilating on time.
The I2C comunication is working by the way.
I don't know if you have any more specific example so you can provided it.
I would really apreciate that.

Thank you very much in advance.

@inflamerzt
Copy link

inflamerzt commented Jan 15, 2021

Hello, I'm grateful for the library that was created,
but after I compailer an error occurred.

error lies when I initialize
bmp_init (& bmp);
'bmp' undeclared (first use in this function); did you mean 'bmp_t'?

you must add definition of "bmp" at main.c


bmp_t bmp;

main () {
bmp_init (&bmp);
while (1) {
bmp.uncomp.temp = get_ut ();
bmp.data.temp = get_temp (&bmp);
bmp.uncomp.press = get_up (bmp.oss);
bmp.data.press = get_pressure (bmp);
bmp.data.altitude = get_altitude (&bmp);
}

@ggirjau
Copy link
Author

ggirjau commented Jan 20, 2021

Hello

Sorry for missing "bmp_t bmp;" declaration in main.c file
Thanks @inflamerzt for helping with missing line. I've updated description comment !

Best Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment