Compare commits

..

5 Commits

Author SHA1 Message Date
b48a6e2fa9 Move the I2C speed config key out of the choice prompt. 2024-11-25 22:44:33 +03:00
PurpleCloudX
2dc752e074 Fix potential null pointer dereference in bmx280_close 2024-11-25 22:43:58 +08:00
PurpleCloudX
744b34a9f3 Fix: Unable to parse symbol 'BMX280_STANDBY_20M' in bmx280_bits.h (Issue #5) 2024-11-25 21:23:52 +08:00
PurpleCloudX
35f236ce03 Changes requested 2024-11-25 19:42:52 +08:00
PurpleCloudX
40a62650f8 Add support for I2C master driver 2024-11-24 20:43:57 +08:00
8 changed files with 316 additions and 60 deletions

@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.1)
set(CMAKE_C_STANDARD 11)
idf_component_register(
SRCS bmx280.c
INCLUDE_DIRS "include"

28
Kconfig

@ -1,4 +1,26 @@
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.
endchoice
config BMX280_I2C_CLK_SPEED_HZ
int "I2C Clock Speed (Hz)"
default 100000
range 1000 400000
help
Set the I2C clock speed in Hz. Only applies to the new I2C Master driver.
choice BMX280_EXPECT_DEVICE
prompt "Installed Sensor Model"
help
@ -20,15 +42,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.

@ -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
-------

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

145
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);
#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 != NULL && bmx280->i2c_dev != NULL)
i2c_master_bus_rm_device(bmx280->i2c_dev);
#endif
free(bmx280);
}

@ -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();
}

@ -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));
}
}

@ -16,9 +16,18 @@ extern "C" {
#include <stdint.h>
#include <limits.h>
#include "driver/i2c.h"
#include <assert.h>
#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.

@ -126,7 +126,7 @@ typedef struct bmx280_config_t {
#elif (CONFIG_BMX280_DEFAULT_STANDBY_10M)
#define BMX280_DEFAULT_STANDBY BME280_STANDBY_10M
#else
#define BMX280_DEFAULT_STANDBY BMX280_STANDBY_20M
#define BMX280_DEFAULT_STANDBY BME280_STANDBY_20M
#endif
#if (CONFIG_BMX280_DEFAULT_IIR_NONE)