2025-09-16 07:23:00 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
#include "freertos/task.h"
|
|
|
|
#include "driver/i2c.h"
|
2025-09-16 09:38:00 -05:00
|
|
|
#include "bme68x.h"
|
2025-09-16 07:23:00 -05:00
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
/* ----- I2C pins (ESP-01S: SDA=GPIO0, SCL=GPIO2) ----- */
|
2025-09-16 07:23:00 -05:00
|
|
|
#define I2C_PORT I2C_NUM_0
|
2025-09-16 09:38:00 -05:00
|
|
|
#define I2C_SDA_PIN 0
|
|
|
|
#define I2C_SCL_PIN 2
|
|
|
|
#define I2C_TIMEOUT_MS 1000
|
|
|
|
|
|
|
|
/* BME68x address: SDO=GND -> LOW(0x76), SDO=VCC -> HIGH(0x77) */
|
|
|
|
#define BME68X_ADDR BME68X_I2C_ADDR_LOW
|
|
|
|
|
|
|
|
/* --------- ESP8266 I2C init (note: clk_stretch_tick field) --------- */
|
|
|
|
static void i2c_init(void)
|
|
|
|
{
|
2025-09-16 10:27:08 -05:00
|
|
|
// i2c_config_t conf = {
|
|
|
|
// .mode = I2C_MODE_MASTER,
|
|
|
|
// .sda_io_num = I2C_SDA_PIN,
|
|
|
|
// .scl_io_num = I2C_SCL_PIN,
|
|
|
|
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
|
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
|
// .clk_stretch_tick = 300, // reasonable default on ESP8266
|
|
|
|
// };
|
|
|
|
// i2c_param_config(I2C_PORT, &conf);
|
|
|
|
// i2c_driver_install(I2C_PORT, conf.mode); // ESP8266 signature: (port, mode)
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
i2c_config_t conf = {
|
|
|
|
.mode = I2C_MODE_MASTER,
|
2025-09-16 10:27:08 -05:00
|
|
|
.sda_io_num = GPIO_NUM_0,
|
|
|
|
.scl_io_num = GPIO_NUM_2,
|
2025-09-16 09:38:00 -05:00
|
|
|
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
|
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
2025-09-16 10:27:08 -05:00
|
|
|
.clk_stretch_tick = 300, // try 300..1000
|
2025-09-16 09:38:00 -05:00
|
|
|
};
|
2025-09-16 10:27:08 -05:00
|
|
|
|
|
|
|
ESP_ERROR_CHECK(i2c_param_config(I2C_PORT, &conf));
|
|
|
|
ESP_ERROR_CHECK(i2c_driver_install(I2C_PORT, conf.mode));
|
2025-09-16 09:38:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------- BME68x I2C read/write helpers ------------- */
|
|
|
|
static int8_t bme68x_i2c_read(uint8_t reg, uint8_t *data, uint32_t len, void *intf_ptr)
|
|
|
|
{
|
|
|
|
uint8_t addr = *(uint8_t *)intf_ptr; // 7-bit address
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
2025-09-16 09:38:00 -05:00
|
|
|
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_master_start(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
|
|
|
|
i2c_master_write_byte(cmd, reg, true);
|
|
|
|
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_master_start(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, true);
|
|
|
|
if (len > 1) i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
|
|
|
|
i2c_master_stop(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
|
|
|
|
esp_err_t ret = i2c_master_cmd_begin(I2C_PORT, cmd, I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_cmd_link_delete(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
return (ret == ESP_OK) ? BME68X_OK : BME68X_E_COM_FAIL;
|
2025-09-16 07:23:00 -05:00
|
|
|
}
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
static int8_t bme68x_i2c_write(uint8_t reg, const uint8_t *data, uint32_t len, void *intf_ptr)
|
|
|
|
{
|
|
|
|
uint8_t addr = *(uint8_t *)intf_ptr;
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
2025-09-16 09:38:00 -05:00
|
|
|
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_master_start(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
|
|
|
|
i2c_master_write_byte(cmd, reg, true);
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_master_write(cmd, (uint8_t*)data, len, true);
|
|
|
|
i2c_master_stop(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
|
|
|
|
esp_err_t ret = i2c_master_cmd_begin(I2C_PORT, cmd, I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_cmd_link_delete(cmd);
|
2025-09-16 09:38:00 -05:00
|
|
|
return (ret == ESP_OK) ? BME68X_OK : BME68X_E_COM_FAIL;
|
2025-09-16 07:23:00 -05:00
|
|
|
}
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
static void bme68x_delay_us(uint32_t period_us, void *intf_ptr)
|
|
|
|
{
|
|
|
|
(void)intf_ptr;
|
|
|
|
/* Delay granularity is ms on FreeRTOS; round up */
|
|
|
|
vTaskDelay((period_us + 999) / 1000 / portTICK_PERIOD_MS);
|
2025-09-16 07:23:00 -05:00
|
|
|
}
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
/* ----------------------- App ----------------------- */
|
|
|
|
void app_main(void)
|
|
|
|
{
|
2025-09-16 07:23:00 -05:00
|
|
|
i2c_init();
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
struct bme68x_dev dev = {0};
|
|
|
|
uint8_t i2c_addr = BME68X_ADDR;
|
|
|
|
|
|
|
|
dev.intf = BME68X_I2C_INTF;
|
|
|
|
dev.read = bme68x_i2c_read;
|
|
|
|
dev.write = bme68x_i2c_write;
|
|
|
|
dev.delay_us = bme68x_delay_us;
|
|
|
|
dev.intf_ptr = &i2c_addr;
|
2025-09-16 07:23:00 -05:00
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
if (bme68x_init(&dev) != BME68X_OK) {
|
|
|
|
printf("BME68x init failed\n");
|
2025-09-16 07:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
/* Oversampling + filter */
|
|
|
|
struct bme68x_conf conf = {
|
|
|
|
.os_hum = BME68X_OS_2X,
|
|
|
|
.os_temp = BME68X_OS_8X,
|
|
|
|
.os_pres = BME68X_OS_4X,
|
|
|
|
.filter = BME68X_FILTER_SIZE_3,
|
|
|
|
.odr = BME68X_ODR_NONE
|
|
|
|
};
|
|
|
|
if (bme68x_set_conf(&conf, &dev) != BME68X_OK) {
|
|
|
|
printf("set_conf failed\n");
|
|
|
|
return;
|
|
|
|
}
|
2025-09-16 07:23:00 -05:00
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
/* Gas heater config for one-shot */
|
|
|
|
struct bme68x_heatr_conf hconf = {
|
|
|
|
.enable = BME68X_ENABLE,
|
|
|
|
.heatr_temp = 320, // °C
|
|
|
|
.heatr_dur = 150 // ms
|
|
|
|
};
|
|
|
|
if (bme68x_set_heatr_conf(BME68X_FORCED_MODE, &hconf, &dev) != BME68X_OK) {
|
|
|
|
printf("set_heatr_conf failed\n");
|
2025-09-16 07:23:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
2025-09-16 09:38:00 -05:00
|
|
|
if (bme68x_set_op_mode(BME68X_FORCED_MODE, &dev) != BME68X_OK) {
|
|
|
|
printf("set_op_mode failed\n");
|
2025-09-16 07:23:00 -05:00
|
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-09-16 09:38:00 -05:00
|
|
|
/* Calculate measurement duration and wait */
|
|
|
|
uint32_t dur_us = bme68x_get_meas_dur(BME68X_FORCED_MODE, &conf, &dev) + (hconf.heatr_dur * 1000);
|
|
|
|
bme68x_delay_us(dur_us, NULL);
|
|
|
|
|
|
|
|
struct bme68x_data data;
|
|
|
|
uint8_t n_fields = 0;
|
|
|
|
|
|
|
|
if (bme68x_get_data(BME68X_FORCED_MODE, &data, &n_fields, &dev) == BME68X_OK && n_fields > 0) {
|
|
|
|
/* Note: API returns fixed-point values; divide per defs */
|
|
|
|
float temp_c = data.temperature / 100.0f; // °C
|
|
|
|
float press_hpa = data.pressure / 100.0f; // hPa
|
|
|
|
float hum_pct = data.humidity / 1000.0f; // %RH
|
|
|
|
float gas_kohm = data.gas_resistance / 1000.0f;
|
2025-09-16 07:23:00 -05:00
|
|
|
|
|
|
|
printf("T=%.2f °C RH=%.2f %% P=%.2f hPa Gas=%.2f kΩ\n",
|
2025-09-16 09:38:00 -05:00
|
|
|
temp_c, hum_pct, press_hpa, gas_kohm);
|
2025-09-16 07:23:00 -05:00
|
|
|
} else {
|
2025-09-16 09:38:00 -05:00
|
|
|
printf("read failed\n");
|
2025-09-16 07:23:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|