/* bme280.c - Driver for Bosch BME280 temperature and pressure sensor */ /* * Copyright (c) 2016, 2017 Intel Corporation * Copyright (c) 2017 IpTronix S.r.l. * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include "bme280.h" LOG_MODULE_REGISTER(BME280, CONFIG_SENSOR_LOG_LEVEL); #if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 #warning "BME280 driver enabled without any devices" #endif /* Maximum oversampling rate on each channel is 16x. * Maximum measurement time is given by (Datasheet appendix B 9.1): * 1.25 + [2.3 * T_over] + [2.3 * P_over + 0.575] + [2.3 * H_over + 0.575] * = 112.8 ms */ #define BME280_MEASUREMENT_TIMEOUT_MS 150 /* Start-up time - Time to first communication after both Vdd > 1.58V and * Vddio > 0.65V */ #define BME280_START_UP_TIME_MS 2 /* Equation 9.1, with the fractional parts rounded down */ #define BME280_EXPECTED_SAMPLE_TIME_MS \ 1 + BME280_TEMP_SAMPLE_TIME + BME280_PRESS_SAMPLE_TIME + BME280_HUMIDITY_SAMPLE_TIME BUILD_ASSERT(BME280_EXPECTED_SAMPLE_TIME_MS < BME280_MEASUREMENT_TIMEOUT_MS, "Expected duration over timeout duration"); struct bme280_config { union bme280_bus bus; const struct bme280_bus_io *bus_io; }; static inline int bme280_bus_check(const struct device *dev) { const struct bme280_config *cfg = dev->config; return cfg->bus_io->check(&cfg->bus); } static inline int bme280_reg_read(const struct device *dev, uint8_t start, uint8_t *buf, int size) { const struct bme280_config *cfg = dev->config; return cfg->bus_io->read(&cfg->bus, start, buf, size); } static inline int bme280_reg_write(const struct device *dev, uint8_t reg, uint8_t val) { const struct bme280_config *cfg = dev->config; return cfg->bus_io->write(&cfg->bus, reg, val); } /* * Compensation code taken from BME280 datasheet, Section 4.2.3 * "Compensation formula". */ static int32_t bme280_compensate_temp(struct bme280_data *data, int32_t adc_temp) { int32_t var1, var2; var1 = (((adc_temp >> 3) - ((int32_t)data->dig_t1 << 1)) * ((int32_t)data->dig_t2)) >> 11; var2 = (((((adc_temp >> 4) - ((int32_t)data->dig_t1)) * ((adc_temp >> 4) - ((int32_t)data->dig_t1))) >> 12) * ((int32_t)data->dig_t3)) >> 14; data->t_fine = var1 + var2; return (data->t_fine * 5 + 128) >> 8; } static uint32_t bme280_compensate_press(struct bme280_data *data, int32_t adc_press) { int64_t var1, var2, p; var1 = ((int64_t)data->t_fine) - 128000; var2 = var1 * var1 * (int64_t)data->dig_p6; var2 = var2 + ((var1 * (int64_t)data->dig_p5) << 17); var2 = var2 + (((int64_t)data->dig_p4) << 35); var1 = ((var1 * var1 * (int64_t)data->dig_p3) >> 8) + ((var1 * (int64_t)data->dig_p2) << 12); var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)data->dig_p1) >> 33; /* Avoid exception caused by division by zero. */ if (var1 == 0) { return 0; } p = 1048576 - adc_press; p = (((p << 31) - var2) * 3125) / var1; var1 = (((int64_t)data->dig_p9) * (p >> 13) * (p >> 13)) >> 25; var2 = (((int64_t)data->dig_p8) * p) >> 19; p = ((p + var1 + var2) >> 8) + (((int64_t)data->dig_p7) << 4); return (uint32_t)p; } static uint32_t bme280_compensate_humidity(struct bme280_data *data, int32_t adc_humidity) { int32_t h; h = (data->t_fine - ((int32_t)76800)); h = ((((adc_humidity << 14) - (((int32_t)data->dig_h4) << 20) - (((int32_t)data->dig_h5) * h)) + ((int32_t)16384)) >> 15) * (((((((h * ((int32_t)data->dig_h6)) >> 10) * (((h * ((int32_t)data->dig_h3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)data->dig_h2) + 8192) >> 14); h = (h - (((((h >> 15) * (h >> 15)) >> 7) * ((int32_t)data->dig_h1)) >> 4)); h = (h > 419430400 ? 419430400 : h); h = (h < 0 ? 0 : h); return (uint32_t)(h >> 12); } static int bme280_wait_until_ready(const struct device *dev, k_timeout_t timeout) { k_timepoint_t end = sys_timepoint_calc(timeout); uint8_t status; int ret; /* Wait for relevant flags to clear */ while (1) { ret = bme280_reg_read(dev, BME280_REG_STATUS, &status, 1); if (ret < 0) { return ret; } if (!(status & (BME280_STATUS_MEASURING | BME280_STATUS_IM_UPDATE))) { break; } /* Check if waiting has timed out */ if (sys_timepoint_expired(end)) { return -EAGAIN; } k_sleep(K_MSEC(3)); } return 0; } int bme280_sample_fetch_helper(const struct device *dev, enum sensor_channel chan, struct bme280_reading *reading) { struct bme280_data *dev_data = dev->data; uint8_t buf[8]; int32_t adc_press, adc_temp, adc_humidity; uint32_t poll_timeout; int size = 6; int ret; __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); #ifdef CONFIG_BME280_MODE_FORCED ret = bme280_reg_write(dev, BME280_REG_CTRL_MEAS, BME280_CTRL_MEAS_VAL); if (ret < 0) { return ret; } /* Wait until the expected measurement time elapses */ k_sleep(K_MSEC(BME280_EXPECTED_SAMPLE_TIME_MS)); poll_timeout = BME280_MEASUREMENT_TIMEOUT_MS - BME280_EXPECTED_SAMPLE_TIME_MS; #else poll_timeout = BME280_MEASUREMENT_TIMEOUT_MS; #endif ret = bme280_wait_until_ready(dev, K_MSEC(poll_timeout)); if (ret < 0) { return ret; } if (dev_data->chip_id == BME280_CHIP_ID) { size = 8; } ret = bme280_reg_read(dev, BME280_REG_PRESS_MSB, buf, size); if (ret < 0) { return ret; } adc_press = (buf[0] << 12) | (buf[1] << 4) | (buf[2] >> 4); adc_temp = (buf[3] << 12) | (buf[4] << 4) | (buf[5] >> 4); reading->comp_temp = bme280_compensate_temp(dev_data, adc_temp); reading->comp_press = bme280_compensate_press(dev_data, adc_press); if (dev_data->chip_id == BME280_CHIP_ID) { adc_humidity = (buf[6] << 8) | buf[7]; reading->comp_humidity = bme280_compensate_humidity(dev_data, adc_humidity); } return 0; } int bme280_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bme280_data *data = dev->data; return bme280_sample_fetch_helper(dev, chan, &data->reading); } static int bme280_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct bme280_data *data = dev->data; switch (chan) { case SENSOR_CHAN_AMBIENT_TEMP: /* * comp_temp has a resolution of 0.01 degC. So * 5123 equals 51.23 degC. */ val->val1 = data->reading.comp_temp / 100; val->val2 = data->reading.comp_temp % 100 * 10000; break; case SENSOR_CHAN_PRESS: /* * comp_press has 24 integer bits and 8 * fractional. Output value of 24674867 represents * 24674867/256 = 96386.2 Pa = 963.862 hPa */ val->val1 = (data->reading.comp_press >> 8) / 1000U; val->val2 = (data->reading.comp_press >> 8) % 1000 * 1000U + (((data->reading.comp_press & 0xff) * 1000U) >> 8); break; case SENSOR_CHAN_HUMIDITY: /* The BMP280 doesn't have a humidity sensor */ if (data->chip_id != BME280_CHIP_ID) { return -ENOTSUP; } /* * comp_humidity has 22 integer bits and 10 * fractional. Output value of 47445 represents * 47445/1024 = 46.333 %RH */ val->val1 = (data->reading.comp_humidity >> 10); val->val2 = (((data->reading.comp_humidity & 0x3ff) * 1000U * 1000U) >> 10); break; default: return -ENOTSUP; } return 0; } static DEVICE_API(sensor, bme280_api_funcs) = { .sample_fetch = bme280_sample_fetch, .channel_get = bme280_channel_get, #ifdef CONFIG_SENSOR_ASYNC_API .submit = bme280_submit, .get_decoder = bme280_get_decoder, #endif }; static int bme280_read_compensation(const struct device *dev) { struct bme280_data *data = dev->data; uint16_t buf[12]; uint8_t hbuf[7]; int err = 0; err = bme280_reg_read(dev, BME280_REG_COMP_START, (uint8_t *)buf, sizeof(buf)); if (err < 0) { LOG_DBG("COMP_START read failed: %d", err); return err; } data->dig_t1 = sys_le16_to_cpu(buf[0]); data->dig_t2 = sys_le16_to_cpu(buf[1]); data->dig_t3 = sys_le16_to_cpu(buf[2]); data->dig_p1 = sys_le16_to_cpu(buf[3]); data->dig_p2 = sys_le16_to_cpu(buf[4]); data->dig_p3 = sys_le16_to_cpu(buf[5]); data->dig_p4 = sys_le16_to_cpu(buf[6]); data->dig_p5 = sys_le16_to_cpu(buf[7]); data->dig_p6 = sys_le16_to_cpu(buf[8]); data->dig_p7 = sys_le16_to_cpu(buf[9]); data->dig_p8 = sys_le16_to_cpu(buf[10]); data->dig_p9 = sys_le16_to_cpu(buf[11]); if (data->chip_id == BME280_CHIP_ID) { err = bme280_reg_read(dev, BME280_REG_HUM_COMP_PART1, &data->dig_h1, 1); if (err < 0) { LOG_DBG("HUM_COMP_PART1 read failed: %d", err); return err; } err = bme280_reg_read(dev, BME280_REG_HUM_COMP_PART2, hbuf, 7); if (err < 0) { LOG_DBG("HUM_COMP_PART2 read failed: %d", err); return err; } data->dig_h2 = (hbuf[1] << 8) | hbuf[0]; data->dig_h3 = hbuf[2]; data->dig_h4 = (hbuf[3] << 4) | (hbuf[4] & 0x0F); data->dig_h5 = ((hbuf[4] >> 4) & 0x0F) | (hbuf[5] << 4); data->dig_h6 = hbuf[6]; } return 0; } static int bme280_chip_init(const struct device *dev) { struct bme280_data *data = dev->data; int err; err = bme280_bus_check(dev); if (err < 0) { LOG_DBG("bus check failed: %d", err); return err; } k_msleep(BME280_START_UP_TIME_MS); err = bme280_reg_read(dev, BME280_REG_ID, &data->chip_id, 1); if (err < 0) { LOG_DBG("ID read failed: %d", err); return err; } if (data->chip_id == BME280_CHIP_ID) { LOG_DBG("ID OK"); } else if (data->chip_id == BMP280_CHIP_ID_MP || data->chip_id == BMP280_CHIP_ID_SAMPLE_1) { LOG_DBG("ID OK (BMP280)"); } else { LOG_DBG("bad chip id 0x%x", data->chip_id); return -ENOTSUP; } /* reset the sensor. This will put the sensor is sleep mode */ err = bme280_reg_write(dev, BME280_REG_RESET, BME280_CMD_SOFT_RESET); if (err < 0) { LOG_DBG("Soft-reset failed: %d", err); } /* The only mention of a soft reset duration is 2ms from the self test timeouts */ err = bme280_wait_until_ready(dev, K_MSEC(100)); if (err < 0) { return err; } err = bme280_read_compensation(dev); if (err < 0) { return err; } if (data->chip_id == BME280_CHIP_ID) { err = bme280_reg_write(dev, BME280_REG_CTRL_HUM, BME280_HUMIDITY_OVER); if (err < 0) { LOG_DBG("CTRL_HUM write failed: %d", err); return err; } } /* Writes to "config" register may be ignored in normal * mode, but never in sleep mode [datasheet 5.4.6]. * * So perform "config" write before "ctrl_meas", as "ctrl_meas" * could cause the sensor to transition from sleep to normal mode. */ err = bme280_reg_write(dev, BME280_REG_CONFIG, BME280_CONFIG_VAL); if (err < 0) { LOG_DBG("CONFIG write failed: %d", err); return err; } err = bme280_reg_write(dev, BME280_REG_CTRL_MEAS, BME280_CTRL_MEAS_VAL); if (err < 0) { LOG_DBG("CTRL_MEAS write failed: %d", err); return err; } /* Wait for the sensor to be ready */ k_sleep(K_MSEC(1)); LOG_DBG("\"%s\" OK", dev->name); return 0; } #ifdef CONFIG_PM_DEVICE static int bme280_pm_action(const struct device *dev, enum pm_device_action action) { int ret = 0; switch (action) { #ifdef CONFIG_BME280_MODE_NORMAL case PM_DEVICE_ACTION_RESUME: /* Re-enable periodic measurement */ ret = bme280_reg_write(dev, BME280_REG_CTRL_MEAS, BME280_CTRL_MEAS_VAL); break; case PM_DEVICE_ACTION_SUSPEND: /* Put the chip into sleep mode */ ret = bme280_reg_write(dev, BME280_REG_CTRL_MEAS, BME280_CTRL_MEAS_OFF_VAL); break; #else case PM_DEVICE_ACTION_RESUME: case PM_DEVICE_ACTION_SUSPEND: /* Nothing to do in forced mode */ break; #endif default: return -ENOTSUP; } return ret; } #endif /* CONFIG_PM_DEVICE */ /* Initializes a struct bme280_config for an instance on a SPI bus. */ #define BME280_CONFIG_SPI(inst) \ { \ .bus.spi = SPI_DT_SPEC_INST_GET( \ inst, BME280_SPI_OPERATION, 0), \ .bus_io = &bme280_bus_io_spi, \ } /* Initializes a struct bme280_config for an instance on an I2C bus. */ #define BME280_CONFIG_I2C(inst) \ { \ .bus.i2c = I2C_DT_SPEC_INST_GET(inst), \ .bus_io = &bme280_bus_io_i2c, \ } /* * Main instantiation macro, which selects the correct bus-specific * instantiation macros for the instance. */ #define BME280_DEFINE(inst) \ static struct bme280_data bme280_data_##inst; \ static const struct bme280_config bme280_config_##inst = \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ (BME280_CONFIG_SPI(inst)), \ (BME280_CONFIG_I2C(inst))); \ \ PM_DEVICE_DT_INST_DEFINE(inst, bme280_pm_action); \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ bme280_chip_init, \ PM_DEVICE_DT_INST_GET(inst), \ &bme280_data_##inst, \ &bme280_config_##inst, \ POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &bme280_api_funcs); /* Create the struct device for every status "okay" node in the devicetree. */ DT_INST_FOREACH_STATUS_OKAY(BME280_DEFINE)