From 40a62650f8cdcdf47f5c7f2adcfd76a96a4e2090 Mon Sep 17 00:00:00 2001 From: PurpleCloudX Date: Sun, 24 Nov 2024 19:45:29 +0800 Subject: [PATCH] Add support for I2C master driver --- CMakeLists.txt | 1 - Kconfig | 30 ++++- README.md | 49 ++------ bmx280.c | 123 ++++++++++++++++++- examples/bmx280_example_with_i2c_master.c | 65 ++++++++++ examples/bmx280_example_without_i2c_master.c | 51 ++++++++ include/bmx280.h | 22 +++- 7 files changed, 289 insertions(+), 52 deletions(-) create mode 100644 examples/bmx280_example_with_i2c_master.c create mode 100644 examples/bmx280_example_without_i2c_master.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fe4285..de30f8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ - idf_component_register( SRCS bmx280.c INCLUDE_DIRS "include" diff --git a/Kconfig b/Kconfig index 9721ffc..07f4f20 100644 --- a/Kconfig +++ b/Kconfig @@ -1,4 +1,28 @@ menu "BMX280 Options" + choice I2C_DRIVER_SETTING + prompt "I2C driver setting" + help + Select I2C driver: I2C_OLD: Use old driver I2C.h, I2C_NEW: Use new i2c_master.h(ESP-IDF >=5.3) + default USE_I2C_OLD_DEVICE + + config USE_I2C_OLD_DEVICE + bool "old I2C driver (I2C.h)" + help + Use the old I2C driver (I2C.h). + + config USE_I2C_NEW_DEVICE + bool "new I2C driver (i2c_master.h)" + help + Use the new I2C driver (i2c_master.h) for ESP-IDF >= 5.2. + + 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 +44,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..e1bd4f4 100644 --- a/README.md +++ b/README.md @@ -10,55 +10,20 @@ 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 new 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 -> new I2C 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 new 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); - } -} -``` License ------- diff --git a/bmx280.c b/bmx280.c index 4be32e3..24fa183 100644 --- a/bmx280.c +++ b/bmx280.c @@ -69,11 +69,28 @@ // Value of REG_CHPID for BMP280 (Production) #define BMP280_ID2 0x58 +#if CONFIG_USE_I2C_NEW_DEVICE +// I2C Master configuration structure (temporary) +typedef struct i2c_config_t{ + // I2C master configuration + i2c_device_config_t dev_cfg; + // I2C master handle via port + i2c_master_bus_handle_t bus_handle; +}*i2c_config_t; +#endif + struct bmx280_t{ + #if !(CONFIG_USE_I2C_NEW_DEVICE) // 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 structure + i2c_config_t i2c_cfg; + #endif // Chip ID of sensor uint8_t chip_id; // Compensation data @@ -122,7 +139,27 @@ struct bmx280_t{ * Returns false if the sensor was not found. * @param bmx280 The driver structure. */ +#if !(CONFIG_USE_I2C_NEW_DEVICE) #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_NEW_DEVICE +/** + * Read from sensor. + * @param bmx280 Driver Sturcture. + * @param dev_addr Chip addresses. + */ +static void 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->i2c_cfg->dev_cfg.device_address = dev_addr; + // Add device to the I2C bus + ESP_ERROR_CHECK(i2c_master_bus_add_device(bmx280->i2c_cfg->bus_handle, &bmx280->i2c_cfg->dev_cfg, &bmx280->i2c_dev)); + ESP_LOGI("bmx280", "device_create success on 0x%x", dev_addr); +} +#endif /** * Read from sensor. @@ -134,6 +171,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_NEW_DEVICE) esp_err_t err; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); if (cmd) @@ -157,11 +195,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_NEW_DEVICE) i2c_cmd_handle_t cmd = i2c_cmd_link_create(); if (cmd) { @@ -184,12 +227,21 @@ static esp_err_t bmx280_write(bmx280_t* bmx280, uint8_t addr, const uint8_t *din { return ESP_ERR_NO_MEM; } + #else + for(int i = 0; i < size; i++) + { + uint8_t addri = addr + i; + uint8_t dat[2] = {addri, 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,23 +254,30 @@ static esp_err_t bmx280_probe_address(bmx280_t *bmx280) #endif ) { + #if !(CONFIG_USE_I2C_NEW_DEVICE) 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->i2c_cfg->dev_cfg.device_address, bmx280->chip_id); + #endif + return ESP_OK; } else { err = ESP_ERR_NOT_FOUND; } } - + #if !(CONFIG_USE_I2C_NEW_DEVICE) 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->i2c_cfg->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_NEW_DEVICE) ESP_LOGI("bmx280", "Probing for BMP280/BME280 sensors on I2C %d", bmx280->i2c_port); - #if CONFIG_BMX280_ADDRESS_HI bmx280->slave = 0xEE; return bmx280_probe_address(bmx280); @@ -240,6 +299,35 @@ 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 + bmx280_device_create(bmx280, 0x77); + err = bmx280_probe_address(bmx280); + free(bmx280->i2c_cfg); + return err; + #elif CONFIG_BMX280_ADDRESS_LO + bmx280_device_create(bmx280, 0x76); + err = bmx280_probe_address(bmx280); + free(bmx280->i2c_cfg); + return err; + #else + bmx280_device_create(bmx280, 0x76); + if ((err = bmx280_probe_address(bmx280)) != ESP_OK) + { + bmx280_device_create(bmx280, 0x77); + if ((err = bmx280_probe_address(bmx280)) != ESP_OK) + { + ESP_LOGE("bmx280", "Sensor not found."); + bmx280->i2c_dev = NULL; + bmx280->chip_id = 0xAD; + } + } + free(bmx280->i2c_cfg); + return err; + #endif + #endif } static esp_err_t bmx280_reset(bmx280_t *bmx280) @@ -309,6 +397,7 @@ static esp_err_t bmx280_calibrate(bmx280_t *bmx280) return ESP_OK; } +#if !(CONFIG_USE_I2C_NEW_DEVICE) bmx280_t* bmx280_create(i2c_port_t port) { bmx280_t* bmx280 = malloc(sizeof(bmx280_t)); @@ -318,13 +407,39 @@ bmx280_t* bmx280_create(i2c_port_t port) bmx280->i2c_port = port; bmx280->slave = 0xDE; +#else +bmx280_t* bmx280_create(i2c_master_bus_handle_t bus_handle) +{ + bmx280_t* bmx280 = malloc(sizeof(bmx280_t)); + i2c_config_t dev_cfg = malloc(sizeof(struct i2c_config_t)); + if (bmx280 && dev_cfg) + { + memset(bmx280, 0, sizeof(bmx280_t)); + memset(dev_cfg, 0, sizeof(struct i2c_config_t)); + bmx280->i2c_cfg = dev_cfg; + bmx280->i2c_cfg->bus_handle = bus_handle; + bmx280->i2c_cfg->dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7; + bmx280->i2c_cfg->dev_cfg.device_address = 0xDE; + bmx280->i2c_cfg->dev_cfg.scl_speed_hz =CONFIG_BMX280_I2C_CLK_SPEED_HZ; + bmx280->i2c_dev = NULL; +#endif bmx280->chip_id = 0xAD; } + else + { + ESP_LOGE("bmx280", "Failed to allocate memory for bmx280."); + bmx280_close(bmx280); + return NULL; + } return bmx280; } void bmx280_close(bmx280_t *bmx280) { + #if CONFIG_USE_I2C_NEW_DEVICE + free(bmx280->i2c_cfg); + 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..fd6d0b0 --- /dev/null +++ b/examples/bmx280_example_with_i2c_master.c @@ -0,0 +1,65 @@ +#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(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..c9f1e44 100644 --- a/include/bmx280.h +++ b/include/bmx280.h @@ -16,9 +16,17 @@ extern "C" { #include #include -#include "driver/i2c.h" #include "sdkconfig.h" +#include "bmx280_bits.h" +#if !(CONFIG_USE_I2C_NEW_DEVICE) +#include "driver/i2c.h" +#else +#include "driver/i2c_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif + #define BMXAPI extern /** @@ -26,14 +34,24 @@ extern "C" { */ typedef struct bmx280_t bmx280_t; -#include "bmx280_bits.h" + + +#if !(CONFIG_USE_I2C_NEW_DEVICE) /** * 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); +#else +/** + * 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(i2c_master_bus_handle_t bus_handle); +#endif /** * Destroy your the instance. * @param bmx280 The instance to destroy.