Initial commit
This commit is contained in:
625
BME68x_manager.c
Normal file
625
BME68x_manager.c
Normal file
@@ -0,0 +1,625 @@
|
||||
#include "BME68x_manager.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static const char *TAG = "BME68x_Manager";
|
||||
|
||||
// BME68x calibration coefficients structure
|
||||
typedef struct
|
||||
{
|
||||
uint16_t par_t1;
|
||||
int16_t par_t2;
|
||||
int8_t par_t3;
|
||||
uint16_t par_p1;
|
||||
int16_t par_p2;
|
||||
int8_t par_p3;
|
||||
int16_t par_p4;
|
||||
int16_t par_p5;
|
||||
int8_t par_p6;
|
||||
int8_t par_p7;
|
||||
int16_t par_p8;
|
||||
int16_t par_p9;
|
||||
uint8_t par_p10;
|
||||
uint16_t par_h1;
|
||||
uint16_t par_h2;
|
||||
int8_t par_h3;
|
||||
int8_t par_h4;
|
||||
int8_t par_h5;
|
||||
uint8_t par_h6;
|
||||
int8_t par_h7;
|
||||
int8_t par_gh1;
|
||||
int16_t par_gh2;
|
||||
int8_t par_gh3;
|
||||
uint8_t res_heat_range;
|
||||
int8_t res_heat_val;
|
||||
int8_t range_sw_err;
|
||||
int32_t t_fine;
|
||||
} BME68x_calib_data_t;
|
||||
|
||||
// Global calibration data and current I2C address
|
||||
static BME68x_calib_data_t calib_data;
|
||||
static uint8_t current_i2c_addr = BME68x_I2C_ADDR_PRIMARY;
|
||||
|
||||
// Static function declarations
|
||||
static esp_err_t BME68x_register_read(uint8_t reg_addr, uint8_t *data, size_t len);
|
||||
static esp_err_t BME68x_register_write_byte(uint8_t reg_addr, uint8_t data);
|
||||
static esp_err_t BME68x_get_calib_data(void);
|
||||
static float BME68x_calc_temperature(uint32_t temp_adc);
|
||||
static float BME68x_calc_pressure(uint32_t pres_adc);
|
||||
static float BME68x_calc_humidity(uint16_t hum_adc);
|
||||
static float BME68x_calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range);
|
||||
static uint8_t BME68x_calc_heater_res(uint16_t temp);
|
||||
static uint8_t BME68x_calc_air_quality_score(float gas_resistance, float humidity);
|
||||
|
||||
/**
|
||||
* @brief i2c master initialization
|
||||
*/
|
||||
esp_err_t bme68x_i2c_init(void)
|
||||
{
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_err_t ret = i2c_param_config(i2c_master_port, &conf);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "I2C param config failed: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "I2C driver install failed: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a sequence of bytes from a BME68x sensor registers
|
||||
*/
|
||||
static esp_err_t BME68x_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
|
||||
{
|
||||
return i2c_master_write_read_device(I2C_MASTER_NUM, current_i2c_addr, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a byte to a BME68x sensor register
|
||||
*/
|
||||
static esp_err_t BME68x_register_write_byte(uint8_t reg_addr, uint8_t data)
|
||||
{
|
||||
uint8_t write_buf[2] = {reg_addr, data};
|
||||
return i2c_master_write_to_device(I2C_MASTER_NUM, current_i2c_addr, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform simple I2C bus recovery
|
||||
*/
|
||||
esp_err_t bme68x_i2c_recovery(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Performing I2C bus recovery...");
|
||||
|
||||
// Simple approach: just reset the pins briefly
|
||||
gpio_reset_pin(I2C_MASTER_SDA_IO);
|
||||
gpio_reset_pin(I2C_MASTER_SCL_IO);
|
||||
|
||||
// Configure pins as outputs temporarily
|
||||
gpio_set_direction(I2C_MASTER_SCL_IO, GPIO_MODE_OUTPUT);
|
||||
gpio_set_direction(I2C_MASTER_SDA_IO, GPIO_MODE_OUTPUT);
|
||||
gpio_set_pull_mode(I2C_MASTER_SCL_IO, GPIO_PULLUP_ONLY);
|
||||
gpio_set_pull_mode(I2C_MASTER_SDA_IO, GPIO_PULLUP_ONLY);
|
||||
|
||||
// Set both pins high
|
||||
gpio_set_level(I2C_MASTER_SCL_IO, 1);
|
||||
gpio_set_level(I2C_MASTER_SDA_IO, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// Send some clock pulses
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
gpio_set_level(I2C_MASTER_SCL_IO, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
gpio_set_level(I2C_MASTER_SCL_IO, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
|
||||
// Reset pins back to default
|
||||
gpio_reset_pin(I2C_MASTER_SDA_IO);
|
||||
gpio_reset_pin(I2C_MASTER_SCL_IO);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
ESP_LOGI(TAG, "I2C bus recovery completed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Scan I2C bus for devices
|
||||
*/
|
||||
void bme68x_i2c_scan(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Scanning I2C bus...");
|
||||
printf("Scanning I2C bus for devices:\n");
|
||||
|
||||
int devices_found = 0;
|
||||
|
||||
// Scan only common I2C addresses to avoid null address errors
|
||||
uint8_t common_addresses[] = {0x76, 0x77, 0x3C, 0x3D, 0x48, 0x49, 0x4A, 0x4B, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75};
|
||||
int num_addresses = sizeof(common_addresses) / sizeof(common_addresses[0]);
|
||||
|
||||
for (int i = 0; i < num_addresses; i++)
|
||||
{
|
||||
uint8_t addr = common_addresses[i];
|
||||
esp_err_t ret = i2c_master_write_to_device(I2C_MASTER_NUM, addr, NULL, 0, 100 / portTICK_PERIOD_MS);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
printf(" Device found at address 0x%02X\n", addr);
|
||||
ESP_LOGI(TAG, "I2C device found at address 0x%02X", addr);
|
||||
devices_found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (devices_found == 0)
|
||||
{
|
||||
printf(" No I2C devices found at common addresses!\n");
|
||||
ESP_LOGW(TAG, "No I2C devices found at common addresses");
|
||||
printf(" (Scanned: 0x76, 0x77, 0x3C, 0x3D, 0x48-0x4B, 0x68-0x75)\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" Found %d I2C device(s)\n", devices_found);
|
||||
ESP_LOGI(TAG, "Found %d I2C device(s) on bus", devices_found);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Software reset BME68x sensor
|
||||
*/
|
||||
esp_err_t bme68x_soft_reset(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Performing BME68x soft reset...");
|
||||
|
||||
// BME68x soft reset command
|
||||
esp_err_t ret = BME68x_register_write_byte(0xE0, 0xB6); // Reset register with reset command
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(10)); // Wait for reset to complete
|
||||
ESP_LOGI(TAG, "BME68x soft reset completed");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "BME68x soft reset failed, but continuing...");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test BME68x sensor connection and read chip ID with recovery attempts
|
||||
*/
|
||||
esp_err_t bme68x_test_connection(void)
|
||||
{
|
||||
uint8_t chip_id;
|
||||
esp_err_t ret;
|
||||
int retry_count = 0;
|
||||
const int max_retries = 3;
|
||||
|
||||
while (retry_count < max_retries)
|
||||
{
|
||||
ESP_LOGI(TAG, "BME68x connection attempt %d/%d", retry_count + 1, max_retries);
|
||||
|
||||
// Try primary address first
|
||||
current_i2c_addr = BME68x_I2C_ADDR_PRIMARY;
|
||||
ret = BME68x_register_read(BME68x_REG_CHIP_ID, &chip_id, 1);
|
||||
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Failed to read from primary address 0x%02X, trying secondary address...", BME68x_I2C_ADDR_PRIMARY);
|
||||
|
||||
// Try secondary address
|
||||
current_i2c_addr = BME68x_I2C_ADDR_SECONDARY;
|
||||
ret = BME68x_register_read(BME68x_REG_CHIP_ID, &chip_id, 1);
|
||||
}
|
||||
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
if (chip_id == BME68x_CHIP_ID)
|
||||
{
|
||||
ESP_LOGI(TAG, "BME68x sensor found! Chip ID: 0x%02X (Address: 0x%02X)", chip_id, current_i2c_addr);
|
||||
return ESP_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Unexpected chip ID: 0x%02X (expected 0x%02X)", chip_id, BME68x_CHIP_ID);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to communicate with BME68x sensor (attempt %d)", retry_count + 1);
|
||||
}
|
||||
|
||||
// If communication failed, try recovery
|
||||
if (ret != ESP_OK && retry_count < max_retries - 1)
|
||||
{
|
||||
ESP_LOGI(TAG, "Attempting I2C bus recovery...");
|
||||
bme68x_i2c_recovery();
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Wait after recovery
|
||||
}
|
||||
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "Failed to communicate with BME68x sensor after %d attempts", max_retries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read calibration coefficients from BME68x
|
||||
*/
|
||||
static esp_err_t BME68x_get_calib_data(void)
|
||||
{
|
||||
uint8_t coeff_array[41];
|
||||
esp_err_t ret;
|
||||
|
||||
// Read first set of coefficients (0x89 to 0xA1)
|
||||
ret = BME68x_register_read(BME68x_COEFF_ADDR1, coeff_array, 25);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Read second set of coefficients (0xE1 to 0xF0)
|
||||
ret = BME68x_register_read(BME68x_COEFF_ADDR2, &coeff_array[25], 16);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Temperature coefficients
|
||||
calib_data.par_t1 = (uint16_t)(((uint16_t)coeff_array[34] << 8) | coeff_array[33]);
|
||||
calib_data.par_t2 = (int16_t)(((uint16_t)coeff_array[2] << 8) | coeff_array[1]);
|
||||
calib_data.par_t3 = (int8_t)coeff_array[3];
|
||||
|
||||
// Pressure coefficients
|
||||
calib_data.par_p1 = (uint16_t)(((uint16_t)coeff_array[6] << 8) | coeff_array[5]);
|
||||
calib_data.par_p2 = (int16_t)(((uint16_t)coeff_array[8] << 8) | coeff_array[7]);
|
||||
calib_data.par_p3 = (int8_t)coeff_array[9];
|
||||
calib_data.par_p4 = (int16_t)(((uint16_t)coeff_array[12] << 8) | coeff_array[11]);
|
||||
calib_data.par_p5 = (int16_t)(((uint16_t)coeff_array[14] << 8) | coeff_array[13]);
|
||||
calib_data.par_p6 = (int8_t)coeff_array[16];
|
||||
calib_data.par_p7 = (int8_t)coeff_array[15];
|
||||
calib_data.par_p8 = (int16_t)(((uint16_t)coeff_array[20] << 8) | coeff_array[19]);
|
||||
calib_data.par_p9 = (int16_t)(((uint16_t)coeff_array[22] << 8) | coeff_array[21]);
|
||||
calib_data.par_p10 = (uint8_t)coeff_array[23];
|
||||
|
||||
// Humidity coefficients
|
||||
calib_data.par_h1 = (uint16_t)(((uint16_t)coeff_array[27] << 4) | (coeff_array[26] & 0x0F));
|
||||
calib_data.par_h2 = (uint16_t)(((uint16_t)coeff_array[25] << 4) | (coeff_array[26] >> 4));
|
||||
calib_data.par_h3 = (int8_t)coeff_array[28];
|
||||
calib_data.par_h4 = (int8_t)coeff_array[29];
|
||||
calib_data.par_h5 = (int8_t)coeff_array[30];
|
||||
calib_data.par_h6 = (uint8_t)coeff_array[31];
|
||||
calib_data.par_h7 = (int8_t)coeff_array[32];
|
||||
|
||||
// Gas sensor coefficients
|
||||
calib_data.par_gh1 = (int8_t)coeff_array[37];
|
||||
calib_data.par_gh2 = (int16_t)(((uint16_t)coeff_array[36] << 8) | coeff_array[35]);
|
||||
calib_data.par_gh3 = (int8_t)coeff_array[38];
|
||||
|
||||
// Other coefficients for gas sensor
|
||||
uint8_t temp_var;
|
||||
ret = BME68x_register_read(0x02, &temp_var, 1);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
calib_data.res_heat_range = ((temp_var & 0x30) >> 4);
|
||||
|
||||
ret = BME68x_register_read(0x00, &temp_var, 1);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
calib_data.res_heat_val = (int8_t)temp_var;
|
||||
|
||||
ret = BME68x_register_read(0x04, &temp_var, 1);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
calib_data.range_sw_err = ((int8_t)temp_var & 0xF0) >> 4;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate temperature from raw ADC value
|
||||
*/
|
||||
static float BME68x_calc_temperature(uint32_t temp_adc)
|
||||
{
|
||||
int64_t var1, var2, var3;
|
||||
float calc_temp;
|
||||
|
||||
var1 = ((int32_t)temp_adc >> 3) - ((int32_t)calib_data.par_t1 << 1);
|
||||
var2 = (var1 * (int32_t)calib_data.par_t2) >> 11;
|
||||
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
|
||||
var3 = ((var3) * ((int32_t)calib_data.par_t3 << 4)) >> 14;
|
||||
|
||||
calib_data.t_fine = (int32_t)(var2 + var3);
|
||||
calc_temp = (((float)calib_data.t_fine * 5) + 128) / 256;
|
||||
|
||||
return calc_temp / 100.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate pressure from raw ADC value
|
||||
*/
|
||||
static float BME68x_calc_pressure(uint32_t pres_adc)
|
||||
{
|
||||
int32_t var1, var2, var3;
|
||||
uint32_t calc_pres;
|
||||
|
||||
var1 = (((int32_t)calib_data.t_fine) >> 1) - 64000;
|
||||
var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * (int32_t)calib_data.par_p6) >> 2;
|
||||
var2 = var2 + ((var1 * (int32_t)calib_data.par_p5) << 1);
|
||||
var2 = (var2 >> 2) + ((int32_t)calib_data.par_p4 << 16);
|
||||
var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * ((int32_t)calib_data.par_p3 << 5)) >> 3) + (((int32_t)calib_data.par_p2 * var1) >> 1);
|
||||
var1 = var1 >> 18;
|
||||
var1 = ((32768 + var1) * (int32_t)calib_data.par_p1) >> 15;
|
||||
calc_pres = 1048576 - pres_adc;
|
||||
calc_pres = ((calc_pres - (var2 >> 12)) * ((uint32_t)3125));
|
||||
|
||||
if (calc_pres >= (1 << 30))
|
||||
calc_pres = (calc_pres / var1) * 2;
|
||||
else
|
||||
calc_pres = (calc_pres * 2) / var1;
|
||||
|
||||
var1 = ((int32_t)calib_data.par_p9 * (int32_t)(((calc_pres >> 3) * (calc_pres >> 3)) >> 13)) >> 12;
|
||||
var2 = ((int32_t)(calc_pres >> 2) * (int32_t)calib_data.par_p8) >> 13;
|
||||
var3 = ((int32_t)(calc_pres >> 8) * (int32_t)(calc_pres >> 8) * (int32_t)(calc_pres >> 8) * (int32_t)calib_data.par_p10) >> 17;
|
||||
|
||||
calc_pres = (calc_pres) + ((var1 + var2 + var3 + ((int32_t)calib_data.par_p7 << 7)) >> 4);
|
||||
|
||||
return (float)calc_pres / 100.0f; // Convert Pa to hPa
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate humidity from raw ADC value
|
||||
*/
|
||||
static float BME68x_calc_humidity(uint16_t hum_adc)
|
||||
{
|
||||
int32_t var1, var2, var3, var4, var5, var6, temp_scaled, calc_hum;
|
||||
|
||||
temp_scaled = (((int32_t)calib_data.t_fine * 5) + 128) >> 8;
|
||||
var1 = (int32_t)(hum_adc - ((int32_t)((int32_t)calib_data.par_h1 * 16))) - (((temp_scaled * (int32_t)calib_data.par_h3) / ((int32_t)100)) >> 1);
|
||||
var2 = ((int32_t)calib_data.par_h2 * (((temp_scaled * (int32_t)calib_data.par_h4) / ((int32_t)100)) + (((temp_scaled * ((temp_scaled * (int32_t)calib_data.par_h5) / ((int32_t)100))) >> 6) / ((int32_t)100)) + (int32_t)(1 << 14))) >> 10;
|
||||
var3 = var1 * var2;
|
||||
var4 = (int32_t)calib_data.par_h6 << 7;
|
||||
var4 = ((var4) + ((temp_scaled * (int32_t)calib_data.par_h7) / ((int32_t)100))) >> 4;
|
||||
var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
|
||||
var6 = (var4 * var5) >> 1;
|
||||
calc_hum = (((var3 + var6) >> 10) * ((int32_t)1000)) >> 12;
|
||||
|
||||
if (calc_hum > 100000) /* Cap at 100%rH */
|
||||
calc_hum = 100000;
|
||||
else if (calc_hum < 0)
|
||||
calc_hum = 0;
|
||||
|
||||
return calc_hum / 1000.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate gas resistance from raw ADC value
|
||||
*/
|
||||
static float BME68x_calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range)
|
||||
{
|
||||
int64_t var1;
|
||||
uint64_t var2;
|
||||
int64_t var3;
|
||||
uint32_t calc_gas_res;
|
||||
uint32_t lookupTable1[16] = {UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647),
|
||||
UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777),
|
||||
UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228),
|
||||
UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647)};
|
||||
uint32_t lookupTable2[16] = {UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000),
|
||||
UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064),
|
||||
UINT32_C(16016016), UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000),
|
||||
UINT32_C(1000000), UINT32_C(500000), UINT32_C(250000), UINT32_C(125000)};
|
||||
|
||||
var1 = (int64_t)((1340 + (5 * (int64_t)calib_data.range_sw_err)) * ((int64_t)lookupTable1[gas_range])) >> 16;
|
||||
var2 = (((int64_t)((int64_t)gas_res_adc << 15) - (int64_t)(16777216)) + var1);
|
||||
var3 = (((int64_t)lookupTable2[gas_range] * (int64_t)var1) >> 9);
|
||||
calc_gas_res = (uint32_t)((var3 + ((int64_t)var2 >> 1)) / (int64_t)var2);
|
||||
|
||||
return (float)calc_gas_res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate heater resistance for target temperature
|
||||
*/
|
||||
static uint8_t BME68x_calc_heater_res(uint16_t temp)
|
||||
{
|
||||
float var1, var2, var3, var4, var5;
|
||||
uint8_t res_heat;
|
||||
|
||||
if (temp < 200) /* Cap temperature */
|
||||
temp = 200;
|
||||
else if (temp > 400)
|
||||
temp = 400;
|
||||
|
||||
var1 = (((float)calib_data.par_gh1 / (16.0f)) + 49.0f);
|
||||
var2 = ((((float)calib_data.par_gh2 / (32768.0f)) * (0.0005f)) + 0.00235f);
|
||||
var3 = ((float)calib_data.par_gh3 / (1024.0f));
|
||||
var4 = (var1 * (1.0f + (var2 * (float)temp)));
|
||||
var5 = (var4 + (var3 * (float)25.0f));
|
||||
res_heat = (uint8_t)(3.4f * ((var5 * (4 / (4 + (float)calib_data.res_heat_range)) *
|
||||
(1 / (1 + ((float)calib_data.res_heat_val * 0.002f)))) -
|
||||
25));
|
||||
|
||||
return res_heat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate air quality score based on gas resistance
|
||||
*/
|
||||
static uint8_t BME68x_calc_air_quality_score(float gas_resistance, float humidity)
|
||||
{
|
||||
float hum_baseline = 40.0f, hum_weighting = 0.15f;
|
||||
float gas_baseline = 80000.0f, gas_weighting = 0.85f;
|
||||
|
||||
// Calculate humidity contribution to IAQ index
|
||||
float hum_score = 0.0f;
|
||||
if (humidity >= 38 && humidity <= 42)
|
||||
hum_score = hum_weighting * 100; // Humidity +/-5% around optimum
|
||||
else
|
||||
{
|
||||
if (humidity < 38)
|
||||
hum_score = (hum_weighting / hum_baseline) * humidity * 100;
|
||||
else
|
||||
hum_score = hum_weighting * 100 * (1.0f - ((humidity - 42) / (100 - 42)));
|
||||
if (hum_score < 0)
|
||||
hum_score = 0; // Don't go negative
|
||||
}
|
||||
|
||||
// Calculate gas contribution to IAQ index
|
||||
float gas_score = (gas_weighting / gas_baseline) * gas_resistance * 100;
|
||||
|
||||
// Combine results for the final IAQ index value (0-100% where 100% is good quality air)
|
||||
float air_quality_score = hum_score + gas_score;
|
||||
|
||||
if (air_quality_score > 100)
|
||||
air_quality_score = 100;
|
||||
if (air_quality_score < 0)
|
||||
air_quality_score = 0;
|
||||
|
||||
return (uint8_t)air_quality_score;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize BME68x sensor
|
||||
*/
|
||||
esp_err_t bme68x_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t reg_data;
|
||||
|
||||
// Read calibration data
|
||||
ret = BME68x_get_calib_data();
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Set humidity oversampling to 2x
|
||||
ret = BME68x_register_write_byte(BME68x_REG_CTRL_HUM, BME68x_OS_2X << BME68x_OSH_SEL);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Set temperature oversampling to 8x and pressure oversampling to 4x
|
||||
reg_data = (BME68x_OS_8X << BME68x_OST_SEL) | (BME68x_OS_4X << BME68x_OSP_SEL);
|
||||
ret = BME68x_register_write_byte(BME68x_REG_CTRL_MEAS, reg_data);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Set IIR filter to 3
|
||||
ret = BME68x_register_write_byte(BME68x_REG_CONFIG, BME68x_FILTER_SIZE_3 << BME68x_FILTER_SEL);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Enable gas sensor
|
||||
uint8_t heater_res = BME68x_calc_heater_res(320); // Set heater to 320°C
|
||||
ret = BME68x_register_write_byte(BME68x_REG_RES_HEAT_0, heater_res);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Set gas wait time (approx 150ms)
|
||||
ret = BME68x_register_write_byte(BME68x_REG_GAS_WAIT_0, 0x59);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Enable gas measurements
|
||||
reg_data = (BME68x_ENABLE_GAS_MEAS << BME68x_RUN_GAS_SEL) | (0 << BME68x_NB_CONV_SEL);
|
||||
ret = BME68x_register_write_byte(BME68x_REG_CTRL_GAS_1, reg_data);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trigger measurement and read sensor data
|
||||
*/
|
||||
esp_err_t bme68x_read_data(BME68x_data_t *data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t reg_data;
|
||||
uint8_t buff[8];
|
||||
uint32_t adc_temp, adc_pres;
|
||||
uint16_t adc_hum;
|
||||
|
||||
// Trigger forced mode measurement
|
||||
ret = BME68x_register_read(BME68x_REG_CTRL_MEAS, ®_data, 1);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
reg_data = (reg_data & 0xFC) | 0x01; // Set mode to forced
|
||||
ret = BME68x_register_write_byte(BME68x_REG_CTRL_MEAS, reg_data);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Wait for measurement to complete
|
||||
do
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ret = BME68x_register_read(BME68x_REG_MEAS_STATUS_0, ®_data, 1);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
} while (reg_data & 0x80); // Wait for measuring bit to clear
|
||||
|
||||
// Read measurement data
|
||||
ret = BME68x_register_read(BME68x_REG_PRESS_MSB, buff, 8);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
// Extract ADC values
|
||||
adc_pres = (uint32_t)buff[0] << 12 | (uint32_t)buff[1] << 4 | (uint32_t)buff[2] >> 4;
|
||||
adc_temp = (uint32_t)buff[3] << 12 | (uint32_t)buff[4] << 4 | (uint32_t)buff[5] >> 4;
|
||||
adc_hum = (uint16_t)buff[6] << 8 | (uint16_t)buff[7];
|
||||
|
||||
// Read gas sensor data
|
||||
uint8_t gas_buff[2];
|
||||
uint16_t adc_gas;
|
||||
uint8_t gas_range;
|
||||
|
||||
ret = BME68x_register_read(BME68x_REG_GAS_R_MSB, gas_buff, 2);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
|
||||
adc_gas = (uint16_t)gas_buff[0] << 2 | (uint16_t)gas_buff[1] >> 6;
|
||||
gas_range = gas_buff[1] & 0x0F;
|
||||
|
||||
// Check gas measurement validity
|
||||
data->gas_valid = (gas_buff[1] & 0x20) >> 5;
|
||||
data->heat_stab = (gas_buff[1] & 0x10) >> 4;
|
||||
|
||||
// Calculate actual values
|
||||
data->temperature = BME68x_calc_temperature(adc_temp) + TEMP_OFFSET;
|
||||
data->pressure = BME68x_calc_pressure(adc_pres);
|
||||
data->humidity = BME68x_calc_humidity(adc_hum);
|
||||
data->gas_resistance = BME68x_calc_gas_resistance(adc_gas, gas_range);
|
||||
|
||||
// Calculate air quality score
|
||||
data->air_quality_score = BME68x_calc_air_quality_score(data->gas_resistance, data->humidity);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current I2C address being used
|
||||
*/
|
||||
uint8_t bme68x_get_current_address(void)
|
||||
{
|
||||
return current_i2c_addr;
|
||||
}
|
||||
139
BME68x_manager.h
Normal file
139
BME68x_manager.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// I2C configuration - can be overridden in config.h
|
||||
#ifndef I2C_MASTER_SCL_IO
|
||||
#define I2C_MASTER_SCL_IO 7 /*!< Default GPIO for I2C master clock */
|
||||
#endif
|
||||
#ifndef I2C_MASTER_SDA_IO
|
||||
#define I2C_MASTER_SDA_IO 6 /*!< Default GPIO for I2C master data */
|
||||
#endif
|
||||
#ifndef I2C_MASTER_NUM
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 /*!< Default I2C port number */
|
||||
#endif
|
||||
#ifndef I2C_MASTER_FREQ_HZ
|
||||
#define I2C_MASTER_FREQ_HZ 100000 /*!< Default I2C frequency */
|
||||
#endif
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
|
||||
#define I2C_MASTER_TIMEOUT_MS 1000
|
||||
|
||||
// BME68x I2C address (can be 0x76 or 0x77 depending on SDO pin)
|
||||
#define BME68x_I2C_ADDR_PRIMARY 0x76
|
||||
#define BME68x_I2C_ADDR_SECONDARY 0x77
|
||||
|
||||
// BME68x register addresses
|
||||
#define BME68x_REG_CHIP_ID 0xD0
|
||||
#define BME68x_CHIP_ID 0x61
|
||||
#define BME68x_REG_CTRL_MEAS 0x74
|
||||
#define BME68x_REG_CTRL_HUM 0x72
|
||||
#define BME68x_REG_CONFIG 0x75
|
||||
#define BME68x_REG_MEAS_STATUS_0 0x1D
|
||||
#define BME68x_REG_PRESS_MSB 0x1F
|
||||
#define BME68x_REG_TEMP_MSB 0x22
|
||||
#define BME68x_REG_HUM_MSB 0x25
|
||||
#define BME68x_REG_GAS_R_MSB 0x2A
|
||||
#define BME68x_REG_GAS_R_LSB 0x2B
|
||||
#define BME68x_REG_CTRL_GAS_1 0x71
|
||||
#define BME68x_REG_GAS_WAIT_0 0x64
|
||||
#define BME68x_REG_RES_HEAT_0 0x5A
|
||||
|
||||
// Calibration coefficient addresses
|
||||
#define BME68x_COEFF_ADDR1 0x89
|
||||
#define BME68x_COEFF_ADDR2 0xE1
|
||||
|
||||
// BME68x oversampling definitions
|
||||
#define BME68x_OS_NONE 0x00
|
||||
#define BME68x_OS_1X 0x01
|
||||
#define BME68x_OS_2X 0x02
|
||||
#define BME68x_OS_4X 0x03
|
||||
#define BME68x_OS_8X 0x04
|
||||
#define BME68x_OS_16X 0x05
|
||||
|
||||
// BME68x field bit positions
|
||||
#define BME68x_OST_SEL 5
|
||||
#define BME68x_OSP_SEL 2
|
||||
#define BME68x_OSH_SEL 0
|
||||
#define BME68x_FILTER_SEL 2
|
||||
|
||||
// BME68x IIR filter definitions
|
||||
#define BME68x_FILTER_SIZE_3 0x02
|
||||
|
||||
// Gas sensor definitions
|
||||
#define BME68x_DISABLE_GAS_MEAS 0x00
|
||||
#define BME68x_ENABLE_GAS_MEAS 0x01
|
||||
#define BME68x_RUN_GAS_SEL 4
|
||||
#define BME68x_NB_CONV_SEL 0
|
||||
|
||||
// BME68x sensor data structure
|
||||
typedef struct
|
||||
{
|
||||
float temperature;
|
||||
float pressure;
|
||||
float humidity;
|
||||
float gas_resistance;
|
||||
uint8_t gas_valid;
|
||||
uint8_t heat_stab;
|
||||
uint8_t air_quality_score;
|
||||
} BME68x_data_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize I2C master interface
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_i2c_init(void);
|
||||
|
||||
/**
|
||||
* @brief Perform I2C bus recovery
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_i2c_recovery(void);
|
||||
|
||||
/**
|
||||
* @brief Scan I2C bus for devices
|
||||
*/
|
||||
void bme68x_i2c_scan(void);
|
||||
|
||||
/**
|
||||
* @brief Test BME68x sensor connection and read chip ID
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_test_connection(void);
|
||||
|
||||
/**
|
||||
* @brief Perform soft reset of BME68x sensor
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_soft_reset(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize BME68x sensor
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_init(void);
|
||||
|
||||
/**
|
||||
* @brief Read sensor data from BME68x
|
||||
* @param data Pointer to BME68x_data_t structure to store the data
|
||||
* @return ESP_OK on success, error code on failure
|
||||
*/
|
||||
esp_err_t bme68x_read_data(BME68x_data_t *data);
|
||||
|
||||
/**
|
||||
* @brief Get current I2C address being used
|
||||
* @return Current I2C address (0x76 or 0x77)
|
||||
*/
|
||||
uint8_t bme68x_get_current_address(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
12
CHANGELOG.md
Normal file
12
CHANGELOG.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v1.0.0] - 2025-06-01
|
||||
|
||||
### Added
|
||||
|
||||
- Repository
|
||||
274
README.md
Normal file
274
README.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# BME68x Manager Library
|
||||
|
||||
A comprehensive ESP-IDF library for interfacing with the Bosch BME68x environmental sensor series (BME680, BME688). This library provides easy-to-use functions for reading temperature, humidity, pressure, and gas resistance measurements with built-in air quality calculations.
|
||||
|
||||
## Features
|
||||
|
||||
- **Complete BME68x Support**: Works with BME680 and BME688 sensors
|
||||
- **I2C Communication**: Robust I2C implementation with automatic address detection
|
||||
- **Auto Recovery**: Built-in I2C bus recovery mechanisms
|
||||
- **Air Quality Index**: Calculates air quality scores based on gas resistance and humidity
|
||||
- **Error Handling**: Comprehensive error checking and recovery
|
||||
- **Easy Integration**: Simple API for quick integration into ESP32 projects
|
||||
|
||||
## Hardware Connections
|
||||
|
||||
| BME68x Pin | ESP32-C6 Pin | Description |
|
||||
| ---------- | ------------ | ---------------------------------------------- |
|
||||
| VCC | 3.3V | Power supply |
|
||||
| GND | GND | Ground |
|
||||
| SDA | GPIO6 | I2C Data line |
|
||||
| SCL | GPIO7 | I2C Clock line |
|
||||
| SDO | GND or 3.3V | I2C Address select (0x76 if GND, 0x77 if 3.3V) |
|
||||
|
||||
## Installation
|
||||
|
||||
1. Copy the `BME68x_manager` folder to your project's `lib/` directory:
|
||||
|
||||
```
|
||||
your_project/
|
||||
├── lib/
|
||||
│ └── BME68x_manager/
|
||||
│ ├── BME68x_manager.h
|
||||
│ └── BME68x_manager.c
|
||||
├── src/
|
||||
└── platformio.ini
|
||||
```
|
||||
|
||||
2. Include the library in your source files:
|
||||
|
||||
```c
|
||||
#include "BME68x_manager.h"
|
||||
```
|
||||
|
||||
3. Configure I2C pins and settings in your `config.h` file:
|
||||
|
||||
```c
|
||||
// Temperature calibration offset
|
||||
#define TEMP_OFFSET -2.0f // Adjust based on your sensor calibration
|
||||
|
||||
// I2C Configuration (optional - defaults shown)
|
||||
#define I2C_MASTER_SCL_IO 7 // SCL GPIO pin
|
||||
#define I2C_MASTER_SDA_IO 6 // SDA GPIO pin
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 // I2C port number
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C frequency (100kHz)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Data Structures
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
float temperature; // Temperature in °C
|
||||
float pressure; // Pressure in hPa
|
||||
float humidity; // Humidity in %
|
||||
float gas_resistance; // Gas resistance in Ω
|
||||
uint8_t gas_valid; // 1 if gas measurement is valid
|
||||
uint8_t heat_stab; // 1 if heater is stable
|
||||
uint8_t air_quality_score; // Air quality score (0-100)
|
||||
} BME68x_data_t;
|
||||
```
|
||||
|
||||
### Core Functions
|
||||
|
||||
#### `esp_err_t bme68x_i2c_init(void)`
|
||||
|
||||
Initializes the I2C master interface.
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `ESP_OK` on success
|
||||
- Error code on failure
|
||||
|
||||
---
|
||||
|
||||
#### `esp_err_t bme68x_test_connection(void)`
|
||||
|
||||
Tests communication with the BME68x sensor and automatically detects the I2C address.
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `ESP_OK` if sensor found and communication successful
|
||||
- Error code on failure
|
||||
|
||||
---
|
||||
|
||||
#### `esp_err_t bme68x_init(void)`
|
||||
|
||||
Initializes the BME68x sensor with optimal settings for air quality monitoring.
|
||||
|
||||
**Configuration:**
|
||||
|
||||
- Temperature oversampling: 8x
|
||||
- Pressure oversampling: 4x
|
||||
- Humidity oversampling: 2x
|
||||
- IIR filter: 3
|
||||
- Gas sensor: Enabled (320°C, 150ms heating)
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `ESP_OK` on success
|
||||
- Error code on failure
|
||||
|
||||
---
|
||||
|
||||
#### `esp_err_t bme68x_read_data(BME68x_data_t *data)`
|
||||
|
||||
Reads sensor data and calculates air quality score.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `data`: Pointer to BME68x_data_t structure to store results
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `ESP_OK` on success
|
||||
- Error code on failure
|
||||
|
||||
### Utility Functions
|
||||
|
||||
#### `esp_err_t bme68x_i2c_recovery(void)`
|
||||
|
||||
Performs I2C bus recovery by sending clock pulses.
|
||||
|
||||
#### `void bme68x_i2c_scan(void)`
|
||||
|
||||
Scans the I2C bus and prints found devices to console.
|
||||
|
||||
#### `esp_err_t bme68x_soft_reset(void)`
|
||||
|
||||
Performs a software reset of the BME68x sensor.
|
||||
|
||||
#### `uint8_t bme68x_get_current_address(void)`
|
||||
|
||||
Returns the current I2C address being used (0x76 or 0x77).
|
||||
|
||||
## Usage Example
|
||||
|
||||
```c
|
||||
#include "BME68x_manager.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char *TAG = "BME68x_Example";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// Initialize I2C
|
||||
ESP_ERROR_CHECK(bme68x_i2c_init());
|
||||
|
||||
// Test sensor connection
|
||||
if (bme68x_test_connection() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "BME68x sensor not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize sensor
|
||||
ESP_ERROR_CHECK(bme68x_init());
|
||||
|
||||
ESP_LOGI(TAG, "BME68x sensor initialized successfully");
|
||||
|
||||
// Main measurement loop
|
||||
while (1) {
|
||||
BME68x_data_t sensor_data;
|
||||
|
||||
if (bme68x_read_data(&sensor_data) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Temperature: %.1f°C", sensor_data.temperature);
|
||||
ESP_LOGI(TAG, "Pressure: %.1f hPa", sensor_data.pressure);
|
||||
ESP_LOGI(TAG, "Humidity: %.1f%%", sensor_data.humidity);
|
||||
|
||||
if (sensor_data.gas_valid && sensor_data.heat_stab) {
|
||||
ESP_LOGI(TAG, "Gas Resistance: %.0f Ω", sensor_data.gas_resistance);
|
||||
ESP_LOGI(TAG, "Air Quality Score: %d%%", sensor_data.air_quality_score);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Gas sensor stabilizing...");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to read sensor data");
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(5000)); // Read every 5 seconds
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Air Quality Scoring
|
||||
|
||||
The library calculates an air quality score (0-100) based on:
|
||||
|
||||
- **Gas Resistance**: Higher resistance indicates cleaner air
|
||||
- **Humidity**: Optimal range is 38-42% RH
|
||||
|
||||
### Air Quality Interpretation
|
||||
|
||||
| Score | Quality | Gas Resistance Range | Description |
|
||||
| ------ | --------- | -------------------- | -------------------------------------- |
|
||||
| 90-100 | Excellent | >50kΩ | Fresh outdoor air quality |
|
||||
| 60-89 | Good | 10-50kΩ | Normal indoor air |
|
||||
| 30-59 | Fair | 5-10kΩ | Moderate pollution (cooking, cleaning) |
|
||||
| 0-29 | Poor | <5kΩ | High pollution (smoke, chemicals) |
|
||||
|
||||
## Configuration Options
|
||||
|
||||
All configuration is done in your project's `config.h` file. The library provides sensible defaults if settings are not specified.
|
||||
|
||||
### I2C Settings (Optional)
|
||||
|
||||
```c
|
||||
// Override default I2C configuration in config.h
|
||||
#define I2C_MASTER_SCL_IO 7 // SCL GPIO pin (default: 7)
|
||||
#define I2C_MASTER_SDA_IO 6 // SDA GPIO pin (default: 6)
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 // I2C port number (default: I2C_NUM_0)
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // I2C frequency (default: 100kHz)
|
||||
```
|
||||
|
||||
### Temperature Calibration (Required)
|
||||
|
||||
```c
|
||||
#define TEMP_OFFSET -2.0f // Temperature offset for calibration
|
||||
```
|
||||
|
||||
### Sensor Addresses
|
||||
|
||||
```c
|
||||
#define BME68x_I2C_ADDR_PRIMARY 0x76 // SDO connected to GND
|
||||
#define BME68x_I2C_ADDR_SECONDARY 0x77 // SDO connected to VCC
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Sensor Not Found
|
||||
|
||||
1. Check wiring connections
|
||||
2. Verify power supply (3.3V)
|
||||
3. Run `bme68x_i2c_scan()` to see detected devices
|
||||
4. Try different I2C pull-up resistor values (4.7kΩ recommended)
|
||||
|
||||
### Invalid Gas Readings
|
||||
|
||||
- Gas sensor requires heating time (~60 seconds for first stable reading)
|
||||
- Check that `gas_valid` and `heat_stab` flags are set
|
||||
- Ensure adequate power supply for heating element
|
||||
|
||||
### Inconsistent Readings
|
||||
|
||||
- Allow sensor to stabilize in target environment
|
||||
- Consider temperature calibration offset in `config.h`
|
||||
- Shield sensor from direct airflow or heat sources
|
||||
|
||||
## Dependencies
|
||||
|
||||
- ESP-IDF framework
|
||||
- FreeRTOS (for delays)
|
||||
- I2C driver (`driver/i2c.h`)
|
||||
- GPIO driver (`driver/gpio.h`)
|
||||
|
||||
## License
|
||||
|
||||
This library is provided as-is for educational and commercial use. Based on Bosch BME68x sensor specifications and ESP-IDF examples.
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0.0** - Initial release with full BME68x support and air quality calculations
|
||||
16
library.json
Normal file
16
library.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "BME68x_manager",
|
||||
"version": "1.0.0",
|
||||
"description": "Custom BME68x sensor library for ESP32",
|
||||
"keywords": "bme68x, temperature, humidity, pressure, gas, sensor, esp32",
|
||||
"authors": {
|
||||
"name": "ESP32C6-BME68x Project"
|
||||
},
|
||||
"license": "MIT",
|
||||
"frameworks": [
|
||||
"espidf"
|
||||
],
|
||||
"platforms": [
|
||||
"espressif32"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user