Thanks for visiting and hope you find something useful. This repository is a library of peripheral, scheduling, storage, and utility components that are compatible with the ESP32 espressif IoT development framework (esp-idf). The code base is maintained as well as one person can manage in their spare time. The development environment is under Visual Studio Code with the PlatformIO (6.1.18) and ESP-IDF (v5.4.0) extensions. There is always room for improvement to optimize the code base and open to suggestions.
PlatformIO components with examples for the ESP32-S3 chipset. This is a revised release utilizing esp-idf suggested design patterns through handles
and using i2c_master.h
for I2C transactions. The drivers are organized in the components folder within the Visual Studio Code and PlatformIO environment.
The folder structure for components, and associated example, are outlined as follows:
|--components
| |
| |--peripherals
| | |
| | |--adc
| | |--i2c
| | | |
| | | |--esp_bmp280
| | | | |--documentation
| | | | |- BMP280 Datasheet.pdf
| | | | |--include
| | | | |- bmp280_version.h
| | | | |- bmp280.h
| | | | |- bmp280.c
| | | | |- CMakeLists.txt
| | | | |- LICENSE
| | | | |- README.md
| | | | |- idf_component.yml
| | | | |- library.json
| | |
| | |--owb
| | |--spi
| | |--uart
| |
| |
| |--utilities
| |--schedule
| |--storage
|
|--templates
| |--component
| | |--include
| | | |- version.h.in
| |
| |--components
| | |--esp_bmp280
| | | |- library.json.in
| | | |- idf_componet.yml.in
|
|--include
| |- app_config.h
| |- bmp280_task.h
|
|--src
| |- bmp280_task.c
| |- main.c
|
|- platformio.ini
The component C header version, yml, and json files are automically generated from templates. The templates utilized to generate these files are located as follows;
- C header version template file:
templates/component/include/version.h.in
. - yml template file:
templates/components/[component]/idf_component.yml.in
. - json template file:
templates/components/[component]/library.json.in
.
If information must be updated, be sure to update the template and not the generated file. Otherwise, files are overwritten when the version is updated. See the component's CMakeLists.txt
file for more details.
To get started, locate and open the app_config.h
file from the include
folder and configure GPIO pins as needed. Now, locate and open the main.c
file from the src
folder and go to the void app_main( void )
subroutine to enable the device of interest. The example code is located in the [sensor]_task.h
and [sensor]_task.c
files.
/**
* @brief Main application entry point.
*/
void app_main( void ) {
/* start a component example */
/* note: only one component can run at a time */
//i2c0_component_example_start(I2C_COMPONENT_AHTXX);
//i2c0_component_example_start(I2C_COMPONENT_AS7341);
//i2c0_component_example_start(I2C_COMPONENT_BH1750);
//i2c0_component_example_start(I2C_COMPONENT_BMP280);
i2c0_component_example_start(I2C_COMPONENT_BMP390);
//i2c0_component_example_start(I2C_COMPONENT_CCS811);
//i2c0_component_example_start(I2C_COMPONENT_ENS160);
//i2c0_component_example_start(I2C_COMPONENT_HDC1080);
//i2c0_component_example_start(I2C_COMPONENT_HMC5883L);
//i2c0_component_example_start(I2C_COMPONENT_MLX90614);
//i2c0_component_example_start(I2C_COMPONENT_MPU6050);
//i2c0_component_example_start(I2C_COMPONENT_SGP4X);
//i2c0_component_example_start(I2C_COMPONENT_SHT4X);
//i2c0_component_example_start(I2C_COMPONENT_SSD1306);
//i2c0_component_example_start(I2C_COMPONENT_TLV493D);
//i2c0_component_example_start(I2C_COMPONENT_VEML7700);
}
Once these initial steps are done, compile and upload the program, assuming your development board is equivalent to the esp32s3box
. Otherwise, you will have to configure the environment for your development board and recompile before uploading the program.
All components use the same implementation model and a basic example is provided below.
To get started, create a new PlatformIO project, and copy the esp_bmp390
component to the components folder. Setup your development board and environment in PlatformIO, and copy the example code to overwrite default code in the main.c
file. I2C port and GPIO assigments: the example assigns I2C_NUM_0
to the master I2C port, SDA
is assigned to GPIO number 45, and SCL
is assigned to GPIO number 48. Interface the BMP390 sensor to the development board, compile example, and upload the binary to the device. Open the serial terminal to monitor the output. Reset the board to view configured registers at startup.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
// bmp390 component
#include <bmp390.h>
#define TSK_MINIMAL_STACK_SIZE (1024)
#define I2C0_MASTER_PORT I2C_NUM_0
#define I2C0_MASTER_SDA_IO GPIO_NUM_45 // blue
#define I2C0_MASTER_SCL_IO GPIO_NUM_48 // yellow
#define I2C0_TASK_NAME "bmp390_tsk"
#define I2C0_TASK_SAMPLING_RATE (10) // seconds
#define I2C0_TASK_STACK_SIZE (TSK_MINIMAL_STACK_SIZE * 8)
#define I2C0_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
#define I2C0_MASTER_CONFIG_DEFAULT { \
.clk_source = I2C_CLK_SRC_DEFAULT, \
.i2c_port = I2C0_MASTER_PORT, \
.scl_io_num = I2C0_MASTER_SCL_IO, \
.sda_io_num = I2C0_MASTER_SDA_IO, \
.glitch_ignore_cnt = 7, \
.flags.enable_internal_pullup = true, }
#define APP_TAG "ESP-IDF BMP390 COMPONENT [APP]"
static inline void print_registers(bmp390_handle_t handle) {
/* configuration registers */
bmp390_power_control_register_t power_ctrl_reg;
bmp390_configuration_register_t config_reg;
bmp390_oversampling_register_t oversampling_reg;
bmp390_output_data_rate_register_t output_data_rate_reg;
bmp390_interrupt_control_register_t interrupt_ctrl_reg;
/* attempt to read configuration register */
bmp390_get_configuration_register(handle, &config_reg);
/* attempt to read oversampling register */
bmp390_get_oversampling_register(handle, &oversampling_reg);
/* attempt to read to power control register */
bmp390_get_power_control_register(handle, &power_ctrl_reg);
/* attempt to read to output data rate register */
bmp390_get_output_data_rate_register(handle, &output_data_rate_reg);
/* attempt to read to interrupt control register */
bmp390_get_interrupt_control_register(handle, &interrupt_ctrl_reg);
ESP_LOGI(APP_TAG, "Configuration (0x%02x): %s", config_reg.reg, uint8_to_binary(config_reg.reg));
ESP_LOGI(APP_TAG, "Oversampling (0x%02x): %s", oversampling_reg.reg, uint8_to_binary(oversampling_reg.reg));
ESP_LOGI(APP_TAG, "Data Rate (0x%02x): %s", output_data_rate_reg.reg, uint8_to_binary(output_data_rate_reg.reg));
ESP_LOGI(APP_TAG, "Power Control (0x%02x): %s", power_ctrl_reg.reg, uint8_to_binary(power_ctrl_reg.reg));
ESP_LOGI(APP_TAG, "Int Control (0x%02x): %s", interrupt_ctrl_reg.reg, uint8_to_binary(interrupt_ctrl_reg.reg));
if(interrupt_ctrl_reg.bits.irq_data_ready_enabled) ESP_LOGE(APP_TAG, "bmp390 irq data ready is enabled");
}
void i2c0_bmp390_task( void *pvParameters ) {
// initialize the xLastWakeTime variable with the current time.
TickType_t last_wake_time = xTaskGetTickCount ();
//
// initialize i2c device configuration
bmp390_config_t dev_cfg = I2C_BMP390_CONFIG_DEFAULT;
bmp390_handle_t dev_hdl;
//
// init device
bmp390_init(i2c0_bus_hdl, &dev_cfg, &dev_hdl);
if (dev_hdl == NULL) {
ESP_LOGE(APP_TAG, "bmp390 handle init failed");
assert(dev_hdl);
}
print_registers(dev_hdl);
// task loop entry point
for ( ;; ) {
ESP_LOGI(APP_TAG, "######################## BMP390 - START #########################");
//
// handle sensor
float temperature, pressure;
esp_err_t result = bmp390_get_measurements(dev_hdl, &temperature, &pressure);
if(result != ESP_OK) {
ESP_LOGE(APP_TAG, "bmp390 device read failed (%s)", esp_err_to_name(result));
} else {
pressure = pressure / 100;
ESP_LOGI(APP_TAG, "air temperature: %.2f °C", temperature);
ESP_LOGI(APP_TAG, "barometric pressure: %.2f hPa", pressure);
}
//
ESP_LOGI(APP_TAG, "######################## BMP390 - END ###########################");
//
//
// pause the task per defined wait period
vTaskDelaySecUntil( &last_wake_time, I2C0_TASK_SAMPLING_RATE );
}
//
// free resources
bmp390_delete( dev_hdl );
vTaskDelete( NULL );
}
/**
* @brief Main application entry point.
*/
void app_main( void ) {
ESP_LOGI(APP_TAG, "Startup..");
ESP_LOGI(APP_TAG, "Free memory: %lu bytes", esp_get_free_heap_size());
ESP_LOGI(APP_TAG, "IDF version: %s", esp_get_idf_version());
/* set log levels */
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set(APP_TAG, ESP_LOG_VERBOSE);
/* instantiate i2c master bus 0 */
ESP_ERROR_CHECK( i2c_new_master_bus(&i2c0_bus_cfg, &i2c0_bus_hdl) );
/* create task pinned to the app core */
xTaskCreatePinnedToCore(
i2c0_bmp390_task,
I2C0_TASK_NAME,
I2C0_TASK_STACK_SIZE,
NULL,
I2C0_TASK_PRIORITY,
NULL,
APP_CPU_NUM );
}
The ESP peripheral components accommodate ADC, I2C, OWB, SPI, and UART device interfacing supported by various device manufacturers.
Supported drivers include the following device peripherals:
- ADC: Roithner LaserTechnik GUVA-S12SD
- I2C: ASAIR AHTXX
- I2C: AKM AK8975
- I2C: AMS AS3935
- I2C: OSRAM AS7341
- I2C: Microchip AT24CXXX
- I2C: ROHM BH1750FVI
- I2C: Bosch BME680
- I2C: Bosch BMP280
- I2C: Bosch BMP390
- I2C: ScioSense CCS811
- I2C: ScioSense ENS160
- I2C: Texas Instruments HDC1080
- I2C: Honeywell HMC5883L
- I2C: Texas Instruments INA226
- I2C: Lite-On LTR390UV
- I2C: Maxim-Integrated MAX30105 - Work in Progress
- I2C: Melexis MLX90614
- I2C: Memsic MMC56X3
- I2C: InvenSense MPU6050
- I2C: NXP Semiconductors PCT2075
- I2C: Sensirion SGP4X
- I2C: Sensirion SHT4X
- I2C: Generic SSD1306
- I2C: Infineon TLV493D - Work in Progress
- I2C: Vishay VEML6040
- I2C: Vishay VEML7700
- OWB: Maxim-Integrated DS18B20
- SPI: Analog Devices MAX31865 - Work in Progress
- UART: MIKROE UART MUX Click
The above peripheral drivers have been tested, and validated with a logic analyzer where applicable, and are still under development. With every ESP-IDF release there are bound to be quirks with the code base. If any problems arise please feel free to log an issue and if you would to contribute please contact me.
The ESP Utilities components are generally used in conjunction with peripheral components for data processing.
Supported components include the following:
Kalman Motion
: Kalman filter for motion based use-cases that leverage sensors such as a gyroscope and/or accelerometer.Sensirion Gas Index Algorithm
: A gas index algorithm for the Sensirion air quality sensors. This code base is maintained by Sensirion.Pressure Tendency
: A pressure tendency algorithm that monitors if pressure is rising, falling, or steady over the past 3-hours.Scalar Trend
: A scalar trend algorithm that monitors if a scalar variable is rising, falling, or steady over the past hour.Type Utilities
: Type definitions common for i2c transactions, byte manipulation, and other tools.UUID Generator
: An RFC-4122 Universally Unique Identifier (UUID) generator.
See the Sensirion SGP4X example on how the gas index algorithm is utilized with this sensor.
The ESP time-into-interval
component synchronizes a FreeRTOS task with the system clock and user-defined time interval for temporal conditional scenarios.
The ESP storage components can be used for use-cases that require volatile and/or non-volatile storage.
Supported components include the following:
Data-Logger
: A user friendly table based data logging component for measurement and control use-cases. See Data-Logger examples for more details, see readme file in the component folder.NVS Ext
: A component extension that simplifies the process of reading and writing information to non-volatile storage (NVS). See readme file in the component folder.
Copyright (c) 2024 Eric Gionet ([email protected])