mirror of
https://github.com/alexandrebobkov/ESP-Nodes.git
synced 2025-10-23 16:32:11 +00:00
373 lines
14 KiB
C
373 lines
14 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "i2c_bus.h"
|
|
#include "bme280.h"
|
|
#include "math.h"
|
|
#include "esp_log.h"
|
|
|
|
bme280_handle_t bme280_create(i2c_bus_handle_t bus, uint8_t dev_addr)
|
|
{
|
|
bme280_dev_t *sens = (bme280_dev_t *) calloc(1, sizeof(bme280_dev_t));
|
|
sens->i2c_dev = i2c_bus_device_create(bus, dev_addr, i2c_bus_get_current_clk_speed(bus));
|
|
if (sens->i2c_dev == NULL) {
|
|
free(sens);
|
|
return NULL;
|
|
}
|
|
sens->dev_addr = dev_addr;
|
|
return (bme280_handle_t)sens;
|
|
}
|
|
|
|
esp_err_t bme280_delete(bme280_handle_t *sensor)
|
|
{
|
|
if (*sensor == NULL) {
|
|
return ESP_OK;
|
|
}
|
|
bme280_dev_t *sens = (bme280_dev_t *)(*sensor);
|
|
i2c_bus_device_delete(&sens->i2c_dev);
|
|
free(sens);
|
|
*sensor = NULL;
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t bme280_read_uint16(bme280_handle_t sensor, uint8_t addr, uint16_t *data)
|
|
{
|
|
esp_err_t ret = ESP_FAIL;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
uint8_t data0, data1;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, addr, &data0) != ESP_OK) {
|
|
return ret;
|
|
}
|
|
if (i2c_bus_read_byte(sens->i2c_dev, addr + 1, &data1) != ESP_OK) {
|
|
return ret;
|
|
}
|
|
*data = (data0 << 8) | data1;
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t bme280_read_uint16_le(bme280_handle_t sensor, uint8_t addr, uint16_t *data)
|
|
{
|
|
esp_err_t ret = ESP_FAIL;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
uint8_t data0, data1;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, addr, &data0) != ESP_OK) {
|
|
return ret;
|
|
}
|
|
if (i2c_bus_read_byte(sens->i2c_dev, addr + 1, &data1) != ESP_OK) {
|
|
return ret;
|
|
}
|
|
*data = (data1 << 8) | data0;
|
|
return ESP_OK;
|
|
}
|
|
|
|
unsigned int bme280_getconfig(bme280_handle_t sensor)
|
|
{
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
return (sens->config_t.t_sb << 5) | (sens->config_t.filter << 3) | sens->config_t.spi3w_en;
|
|
}
|
|
|
|
unsigned int bme280_getctrl_meas(bme280_handle_t sensor)
|
|
{
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
return (sens->ctrl_meas_t.osrs_t << 5) | (sens->ctrl_meas_t.osrs_p << 3) | sens->ctrl_meas_t.mode;
|
|
}
|
|
|
|
unsigned int bme280_getctrl_hum(bme280_handle_t sensor)
|
|
{
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
return (sens->ctrl_hum_t.osrs_h);
|
|
}
|
|
|
|
bool bme280_is_reading_calibration(bme280_handle_t sensor)
|
|
{
|
|
uint8_t rstatus = 0;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_STATUS, &rstatus) != ESP_OK) {
|
|
return false;
|
|
}
|
|
return (rstatus & (1 << 0)) != 0;
|
|
}
|
|
|
|
esp_err_t bme280_read_coefficients(bme280_handle_t sensor)
|
|
{
|
|
uint8_t data = 0;
|
|
uint8_t data1 = 0;
|
|
uint16_t data16 = 0;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_T1, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_t1 = data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_T2, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_t2 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_T3, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_t3 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P1, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p1 = data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P2, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p2 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P3, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p3 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P4, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p4 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P5, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p5 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P6, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p6 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P7, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p7 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P8, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p8 = (int16_t) data16;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_P9, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_p9 = (int16_t) data16;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H1, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h1 = data;
|
|
if (bme280_read_uint16_le(sensor, BME280_REGISTER_DIG_H2, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h2 = (int16_t) data16;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H3, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h3 = data;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H4, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H4 + 1, &data1) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h4 = (data << 4) | (data1 & 0xF);
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H5 + 1, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H5, &data1) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h5 = (data << 4) | (data1 >> 4);
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_DIG_H6, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
sens->data_t.dig_h6 = (int8_t) data;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_set_sampling(bme280_handle_t sensor, bme280_sensor_mode mode, bme280_sensor_sampling tempSampling, bme280_sensor_sampling pressSampling, bme280_sensor_sampling humSampling, bme280_sensor_filter filter, bme280_standby_duration duration)
|
|
{
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
sens->ctrl_meas_t.mode = mode;
|
|
sens->ctrl_meas_t.osrs_t = tempSampling;
|
|
sens->ctrl_meas_t.osrs_p = pressSampling;
|
|
sens->ctrl_hum_t.osrs_h = humSampling;
|
|
sens->config_t.filter = filter;
|
|
sens->config_t.t_sb = duration;
|
|
// you must make sure to also set REGISTER_CONTROL after setting the
|
|
// CONTROLHUMID register, otherwise the values won't be applied (see DS 5.4.3)
|
|
if (i2c_bus_write_byte(sens->i2c_dev, BME280_REGISTER_CONTROLHUMID, bme280_getctrl_hum(sensor)) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
if (i2c_bus_write_byte(sens->i2c_dev, BME280_REGISTER_CONFIG, bme280_getconfig(sensor)) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
if (i2c_bus_write_byte(sens->i2c_dev, BME280_REGISTER_CONTROL, bme280_getctrl_meas(sensor)) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_default_init(bme280_handle_t sensor)
|
|
{
|
|
// check if sensor, i.e. the chip ID is correct
|
|
uint8_t chipid = 0;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_CHIPID, &chipid) != ESP_OK) {
|
|
ESP_LOGI("BME280:", "bme280_default_init->bme280_read_byte ->BME280_REGISTER_CHIPID failed!!!!:%x", chipid);
|
|
return ESP_FAIL;
|
|
}
|
|
if (chipid != BME280_DEFAULT_CHIPID) {
|
|
ESP_LOGI("BME280:", "bme280_default_init->BME280_DEFAULT_CHIPID:%x", chipid);
|
|
return ESP_FAIL;
|
|
}
|
|
// reset the sens using soft-reset, this makes sure the IIR is off, etc.
|
|
if (i2c_bus_write_byte(sens->i2c_dev, BME280_REGISTER_SOFTRESET, 0xB6) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
// wait for chip to wake up.
|
|
vTaskDelay(300 / portTICK_RATE_MS);
|
|
// if chip is still reading calibration, delay
|
|
while (bme280_is_reading_calibration(sensor)) {
|
|
vTaskDelay(100 / portTICK_RATE_MS);
|
|
}
|
|
if (bme280_read_coefficients(sensor) != ESP_OK) { // read trimming parameters, see DS 4.2.2
|
|
return ESP_FAIL;
|
|
}
|
|
if (bme280_set_sampling(sensor, BME280_MODE_NORMAL, BME280_SAMPLING_X16, BME280_SAMPLING_X16, BME280_SAMPLING_X16, BME280_FILTER_OFF, BME280_STANDBY_MS_0_5) != ESP_OK) { // use defaults
|
|
return ESP_FAIL;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_take_forced_measurement(bme280_handle_t sensor)
|
|
{
|
|
uint8_t data = 0;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
if (sens->ctrl_meas_t.mode == BME280_MODE_FORCED) {
|
|
// set to forced mode, i.e. "take next measurement"
|
|
if (i2c_bus_write_byte(sens->i2c_dev, BME280_REGISTER_CONTROL, bme280_getctrl_meas(sensor)) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
// wait until measurement has been completed, otherwise we would read, the values from the last measurement
|
|
if (i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_STATUS, &data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
while (data & 0x08) {
|
|
i2c_bus_read_byte(sens->i2c_dev, BME280_REGISTER_STATUS, &data);
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_read_temperature(bme280_handle_t sensor, float *temperature)
|
|
{
|
|
int32_t var1, var2;
|
|
uint8_t data[3] = { 0 };
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
if (i2c_bus_read_bytes(sens->i2c_dev, BME280_REGISTER_TEMPDATA, 3, data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
int32_t adc_T = (data[0] << 16) | (data[1] << 8) | data[2];
|
|
if (adc_T == 0x800000) { // value in case temp measurement was disabled
|
|
return ESP_FAIL;
|
|
}
|
|
adc_T >>= 4;
|
|
|
|
var1 = ((((adc_T >> 3) - ((int32_t) sens->data_t.dig_t1 << 1)))
|
|
* ((int32_t) sens->data_t.dig_t2)) >> 11;
|
|
|
|
var2 = (((((adc_T >> 4) - ((int32_t) sens->data_t.dig_t1))
|
|
* ((adc_T >> 4) - ((int32_t) sens->data_t.dig_t1))) >> 12)
|
|
* ((int32_t) sens->data_t.dig_t3)) >> 14;
|
|
|
|
sens->t_fine = var1 + var2;
|
|
*temperature = ((sens->t_fine * 5 + 128) >> 8) / 100.0;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_read_pressure(bme280_handle_t sensor, float *pressure)
|
|
{
|
|
int64_t var1, var2, p;
|
|
uint8_t data[3] = { 0 };
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
float temp = 0.0;
|
|
if (bme280_read_temperature(sensor, &temp) != ESP_OK) {
|
|
// must be done first to get t_fine
|
|
return ESP_FAIL;
|
|
}
|
|
if (i2c_bus_read_bytes(sens->i2c_dev, BME280_REGISTER_PRESSUREDATA, 3, data) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
int32_t adc_P = (data[0] << 16) | (data[1] << 8) | data[2];
|
|
if (adc_P == 0x800000) { // value in case pressure measurement was disabled
|
|
return ESP_FAIL;
|
|
}
|
|
adc_P >>= 4;
|
|
var1 = ((int64_t) sens->t_fine) - 128000;
|
|
var2 = var1 * var1 * (int64_t) sens->data_t.dig_p6;
|
|
var2 = var2 + ((var1 * (int64_t) sens->data_t.dig_p5) << 17);
|
|
var2 = var2 + (((int64_t) sens->data_t.dig_p4) << 35);
|
|
var1 = ((var1 * var1 * (int64_t) sens->data_t.dig_p3) >> 8) + ((var1 * (int64_t) sens->data_t.dig_p2) << 12);
|
|
var1 = (((((int64_t) 1) << 47) + var1)) * ((int64_t) sens->data_t.dig_p1) >> 33;
|
|
if (var1 == 0) {
|
|
return ESP_FAIL; // avoid exception caused by division by zero
|
|
}
|
|
p = 1048576 - adc_P;
|
|
p = (((p << 31) - var2) * 3125) / var1;
|
|
var1 = (((int64_t) sens->data_t.dig_p9) * (p >> 13) * (p >> 13)) >> 25;
|
|
var2 = (((int64_t) sens->data_t.dig_p8) * p) >> 19;
|
|
p = ((p + var1 + var2) >> 8) + (((int64_t) sens->data_t.dig_p7) << 4);
|
|
p = p >> 8; // /256
|
|
*pressure = (float) p / 100;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_read_humidity(bme280_handle_t sensor, float *humidity)
|
|
{
|
|
uint16_t data16;
|
|
bme280_dev_t *sens = (bme280_dev_t *) sensor;
|
|
float temp = 0.0;
|
|
if (bme280_read_temperature(sensor, &temp) != ESP_OK) {
|
|
// must be done first to get t_fine
|
|
return ESP_FAIL;
|
|
}
|
|
if (bme280_read_uint16(sensor, BME280_REGISTER_HUMIDDATA, &data16) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
int32_t adc_H = data16;
|
|
if (adc_H == 0x8000) { // value in case humidity measurement was disabled
|
|
return ESP_FAIL;
|
|
}
|
|
int32_t v_x1_u32r;
|
|
v_x1_u32r = (sens->t_fine - ((int32_t) 76800));
|
|
v_x1_u32r = (((((adc_H << 14) - (((int32_t) sens->data_t.dig_h4) << 20)
|
|
- (((int32_t) sens->data_t.dig_h5) * v_x1_u32r))
|
|
+ ((int32_t) 16384)) >> 15)
|
|
* (((((((v_x1_u32r * ((int32_t) sens->data_t.dig_h6)) >> 10)
|
|
* (((v_x1_u32r * ((int32_t) sens->data_t.dig_h3)) >> 11) + ((int32_t) 32768))) >> 10) + ((int32_t) 2097152))
|
|
* ((int32_t) sens->data_t.dig_h2) + 8192) >> 14));
|
|
v_x1_u32r = (v_x1_u32r
|
|
- (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7)
|
|
* ((int32_t) sens->data_t.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;
|
|
*humidity = (v_x1_u32r >> 12) / 1024.0;
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_read_altitude(bme280_handle_t sensor, float seaLevel, float *altitude)
|
|
{
|
|
float pressure = 0.0;
|
|
float temp = 0.0;
|
|
if (bme280_read_pressure(sensor, &temp) != ESP_OK) {
|
|
return ESP_FAIL;
|
|
}
|
|
float atmospheric = pressure / 100.0F;
|
|
*altitude = 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t bme280_calculates_pressure(bme280_handle_t sensor, float altitude,
|
|
float atmospheric, float *pressure)
|
|
{
|
|
*pressure = atmospheric / pow(1.0 - (altitude / 44330.0), 5.255);
|
|
return ESP_OK;
|
|
}
|