From 0f933dda31b4d390f9b6b2c88797daf97f552200 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Sun, 22 Apr 2018 09:37:45 +0200 Subject: [PATCH] Add partial BMP280/BME280 driver --- src/mgos_barometer_bme280.c | 90 +++++++++++++++++++++++++++++++++++-- src/mgos_barometer_bme280.h | 65 ++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 4 deletions(-) diff --git a/src/mgos_barometer_bme280.c b/src/mgos_barometer_bme280.c index 0e0f1e3..8b94f4c 100644 --- a/src/mgos_barometer_bme280.c +++ b/src/mgos_barometer_bme280.c @@ -5,15 +5,57 @@ // https://cdn-shop.adafruit.com/datasheets/MPL115A2.pdf bool mgos_barometer_bme280_detect(struct mgos_barometer *dev) { + int val; + if (!dev) return false; - return false; + + if ((val = mgos_i2c_read_reg_b(dev->i2c, dev->i2caddr, BME280_REG_DEVID)) < 0) { + return false; + } + + if (val == 0x56 || val == 0x57) { + LOG(LL_INFO, ("Preproduction version of BMP280 detected (0x%02x)", val)); + return true; + } + if (val == 0x58) // Mass production BMP280 + return true; + + if (val == 0x60) // Mass production BME280 + return true; + + return true; } bool mgos_barometer_bme280_create(struct mgos_barometer *dev) { struct mgos_barometer_bme280_data *bme280_data; if (!dev) return false; - return false; + + bme280_data=calloc(1, sizeof(struct mgos_barometer_bme280_data)); + if (!bme280_data) return false; + dev->user_data=bme280_data; + + if (!mgos_i2c_read_reg_n(dev->i2c, dev->i2caddr, BME280_REG_TEMPERATURE_CALIB_DIG_T1_LSB, 24, (uint8_t *)bme280_data)) + return false; + + // Mode | Pressure OS | Temp OS + if (!mgos_i2c_write_reg_b(dev->i2c, dev->i2caddr, BME280_REG_CTRL_MEAS, BME280_MODE_SLEEP | BME280_OVERSAMP_1X << 2 | BME280_OVERSAMP_1X << 5)) + return false; + mgos_usleep(10000); + + // SPI | 250ms period | no filter + if (!mgos_i2c_write_reg_b(dev->i2c, dev->i2caddr, BME280_REG_CONFIG, 0x00 | 0x04 << 2 | 0x00 << 5)) + return false; + mgos_usleep(10000); + + // Mode | Pressure OS | Temp OS + if (!mgos_i2c_write_reg_b(dev->i2c, dev->i2caddr, BME280_REG_CTRL_MEAS, BME280_MODE_NORMAL | BME280_OVERSAMP_1X << 2 | BME280_OVERSAMP_1X << 5)) + return false; + + dev->has_barometer=true; + dev->has_thermometer=true; + + return true; } bool mgos_barometer_bme280_destroy(struct mgos_barometer *dev) { @@ -32,6 +74,48 @@ bool mgos_barometer_bme280_read(struct mgos_barometer *dev) { bme280_data=(struct mgos_barometer_bme280_data *) dev->user_data; if (!bme280_data) return false; - return false; + // Forced Mode | 8x OS Pressure | 1x OS Temp + // 0x01 | 0x04 << 2 | 0x01 << 5 + if (!mgos_i2c_write_reg_b(dev->i2c, dev->i2caddr, BME280_REG_CTRL_MEAS, 0x01 | 0x04 << 2 | 0x01 << 5)) + return false; + mgos_usleep(10000); + + // read data from sensor + uint8_t data[6]; + if (!mgos_i2c_read_reg_n(dev->i2c, dev->i2caddr, BME280_REG_PRESSURE_MSB, 6, data)) + return false; + int32_t Padc, Tadc; + Padc = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4)); + Tadc = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | ((uint32_t)data[5] >> 4)); +// LOG(LL_DEBUG, ("Padc=%d Tadc=%d", Padc, Tadc)); + + int32_t var1, var2, T, t_fine, P; + // Temp conversion: + var1 = ((((Tadc >> 3) - ((int32_t)bme280_data->calib.dig_T1 << 1))) * ((int32_t)bme280_data->calib.dig_T2)) >> 11; + var2 = (((((Tadc >> 4) - ((int32_t)bme280_data->calib.dig_T1)) * ((Tadc >> 4) - ((int32_t)bme280_data->calib.dig_T1))) >> 12) * ((int32_t)bme280_data->calib.dig_T3)) >> 14; + t_fine = var1 + var2; + T = (t_fine * 5 + 128) >> 8; // in hundredth of degrees C; 5123 means 51.23C + dev->temperature=(float)T/100.0; + + // Pressure conversion: + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)bme280_data->calib.dig_P6; + var2 = var2 + ((var1*(int64_t)bme280_data->calib.dig_P5) << 17); + var2 = var2 + (((int64_t)bme280_data->calib.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)bme280_data->calib.dig_P3) >> 8) + ((var1 * (int64_t)bme280_data->calib.dig_P2) << 12); + var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)bme280_data->calib.dig_P1) >> 33; + if (var1 == 0) { + P=0; + } else { + P = 1048576 - Padc; + P = (((P << 31) - var2) * 3125) / var1; + var1 = (((int64_t)bme280_data->calib.dig_P9) * (P >> 13) * (P >> 13)) >> 25; + var2 = (((int64_t)bme280_data->calib.dig_P8) * P) >> 19; + P = ((P + var1 + var2) >> 8) + (((int64_t)bme280_data->calib.dig_P7) << 4); + } + dev->pressure=((float)P/256.0)*1000; +// LOG(LL_DEBUG, ("P=%.2f T=%.2f", dev->pressure, dev->temperature)); + + return true; } diff --git a/src/mgos_barometer_bme280.h b/src/mgos_barometer_bme280.h index fec78d5..938e954 100644 --- a/src/mgos_barometer_bme280.h +++ b/src/mgos_barometer_bme280.h @@ -3,8 +3,71 @@ #include "mgos.h" #include "mgos_barometer_internal.h" +// DevID: 0x56/0x57 are samples of BMP280; 0x58 is mass production BMP280; 0x60 is BME280 +#define BME280_REG_DEVID (0xD0) /* Chip ID Register */ +#define BME280_REG_RESET (0xE0) /* Softreset Register */ +#define BME280_REG_STATUS (0xF3) /* Status Register */ +#define BME280_REG_CTRL_MEAS (0xF4) /* Ctrl Measure Register */ +#define BME280_REG_CONFIG (0xF5) /* Configuration Register */ +#define BME280_REG_PRESSURE_MSB (0xF7) /* Pressure MSB Register */ +#define BME280_REG_PRESSURE_LSB (0xF8) /* Pressure LSB Register */ +#define BME280_REG_PRESSURE_XLSB (0xF9) /* Pressure XLSB Register */ +#define BME280_REG_TEMPERATURE_MSB (0xFA) /* Temperature MSB Reg */ +#define BME280_REG_TEMPERATURE_LSB (0xFB) /* Temperature LSB Reg */ +#define BME280_REG_TEMPERATURE_XLSB (0xFC) /* Temperature XLSB Reg */ +#define BME280_REG_HUMIDITY_MSB (0xFD) /* Humidity MSB Reg (BME280 only)*/ +#define BME280_REG_HUMIDITY_LSB (0xFE) /* Humidity LSB Reg (BME280 only)*/ +#define BME280_MODE_SLEEP (0x00) +#define BME280_MODE_FORCED (0x01) +#define BME280_MODE_NORMAL (0x03) + +#define BME280_REG_TEMPERATURE_CALIB_DIG_T1_LSB (0x88) + +#define BME280_OVERSAMP_NONE (0x00) +#define BME280_OVERSAMP_1X (0x01) +#define BME280_OVERSAMP_2X (0x02) +#define BME280_OVERSAMP_4X (0x03) +#define BME280_OVERSAMP_8X (0x04) +#define BME280_OVERSAMP_16X (0x05) + +#define BME280_STANDBY_500us (0x00) +#define BME280_STANDBY_62ms (0x01) +#define BME280_STANDBY_125ms (0x02) +#define BME280_STANDBY_250ms (0x03) +#define BME280_STANDBY_500ms (0x04) +#define BME280_STANDBY_1000ms (0x05) +// Note: Datasheet defines 110 == 10ms, 111 == 20ms, but BME280 and BMP280 +// implement this differently. + + +struct mgos_barometer_bme280_calib_data { + // Calibration data: + 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; + + // Additional calibration data for BME280 + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; // Note: this is 0xE4 / 0xE5[3:0] + int16_t dig_H5; // Note: this is 0xE5[7:4] / 0xE6 + int8_t dig_H6; +}; + struct mgos_barometer_bme280_data { - float a0, b1, b2, c12; + struct mgos_barometer_bme280_calib_data calib; + + float humidity; }; bool mgos_barometer_bme280_detect(struct mgos_barometer *dev);