diff --git a/examples/bmp280/bmp280_example.c b/examples/bmp280/bmp280_example.c index 625a60e..6621158 100644 --- a/examples/bmp280/bmp280_example.c +++ b/examples/bmp280/bmp280_example.c @@ -6,43 +6,55 @@ #include "FreeRTOS.h" #include "task.h" +#include "i2c/i2c.h" #include "bmp280/bmp280.h" // In forced mode user initiate measurement each time. // In normal mode measurement is done continuously with specified standby time. // #define MODE_FORCED -const uint8_t scl_pin = 5; -const uint8_t sda_pin = 4; +const uint8_t scl_pin = 0; +const uint8_t sda_pin = 2; #ifdef MODE_FORCED static void bmp280_task_forced(void *pvParameters) { bmp280_params_t params; - float pressure, temperature; + float pressure, temperature, humidity; bmp280_init_default_params(¶ms); params.mode = BMP280_MODE_FORCED; + bmp280_t bmp280_dev; + bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; + while (1) { - while (!bmp280_init(¶ms, scl_pin, sda_pin)) { + while (!bmp280_init(&bmp280_dev, ¶ms)) { printf("BMP280 initialization failed\n"); vTaskDelay(1000 / portTICK_RATE_MS); } + bool bme280p = bmp280_dev.id == BME280_CHIP_ID; + printf("BMP280: found %s\n", bme280p ? "BME280" : "BMP280"); + while(1) { vTaskDelay(1000 / portTICK_RATE_MS); - if (!bmp280_force_measurement()) { + if (!bmp280_force_measurement(&bmp280_dev)) { printf("Failed initiating measurement\n"); break; } - while (bmp280_is_measuring()) {}; // wait for measurement to complete + // wait for measurement to complete + while (bmp280_is_measuring(&bmp280_dev)) {}; - if (!bmp280_read(&temperature, &pressure)) { + if (!bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity)) { printf("Temperature/pressure reading failed\n"); break; } - printf("Pressure: %.2f Pa, Temperature: %.2f C\n", pressure, temperature); + printf("Pressure: %.2f Pa, Temperature: %.2f C", pressure, temperature); + if (bme280p) + printf(", Humidity: %.2f\n", humidity); + else + printf("\n"); } } } @@ -50,22 +62,33 @@ static void bmp280_task_forced(void *pvParameters) static void bmp280_task_normal(void *pvParameters) { bmp280_params_t params; - float pressure, temperature; + float pressure, temperature, humidity; bmp280_init_default_params(¶ms); + + bmp280_t bmp280_dev; + bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; + while (1) { - while (!bmp280_init(¶ms, scl_pin, sda_pin)) { + while (!bmp280_init(&bmp280_dev, ¶ms)) { printf("BMP280 initialization failed\n"); vTaskDelay(1000 / portTICK_RATE_MS); } + bool bme280p = bmp280_dev.id == BME280_CHIP_ID; + printf("BMP280: found %s\n", bme280p ? "BME280" : "BMP280"); + while(1) { vTaskDelay(1000 / portTICK_RATE_MS); - if (!bmp280_read(&temperature, &pressure)) { + if (!bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity)) { printf("Temperature/pressure reading failed\n"); break; } - printf("Pressure: %.2f Pa, Temperature: %.2f C\n", pressure, temperature); + printf("Pressure: %.2f Pa, Temperature: %.2f C", pressure, temperature); + if (bme280p) + printf(", Humidity: %.2f\n", humidity); + else + printf("\n"); } } } @@ -80,6 +103,8 @@ void user_init(void) printf("SDK version : %s\n", sdk_system_get_sdk_version()); printf("GIT version : %s\n", GITSHORTREV); + i2c_init(scl_pin, sda_pin); + #ifdef MODE_FORCED xTaskCreate(bmp280_task_forced, (signed char *)"bmp280_task", 256, NULL, 2, NULL); #else diff --git a/extras/bmp280/README.md b/extras/bmp280/README.md index 64ffc1c..9faed88 100644 --- a/extras/bmp280/README.md +++ b/extras/bmp280/README.md @@ -1,10 +1,10 @@ -# Driver for BMP280 absolute barometric pressure sensor +# Driver for BMP280 and BME280 absolute barometric pressure sensors -The driver works only with BMP280 sensor. For BMP080/BMP180 there's a separate -driver. Even though BMP280 is a successor of BMP180 they are not compatible. -They have different registers and different operation modes. -BMP280 supports two ways of communication: spi and i2c. -This driver provides only i2c communication. +The driver works only with BMP280 and BME280 sensors. For BMP080/BMP180 there's +a separate driver. Even though BMP280 is a successor of BMP180 they are not +compatible. They have different registers and different operation modes. +BMP280 supports two ways of communication: spi and i2c. This driver provides +only i2c communication. The driver is written for [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos) framework and requires [i2c driver](https://github.com/SuperHouse/esp-open-rtos/tree/master/extras/i2c) from it. @@ -18,17 +18,21 @@ from it. ## Usage -Connect BMP280 module to you ESP8266 module and specify SCL and SDA pins: +Connect BMP280 or BME280 module to you ESP8266 module and initialize the I2C SCL and SDA pins: ``` -const uint8_t scl_pin = 5; -const uint8_t sda_pin = 4; +const uint8_t scl_pin = 0; +const uint8_t sda_pin = 2; +i2c_init(scl_pin, sda_pin); + ``` -Pull up SDO pin of BMP280 in order to have address 0x77. -Or pull down SDO pin and change `#define BMP280_ADDRESS 0x77` to -`#define BMP280_ADDRESS 0x76`. Otherwise your sensor will not work. -By default address 0x77 is used, so SDO pin should be high. +Pull up SDO pin of BMP280 in order to have address 0x77 `BMP280_I2C_ADDRESS_1`. +Or pull down SDO pin for address 0x76 `BMP280_I2C_ADDRESS_0`. Otherwise your +sensor will not work. + +The BMP280 or BME280 are auto-detected at initialization based on the chip ID +and this ID is stored in the device descriptor. BMP280 supports two operation modes. @@ -48,22 +52,27 @@ whose time is defined by standby_time. ### Forced mode ``` -const uint8_t scl_pin = 5; -const uint8_t sda_pin = 4; bmp280_params_t params; -float pressure, temperature; +float pressure, temperature, humidity; bmp280_init_default_params(¶ms); params.mode = BMP280_MODE_FORCED; -bmp280_init(¶ms, scl_pin, sda_pin); -while (1) { - bmp280_force_measurement(); - while (bmp280_is_measuring()) {}; // wait for measurement to complete +bmp280_t bmp280_dev; +bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; +bmp280_init(&bmp280_dev, ¶ms); +bool bme280p = bmp280_dev.id == BME280_CHIP_ID; - bmp280_read(&temperature, &pressure); - printf("Pressure: %.2f Pa, Temperature: %.2f C\n", pressure, temperature); - vTaskDelay(1000 / portTICK_RATE_MS); +while(1) { + bmp280_force_measurement(&bmp280_dev)); + // wait for measurement to complete + while (bmp280_is_measuring(&bmp280_dev)) {}; + + bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity); + printf("Pressure: %.2f Pa, Temperature: %.2f C", pressure, temperature); + if (bme280p) + printf(", Humidity: %.2f\n", humidity); + vTaskDelay(1000 / portTICK_RATE_MS); } ``` @@ -71,15 +80,23 @@ while (1) { ``` bmp280_params_t params; -float pressure, temperature; +float pressure, temperature, humidity; bmp280_init_default_params(¶ms); -bmp280_init(¶ms, scl_pin, sda_pin); -while (1) { - bmp280_read(&temperature, &pressure); - printf("Pressure: %.2f Pa, Temperature: %.2f C\n", pressure, temperature); - vTaskDelay(1000 / portTICK_RATE_MS); +bmp280_t bmp280_dev; +bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; +bmp280_init(&bmp280_dev, ¶ms); +bool bme280p = bmp280_dev.id == BME280_CHIP_ID; + +while(1) { + bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity); + printf("Pressure: %.2f Pa, Temperature: %.2f C", pressure, temperature); + if (bme280p) + printf(", Humidity: %.2f\n", humidity); + else + printf("\n"); + vTaskDelay(1000 / portTICK_RATE_MS); } ``` diff --git a/extras/bmp280/bmp280.c b/extras/bmp280/bmp280.c index b880254..ab81dae 100644 --- a/extras/bmp280/bmp280.c +++ b/extras/bmp280/bmp280.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include "bmp280.h" #include "i2c/i2c.h" - #ifdef BMP280_DEBUG #include #define debug(fmt, ...) printf("%s" fmt "\n", "bmp280: ", ## __VA_ARGS__); @@ -46,116 +46,150 @@ #define BMP280_REG_CONFIG 0xF5 /* bits: 7-5 t_sb; 4-2 filter; 0 spi3w_en */ #define BMP280_REG_CTRL 0xF4 /* bits: 7-5 osrs_t; 4-2 osrs_p; 1-0 mode */ #define BMP280_REG_STATUS 0xF3 /* bits: 3 measuring; 0 im_update */ +#define BMP280_REG_CTRL_HUM 0xF2 /* bits: 2-0 osrs_h; */ #define BMP280_REG_RESET 0xE0 #define BMP280_REG_ID 0xD0 #define BMP280_REG_CALIB 0x88 +#define BMP280_REG_HUM_CALIB 0x88 -#define BMP280_CHIP_ID 0x58 /* BMP280 has chip-id 0x58 */ #define BMP280_RESET_VALUE 0xB6 -typedef struct __attribute__((packed)) { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; -} BMP280_Calib; - -static BMP280_Calib calib_data; void bmp280_init_default_params(bmp280_params_t *params) { params->mode = BMP280_MODE_NORMAL; params->filter = BMP280_FILTER_OFF; params->oversampling = BMP280_STANDARD; + params->oversampling_humidity = BMP280_STANDARD; params->standby = BMP280_STANDBY_250; } -static uint8_t read_register8(uint8_t addr) +static bool read_register16(uint8_t i2c_addr, uint8_t addr, uint16_t *value) { - uint8_t r = 0; - if (!i2c_slave_read(BMP280_ADDRESS, addr, &r, 1)) { - r = 0; - } - return r; -} - -/** - * Even though value is signed the actual value is always positive. - * So, no need to take care of sign bit. - */ -static bool read_register24(uint8_t addr, int32_t *value) -{ - uint8_t d[] = {0, 0, 0}; - if (i2c_slave_read(BMP280_ADDRESS, addr, d, sizeof(d))) { - *value = d[0]; - *value <<= 8; - *value |= d[1]; - *value <<= 4; - *value |= d[2]>>4; + uint8_t d[] = {0, 0}; + if (i2c_slave_read(i2c_addr, addr, d, sizeof(d))) { + *value = d[0] | (d[1] << 8); return true; } return false; } -static bool check_chip_id() +static bool read_calibration_data(bmp280_t *dev) { - return (read_register8(BMP280_REG_ID)==BMP280_CHIP_ID); -} + uint8_t i2c_addr = dev->i2c_addr; -static bool read_calibration_data() -{ - if (!i2c_slave_read(BMP280_ADDRESS, BMP280_REG_CALIB, - (uint8_t*)&calib_data, sizeof(calib_data))) { - return false; + if (read_register16(i2c_addr, 0x88, &dev->dig_T1) && + read_register16(i2c_addr, 0x8a, (uint16_t *)&dev->dig_T2) && + read_register16(i2c_addr, 0x8c, (uint16_t *)&dev->dig_T3) && + read_register16(i2c_addr, 0x8e, &dev->dig_P1) && + read_register16(i2c_addr, 0x90, (uint16_t *)&dev->dig_P2) && + read_register16(i2c_addr, 0x92, (uint16_t *)&dev->dig_P3) && + read_register16(i2c_addr, 0x94, (uint16_t *)&dev->dig_P4) && + read_register16(i2c_addr, 0x96, (uint16_t *)&dev->dig_P5) && + read_register16(i2c_addr, 0x98, (uint16_t *)&dev->dig_P6) && + read_register16(i2c_addr, 0x9a, (uint16_t *)&dev->dig_P7) && + read_register16(i2c_addr, 0x9c, (uint16_t *)&dev->dig_P8) && + read_register16(i2c_addr, 0x9e, (uint16_t *)&dev->dig_P9)) { + + debug("Calibration data received:"); + debug("dig_T1=%d", dev->dig_T1); + debug("dig_T2=%d", dev->dig_T2); + debug("dig_T3=%d", dev->dig_T3); + debug("dig_P1=%d", dev->dig_P1); + debug("dig_P2=%d", dev->dig_P2); + debug("dig_P3=%d", dev->dig_P3); + debug("dig_P4=%d", dev->dig_P4); + debug("dig_P5=%d", dev->dig_P5); + debug("dig_P6=%d", dev->dig_P6); + debug("dig_P7=%d", dev->dig_P7); + debug("dig_P8=%d", dev->dig_P8); + debug("dig_P9=%d", dev->dig_P9); + + return true; } - debug("Calibration data received:"); - debug("dig_T1=%d", calib_data.dig_T1); - debug("dig_T2=%d", calib_data.dig_T2); - debug("dig_T3=%d", calib_data.dig_T3); - debug("dig_P1=%d", calib_data.dig_P1); - debug("dig_P2=%d", calib_data.dig_P2); - debug("dig_P3=%d", calib_data.dig_P3); - debug("dig_P4=%d", calib_data.dig_P4); - debug("dig_P5=%d", calib_data.dig_P5); - debug("dig_P6=%d", calib_data.dig_P6); - debug("dig_P7=%d", calib_data.dig_P7); - debug("dig_P8=%d", calib_data.dig_P8); - debug("dig_P9=%d", calib_data.dig_P9); - return true; + + return false; } -static bool write_register8(uint8_t addr, uint8_t value) +static bool read_hum_calibration_data(bmp280_t *dev) +{ + uint8_t i2c_addr = dev->i2c_addr; + uint16_t h4, h5; + + if (i2c_slave_read(i2c_addr, 0xa1, &dev->dig_H1, 1) && + read_register16(i2c_addr, 0xe1, (uint16_t *)&dev->dig_H2) && + i2c_slave_read(i2c_addr, 0xe3, &dev->dig_H3, 1) && + read_register16(i2c_addr, 0xe4, &h4) && + read_register16(i2c_addr, 0xe5, &h5) && + i2c_slave_read(i2c_addr, 0xe7, (uint8_t *)&dev->dig_H6, 1)) { + dev->dig_H4 = (h4 & 0x00ff) << 4 | (h4 & 0x0f00) >> 8; + dev->dig_H5 = h5 >> 4; + debug("Calibration data received:"); + debug("dig_H1=%d", dev->dig_H1); + debug("dig_H2=%d", dev->dig_H2); + debug("dig_H3=%d", dev->dig_H3); + debug("dig_H4=%d", dev->dig_H4); + debug("dig_H5=%d", dev->dig_H5); + debug("dig_H6=%d", dev->dig_H6); + return true; + } + + return false; +} + +static bool write_register8(uint8_t i2c_addr, uint8_t addr, uint8_t value) { uint8_t d[] = {addr, value}; - return i2c_slave_write(BMP280_ADDRESS, d, 2); + return i2c_slave_write(i2c_addr, d, 2); } -bool bmp280_init(bmp280_params_t *params, uint8_t scl_pin, uint8_t sda_pin) +bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) { - i2c_init(scl_pin, sda_pin); - if (!check_chip_id()) { - debug("Sensor not found or wrong sensor version"); + uint8_t i2c_addr = dev->i2c_addr; + + if (i2c_addr != BMP280_I2C_ADDRESS_0 && i2c_addr != BMP280_I2C_ADDRESS_1) { + debug("Invalid I2C address"); return false; } - if (!read_calibration_data()) { + if (!i2c_slave_read(i2c_addr, BMP280_REG_ID, &dev->id, 1)) { + debug("Sensor not found"); + return false; + } + + if (dev->id != BMP280_CHIP_ID && dev->id != BME280_CHIP_ID) { + debug("Sensor wrong version"); + return false; + } + + // Soft reset. + if (!write_register8(i2c_addr, BMP280_REG_RESET, BMP280_RESET_VALUE)) { + debug("Failed resetting sensor"); + return false; + } + + // Wait until finished copying over the NVP data. + while (1) { + uint8_t status; + if (i2c_slave_read(i2c_addr, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0) + break; + } + + if (!read_calibration_data(dev)) { debug("Failed to read calibration data"); return false; } + if (dev->id == BME280_CHIP_ID && !read_hum_calibration_data(dev)) { + debug("Failed to read humidity calibration data"); + return false; + } + uint8_t config = (params->standby << 5) | (params->filter << 2); debug("Writing config reg=%x", config); - if (!write_register8(BMP280_REG_CONFIG, config)) { + if (!write_register8(i2c_addr, BMP280_REG_CONFIG, config)) { debug("Failed configuring sensor"); return false; } @@ -170,31 +204,47 @@ bool bmp280_init(bmp280_params_t *params, uint8_t scl_pin, uint8_t sda_pin) uint8_t ctrl = (oversampling_temp << 5) | (params->oversampling << 2) | (params->mode); + + if (dev->id == BME280_CHIP_ID) { + // Write crtl hum reg first, only active after write to BMP280_REG_CTRL. + uint8_t ctrl_hum = params->oversampling_humidity; + debug("Writing ctrl hum reg=%x", ctrl_hum); + if (!write_register8(i2c_addr, BMP280_REG_CTRL_HUM, ctrl_hum)) { + debug("Failed controlling sensor"); + return false; + } + } + debug("Writing ctrl reg=%x", ctrl); - if (!write_register8(BMP280_REG_CTRL, ctrl)) { + if (!write_register8(i2c_addr, BMP280_REG_CTRL, ctrl)) { debug("Failed controlling sensor"); return false; } + return true; } -bool bmp280_force_measurement() +bool bmp280_force_measurement(bmp280_t *dev) { - uint8_t ctrl = read_register8(BMP280_REG_CTRL); + uint8_t ctrl; + if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_CTRL, &ctrl, 1)) + return false; ctrl &= ~0b11; // clear two lower bits ctrl |= BMP280_MODE_FORCED; debug("Writing ctrl reg=%x", ctrl); - if (!write_register8(BMP280_REG_CTRL, ctrl)) { + if (!write_register8(dev->i2c_addr, BMP280_REG_CTRL, ctrl)) { debug("Failed starting forced mode"); return false; } return true; } -bool bmp280_is_measuring() +bool bmp280_is_measuring(bmp280_t *dev) { - uint8_t status = read_register8(BMP280_REG_STATUS); - if (status & (1<<3)) { + uint8_t status; + if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_STATUS, &status, 1)) + return false; + if (status & (1 << 3)) { debug("Status: measuring"); return true; } @@ -207,82 +257,130 @@ bool bmp280_is_measuring() * * Return value is in degrees Celsius. */ -static inline float compensate_temperature(int32_t raw_temp, int32_t *fine_temp) +static inline int32_t compensate_temperature(bmp280_t *dev, + int32_t adc_temp, int32_t *fine_temp) { - int32_t var1, var2, T; + int32_t var1, var2; - var1 = ((((raw_temp>>3) - ((int32_t)calib_data.dig_T1<<1))) - * ((int32_t)calib_data.dig_T2)) >> 11; - - var2 = (((((raw_temp>>4) - ((int32_t)calib_data.dig_T1)) - * ((raw_temp>>4) - ((int32_t)calib_data.dig_T1))) >> 12) - * ((int32_t)calib_data.dig_T3)) >> 14; + var1 = ((((adc_temp >> 3) - ((int32_t)dev->dig_T1 << 1))) + * (int32_t)dev->dig_T2) >> 11; + var2 = (((((adc_temp >> 4) - (int32_t)dev->dig_T1) + * ((adc_temp >> 4) - (int32_t)dev->dig_T1)) >> 12) + * (int32_t)dev->dig_T3) >> 14; *fine_temp = var1 + var2; - T = (*fine_temp * 5 + 128) >> 8; - return (float)T/100; + return (*fine_temp * 5 + 128) >> 8; } /** * Compensation algorithm is taken from BMP280 datasheet. * - * Return value is in Pa. + * Return value is in Pa, 24 integer bits and 8 fractional bits. */ -static inline float compensate_pressure(int32_t raw_press, int32_t fine_temp) +static inline uint32_t compensate_pressure(bmp280_t *dev, + int32_t adc_press, int32_t fine_temp) { int64_t var1, var2, p; - var1 = ((int64_t)fine_temp) - 128000; - var2 = var1 * var1 * (int64_t)calib_data.dig_P6; - var2 = var2 + ((var1*(int64_t)calib_data.dig_P5)<<17); - var2 = var2 + (((int64_t)calib_data.dig_P4)<<35); - var1 = ((var1 * var1 * (int64_t)calib_data.dig_P3)>>8) + - ((var1 * (int64_t)calib_data.dig_P2)<<12); - var1 = (((((int64_t)1)<<47)+var1))*((int64_t)calib_data.dig_P1)>>33; + var1 = (int64_t)fine_temp - 128000; + var2 = var1 * var1 * (int64_t)dev->dig_P6; + var2 = var2 + ((var1 * (int64_t)dev->dig_P5) << 17); + var2 = var2 + (((int64_t)dev->dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)dev->dig_P3) >> 8) + + ((var1 * (int64_t)dev->dig_P2) << 12); + var1 = (((int64_t)1 << 47) + var1) * ((int64_t)dev->dig_P1) >> 33; if (var1 == 0) { return 0; // avoid exception caused by division by zero } - p = 1048576 - raw_press; - p = (((p<<31) - var2)*3125) / var1; - var1 = (((int64_t)calib_data.dig_P9) * (p>>13) * (p>>13)) >> 25; - var2 = (((int64_t)calib_data.dig_P8) * p) >> 19; + p = 1048576 - adc_press; + p = (((p << 31) - var2) * 3125) / var1; + var1 = ((int64_t)dev->dig_P9 * (p >> 13) * (p >> 13)) >> 25; + var2 = ((int64_t)dev->dig_P8 * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((int64_t)calib_data.dig_P7)<<4); - return (float)p/256; + p = ((p + var1 + var2) >> 8) + ((int64_t)dev->dig_P7 << 4); + return p; } -bool bmp280_read(float *temperature, float *pressure) +/** + * Compensation algorithm is taken from BME280 datasheet. + * + * Return value is in Pa, 24 integer bits and 8 fractional bits. + */ +static inline uint32_t compensate_humidity(bmp280_t *dev, + int32_t adc_hum, int32_t fine_temp) { - int32_t raw_pressure; - int32_t raw_temp; + int32_t v_x1_u32r; + + v_x1_u32r = fine_temp - (int32_t)76800; + v_x1_u32r = ((((adc_hum << 14) - ((int32_t)dev->dig_H4 << 20) - + ((int32_t)dev->dig_H5 * v_x1_u32r)) + + (int32_t)16384) >> 15) * + (((((((v_x1_u32r * (int32_t)dev->dig_H6) >> 10) * + (((v_x1_u32r * (int32_t)dev->dig_H3) >> 11) + + (int32_t)32768)) >> 10) + (int32_t)2097152) * + (int32_t)dev->dig_H2 + 8192) >> 14); + v_x1_u32r = v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + (int32_t)dev->dig_H1) >> 4); + v_x1_u32r = v_x1_u32r < 0 ? 0 : v_x1_u32r; + v_x1_u32r = v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r; + return v_x1_u32r >> 12; +} + +bool bmp280_read_fixed(bmp280_t *dev, int32_t *temperature, + uint32_t *pressure, uint32_t *humidity) +{ + int32_t adc_pressure; + int32_t adc_temp; + uint8_t data[8]; + + // Only the BME280 supports reading the humidity. + if (dev->id != BME280_CHIP_ID) { + if (humidity) + *humidity = 0; + humidity = NULL; + } + + // Need to read in one sequence to ensure they match. + size_t size = humidity ? 8 : 6; + if (!i2c_slave_read(dev->i2c_addr, 0xf7, data, size)) { + debug("Failed reading"); + return false; + } + + adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4; + adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4; + debug("ADC temperature: %d", adc_temp); + debug("ADC pressure: %d", adc_pressure); + int32_t fine_temp; + *temperature = compensate_temperature(dev, adc_temp, &fine_temp); + *pressure = compensate_pressure(dev, adc_pressure, fine_temp); - if (!read_register24(BMP280_REG_TEMP, &raw_temp)) { - debug("Failed reading temperature"); - return false; + if (humidity) { + int32_t adc_humidity = data[6] << 8 | data[7]; + debug("ADC humidity: %d", adc_humidity); + *humidity = compensate_humidity(dev, adc_humidity, fine_temp); } - if (!read_register24(BMP280_REG_PRESSURE, &raw_pressure)) { - debug("Failed reading pressure"); - return false; - } - - debug("Raw temperature: %d", raw_temp); - debug("Raw pressure: %d", raw_pressure); - - *temperature = compensate_temperature(raw_temp, &fine_temp); - *pressure = compensate_pressure(raw_pressure, fine_temp); - return true; } -bool bmp280_soft_reset() +bool bmp280_read_float(bmp280_t *dev, float *temperature, + float *pressure, float *humidity) { - if (!write_register8(BMP280_REG_RESET, BMP280_RESET_VALUE)) { - debug("Failed resetting sensor"); - return false; + int32_t fixed_temperature; + uint32_t fixed_pressure; + uint32_t fixed_humidity; + if (bmp280_read_fixed(dev, &fixed_temperature, &fixed_pressure, + humidity ? &fixed_humidity : NULL)) { + *temperature = (float)fixed_temperature/100; + *pressure = (float)fixed_pressure/256; + if (humidity) + *humidity = (float)fixed_humidity/1024; + return true; } - return true; + + return false; } diff --git a/extras/bmp280/bmp280.h b/extras/bmp280/bmp280.h index 9307932..8a43ad0 100644 --- a/extras/bmp280/bmp280.h +++ b/extras/bmp280/bmp280.h @@ -33,10 +33,14 @@ // #define BMP280_DEBUG /** - * BMP280 address is 0x77 if SDO pin is high, - * Address is 0x76 if SDO pin is low. + * BMP280 or BME280 address is 0x77 if SDO pin is high, and is 0x76 if + * SDO pin is low. */ -#define BMP280_ADDRESS 0x77 +#define BMP280_I2C_ADDRESS_0 0x76 +#define BMP280_I2C_ADDRESS_1 0x77 + +#define BMP280_CHIP_ID 0x58 /* BMP280 has chip-id 0x58 */ +#define BME280_CHIP_ID 0x60 /* BME280 has chip-id 0x60 */ /** * Mode of BMP280 module operation. @@ -78,8 +82,8 @@ typedef enum { BMP280_STANDBY_250 = 3, /* stand by time 250ms */ BMP280_STANDBY_500 = 4, /* stand by time 500ms */ BMP280_STANDBY_1000 = 5, /* stand by time 1s */ - BMP280_STANDBY_2000 = 6, /* stand by time 2s */ - BMP280_STANDBY_4000 = 7, /* stand by time 4s */ + BMP280_STANDBY_2000 = 6, /* stand by time 2s BMP280, 10ms BME280 */ + BMP280_STANDBY_4000 = 7, /* stand by time 4s BMP280, 20ms BME280 */ } BMP280_StandbyTime; /** @@ -90,10 +94,37 @@ typedef struct { BMP280_Mode mode; BMP280_Filter filter; BMP280_Oversampling oversampling; // pressure oversampling + BMP280_Oversampling oversampling_humidity; BMP280_StandbyTime standby; } bmp280_params_t; +typedef struct { + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + + /* Humidity compensation for BME280 */ + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; + + uint8_t i2c_addr; /* I2C address. */ + uint8_t id; /* Chip ID */ +} bmp280_t; + /** * Initialize default parameters. * Default configuration: @@ -105,33 +136,52 @@ typedef struct { void bmp280_init_default_params(bmp280_params_t *params); /** - * Initialize BMP280 module. + * Initialize BMP280 module, probes for the device, soft resets the device, + * reads the calibration constants, and configures the device using the supplied + * parameters. Returns true on success otherwise false. + * + * The I2C address is assumed to have been initialized in the dev, and + * may be either BMP280_I2C_ADDRESS_0 or BMP280_I2C_ADDRESS_1. If the I2C + * address is unknown then try initializing each in turn. + * + * This may be called again to soft reset the device and initialize it again. */ -bool bmp280_init(bmp280_params_t *params, uint8_t scl_pin, uint8_t sda_pin); +bool bmp280_init(bmp280_t *dev, bmp280_params_t *params); /** * Start measurement in forced mode. * The module remains in forced mode after this call. * Do not call this method in normal mode. */ -bool bmp280_force_measurement(); +bool bmp280_force_measurement(bmp280_t *dev); /** * Check if BMP280 is busy with measuring temperature/pressure. * Return true if BMP280 is busy. */ -bool bmp280_is_measuring(); +bool bmp280_is_measuring(bmp280_t *dev); /** - * Read compensated temperature and pressure data. - * Temperature in degrees Celsius. - * Pressure in Pascals. + * Read compensated temperature and pressure data: + * + * Temperature in degrees Celsius times 100. + * + * Pressure in Pascals in fixed point 24 bit integer 8 bit fraction format. + * + * Humidity is optional and only read for the BME280, in percent relative + * humidity as a fixed point 22 bit interger and 10 bit fraction format. */ -bool bmp280_read(float *temperature, float *pressure); +bool bmp280_read_fixed(bmp280_t *dev, int32_t *temperature, + uint32_t *pressure, uint32_t *humidity); /** - * Restart BMP280 module. + * Read compensated temperature and pressure data: + * Temperature in degrees Celsius. + * Pressure in Pascals. + * Humidity is optional and only read for the BME280, in percent relative + * humidity. */ -bool bmp280_soft_reset(); +bool bmp280_read_float(bmp280_t *dev, float *temperature, + float *pressure, float *humidity); #endif // __BMP280_H__