diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fe4285..6f44e8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ - +cmake_minimum_required(VERSION 3.1) +set(CMAKE_C_STANDARD 11) idf_component_register( SRCS bmx280.c INCLUDE_DIRS "include" diff --git a/Kconfig b/Kconfig index 9721ffc..224d572 100644 --- a/Kconfig +++ b/Kconfig @@ -1,4 +1,25 @@ menu "BMX280 Options" + choice I2C_DRIVER_SETTING + prompt "I2C driver setting" + help + Select I2C Driver: I2C Legacy Driver: I2C.h , I2C Master Driver i2c_master.h for ESP-IDF >= 5.3 AND Set I2C Clock Speed. + default USE_I2C_LEGACY_DRIVER + config USE_I2C_LEGACY_DRIVER + bool "I2C Legacy Driver (I2C.h)" + help + Use I2C Legacy Driver (I2C.h). + config USE_I2C_MASTER_DRIVER + bool "I2C Master Driver (i2c_master.h)" + help + Use I2C Master Driver (i2c_master.h) for ESP-IDF >= 5.3. + config BMX280_I2C_CLK_SPEED_HZ + int "I2C Clock Speed (Hz)" + default 100000 + range 1000 400000 + help + Set the I2C clock speed in Hz. + endchoice + choice BMX280_EXPECT_DEVICE prompt "Installed Sensor Model" help @@ -20,15 +41,15 @@ menu "BMX280 Options" default BMX280_ADDRESS_DETECT config BMX280_ADDRESS_DETECT bool "Auto" - config BMX280_ADDERSS_LO + config BMX280_ADDRESS_LO bool "0x76 (SDO LOW)" - config BMX280_ADDERSS_HI + config BMX280_ADDRESS_HI bool "0x77 (SDO HIGH)" endchoice config BMX280_TIMEOUT int "Read/Write Timeout" - default 5 + default 50 help Number of ticks to wait for I2C read/write operations. diff --git a/README.md b/README.md index 6f77c24..e773996 100644 --- a/README.md +++ b/README.md @@ -10,55 +10,21 @@ Add the module as a requirement to your main module, or other modules. Example Code ------------ -```c -#include "esp_log.h" -#include "bmx280.h" +To use the legacy i2c.h driver, please refer to the [example_with_i2c.h](examples/bmx280_example_without_i2c_master.c). -void app_main(void) -{ - // Entry Point - //ESP_ERROR_CHECK(nvs_flash_init()); - i2c_config_t i2c_cfg = { - .mode = I2C_MODE_MASTER, - .sda_io_num = GPIO_NUM_17, - .scl_io_num = GPIO_NUM_16, - .sda_pullup_en = false, - .scl_pullup_en = false, +To use the i2c_master.h driver (ESP-IDF >= 5.3): - .master = { - .clk_speed = 100000 - } - }; +* First, run `idf.py menuconfig` to configure the project. - ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_cfg)); - ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0)); +* Navigate to Component Config -> BMX280 Options -> I2C driver setting -> I2C Master Driver (i2c_master.h). - bmx280_t* bmx280 = bmx280_create(I2C_NUM_0); +* Press the 'S' key to save the configuration. - if (!bmx280) { - ESP_LOGE("test", "Could not create bmx280 driver."); - return; - } +* You can then use the I2C Master driver to complete your code. - ESP_ERROR_CHECK(bmx280_init(bmx280)); +For example code, please see the [example_with_i2c_master.h](examples/bmx280_example_with_i2c_master.c). - bmx280_config_t bmx_cfg = BMX280_DEFAULT_CONFIG; - ESP_ERROR_CHECK(bmx280_configure(bmx280, &bmx_cfg)); - - while (1) - { - ESP_ERROR_CHECK(bmx280_setMode(bmx280, BMX280_MODE_FORCE)); - do { - vTaskDelay(pdMS_TO_TICKS(1)); - } while(bmx280_isSampling(bmx280)); - - float temp = 0, pres = 0, hum = 0; - ESP_ERROR_CHECK(bmx280_readoutFloat(bmx280, &temp, &pres, &hum)); - - ESP_LOGI("test", "Read Values: temp = %f, pres = %f, hum = %f", temp, pres, hum); - } -} -``` +**Note:** If you want to use the legacy i2c.h driver, no changes are needed; continue using `bmx280_create` to create the anonymous structure `bmx280`. If you use the i2c_master.h driver, you need to use `bmx280_create_master` to create the structure. License ------- diff --git a/bmx280.c b/bmx280.c index 4be32e3..240c7fa 100644 --- a/bmx280.c +++ b/bmx280.c @@ -70,10 +70,19 @@ #define BMP280_ID2 0x58 struct bmx280_t{ + #if !(CONFIG_USE_I2C_MASTER_DRIVER) // I2C port. i2c_port_t i2c_port; // Slave Address of sensor. uint8_t slave; + #else + // I2C master handle via port with configuration + i2c_master_dev_handle_t i2c_dev; + // I2C master configuration + i2c_device_config_t dev_cfg; + // I2C master handle via port + i2c_master_bus_handle_t bus_handle; + #endif // Chip ID of sensor uint8_t chip_id; // Compensation data @@ -122,7 +131,36 @@ struct bmx280_t{ * Returns false if the sensor was not found. * @param bmx280 The driver structure. */ +#if !(CONFIG_USE_I2C_MASTER_DRIVER) #define bmx280_validate(bmx280) (!(bmx280->slave == 0xDE && bmx280->chip_id == 0xAD)) +#else +#define bmx280_validate(bmx280) (!(bmx280->i2c_dev == NULL && bmx280->chip_id == 0xAD)) +#endif + +#if CONFIG_USE_I2C_MASTER_DRIVER +/** + * Read from sensor. + * @param bmx280 Driver Sturcture. + * @param dev_addr Chip addresses. + */ +static esp_err_t bmx280_device_create(bmx280_t *bmx280, const uint16_t dev_addr) +{ + ESP_LOGI("bmx280", "device_create for BMP280/BME280 sensors on ADDR %X", dev_addr); + bmx280->dev_cfg.device_address = dev_addr; + // Add device to the I2C bus + esp_err_t err = i2c_master_bus_add_device(bmx280->bus_handle, &bmx280->dev_cfg, &bmx280->i2c_dev); + if (err == ESP_OK) + { + ESP_LOGI("bmx280", "device_create success on 0x%x", dev_addr); + return err; + } + else + { + ESP_LOGE("bmx280", "device_create error on 0x%x", dev_addr); + return err; + } +} +#endif /** * Read from sensor. @@ -134,6 +172,7 @@ struct bmx280_t{ */ static esp_err_t bmx280_read(bmx280_t *bmx280, uint8_t addr, uint8_t *dout, size_t size) { + #if !(CONFIG_USE_I2C_MASTER_DRIVER) esp_err_t err; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); if (cmd) @@ -157,11 +196,16 @@ static esp_err_t bmx280_read(bmx280_t *bmx280, uint8_t addr, uint8_t *dout, size { return ESP_ERR_NO_MEM; } + #else + return i2c_master_transmit_receive(bmx280->i2c_dev, &addr, sizeof(addr), dout, size, CONFIG_BMX280_TIMEOUT); + #endif + } static esp_err_t bmx280_write(bmx280_t* bmx280, uint8_t addr, const uint8_t *din, size_t size) { esp_err_t err; + #if !(CONFIG_USE_I2C_MASTER_DRIVER) i2c_cmd_handle_t cmd = i2c_cmd_link_create(); if (cmd) { @@ -184,12 +228,20 @@ static esp_err_t bmx280_write(bmx280_t* bmx280, uint8_t addr, const uint8_t *din { return ESP_ERR_NO_MEM; } + #else + for(uint8_t i = 0; i < size; i++) + { + uint8_t dat[2] = {(addr + i), din[i]}; + if ((err = i2c_master_transmit(bmx280->i2c_dev, dat, 2, CONFIG_BMX280_TIMEOUT)) != ESP_OK) + return err; + } + return ESP_OK; + #endif } static esp_err_t bmx280_probe_address(bmx280_t *bmx280) { esp_err_t err = bmx280_read(bmx280, BMX280_REG_CHPID, &bmx280->chip_id, sizeof bmx280->chip_id); - if (err == ESP_OK) { if ( @@ -202,31 +254,43 @@ static esp_err_t bmx280_probe_address(bmx280_t *bmx280) #endif ) { + #if !(CONFIG_USE_I2C_MASTER_DRIVER) ESP_LOGI("bmx280", "Probe success: address=%hhx, id=%hhx", bmx280->slave, bmx280->chip_id); - return ESP_OK; + #else + ESP_LOGI("bmx280", "Probe success: address=%hhx, id=%hhx", bmx280->dev_cfg.device_address, bmx280->chip_id); + #endif + return ESP_OK; } else { + ESP_LOGE("bmx280", "Sensor model may be incorrect. Please check the sensor model configuration. If unsure, set it to AUTO."); err = ESP_ERR_NOT_FOUND; } } - + #if !(CONFIG_USE_I2C_MASTER_DRIVER) ESP_LOGW("bmx280", "Probe failure: address=%hhx, id=%hhx, reason=%s", bmx280->slave, bmx280->chip_id, esp_err_to_name(err)); + #else + ESP_LOGW("bmx280", "Probe failure: address=%hhx, id=%hhx, reason=%s", bmx280->dev_cfg.device_address, bmx280->chip_id, esp_err_to_name(err)); + #endif return err; } static esp_err_t bmx280_probe(bmx280_t *bmx280) { + #if !(CONFIG_USE_I2C_MASTER_DRIVER) ESP_LOGI("bmx280", "Probing for BMP280/BME280 sensors on I2C %d", bmx280->i2c_port); - + esp_err_t err; #if CONFIG_BMX280_ADDRESS_HI bmx280->slave = 0xEE; - return bmx280_probe_address(bmx280); + err = bmx280_probe_address(bmx280); + if (err != ESP_OK) ESP_LOGE("bmx280", "Sensor not found at 0x77 , Please check the address."); + return err; #elif CONFIG_BMX280_ADDRESS_LO bmx280->slave = 0xEC; - return bmx280_probe_address(bmx280); + err = bmx280_probe_address(bmx280); + if (err != ESP_OK) ESP_LOGE("bmx280", "Sensor not found at 0x76 , Please check the address."); + return err; #else - esp_err_t err; bmx280->slave = 0xEC; if ((err = bmx280_probe_address(bmx280)) != ESP_OK) { @@ -240,6 +304,38 @@ static esp_err_t bmx280_probe(bmx280_t *bmx280) } return err; #endif + #else + ESP_LOGI("bmx280", "Probing for BMP280/BME280 sensors on I2C"); + esp_err_t err; + #if CONFIG_BMX280_ADDRESS_HI + err = bmx280_device_create(bmx280, 0x77); + if (err != ESP_OK) return err; + err = bmx280_probe_address(bmx280); + if (err != ESP_OK) ESP_LOGE("bmx280", "Sensor not found at 0x77 , Please check the address."); + return err; + #elif CONFIG_BMX280_ADDRESS_LO + err = bmx280_device_create(bmx280, 0x76); + if (err != ESP_OK) return err; + err = bmx280_probe_address(bmx280); + if (err != ESP_OK) ESP_LOGE("bmx280", "Sensor not found at 0x76 , Please check the address."); + return err; + #else + err = bmx280_device_create(bmx280, 0x76); + if (err != ESP_OK) return err; + if ((err = bmx280_probe_address(bmx280)) != ESP_OK) + { + err = bmx280_device_create(bmx280, 0x77); + if (err != ESP_OK) return err; + if ((err = bmx280_probe_address(bmx280)) != ESP_OK) + { + ESP_LOGE("bmx280", "Sensor not found."); + bmx280->i2c_dev = NULL; + bmx280->chip_id = 0xAD; + } + } + return err; + #endif + #endif } static esp_err_t bmx280_reset(bmx280_t *bmx280) @@ -309,22 +405,55 @@ static esp_err_t bmx280_calibrate(bmx280_t *bmx280) return ESP_OK; } -bmx280_t* bmx280_create(i2c_port_t port) +#if !(CONFIG_USE_I2C_MASTER_DRIVER) +bmx280_t* bmx280_create_legacy(i2c_port_t port) { bmx280_t* bmx280 = malloc(sizeof(bmx280_t)); if (bmx280) { memset(bmx280, 0, sizeof(bmx280_t)); - bmx280->i2c_port = port; bmx280->slave = 0xDE; bmx280->chip_id = 0xAD; } + else + { + ESP_LOGE("bmx280", "Failed to allocate memory for bmx280."); + bmx280_close(bmx280); + return NULL; + } return bmx280; } +#else +bmx280_t* bmx280_create_master(i2c_master_bus_handle_t bus_handle) +{ + bmx280_t* bmx280 = malloc(sizeof(bmx280_t)); + if (bmx280) + { + memset(bmx280, 0, sizeof(bmx280_t)); + bmx280->bus_handle = bus_handle; + bmx280->dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7; + bmx280->dev_cfg.device_address = 0xDE; + bmx280->dev_cfg.scl_speed_hz =CONFIG_BMX280_I2C_CLK_SPEED_HZ; + bmx280->i2c_dev = NULL; + bmx280->chip_id = 0xAD; + } + else + { + ESP_LOGE("bmx280", "Failed to allocate memory for bmx280."); + bmx280_close(bmx280); + return NULL; + } + return bmx280; +} +#endif void bmx280_close(bmx280_t *bmx280) { + #if CONFIG_USE_I2C_MASTER_DRIVER + if(bmx280->i2c_dev!=NULL) + i2c_master_bus_rm_device(bmx280->i2c_dev); + #endif free(bmx280); } diff --git a/examples/bmx280_example_with_i2c_master.c b/examples/bmx280_example_with_i2c_master.c new file mode 100644 index 0000000..0d7e0be --- /dev/null +++ b/examples/bmx280_example_with_i2c_master.c @@ -0,0 +1,64 @@ +#include "esp_log.h" +#include "bmx280.h" +#include "driver/i2c_types.h" + +#define I2C_PORT_AUTO -1 +#define BMX280_SDA_NUM GPIO_NUM_13 +#define BMX280_SCL_NUM GPIO_NUM_14 + +i2c_master_bus_handle_t i2c_bus_init(uint8_t sda_io, uint8_t scl_io) +{ + i2c_master_bus_config_t i2c_bus_config = { + .i2c_port = I2C_PORT_AUTO, + .sda_io_num = sda_io, + .scl_io_num = scl_io, + .clk_source = I2C_CLK_SRC_DEFAULT, + .glitch_ignore_cnt = 7, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle)); + ESP_LOGI("test","I2C master bus created"); + return bus_handle; +} + +esp_err_t bmx280_dev_init(bmx280_t** bmx280,i2c_master_bus_handle_t bus_handle) +{ + *bmx280 = bmx280_create_master(bus_handle); + if (!*bmx280) { + ESP_LOGE("test", "Could not create bmx280 driver."); + return ESP_FAIL; + } + + ESP_ERROR_CHECK(bmx280_init(*bmx280)); + bmx280_config_t bmx_cfg = BMX280_DEFAULT_CONFIG; + ESP_ERROR_CHECK(bmx280_configure(*bmx280, &bmx_cfg)); + return ESP_OK; +} + +void app_main(void) +{ + // Entry Point + //ESP_ERROR_CHECK(nvs_flash_init()); + i2c_master_bus_handle_t bus_handle = i2c_bus_init(BMX280_SDA_NUM, BMX280_SCL_NUM); + bmx280_t* bmx280 = NULL; + ESP_ERROR_CHECK(bmx280_dev_init(&bmx280,bus_handle)); + + ESP_ERROR_CHECK(bmx280_setMode(bmx280, BMX280_MODE_CYCLE)); + float temp = 0, pres = 0, hum = 0; + for(int i = 0; i < 10; i++) + { + do { + vTaskDelay(pdMS_TO_TICKS(1)); + } while(bmx280_isSampling(bmx280)); + + ESP_ERROR_CHECK(bmx280_readoutFloat(bmx280, &temp, &pres, &hum)); + ESP_LOGI("test", "Read Values: temp = %f, pres = %f, hum = %f", temp, pres, hum); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + bmx280_close(bmx280); + i2c_del_master_bus(bus_handle); + ESP_LOGI("test", "Restarting now."); + esp_restart(); +} \ No newline at end of file diff --git a/examples/bmx280_example_without_i2c_master.c b/examples/bmx280_example_without_i2c_master.c new file mode 100644 index 0000000..848d00d --- /dev/null +++ b/examples/bmx280_example_without_i2c_master.c @@ -0,0 +1,51 @@ +#include "esp_log.h" +#include "bmx280.h" + +#define BMX280_SDA_NUM GPIO_NUM_13 +#define BMX280_SCL_NUM GPIO_NUM_14 + +void app_main(void) +{ + // Entry Point + //ESP_ERROR_CHECK(nvs_flash_init()); + i2c_config_t i2c_cfg = { + .mode = I2C_MODE_MASTER, + .sda_io_num = BMX280_SDA_NUM, + .scl_io_num = BMX280_SCL_NUM, + .sda_pullup_en = false, + .scl_pullup_en = false, + + .master = { + .clk_speed = CONFIG_BMX280_I2C_CLK_SPEED_HZ + } + }; + + ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_cfg)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0)); + + bmx280_t* bmx280 = bmx280_create(I2C_NUM_0); + + if (!bmx280) { + ESP_LOGE("test", "Could not create bmx280 driver."); + return; + } + + ESP_ERROR_CHECK(bmx280_init(bmx280)); + + bmx280_config_t bmx_cfg = BMX280_DEFAULT_CONFIG; + ESP_ERROR_CHECK(bmx280_configure(bmx280, &bmx_cfg)); + ESP_ERROR_CHECK(bmx280_setMode(bmx280, BMX280_MODE_CYCLE)); + + float temp = 0, pres = 0, hum = 0; + while (1) + { + do { + vTaskDelay(pdMS_TO_TICKS(1)); + } while(bmx280_isSampling(bmx280)); + + ESP_ERROR_CHECK(bmx280_readoutFloat(bmx280, &temp, &pres, &hum)); + + ESP_LOGI("test", "Read Values: temp = %f, pres = %f, hum = %f", temp, pres, hum); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} \ No newline at end of file diff --git a/include/bmx280.h b/include/bmx280.h index 403a10b..2333d16 100644 --- a/include/bmx280.h +++ b/include/bmx280.h @@ -16,9 +16,18 @@ extern "C" { #include #include -#include "driver/i2c.h" +#include #include "sdkconfig.h" +#include "bmx280_bits.h" +#if !(CONFIG_USE_I2C_MASTER_DRIVER) +#include "driver/i2c.h" +#else +#include "driver/i2c_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif + #define BMXAPI extern /** @@ -26,14 +35,28 @@ extern "C" { */ typedef struct bmx280_t bmx280_t; -#include "bmx280_bits.h" - +#if CONFIG_USE_I2C_MASTER_DRIVER +/** + * Create an instance of the BMX280 driver. + * @param bus_handle The I2C master handle via port. + * @return A non-null pointer to the driver structure on success. + */ +BMXAPI bmx280_t* bmx280_create_master(i2c_master_bus_handle_t bus_handle); +// legacy define for existing code bases +#define bmx280_create(port) bmx280_create_legacy(port) +#define bmx280_create_legacy(port) static_assert(0, "You have the wrong driver configuration for using the legacy I2C driver.") +#else /** * Create an instance of the BMX280 driver. * @param port The I2C port to use. * @return A non-null pointer to the driver structure on success. */ -BMXAPI bmx280_t* bmx280_create(i2c_port_t port); +BMXAPI bmx280_t* bmx280_create_legacy(i2c_port_t port); +// legacy define for existing code bases +#define bmx280_create(port) bmx280_create_legacy(port) +#define bmx280_create_master(port) static_assert(0, "You have the wrong driver configuration for using the new I2C master driver.") +#endif + /** * Destroy your the instance. * @param bmx280 The instance to destroy.