1350 lines
57 KiB
C
1350 lines
57 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2024 Eric Gionet (gionet.c.eric@gmail.com)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
* @file bme680.c
|
|
*
|
|
* ESP-IDF driver for BME680 temperature, humidity, pressure, and gas sensor
|
|
*
|
|
* Ported from esp-open-rtos
|
|
*
|
|
* https://github.com/boschsensortec/BME68x_SensorAPI/blob/master/bme68x.c
|
|
*
|
|
* iaq: https://github.com/3KUdelta/heltec_wifi_kit_32_BME680/blob/master/Wifi_Kit_32_BME680.ino
|
|
*
|
|
* Copyright (c) 2024 Eric Gionet (gionet.c.eric@gmail.com)
|
|
*
|
|
* MIT Licensed as described in the file LICENSE
|
|
*/
|
|
#include "include/bme680.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <sdkconfig.h>
|
|
#include <esp_types.h>
|
|
#include <esp_log.h>
|
|
#include <esp_check.h>
|
|
#include <esp_timer.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/task.h>
|
|
|
|
/**
|
|
* possible BME680 registers
|
|
*/
|
|
|
|
#define BME680_REG_STATUS0 UINT8_C(0x1D)
|
|
#define BME680_REG_RESET UINT8_C(0xE0) /*!< reset value: 0xB6 */
|
|
#define BME680_REG_ID UINT8_C(0xD0)
|
|
#define BME680_REG_CONFIG UINT8_C(0x75)
|
|
#define BME680_REG_CTRL_MEAS UINT8_C(0x74)
|
|
#define BME680_REG_CTRL_HUMI UINT8_C(0x72)
|
|
#define BME680_REG_CTRL_GAS1 UINT8_C(0x71)
|
|
#define BME680_REG_CTRL_GAS0 UINT8_C(0x70)
|
|
#define BME680_REG_GAS_WAIT UINT8_C(0x64) /*!< gas_wait_x: 0x64 to 0x6D */
|
|
#define BME680_REG_RES_HEAT UINT8_C(0x5A) /*!< res_heat_x: 0x5A to 0x63 */
|
|
#define BME680_REG_IDAC_HEAT UINT8_C(0x50) /*!< idac_heat_x: 0x50 to 0x59 */
|
|
#define BME680_REG_GAS_R_LSB UINT8_C(0x2B)
|
|
#define BME680_REG_GAS_R_MSB UINT8_C(0x2A)
|
|
#define BME680_REG_GAS_R UINT8_C(BME680_REG_GAS_R_MSB)
|
|
#define BME680_REG_HUMI_LSB UINT8_C(0x26)
|
|
#define BME680_REG_HUMI_MSB UINT8_C(0x25)
|
|
#define BME680_REG_HUMI UINT8_C(BME680_REG_HUMI_MSB)
|
|
#define BME680_REG_TEMP_XLSB UINT8_C(0x24)
|
|
#define BME680_REG_TEMP_LSB UINT8_C(0x23)
|
|
#define BME680_REG_TEMP_MSB UINT8_C(0x22)
|
|
#define BME680_REG_TEMP UINT8_C(BME680_REG_TEMP_MSB)
|
|
#define BME680_REG_PRESS_XLSB UINT8_C(0x21)
|
|
#define BME680_REG_PRESS_LSB UINT8_C(0x20)
|
|
#define BME680_REG_PRESS_MSB UINT8_C(0x1F)
|
|
#define BME680_REG_PRESS UINT8_C(BME680_REG_PRESS_MSB)
|
|
#define BME680_RESET_VALUE UINT8_C(0xB6)
|
|
#define BME680_REG_SHD_HEATR_DUR UINT8_C(0x6E) /* Shared heating duration address */
|
|
|
|
#define BME680_REG_VARIANT_ID UINT8_C(0xF0)
|
|
|
|
#define BME680_VARIANT_GAS_LOW UINT8_C(0x00) /* Low Gas variant */
|
|
#define BME680_VARIANT_GAS_HIGH UINT8_C(0x01) /* High Gas variant */
|
|
|
|
#define BME680_ENABLE_GAS_MEAS_L UINT8_C(0x01) /* Enable gas measurement low */
|
|
#define BME680_ENABLE_GAS_MEAS_H UINT8_C(0x02) /* Enable gas measurement high */
|
|
|
|
// field data 1 registers (not documented, used in SEQUENTIAL_MODE)
|
|
#define BME680_REG_MEAS_STATUS_1 UINT8_C(0x2e)
|
|
#define BME680_REG_MEAS_INDEX_1 UINT8_C(0x2f)
|
|
|
|
// field data 2 registers (not documented, used in SEQUENTIAL_MODE)
|
|
#define BME680_REG_MEAS_STATUS_2 UINT8_C(0x3f)
|
|
#define BME680_REG_MEAS_INDEX_2 UINT8_C(0x40)
|
|
|
|
#define BME680_CHIP_ID UINT8_C(0x61)
|
|
|
|
#define BME680_AQI_TEMP_CORR (-3) // Calibration offset - calibrate yourself the temp reading --> humidity will
|
|
// be automatically adjusted using the August-Roche-Magnus approximation
|
|
// http://bmcnoldy.rsmas.miami.edu/Humidity.html
|
|
|
|
|
|
#define BME680_DATA_POLL_TIMEOUT_MS UINT16_C(250) // ? see datasheet tables 13 and 14, standby-time could be 2-seconds (2000ms)
|
|
#define BME680_DATA_READY_DELAY_MS UINT16_C(1)
|
|
#define BME680_POWERUP_DELAY_MS UINT16_C(25)
|
|
#define BME680_APPSTART_DELAY_MS UINT16_C(25)
|
|
#define BME680_RESET_DELAY_MS UINT16_C(25)
|
|
#define BME680_CMD_DELAY_MS UINT16_C(5)
|
|
#define BME680_TX_RX_DELAY_MS UINT16_C(10)
|
|
|
|
/*
|
|
* macro definitions
|
|
*/
|
|
#define ESP_TIMEOUT_CHECK(start, len) ((uint64_t)(esp_timer_get_time() - (start)) >= (len))
|
|
#define ESP_ARG_CHECK(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)
|
|
|
|
/*
|
|
* static constant declarations
|
|
*/
|
|
static const char *TAG = "bme680";
|
|
|
|
|
|
/**
|
|
* @brief BME680 I2C read from register address transaction. This is a write and then read process.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param reg_addr BME680 register address to read from.
|
|
* @param buffer BME680 read transaction return buffer.
|
|
* @param size Length of buffer to store results from read transaction.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_i2c_read_from(bme680_handle_t handle, const uint8_t reg_addr, uint8_t *buffer, const uint8_t size) {
|
|
const bit8_uint8_buffer_t tx = { reg_addr };
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
ESP_RETURN_ON_ERROR( i2c_master_transmit_receive(handle->i2c_handle, tx, BIT8_UINT8_BUFFER_SIZE, buffer, size, I2C_XFR_TIMEOUT_MS), TAG, "bme680_i2c_read_from failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief BME680 I2C read halfword from register address transaction.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param reg_addr BME680 register address to read from.
|
|
* @param halfword BME680 read transaction return halfword.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_i2c_read_word_from(bme680_handle_t handle, const uint8_t reg_addr, uint16_t *const word) {
|
|
const bit8_uint8_buffer_t tx = { reg_addr };
|
|
bit16_uint8_buffer_t rx = { 0 };
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
ESP_RETURN_ON_ERROR( i2c_master_transmit_receive(handle->i2c_handle, tx, BIT8_UINT8_BUFFER_SIZE, rx, BIT16_UINT8_BUFFER_SIZE, I2C_XFR_TIMEOUT_MS), TAG, "bme680_i2c_read_word_from failed" );
|
|
|
|
/* set output parameter */
|
|
*word = (uint16_t)rx[0] | ((uint16_t)rx[1] << 8);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief BME680 I2C read byte from register address transaction.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param reg_addr BME680 register address to read from.
|
|
* @param byte BME680 read transaction return byte.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_i2c_read_byte_from(bme680_handle_t handle, const uint8_t reg_addr, uint8_t *const byte) {
|
|
const bit8_uint8_buffer_t tx = { reg_addr };
|
|
bit8_uint8_buffer_t rx = { 0 };
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
ESP_RETURN_ON_ERROR( i2c_master_transmit_receive(handle->i2c_handle, tx, BIT8_UINT8_BUFFER_SIZE, rx, BIT8_UINT8_BUFFER_SIZE, I2C_XFR_TIMEOUT_MS), TAG, "bme680_i2c_read_byte_from failed" );
|
|
|
|
/* set output parameter */
|
|
*byte = rx[0];
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief BME680 I2C write byte to register address transaction.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param reg_addr BME680 register address to write to.
|
|
* @param byte BME680 write transaction input byte.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_i2c_write_byte_to(bme680_handle_t handle, const uint8_t reg_addr, const uint8_t byte) {
|
|
const bit16_uint8_buffer_t tx = { reg_addr, byte };
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( i2c_master_transmit(handle->i2c_handle, tx, BIT16_UINT8_BUFFER_SIZE, I2C_XFR_TIMEOUT_MS), TAG, "i2c_master_transmit, i2c write failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates dew-point temperature from air temperature and relative humidity.
|
|
*
|
|
* @param[in] temperature air temperature in degrees Celsius.
|
|
* @param[in] humidity relative humidity in percent.
|
|
* @return float calculated dew-point temperature in degrees Celsius.
|
|
*/
|
|
static inline float bme680_calculate_dewpoint(const float temperature, const float humidity) {
|
|
// validate parameters
|
|
if(temperature > 80.0f || temperature < -40.0f) return ESP_ERR_INVALID_ARG;
|
|
if(humidity > 100.0f || humidity < 0.0f) return ESP_ERR_INVALID_ARG;
|
|
// calculate dew-point temperature
|
|
float H = (log10f(humidity)-2.0f)/0.4343f + (17.62f*temperature)/(243.12f+temperature);
|
|
return 243.12f*H/(17.62f-H);
|
|
}
|
|
|
|
/**
|
|
* @brief Temperature compensation algorithm is taken from datasheet. See datasheet for details.
|
|
*
|
|
* @param[in] handle BME680 device handle.
|
|
* @param[in] adc_temperature raw adc temperature.
|
|
* @return float Temperature in degrees Celsius.
|
|
*/
|
|
static inline float bme680_compensate_temperature(bme680_handle_t handle, const uint32_t adc_temperature) {
|
|
/* calculate var1 data */
|
|
float var1 = ((((float)adc_temperature / 16384.0f) - ((float)handle->dev_cal_factors->par_T1 / 1024.0f)) * ((float)handle->dev_cal_factors->par_T2));
|
|
|
|
/* calculate var2 data */
|
|
float var2 =
|
|
(((((float)adc_temperature / 131072.0f) - ((float)handle->dev_cal_factors->par_T1 / 8192.0f)) *
|
|
(((float)adc_temperature / 131072.0f) - ((float)handle->dev_cal_factors->par_T1 / 8192.0f))) * ((float)handle->dev_cal_factors->par_T3 * 16.0f));
|
|
|
|
/* t_fine value*/
|
|
handle->dev_cal_factors->temperature_fine = (var1 + var2);
|
|
|
|
/* compensated temperature data*/
|
|
return ((handle->dev_cal_factors->temperature_fine) / 5120.0f);
|
|
}
|
|
|
|
/**
|
|
* @brief Humidity compensation algorithm is taken from datasheet. See datasheet for details.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param adc_humidity Raw ADC humidity.
|
|
* @return float Humidity in percentage.
|
|
*/
|
|
static inline float bme680_compensate_humidity(bme680_handle_t handle, const uint16_t adc_humidity) {
|
|
/* compensated temperature data*/
|
|
float temp_comp = ((handle->dev_cal_factors->temperature_fine) / 5120.0f);
|
|
float var1 = (float)((float)adc_humidity) -
|
|
(((float)handle->dev_cal_factors->par_H1 * 16.0f) + (((float)handle->dev_cal_factors->par_H3 / 2.0f) * temp_comp));
|
|
float var2 = var1 *
|
|
((float)(((float)handle->dev_cal_factors->par_H2 / 262144.0f) *
|
|
(1.0f + (((float)handle->dev_cal_factors->par_H4 / 16384.0f) * temp_comp) +
|
|
(((float)handle->dev_cal_factors->par_H5 / 1048576.0f) * temp_comp * temp_comp))));
|
|
float var3 = (float)handle->dev_cal_factors->par_H6 / 16384.0f;
|
|
float var4 = (float)handle->dev_cal_factors->par_H7 / 2097152.0f;
|
|
float calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);
|
|
if (calc_hum > 100.0f) {
|
|
calc_hum = 100.0f;
|
|
} else if (calc_hum < 0.0f) {
|
|
calc_hum = 0.0f;
|
|
}
|
|
|
|
return calc_hum;
|
|
}
|
|
|
|
/**
|
|
* @brief Pressure compensation algorithm is taken from datasheet. see datasheet for details.
|
|
*
|
|
* @param[in] handle BME680 device handle.
|
|
* @param[in] adc_pressure raw adc pressure.
|
|
* @return float Pressure in Pascal. Divide by 100 for Hecto-Pascals.
|
|
*/
|
|
static inline float bme680_compensate_pressure(bme680_handle_t handle, const uint32_t adc_pressure) {
|
|
float var1 = (((float)handle->dev_cal_factors->temperature_fine / 2.0f) - 64000.0f);
|
|
float var2 = var1 * var1 * (((float)handle->dev_cal_factors->par_P6) / (131072.0f));
|
|
var2 = var2 + (var1 * ((float)handle->dev_cal_factors->par_P5) * 2.0f);
|
|
var2 = (var2 / 4.0f) + (((float)handle->dev_cal_factors->par_P4) * 65536.0f);
|
|
var1 = (((((float)handle->dev_cal_factors->par_P3 * var1 * var1) / 16384.0f) + ((float)handle->dev_cal_factors->par_P2 * var1)) / 524288.0f);
|
|
var1 = ((1.0f + (var1 / 32768.0f)) * ((float)handle->dev_cal_factors->par_P1));
|
|
float calc_pres = (1048576.0f - ((float)adc_pressure));
|
|
|
|
/* Avoid exception caused by division by zero */
|
|
if ((int)var1 != 0) {
|
|
calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1);
|
|
var1 = (((float)handle->dev_cal_factors->par_P9) * calc_pres * calc_pres) / 2147483648.0f;
|
|
var2 = calc_pres * (((float)handle->dev_cal_factors->par_P8) / 32768.0f);
|
|
float var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) * (handle->dev_cal_factors->par_P10 / 131072.0f));
|
|
calc_pres = (calc_pres + (var1 + var2 + var3 + ((float)handle->dev_cal_factors->par_P7 * 128.0f)) / 16.0f);
|
|
} else {
|
|
calc_pres = 0;
|
|
}
|
|
|
|
return calc_pres;
|
|
}
|
|
|
|
static inline float bme680_compensate_gas_resistance(bme680_handle_t handle, uint16_t adc_gas_res, uint8_t gas_range) {
|
|
const float lookup_k1_range[16] = {
|
|
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.99f, 1.0f, 0.992f, 1.0f, 1.0f, 0.998f, 0.995f, 1.0f, 0.99f, 1.0f, 1.0f
|
|
};
|
|
const float lookup_k2_range[16] = {
|
|
8000000.0f, 4000000.0f, 2000000.0f, 1000000.0f, 499500.4995f, 248262.1648f, 125000.0f, 63004.03226f,
|
|
31281.28128f, 15625.0f, 7812.5f, 3906.25f, 1953.125f, 976.5625f, 488.28125f, 244.140625f
|
|
};
|
|
float var1 = (1340.0f + 5.0f * handle->dev_cal_factors->range_switching_error) * lookup_k1_range[gas_range];
|
|
return var1 * lookup_k2_range[gas_range] / (adc_gas_res - 512.0f + var1);
|
|
}
|
|
|
|
static inline uint8_t bme680_compensate_heater_resistance(bme680_handle_t handle, uint16_t temperature) {
|
|
/* Cap temperature */
|
|
if (temperature > 400) {
|
|
temperature = 400;
|
|
}
|
|
|
|
float var1 = (((float)handle->dev_cal_factors->par_G1 / (16.0f)) + 49.0f);
|
|
float var2 = ((((float)handle->dev_cal_factors->par_G2 / (32768.0f)) * (0.0005f)) + 0.00235f);
|
|
float var3 = ((float)handle->dev_cal_factors->par_G3 / (1024.0f));
|
|
float var4 = (var1 * (1.0f + (var2 * (float)temperature)));
|
|
float var5 = (var4 + (var3 * (float)handle->ambient_temperature));
|
|
uint8_t res_heat =
|
|
(uint8_t)(3.4f *
|
|
((var5 * (4 / (4 + (float)handle->dev_cal_factors->res_heat_range)) *
|
|
(1 / (1 + ((float)handle->dev_cal_factors->res_heat_val * 0.002f)))) -
|
|
25.0f));
|
|
|
|
return res_heat;
|
|
}
|
|
|
|
/**
|
|
* @brief Calculates the gas wait time.
|
|
*
|
|
* @param duration
|
|
* @return uint8_t Gas wait time duration.
|
|
*/
|
|
static inline uint8_t bme680_compute_gas_wait(const uint16_t duration) {
|
|
uint8_t factor = 0;
|
|
uint8_t durval;
|
|
uint16_t dura = duration;
|
|
|
|
if (dura >= 0xfc0) {
|
|
durval = 0xff; /* Max duration*/
|
|
} else {
|
|
while (dura > 0x3F) {
|
|
dura = dura / 4;
|
|
factor += 1;
|
|
}
|
|
durval = (uint8_t)(dura + (factor * 64));
|
|
}
|
|
|
|
return durval;
|
|
}
|
|
|
|
static inline uint8_t bme680_compute_heater_shared_duration(const uint16_t duration) {
|
|
uint8_t factor = 0;
|
|
uint8_t heatdurval;
|
|
uint16_t dura = duration;
|
|
|
|
if (dura >= 0x783) {
|
|
heatdurval = 0xff; /* Max duration */
|
|
} else {
|
|
/* Step size of 0.477ms */
|
|
dura = (uint16_t)(((uint32_t)dura * 1000) / 477);
|
|
while (dura > 0x3F) {
|
|
dura = dura >> 2;
|
|
factor += 1;
|
|
}
|
|
|
|
heatdurval = (uint8_t)(dura + (factor * 64));
|
|
}
|
|
|
|
return heatdurval;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets an estimated measurement duration in milliseconds.
|
|
*
|
|
* @param handle bmp280 device handle.
|
|
* @return uint32_t Estimated measurement duration in milliseconds.
|
|
*/
|
|
static inline uint32_t bme680_get_measurement_duration(bme680_handle_t handle) {
|
|
const uint8_t os_to_meas_cycles[6] = { 0, 1, 2, 4, 8, 16 };
|
|
uint32_t meas_dur = 0; /* Calculate in us */
|
|
uint32_t meas_cycles;
|
|
|
|
/* validate arguments */
|
|
if((handle) != NULL) {
|
|
meas_cycles = os_to_meas_cycles[handle->dev_config.temperature_oversampling];
|
|
meas_cycles += os_to_meas_cycles[handle->dev_config.pressure_oversampling];
|
|
meas_cycles += os_to_meas_cycles[handle->dev_config.humidity_oversampling];
|
|
|
|
/* TPH measurement duration */
|
|
meas_dur = meas_cycles * (uint32_t)(1963);
|
|
meas_dur += (uint32_t)(477 * 4); /* TPH switching duration */
|
|
meas_dur += (uint32_t)(477 * 5); /* Gas measurement duration */
|
|
|
|
if (handle->dev_config.power_mode != BME680_POWER_MODE_PARALLEL) {
|
|
meas_dur += (uint32_t)(1000); /* Wake up duration of 1ms */
|
|
}
|
|
}
|
|
|
|
return meas_dur;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the calibration factors onboard the bme680. see datasheet for details.
|
|
*
|
|
* @param[in] bme680_handle bmp280 device handle.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_get_cal_factors(bme680_handle_t handle) {
|
|
bit16_uint8_buffer_t rx;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* bme680 attempt to request T1-T3 calibration values from device */
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0xe9, &handle->dev_cal_factors->par_T1) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x8a, (uint16_t *)&handle->dev_cal_factors->par_T2) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x8c, (uint8_t *)&handle->dev_cal_factors->par_T3) );
|
|
/* bme680 attempt to request H1-H7 calibration values from device */
|
|
ESP_ERROR_CHECK( bme680_i2c_read_from(handle, 0xe2, rx, BIT16_UINT8_BUFFER_SIZE) );
|
|
handle->dev_cal_factors->par_H1 = (uint16_t)(((uint16_t)rx[1] << 4) | (rx[0] & 0x0F));
|
|
ESP_ERROR_CHECK( bme680_i2c_read_from(handle, 0xe1, rx, BIT16_UINT8_BUFFER_SIZE) );
|
|
handle->dev_cal_factors->par_H2 = (uint16_t)(((uint16_t)rx[0] << 4) | (rx[1] >> 4));
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe4, (uint8_t *)&handle->dev_cal_factors->par_H3) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe5, (uint8_t *)&handle->dev_cal_factors->par_H4) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe6, (uint8_t *)&handle->dev_cal_factors->par_H5) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe7, &handle->dev_cal_factors->par_H6) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe8, (uint8_t *)&handle->dev_cal_factors->par_H7) );
|
|
/* bme680 attempt to request P1-P10 calibration values from device */
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x8e, &handle->dev_cal_factors->par_P1) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x90, (uint16_t *)&handle->dev_cal_factors->par_P2) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x92, (uint8_t *)&handle->dev_cal_factors->par_P3) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x94, (uint16_t *)&handle->dev_cal_factors->par_P4) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x96, (uint16_t *)&handle->dev_cal_factors->par_P5) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x99, (uint8_t *)&handle->dev_cal_factors->par_P6) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x98, (uint8_t *)&handle->dev_cal_factors->par_P7) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x9c, (uint16_t *)&handle->dev_cal_factors->par_P8) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x9e, (uint16_t *)&handle->dev_cal_factors->par_P9) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xa0, &handle->dev_cal_factors->par_P10) );
|
|
/* bme680 attempt to request G1-G3 calibration values from device */
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xed, (uint8_t *)&handle->dev_cal_factors->par_G1) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0xeb, (uint16_t *)&handle->dev_cal_factors->par_G2) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xee, (uint8_t *)&handle->dev_cal_factors->par_G3) );
|
|
/* bme680 attempt to request gas range and switching error values from device */
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x02, &handle->dev_cal_factors->res_heat_range) );
|
|
handle->dev_cal_factors->res_heat_range = (handle->dev_cal_factors->res_heat_range & 0x30) / 16;
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x00, (uint8_t *)&handle->dev_cal_factors->res_heat_val) );
|
|
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x04, (uint8_t *)&handle->dev_cal_factors->range_switching_error) );
|
|
handle->dev_cal_factors->range_switching_error = (handle->dev_cal_factors->range_switching_error & 0xf0) / 16;
|
|
|
|
/*
|
|
ESP_LOGD(TAG, "Calibration data received:");
|
|
//
|
|
ESP_LOGD(TAG, "par_T1=%u", handle->dev_cal_factors->par_T1);
|
|
ESP_LOGD(TAG, "par_T2=%d", handle->dev_cal_factors->par_T2);
|
|
ESP_LOGD(TAG, "par_T3=%d", handle->dev_cal_factors->par_T3);
|
|
//
|
|
ESP_LOGD(TAG, "par_P1=%u", handle->dev_cal_factors->par_P1);
|
|
ESP_LOGD(TAG, "par_P2=%d", handle->dev_cal_factors->par_P2);
|
|
ESP_LOGD(TAG, "par_P3=%d", handle->dev_cal_factors->par_P3);
|
|
ESP_LOGD(TAG, "par_P4=%d", handle->dev_cal_factors->par_P4);
|
|
ESP_LOGD(TAG, "par_P5=%d", handle->dev_cal_factors->par_P5);
|
|
ESP_LOGD(TAG, "par_P6=%d", handle->dev_cal_factors->par_P6);
|
|
ESP_LOGD(TAG, "par_P7=%d", handle->dev_cal_factors->par_P7);
|
|
ESP_LOGD(TAG, "par_P8=%d", handle->dev_cal_factors->par_P8);
|
|
ESP_LOGD(TAG, "par_P9=%d", handle->dev_cal_factors->par_P9);
|
|
ESP_LOGD(TAG, "par_P10=%d", handle->dev_cal_factors->par_P10);
|
|
*/
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Setup and configuration of BME680 gas and heater profile registers.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_setup_heater_profiles(bme680_handle_t handle, bme680_heater_setpoints_t *const heater_setpoint) {
|
|
uint8_t i;
|
|
uint8_t shared_dur;
|
|
uint8_t write_len = 0;
|
|
uint8_t rh_reg_addr[BME680_HEATER_PROFILE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t rh_reg_data[BME680_HEATER_PROFILE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t gw_reg_addr[BME680_HEATER_PROFILE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t gw_reg_data[BME680_HEATER_PROFILE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
switch(handle->dev_config.power_mode) {
|
|
case BME680_POWER_MODE_FORCED:
|
|
rh_reg_addr[0] = BME680_REG_RES_HEAT;
|
|
rh_reg_data[0] = bme680_compensate_heater_resistance(handle, handle->dev_config.heater_temperature);
|
|
gw_reg_addr[0] = BME680_REG_GAS_WAIT;
|
|
gw_reg_data[0] = bme680_compute_gas_wait(handle->dev_config.heater_duration);
|
|
|
|
(*heater_setpoint) = handle->dev_config.heater_profile_size - 1;
|
|
write_len = handle->dev_config.heater_profile_size;;
|
|
break;
|
|
case BME680_POWER_MODE_SEQUENTIAL:
|
|
if ((handle->dev_config.heater_profile_size == 0) || (handle->dev_config.heater_profile_size > 10)) {
|
|
ESP_RETURN_ON_FALSE( false, ESP_ERR_INVALID_ARG, TAG, "heater duration or temperature profile are empty and cannot be larger than 10, setup heater setpoints failed");
|
|
}
|
|
|
|
for (i = 0; i < handle->dev_config.heater_profile_size; i++) {
|
|
rh_reg_addr[i] = BME680_REG_RES_HEAT + i;
|
|
rh_reg_data[i] = bme680_compensate_heater_resistance(handle, handle->dev_config.heater_temperature_profile[i]);
|
|
gw_reg_addr[i] = BME680_REG_GAS_WAIT + i;
|
|
gw_reg_data[i] = bme680_compute_gas_wait(handle->dev_config.heater_duration_profile[i]);
|
|
}
|
|
|
|
(*heater_setpoint) = handle->dev_config.heater_profile_size - 1;
|
|
write_len = handle->dev_config.heater_profile_size;
|
|
break;
|
|
case BME680_POWER_MODE_PARALLEL:
|
|
if ((handle->dev_config.heater_profile_size == 0) || (handle->dev_config.heater_profile_size > 10)) {
|
|
ESP_RETURN_ON_FALSE( false, ESP_ERR_INVALID_ARG, TAG, "heater duration or temperature profile are empty and cannot be larger than 10, setup heater setpoints failed");
|
|
}
|
|
|
|
if(handle->dev_config.heater_shared_duration == 0) {
|
|
ESP_RETURN_ON_FALSE( false, ESP_ERR_INVALID_ARG, TAG, "heater shared duration must be greater than 0, setup heater setpoints failed");
|
|
}
|
|
|
|
for (i = 0; i < handle->dev_config.heater_profile_size; i++) {
|
|
rh_reg_addr[i] = BME680_REG_RES_HEAT + i;
|
|
rh_reg_data[i] = bme680_compensate_heater_resistance(handle, handle->dev_config.heater_temperature_profile[i]);
|
|
gw_reg_addr[i] = BME680_REG_GAS_WAIT + i;
|
|
gw_reg_data[i] = (uint8_t)handle->dev_config.heater_duration_profile[i];
|
|
}
|
|
|
|
(*heater_setpoint) = handle->dev_config.heater_profile_size - 1;
|
|
write_len = handle->dev_config.heater_profile_size;
|
|
shared_dur = bme680_compute_heater_shared_duration(handle->dev_config.heater_shared_duration);
|
|
ESP_RETURN_ON_ERROR(bme680_i2c_write_byte_to(handle, BME680_REG_SHD_HEATR_DUR, shared_dur), TAG, "unable to write shared heater duration, setup heater setpoints failed");
|
|
break;
|
|
case BME680_POWER_MODE_SLEEP:
|
|
return ESP_ERR_INVALID_ARG;
|
|
};
|
|
|
|
/* attempt to write resistance heater and gas wait profile */
|
|
for (i = 0; i < write_len; i++) {
|
|
ESP_RETURN_ON_ERROR(bme680_i2c_write_byte_to(handle, rh_reg_addr[i], rh_reg_data[i]), TAG, "unable to write resistance heater profile, setup heater setpoints failed");
|
|
ESP_RETURN_ON_ERROR(bme680_i2c_write_byte_to(handle, gw_reg_addr[i], gw_reg_data[i]), TAG, "unable to write gas wait profile, setup heater setpoints failed");
|
|
|
|
ESP_LOGI(TAG, "bme680_setup_heater_profiles: rh_reg_data %d | gw_reg_data %d", rh_reg_data[i], gw_reg_data[i]);
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Setup and configuration of BME680 gas and heater registers.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_setup_heater(bme680_handle_t handle) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
bme680_heater_setpoints_t heater_setpoint;
|
|
bme680_control_gas0_register_t ctrl_gas0_reg;
|
|
bme680_control_gas1_register_t ctrl_gas1_reg;
|
|
|
|
ESP_RETURN_ON_ERROR(bme680_setup_heater_profiles(handle, &heater_setpoint), TAG, "setup heater profiles for setup heater failed");
|
|
|
|
/* attempt to read control gas 0 register */
|
|
ESP_RETURN_ON_ERROR(bme680_get_control_gas0_register(handle, &ctrl_gas0_reg), TAG, "read control gas 0 register for setup heater failed");
|
|
|
|
/* attempt to read control gas 1 register */
|
|
ESP_RETURN_ON_ERROR(bme680_get_control_gas1_register(handle, &ctrl_gas1_reg), TAG, "read control gas 1 register for setup heater failed");
|
|
|
|
/* initialize control gas 0 and 1 from configuration params */
|
|
if(handle->dev_config.gas_enabled) {
|
|
ctrl_gas0_reg.bits.heater_disabled = false;
|
|
ctrl_gas1_reg.bits.gas_conversion_enabled = true;
|
|
ctrl_gas1_reg.bits.heater_setpoint = heater_setpoint;
|
|
} else {
|
|
ctrl_gas1_reg.bits.gas_conversion_enabled = false;
|
|
ctrl_gas0_reg.bits.heater_disabled = true;
|
|
}
|
|
|
|
/* attempt to write control gas 0 register */
|
|
ESP_RETURN_ON_ERROR(bme680_set_control_gas0_register(handle, ctrl_gas0_reg), TAG, "write control gas 0 register for setup heater failed");
|
|
|
|
/* attempt to write control gas 1 register */
|
|
ESP_RETURN_ON_ERROR(bme680_set_control_gas1_register(handle, ctrl_gas1_reg), TAG, "write control gas 1 register for setup heater failed");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Setup and configuration of BME680 context and registers.
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline esp_err_t bme680_setup(bme680_handle_t handle) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
bme680_control_humidity_register_t ctrl_humi_reg;
|
|
bme680_config_register_t config_reg;
|
|
|
|
/* set ambient temperature of sensor to default value (25 degree C) */
|
|
handle->ambient_temperature = 25;
|
|
|
|
/* attempt to read calibration factors from device */
|
|
ESP_RETURN_ON_ERROR(bme680_get_cal_factors(handle), TAG, "read calibration factors for setup failed" );
|
|
|
|
/* attempt to read variant identifier register from device */
|
|
ESP_RETURN_ON_ERROR(bme680_get_variant_id_register(handle, &handle->variant_id), TAG, "read variant identifier register for setup failed" );
|
|
|
|
/* attempt to read control humidity register */
|
|
ESP_RETURN_ON_ERROR(bme680_get_control_humidity_register(handle, &ctrl_humi_reg), TAG, "read control humidity register for setup failed");
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR(bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for setup failed");
|
|
|
|
/* attempt to read configuration register */
|
|
ESP_RETURN_ON_ERROR(bme680_get_configuration_register(handle, &config_reg), TAG, "read configuration register for setup failed");
|
|
|
|
/* initialize configuration register from configuration params */
|
|
config_reg.bits.iir_filter = handle->dev_config.iir_filter;
|
|
config_reg.bits.spi_enabled = false;
|
|
|
|
/* initialize control measurement register from configuration params */
|
|
ctrl_meas_reg.bits.power_mode = handle->dev_config.power_mode;
|
|
ctrl_meas_reg.bits.temperature_oversampling = handle->dev_config.temperature_oversampling;
|
|
ctrl_meas_reg.bits.pressure_oversampling = handle->dev_config.pressure_oversampling;
|
|
|
|
/* initialize control humidity register from configuration params */
|
|
ctrl_humi_reg.bits.humidity_oversampling = handle->dev_config.humidity_oversampling;
|
|
ctrl_humi_reg.bits.spi_irq_enabled = false;
|
|
|
|
/* attempt to write control humidity register */
|
|
ESP_RETURN_ON_ERROR(bme680_set_control_humidity_register(handle, ctrl_humi_reg), TAG, "write control humidity register for setup failed");
|
|
|
|
/* attempt to write control measurement register */
|
|
ESP_RETURN_ON_ERROR(bme680_set_control_measurement_register(handle, ctrl_meas_reg), TAG, "write control measurement register for setup failed");
|
|
|
|
/* attempt to write configuration register */
|
|
ESP_RETURN_ON_ERROR(bme680_set_configuration_register(handle, config_reg), TAG, "write configuration register for setup failed");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief IAQ calculations following Dr. Julie Riggs, The IAQ Rating Index, www.iaquk.org.uk.
|
|
*
|
|
* - Weighting: Temperature, Humidity each one tenth of the rating ==> 6.5 points max each
|
|
* giving gas resistance readings 8 tenths of the rating ==> 52 points max
|
|
*
|
|
* @param handle BME680 device handle.
|
|
* @param data BME680 data structure, air temperature, dew-point temperature, and
|
|
* relative humidity parameters must be initialized as a minimum.
|
|
* @return esp_err_t ESP_OK on success.
|
|
*/
|
|
static inline void bme680_compute_iaq(bme680_data_t *const data) {
|
|
float adjusted_temp = data->air_temperature + BME680_AQI_TEMP_CORR;
|
|
|
|
// August-Roche-Magnus approximation (http://bmcnoldy.rsmas.miami.edu/Humidity.html)
|
|
float adjusted_humi = 100 * (exp((17.625 * data->dewpoint_temperature) / (243.04 + data->dewpoint_temperature)) / exp((17.625 * adjusted_temp) / (243.04 + adjusted_temp)));
|
|
|
|
uint32_t gas = data->gas_resistance;
|
|
|
|
// Calculate humidity score
|
|
if (adjusted_humi >= 40 && adjusted_humi <= 60) data->humidity_score = 6.5; //ideal condition, full points
|
|
else if ((adjusted_humi >= 30 && adjusted_humi < 40) || (adjusted_humi > 60 && adjusted_humi <= 70)) data->humidity_score = 5.2; //20% less
|
|
else if ((adjusted_humi >= 20 && adjusted_humi < 30) || (adjusted_humi > 70 && adjusted_humi <= 80)) data->humidity_score = 3.9; //40% less
|
|
else if ((adjusted_humi >= 10 && adjusted_humi < 20) || (adjusted_humi > 80 && adjusted_humi <= 90)) data->humidity_score = 2.6; //60% less
|
|
else if (adjusted_humi < 10 && adjusted_humi > 90) data->humidity_score = 1.3; //80% less
|
|
|
|
// Calculate temperature score
|
|
int compare_temp = adjusted_temp; // round to full degree
|
|
if (compare_temp >= 18 && compare_temp <= 22) data->temperature_score = 6.5; //ideal condition, full points
|
|
else if (compare_temp == 17 || compare_temp == 23) data->temperature_score = 5.2; //20% less
|
|
else if (compare_temp == 16 || compare_temp == 24) data->temperature_score = 3.9; //40% less
|
|
else if (compare_temp == 15 || compare_temp == 25) data->temperature_score = 2.6; //60% less
|
|
else if (compare_temp == 14 || compare_temp == 26) data->temperature_score = 1.3; //80% less
|
|
else if (compare_temp < 14 || compare_temp > 26) data->temperature_score = 0; //100% less
|
|
|
|
// Calculate gas score on resistance values - best practices
|
|
if (gas >= 430000) data->gas_score = 52; //ideal condition, full points
|
|
else if (gas >= 210000 && gas < 430000) data->gas_score = 43;
|
|
else if (gas >= 100000 && gas < 210000) data->gas_score = 35;
|
|
else if (gas >= 55000 && gas < 100000) data->gas_score = 26;
|
|
else if (gas >= 27000 && gas < 55000) data->gas_score = 18;
|
|
else if (gas >= 13500 && gas > 9000) data->gas_score = 9;
|
|
else if (gas < 9000) data->gas_score = 0;
|
|
|
|
// calculate iaq score
|
|
data->iaq_score = data->humidity_score + data->temperature_score + data->gas_score;
|
|
}
|
|
|
|
esp_err_t bme680_get_chip_id_register(bme680_handle_t handle, uint8_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_ID, reg), TAG, "read chip identifier register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_variant_id_register(bme680_handle_t handle, uint8_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_VARIANT_ID, reg), TAG, "read variant identifier register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_status0_register(bme680_handle_t handle, bme680_status0_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_STATUS0, ®->reg), TAG, "read status register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_gas_lsb_register(bme680_handle_t handle, bme680_gas_lsb_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_GAS_R_LSB, ®->reg), TAG, "read gas lsb register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_gas_lsb_register(bme680_handle_t handle, const bme680_gas_lsb_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_GAS_R_LSB, reg.reg), TAG, "write control measurement register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_control_measurement_register(bme680_handle_t handle, bme680_control_measurement_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_CTRL_MEAS, ®->reg), TAG, "read control measurement register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_control_measurement_register(bme680_handle_t handle, const bme680_control_measurement_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_CTRL_MEAS, reg.reg), TAG, "write control measurement register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_control_humidity_register(bme680_handle_t handle, bme680_control_humidity_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_CTRL_HUMI, ®->reg), TAG, "read control humidity register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_control_humidity_register(bme680_handle_t handle, const bme680_control_humidity_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
bme680_control_humidity_register_t ctrl_hum = { .reg = reg.reg };
|
|
ctrl_hum.bits.reserved1 = 0;
|
|
ctrl_hum.bits.reserved2 = 0;
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_CTRL_HUMI, ctrl_hum.reg), TAG, "write control humidity register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_control_gas0_register(bme680_handle_t handle, bme680_control_gas0_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_CTRL_GAS0, ®->reg), TAG, "read control gas 0 register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_control_gas0_register(bme680_handle_t handle, const bme680_control_gas0_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
bme680_control_gas0_register_t gas0 = { .reg = reg.reg };
|
|
gas0.bits.reserved1 = 0;
|
|
gas0.bits.reserved2 = 0;
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_CTRL_GAS0, gas0.reg), TAG, "write control gas 0 register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_control_gas1_register(bme680_handle_t handle, bme680_control_gas1_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_CTRL_GAS1, ®->reg), TAG, "read control gas 1 register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_control_gas1_register(bme680_handle_t handle, const bme680_control_gas1_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
bme680_control_gas1_register_t gas1 = { .reg = reg.reg };
|
|
gas1.bits.reserved = 0;
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_CTRL_GAS1, gas1.reg), TAG, "write control gas 1 register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_configuration_register(bme680_handle_t handle, bme680_config_register_t *const reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c read transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_read_byte_from(handle, BME680_REG_CONFIG, ®->reg), TAG, "read configuration register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_configuration_register(bme680_handle_t handle, const bme680_config_register_t reg) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* copy register */
|
|
bme680_config_register_t config = { .reg = reg.reg };
|
|
|
|
/* set reserved to 0 */
|
|
config.bits.reserved1 = 0;
|
|
config.bits.reserved2 = 0;
|
|
|
|
/* attempt i2c write transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_CONFIG, config.reg), TAG, "write configuration register failed" );
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_init(i2c_master_bus_handle_t master_handle, const bme680_config_t *bme680_config, bme680_handle_t *bme680_handle) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( master_handle && bme680_config );
|
|
|
|
/* delay task before i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_POWERUP_DELAY_MS));
|
|
|
|
/* validate device exists on the master bus */
|
|
esp_err_t ret = i2c_master_probe(master_handle, bme680_config->i2c_address, I2C_XFR_TIMEOUT_MS);
|
|
ESP_GOTO_ON_ERROR(ret, err, TAG, "device does not exist at address 0x%02x, bmp280 device handle initialization failed", bme680_config->i2c_address);
|
|
|
|
/* validate memory availability for handle */
|
|
bme680_handle_t out_handle;
|
|
out_handle = (bme680_handle_t)calloc(1, sizeof(*out_handle));
|
|
ESP_GOTO_ON_FALSE(out_handle, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c0 bmp280 device for init");
|
|
|
|
/* validate memory availability for handle calibration factors */
|
|
out_handle->dev_cal_factors = (bme680_cal_factors_t*)calloc(1, sizeof(bme680_cal_factors_t));
|
|
ESP_GOTO_ON_FALSE(out_handle->dev_cal_factors, ESP_ERR_NO_MEM, err_handle, TAG, "no memory for i2c bmp280 device calibration factors for init");
|
|
|
|
/* copy configuration */
|
|
out_handle->dev_config = *bme680_config;
|
|
|
|
/* set i2c device configuration */
|
|
const i2c_device_config_t i2c_dev_conf = {
|
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
.device_address = out_handle->dev_config.i2c_address,
|
|
.scl_speed_hz = out_handle->dev_config.i2c_clock_speed,
|
|
};
|
|
|
|
/* validate device handle */
|
|
if (out_handle->i2c_handle == NULL) {
|
|
ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(master_handle, &i2c_dev_conf, &out_handle->i2c_handle), err_handle, TAG, "i2c0 new bus failed for init");
|
|
}
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
/* read and validate device type */
|
|
ESP_GOTO_ON_ERROR(bme680_get_chip_id_register(out_handle, &out_handle->chip_id), err_handle, TAG, "read chip identifier for init failed");
|
|
if(out_handle->chip_id != BME680_CHIP_ID) {
|
|
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_VERSION, err_handle, TAG, "detected an invalid chip type for init, got: %02x", out_handle->chip_id);
|
|
}
|
|
|
|
/* attempt to reset the device and initialize registers */
|
|
ESP_GOTO_ON_ERROR(bme680_reset(out_handle), err_handle, TAG, "soft-reset and initialize registers for init failed");
|
|
|
|
/* copy configuration */
|
|
*bme680_handle = out_handle;
|
|
|
|
/* delay task before i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_APPSTART_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
|
|
err_handle:
|
|
if (out_handle && out_handle->i2c_handle) {
|
|
i2c_master_bus_rm_device(out_handle->i2c_handle);
|
|
}
|
|
free(out_handle);
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
char *bme680_air_quality_to_string(float iaq_score) {
|
|
if (iaq_score < 25) return "Hazardous";
|
|
else if (iaq_score >= 25 && iaq_score <= 38) return "Unhealthy";
|
|
else if (iaq_score > 38 && iaq_score <= 51) return "Moderate";
|
|
else if (iaq_score > 51 && iaq_score <= 60) return "Good";
|
|
else if (iaq_score > 60 && iaq_score <= 65) return "Excellent";
|
|
else return "Unknown";
|
|
}
|
|
|
|
esp_err_t bme680_get_adc_signals(bme680_handle_t handle, bme680_adc_data_t *const data) {
|
|
esp_err_t ret = ESP_OK;
|
|
bool data_is_ready = false;
|
|
uint8_t gas_index = 0;
|
|
uint16_t adc_gas_r;
|
|
uint32_t adc_press;
|
|
uint16_t adc_humi;
|
|
uint32_t adc_temp;
|
|
bit104_uint8_buffer_t rx;
|
|
bme680_status0_register_t status0_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle && data );
|
|
|
|
/* trigger measurement when in forced mode */
|
|
if(handle->dev_config.power_mode == BME680_POWER_MODE_FORCED) {
|
|
bme680_set_power_mode(handle, BME680_POWER_MODE_FORCED);
|
|
}
|
|
|
|
/* set start time for timeout monitoring */
|
|
uint64_t start_time = esp_timer_get_time();
|
|
|
|
/* attempt to poll until data is available or timeout */
|
|
do {
|
|
/* attempt to check if data is ready */
|
|
//ESP_GOTO_ON_ERROR( bme680_get_data_status(handle, &data_is_ready), err, TAG, "data ready for get adc signals failed." );
|
|
ESP_GOTO_ON_ERROR( bme680_get_status0_register(handle, &status0_reg), err, TAG, "status 0 register for get adc signals failed." );
|
|
|
|
data_is_ready = status0_reg.bits.new_data;
|
|
gas_index = status0_reg.bits.gas_measurement_index;
|
|
|
|
/* delay task before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_DATA_READY_DELAY_MS));
|
|
|
|
/* validate timeout condition */
|
|
if (ESP_TIMEOUT_CHECK(start_time, BME680_DATA_POLL_TIMEOUT_MS * 1000))
|
|
return ESP_ERR_TIMEOUT;
|
|
} while (data_is_ready == false);
|
|
|
|
// need to read in one sequence to ensure they match.
|
|
ESP_GOTO_ON_ERROR( bme680_i2c_read_from(handle, BME680_REG_PRESS, rx, BIT104_UINT8_BUFFER_SIZE), err, TAG, "read adc data failed" );
|
|
|
|
/* instantiate gas lsb register */
|
|
bme680_gas_lsb_register_t gas_lsb_reg = { .reg = rx[12] };
|
|
|
|
/* concat parameters */
|
|
adc_press = ((uint32_t)rx[0] << 12) | ((uint32_t)rx[1] << 4) | ((uint32_t)rx[2] >> 4);
|
|
adc_temp = ((uint32_t)rx[3] << 12) | ((uint32_t)rx[4] << 4) | ((uint32_t)rx[5] >> 4);
|
|
adc_humi = ((uint16_t)rx[6] << 8) | (uint16_t)rx[7];
|
|
adc_gas_r = ((uint16_t)rx[11] << 2) | ((uint16_t)rx[12] >> 6);
|
|
|
|
ESP_LOGD(TAG, "ADC humidity: %" PRIu16, adc_humi);
|
|
ESP_LOGD(TAG, "ADC temperature: %" PRIu32, adc_temp);
|
|
ESP_LOGD(TAG, "ADC pressure: %" PRIu32, adc_press);
|
|
ESP_LOGD(TAG, "ADC gas: %" PRIu16, adc_gas_r);
|
|
|
|
/* initialize data structure */
|
|
data->temperature = adc_temp;
|
|
data->humidity = adc_humi;
|
|
data->pressure = adc_press;
|
|
data->gas = adc_gas_r;
|
|
data->gas_index = gas_index;
|
|
data->gas_range = gas_lsb_reg.bits.gas_range;
|
|
data->heater_stable = gas_lsb_reg.bits.heater_stable;
|
|
data->gas_valid = gas_lsb_reg.bits.gas_valid;
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
esp_err_t bme680_get_data(bme680_handle_t handle, bme680_data_t *const data) {
|
|
bme680_adc_data_t adc_data;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle && data );
|
|
|
|
/* attempt to read adc signals */
|
|
ESP_RETURN_ON_ERROR( bme680_get_adc_signals(handle, &adc_data), TAG, "read adc signals failed" );
|
|
|
|
/* initialize data structure */
|
|
data->air_temperature = bme680_compensate_temperature(handle, adc_data.temperature);
|
|
data->relative_humidity = bme680_compensate_humidity(handle, adc_data.humidity);
|
|
data->dewpoint_temperature = bme680_calculate_dewpoint(data->air_temperature, data->relative_humidity);
|
|
data->barometric_pressure = bme680_compensate_pressure(handle, adc_data.pressure);
|
|
data->gas_resistance = bme680_compensate_gas_resistance(handle, adc_data.gas, adc_data.gas_range);
|
|
data->gas_range = adc_data.gas_range;
|
|
data->heater_stable = adc_data.heater_stable;
|
|
data->gas_valid = adc_data.gas_valid;
|
|
|
|
data->raw_data = adc_data;
|
|
|
|
/* compute scores */
|
|
bme680_compute_iaq(data);
|
|
|
|
/* delay before next i2c transaction */
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_CMD_DELAY_MS));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_data_status(bme680_handle_t handle, bool *const ready) {
|
|
bme680_status0_register_t status0_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read device status register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_status0_register(handle, &status0_reg), TAG, "read status register (data ready state) failed" );
|
|
|
|
/* set ready state */
|
|
*ready = status0_reg.bits.new_data;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_gas_measurement_index(bme680_handle_t handle, uint8_t *const index) {
|
|
bme680_status0_register_t status0_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read device status register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_status0_register(handle, &status0_reg), TAG, "read status register (gas measurement index) failed" );
|
|
|
|
/* set gas measurement index */
|
|
*index = status0_reg.bits.gas_measurement_index;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_power_mode(bme680_handle_t handle, bme680_power_modes_t *const power_mode) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get power mode failed" );
|
|
|
|
/* set power mode */
|
|
*power_mode = ctrl_meas_reg.bits.power_mode;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_power_mode(bme680_handle_t handle, const bme680_power_modes_t power_mode) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get power mode failed" );
|
|
|
|
/* initialize control measurement register */
|
|
ctrl_meas_reg.bits.power_mode = power_mode;
|
|
|
|
/* attempt to write control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_set_control_measurement_register(handle, ctrl_meas_reg), TAG, "write control measurement register for set power mode failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_pressure_oversampling(bme680_handle_t handle, bme680_pressure_oversampling_t *const oversampling) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get pressure oversampling failed" );
|
|
|
|
/* set oversampling */
|
|
*oversampling = ctrl_meas_reg.bits.pressure_oversampling;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_pressure_oversampling(bme680_handle_t handle, const bme680_pressure_oversampling_t oversampling) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get pressure oversampling failed" );
|
|
|
|
/* initialize control measurement register */
|
|
ctrl_meas_reg.bits.pressure_oversampling = oversampling;
|
|
|
|
/* attempt to write control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_set_control_measurement_register(handle, ctrl_meas_reg), TAG, "write control measurement register for set pressure oversampling failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_temperature_oversampling(bme680_handle_t handle, bme680_temperature_oversampling_t *const oversampling) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get temperature oversampling failed" );
|
|
|
|
/* set oversampling */
|
|
*oversampling = ctrl_meas_reg.bits.temperature_oversampling;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_temperature_oversampling(bme680_handle_t handle, const bme680_temperature_oversampling_t oversampling) {
|
|
bme680_control_measurement_register_t ctrl_meas_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_measurement_register(handle, &ctrl_meas_reg), TAG, "read control measurement register for get temperature oversampling failed" );
|
|
|
|
/* initialize control measurement register */
|
|
ctrl_meas_reg.bits.temperature_oversampling = oversampling;
|
|
|
|
/* attempt to write control measurement register */
|
|
ESP_RETURN_ON_ERROR( bme680_set_control_measurement_register(handle, ctrl_meas_reg), TAG, "write control measurement register for set temperature oversampling failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_humidity_oversampling(bme680_handle_t handle, bme680_humidity_oversampling_t *const oversampling) {
|
|
bme680_control_humidity_register_t ctrl_humi_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control humidity register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_humidity_register(handle, &ctrl_humi_reg), TAG, "read control humidity register for get humidity oversampling failed" );
|
|
|
|
/* set oversampling */
|
|
*oversampling = ctrl_humi_reg.bits.humidity_oversampling;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_humidity_oversampling(bme680_handle_t handle, const bme680_humidity_oversampling_t oversampling) {
|
|
bme680_control_humidity_register_t ctrl_humi_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read control humidity register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_control_humidity_register(handle, &ctrl_humi_reg), TAG, "read control humidity register for get humidity oversampling failed" );
|
|
|
|
/* set oversampling */
|
|
ctrl_humi_reg.bits.humidity_oversampling = oversampling;
|
|
|
|
/* attempt to write control humidity register */
|
|
ESP_RETURN_ON_ERROR( bme680_set_control_humidity_register(handle, ctrl_humi_reg), TAG, "write control humidity register for get humidity oversampling failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_get_iir_filter(bme680_handle_t handle, bme680_iir_filters_t *const iir_filter) {
|
|
bme680_config_register_t config_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read configuration register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_configuration_register(handle, &config_reg), TAG, "read configuration register for get IIR filter failed" );
|
|
|
|
/* set standby time */
|
|
*iir_filter = config_reg.bits.iir_filter;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_set_iir_filter(bme680_handle_t handle, const bme680_iir_filters_t iir_filter) {
|
|
bme680_config_register_t config_reg;
|
|
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt to read configuration register */
|
|
ESP_RETURN_ON_ERROR( bme680_get_configuration_register(handle, &config_reg), TAG, "read configuration register for get IIR filter failed" );
|
|
|
|
/* initialize configuration register */
|
|
config_reg.bits.iir_filter = iir_filter;
|
|
|
|
/* attempt to write configuration register */
|
|
ESP_RETURN_ON_ERROR( bme680_set_configuration_register(handle, config_reg), TAG, "write configuration register for set IIR filter failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_reset(bme680_handle_t handle) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* attempt i2c transaction */
|
|
ESP_RETURN_ON_ERROR( bme680_i2c_write_byte_to(handle, BME680_REG_RESET, BME680_RESET_VALUE), TAG, "write reset register for reset failed" );
|
|
|
|
/* wait until finished copying NVP data */
|
|
// forced delay before next transaction - see datasheet for details
|
|
vTaskDelay(pdMS_TO_TICKS(BME680_RESET_DELAY_MS)); // check is busy in timeout loop...
|
|
|
|
/* attempt to setup device */
|
|
ESP_RETURN_ON_ERROR( bme680_setup(handle), TAG, "setup device for reset failed" );
|
|
|
|
/* attempt to setup device heaters */
|
|
ESP_RETURN_ON_ERROR( bme680_setup_heater(handle), TAG, "setup device heaters for reset failed" );
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme680_remove(bme680_handle_t handle) {
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
return i2c_master_bus_rm_device(handle->i2c_handle);
|
|
}
|
|
|
|
esp_err_t bme680_delete(bme680_handle_t handle){
|
|
/* validate arguments */
|
|
ESP_ARG_CHECK( handle );
|
|
|
|
/* remove device from master bus */
|
|
ESP_RETURN_ON_ERROR( bme680_remove(handle), TAG, "unable to remove device from i2c master bus, delete handle failed" );
|
|
|
|
/* validate handle instance and free handles */
|
|
if(handle->i2c_handle) {
|
|
free(handle->i2c_handle);
|
|
free(handle);
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
const char* bme680_get_fw_version(void) {
|
|
return (const char*)BME680_FW_VERSION_STR;
|
|
}
|
|
|
|
int32_t bme680_get_fw_version_number(void) {
|
|
return BME680_FW_VERSION_INT32;
|
|
}
|