diff --git a/.gitignore b/.gitignore index e4ce498..ec8c6ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ sdkconfig* !sdkconfig.defaults + +# Build directory +build/ + +# IDE directory +.pio +.vscode + +# CLang +.clangd \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 299d92e..ab499eb 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -65,24 +65,22 @@ else() INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/.." REQUIRES soc ulp PRIV_REQUIRES - esp_driver_tsens - esp_driver_gpio - esp_http_server - esp_event - esp_timer - esp_netif - esp_hw_support - driver) + idf::driver + idf::esp_driver_i2c + idf::esp_driver_tsens + idf::esp_driver_gpio + idf::esp_http_server + idf::esp_event + idf::esp_timer + idf::esp_netif + idf::esp_hw_support) set(TARGET_NAME "${COMPONENT_LIB}") - include(../cmake/CPM.cmake) CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#main") target_link_libraries(${TARGET_NAME} PRIVATE aether) - ulp_add_project("ulp_main" "${CMAKE_CURRENT_LIST_DIR}/../ulp") - if (NOT "${WIFI_SSID}" STREQUAL "") target_compile_definitions(${TARGET_NAME} PRIVATE "WIFI_SSID=\"${WIFI_SSID}\"") endif() @@ -93,6 +91,19 @@ else() target_compile_definitions(${TARGET_NAME} PRIVATE "BOARD=${BOARD}") endif() + # Define the path to the board configuration file in the build folder + set(ULP_BOARD_FILE "${CMAKE_BINARY_DIR}/ulp_board_config.cmake") + + # Write the value of the BOARD variable to this file + if(NOT "${BOARD}" STREQUAL "") + file(WRITE "${ULP_BOARD_FILE}" "set(BOARD \"${BOARD}\")\n") + else() + file(WRITE "${ULP_BOARD_FILE}" "set(BOARD \"\")\n") + endif() + + # We call the project addition as usual + ulp_add_project("ulp_main" "${CMAKE_CURRENT_LIST_DIR}/../ulp") + else() #Other platforms message(FATAL_ERROR "Platform ${CM_PLATFORM} is not supported") diff --git a/main/boards/aether_esp32_c6.h b/main/boards/aether_esp32_c6.h index 5e813c5..bc92e41 100644 --- a/main/boards/aether_esp32_c6.h +++ b/main/boards/aether_esp32_c6.h @@ -20,7 +20,7 @@ # error "Illegal CPU! It must be an ESP32C6." #endif -#include "hal/i2c_types.h" +#include "soc/gpio_num.h" #ifndef BOARD_HAS_ULP # define BOARD_HAS_ULP 0 @@ -28,20 +28,28 @@ #ifndef BOARD_HAS_LED # define BOARD_HAS_LED 1 #endif +#ifndef BOARD_HAS_PWR_ON +# define BOARD_HAS_PWR_ON 1 +#endif #ifndef STATUS_LED_PIN -# define STATUS_LED_PIN GPIO_NUM_7 +# define STATUS_LED_ON_PIN GPIO_NUM_17 +# define STATUS_LED_PIN GPIO_NUM_18 +#endif +#ifndef PWR_ON_GPIO +# define PWR_ON_GPIO GPIO_NUM_2 +# define LP_PWR_ON_GPIO LP_IO_NUM_2 #endif #ifndef RESET_BUTTON_PIN # define RESET_BUTTON_PIN GPIO_NUM_9 #endif // --- Sensors --- #define BOARD_HAS_SHTC3 0 -#define BOARD_HAS_SHT45 1 +#define BOARD_HAS_SHT45 0 #define BOARD_HAS_STCC4 1 #define BOARD_HAS_BME688 0 // --- Hardware Settings --- -#define SENSOR_SDA_PIN 19 -#define SENSOR_SCL_PIN 18 +#define SENSOR_SDA_PIN GPIO_NUM_6 +#define SENSOR_SCL_PIN GPIO_NUM_7 // FIX 1: Use a Fixed Buffer instead of VLA (Variable Length Array) to prevent // stack smash #define MAX_I2C_BUFFER 64 diff --git a/main/boards/m5stack_atom_lite.h b/main/boards/m5stack_atom_lite.h index 509b70b..d89f8c0 100644 --- a/main/boards/m5stack_atom_lite.h +++ b/main/boards/m5stack_atom_lite.h @@ -21,6 +21,7 @@ #endif #include "hal/i2c_types.h" +#include "soc/gpio_num.h" #ifndef BOARD_HAS_ULP # define BOARD_HAS_ULP 0 @@ -28,9 +29,16 @@ #ifndef BOARD_HAS_LED # define BOARD_HAS_LED 1 #endif +#ifndef BOARD_HAS_PWR_ON +# define BOARD_HAS_PWR_ON 0 +#endif #ifndef STATUS_LED_PIN # define STATUS_LED_PIN GPIO_NUM_35 #endif +#ifndef PWR_ON_GPIO +# define PWR_ON_GPIO -1 +# define LP_PWR_ON_GPIO -1 +#endif #ifndef RESET_BUTTON_PIN # define RESET_BUTTON_PIN GPIO_NUM_41 #endif @@ -40,8 +48,8 @@ #define BOARD_HAS_STCC4 0 #define BOARD_HAS_BME688 1 // --- Hardware Settings --- -#define SENSOR_SDA_PIN 2 -#define SENSOR_SCL_PIN 1 +#define SENSOR_SDA_PIN GPIO_NUM_2 +#define SENSOR_SCL_PIN GPIO_NUM_1 // FIX 1: Use a Fixed Buffer instead of VLA (Variable Length Array) to prevent // stack smash #define MAX_I2C_BUFFER 64 diff --git a/main/boards/nano_esp32_c6.h b/main/boards/nano_esp32_c6.h index d0ae5a5..266137f 100644 --- a/main/boards/nano_esp32_c6.h +++ b/main/boards/nano_esp32_c6.h @@ -29,17 +29,24 @@ #ifndef BOARD_HAS_LED # define BOARD_HAS_LED 1 #endif +#ifndef BOARD_HAS_PWR_ON +# define BOARD_HAS_PWR_ON 0 +#endif #ifndef STATUS_LED_PIN # define STATUS_LED_PIN GPIO_NUM_8 #endif +#ifndef PWR_ON_GPIO +# define PWR_ON_GPIO -1 +# define LP_PWR_ON_GPIO -1 +#endif #ifndef RESET_BUTTON_PIN # define RESET_BUTTON_PIN GPIO_NUM_9 #endif // --- Sensors --- #define BOARD_HAS_SHTC3 0 -#define BOARD_HAS_SHT45 1 +#define BOARD_HAS_SHT45 0 #define BOARD_HAS_STCC4 0 -#define BOARD_HAS_BME688 0 +#define BOARD_HAS_BME688 1 // --- Hardware Settings --- #define SENSOR_SDA_PIN GPIO_NUM_6 #define SENSOR_SCL_PIN GPIO_NUM_7 diff --git a/main/controller.cpp b/main/controller.cpp index d8cda40..9e753b5 100644 --- a/main/controller.cpp +++ b/main/controller.cpp @@ -155,8 +155,11 @@ void loop() { // implemented in sensors/ void UpdateSensors() { std::int16_t temperature = {}; - ReadSensors(&temperature, nullptr, nullptr, nullptr, nullptr); - std::cout << ae::Format(" >>> Temperature: [{}]\n", temperature); + std::uint32_t humidity = {}; + std::uint32_t co2 = {}; + ReadSensors(&temperature, &humidity, nullptr, &co2, nullptr); + std::cout << ae::Format(" >>> Temperature: [{}], Humidity: [{}], CO2: [{}]\n", + temperature, humidity, co2); // TODO: add check if wakeup cause is ulp then send value SendValue(temperature); } diff --git a/main/sensors/bme688.c b/main/sensors/bme688.c index 06fdac0..84cc6bb 100644 --- a/main/sensors/bme688.c +++ b/main/sensors/bme688.c @@ -33,22 +33,34 @@ # include "sensors/sensors.h" # include "sensors/utils.h" -# ifdef IS_ULP_COCPU -# define BME_I2C_NUM LP_I2C_NUM_0 -# else -# define BME_I2C_NUM I2C_NUM_0 +# if ULP_COMP == 0 +static i2c_master_bus_handle_t bus_handle; +static i2c_master_dev_handle_t dev_handle_bme688; +# endif + +# if ULP_COMP == 1 +# define BME688_I2C_NUM_0 LP_I2C_NUM_0 +# define I2C_BUS_HANDLE_S 0 +# define I2C_HANDLE_PORT_S BME688_I2C_NUM_0 +# elif ULP_COMP == 0 +# define BME688_I2C_NUM_0 I2C_NUM_0 +# define I2C_BUS_HANDLE_S &bus_handle +# define I2C_HANDLE_PORT_S dev_handle_bme688 # endif // Constants # define I2C_TRANS_TIMEOUT_CYCLES 5000 # define I2C_TRANS_WAIT_FOREVER -1 +# define I2C_BUS_SPEED 400000 // 400 KHz // --- SAFER Interface Functions --- static BME68X_INTF_RET_TYPE bme_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr) { uint8_t dev_addr = *(uint8_t*)intf_ptr; - esp_err_t err = i2c_write_read(BME_I2C_NUM, dev_addr, ®_addr, 1, reg_data, + + esp_err_t err = i2c_write_read(I2C_HANDLE_PORT_S, dev_addr, ®_addr, 1, reg_data, len, I2C_TRANS_TIMEOUT_CYCLES); + return (err == ESP_OK) ? BME68X_OK : BME68X_E_COM_FAIL; } @@ -67,8 +79,8 @@ static BME68X_INTF_RET_TYPE bme_i2c_write(uint8_t reg_addr, // Safe copy memcpy(&buffer[1], reg_data, len); - esp_err_t err = - i2c_write(BME_I2C_NUM, dev_addr, buffer, len + 1, I2C_TRANS_WAIT_FOREVER); + esp_err_t err = i2c_write(I2C_HANDLE_PORT_S, dev_addr, buffer, len + 1, I2C_TRANS_WAIT_FOREVER); + return (err == ESP_OK) ? BME68X_OK : BME68X_E_COM_FAIL; } @@ -82,12 +94,30 @@ struct bme68x_dev bme; struct bme68x_conf conf; uint8_t dev_addr = BME68X_I2C_ADDR_LOW; -bool Init() { - // 1. INSTALL I2C DRIVER - if (i2c_init(BME_I2C_NUM, SENSOR_SDA_PIN, SENSOR_SCL_PIN) != ESP_OK) { +bool init_i2c(uint8_t dev_addr){ + // 2. Install I2C driver + if (i2c_init(I2C_BUS_HANDLE_S, BME688_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN, I2C_BUS_SPEED) != ESP_OK) { return false; } +#if ULP_COMP == 0 + // Configuration of a specific device on the bus + i2c_device_config_t dev_cfg_bme688 = {}; + dev_cfg_bme688.dev_addr_length = I2C_ADDR_BIT_LEN_7; + dev_cfg_bme688.device_address = dev_addr; // Address BME688 + dev_cfg_bme688.scl_speed_hz = I2C_BUS_SPEED; + + if(i2c_master_bus_add_device(bus_handle, &dev_cfg_bme688, &dev_handle_bme688) != ESP_OK){ + return false; + } +#endif + + return true; +} + +bool Init() { + init_i2c(dev_addr); + // 2. Initialize BME Sensor bme.read = bme_i2c_read; bme.write = bme_i2c_write; @@ -98,6 +128,10 @@ bool Init() { if (bme68x_init(&bme) != BME68X_OK) { dev_addr = BME68X_I2C_ADDR_HIGH; // Try alternate address +#if ULP_COMP == 0 + i2c_master_bus_rm_device(dev_handle_bme688); +#endif + init_i2c(dev_addr); if (bme68x_init(&bme) != BME68X_OK) { return false; } diff --git a/main/sensors/esp_main_utils.c b/main/sensors/esp_main_utils.c index 4788fa1..850d998 100644 --- a/main/sensors/esp_main_utils.c +++ b/main/sensors/esp_main_utils.c @@ -14,44 +14,55 @@ * limitations under the License. */ -#if defined ESP_PLATFORM && !defined IS_ULP_COCPU +#include "user_config.h" + +#if defined ESP_PLATFORM && ULP_COMP == 0 # include # include -# include "driver/i2c.h" +# include "driver/i2c_master.h" # include "esp_log.h" -esp_err_t i2c_init(i2c_port_t port, int sda_pin, int scl_pin) { - i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = sda_pin, - .scl_io_num = scl_pin, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master = {.clk_speed = 100000}, - .clk_flags = 0, - }; - if (i2c_param_config(port, &conf) != ESP_OK) { +static const char *TAG_I2C = "I2C"; + +esp_err_t i2c_init(i2c_master_bus_handle_t *bus_handle, i2c_port_t i2c_handle_port, int sda_pin, int scl_pin, int i2c_speed) { + esp_err_t err; + + i2c_master_bus_config_t bus_cfg = {}; + + ESP_LOGI(TAG_I2C, "Init ESP i2c"); + bus_cfg.i2c_port = i2c_handle_port; + bus_cfg.sda_io_num = sda_pin; + bus_cfg.scl_io_num = scl_pin; + bus_cfg.clk_source = I2C_CLK_SRC_DEFAULT; + bus_cfg.glitch_ignore_cnt = 7; + bus_cfg.intr_priority = 0; + bus_cfg.flags.enable_internal_pullup = 0; + bus_cfg.flags.allow_pd = 0; + + err = i2c_new_master_bus(&bus_cfg, bus_handle); + if(err != ESP_OK){ + ESP_LOGE(TAG_I2C, "Failed to install the i2c driver! Error: %s", esp_err_to_name(err)); return ESP_ERR_INVALID_STATE; } - return i2c_driver_install(port, conf.mode, 0, 0, 0); + + return ESP_OK; } -esp_err_t i2c_write(i2c_port_t port, uint8_t address, uint8_t const* data, +esp_err_t i2c_write(i2c_master_bus_handle_t *bus_handle, i2c_master_dev_handle_t i2c_handle_port, uint8_t address, uint8_t const* data, uint8_t len, int32_t ms_dur) { - return i2c_master_write_to_device(port, address, data, len, - ms_dur); + return i2c_master_transmit(i2c_handle_port, data, len, ms_dur); } -esp_err_t i2c_read(i2c_port_t port, uint8_t address, uint8_t* data, uint8_t len, +esp_err_t i2c_read(i2c_master_bus_handle_t *bus_handle, i2c_master_dev_handle_t i2c_handle_port, uint8_t address, uint8_t* data, uint8_t len, int32_t ms_dur) { - return i2c_master_read_from_device(port, address, data, len, ms_dur); + return i2c_master_receive(i2c_handle_port, data, len, ms_dur); } -esp_err_t i2c_write_read(i2c_port_t port, uint8_t address, +esp_err_t i2c_write_read(i2c_master_bus_handle_t *bus_handle, i2c_master_dev_handle_t i2c_handle_port, uint8_t address, uint8_t const* write_data, uint8_t write_len, uint8_t* read_data, uint8_t read_len, int32_t ms_dur) { - return i2c_master_write_read_device(port, address, write_data, write_len, + return i2c_master_transmit_receive(i2c_handle_port, write_data, write_len, read_data, read_len, ms_dur); } diff --git a/main/sensors/sht45.c b/main/sensors/sht45.c index 6cc9fe2..81eb773 100644 --- a/main/sensors/sht45.c +++ b/main/sensors/sht45.c @@ -39,30 +39,59 @@ // Constants # define LP_I2C_TRANS_TIMEOUT_CYCLES 5000 # define LP_I2C_TRANS_WAIT_FOREVER -1 +# define I2C_BUS_SPEED 400000 // 400 KHz // I2C Buffers static uint8_t data_wr[2]; static uint8_t data_rd[6]; +# if ULP_COMP == 0 +static i2c_master_bus_handle_t bus_handle; +static i2c_master_dev_handle_t dev_handle_sht45; +# endif #if ULP_COMP == 1 # define SHT45_I2C_NUM_0 LP_I2C_NUM_0 -#else +# define I2C_BUS_HANDLE_S 0 +# define I2C_HANDLE_PORT_S SHT45_I2C_NUM_0 +#elif ULP_COMP == 0 # define SHT45_I2C_NUM_0 I2C_NUM_0 +# define I2C_BUS_HANDLE_S &bus_handle +# define I2C_HANDLE_PORT_S dev_handle_sht45 #endif bool initialized = false; // Helper function to send an 8-bit command -static void send_command_8bit(uint8_t cmd, uint8_t slave_addr) { +static esp_err_t send_command_8bit(uint8_t cmd, uint8_t slave_addr) { data_wr[0] = cmd; - i2c_write(SHT45_I2C_NUM_0, slave_addr, data_wr, 1, LP_I2C_TRANS_WAIT_FOREVER); + + esp_err_t err = i2c_write(I2C_HANDLE_PORT_S, slave_addr, data_wr, 1, LP_I2C_TRANS_WAIT_FOREVER); + + if (err != ESP_OK) { + // Bail and try again + return err; + } + + return ESP_OK; } bool Init() { - // 1. INSTALL I2C DRIVER - if (i2c_init(SHT45_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN) != ESP_OK) { + // 2. Install I2C driver + if (i2c_init(I2C_BUS_HANDLE_S, SHT45_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN, I2C_BUS_SPEED) != ESP_OK) { + return false; + } +#if ULP_COMP == 0 + // Configuration of a specific device on the bus + i2c_device_config_t dev_cfg_sht45 = {}; + dev_cfg_sht45.dev_addr_length = I2C_ADDR_BIT_LEN_7; + dev_cfg_sht45.device_address = SHT45_SLAVE_ADDR; // Address SHT45 + dev_cfg_sht45.scl_speed_hz = I2C_BUS_SPEED; + + if(i2c_master_bus_add_device(bus_handle, &dev_cfg_sht45, &dev_handle_sht45) != ESP_OK){ return false; } +#endif + return true; } @@ -77,14 +106,17 @@ void ReadSensors(int16_t* temperature, uint32_t* humidity, uint32_t* pressure, } // Send measurement command - send_command_8bit(SHT4X_CMD_MEASURE_HIGH_PRECISION, SHT45_SLAVE_ADDR); + ret = send_command_8bit(SHT4X_CMD_MEASURE_HIGH_PRECISION, SHT45_SLAVE_ADDR); + + if (ret != ESP_OK) { + return; + } // Measurement time for high precision wait_for(1100000); // 1.1 S // Read 6 bytes: temperature and humidity with CRC - ret = i2c_read(SHT45_I2C_NUM_0, SHT45_SLAVE_ADDR, data_rd, 6, - LP_I2C_TRANS_TIMEOUT_CYCLES); + ret = i2c_read(I2C_HANDLE_PORT_S, SHT45_SLAVE_ADDR, data_rd, 6, LP_I2C_TRANS_TIMEOUT_CYCLES); if (ret == ESP_OK) { uint16_t raw_temp = (data_rd[0] << 8) | data_rd[1]; diff --git a/main/sensors/shtc3.c b/main/sensors/shtc3.c index 4818513..1db2027 100644 --- a/main/sensors/shtc3.c +++ b/main/sensors/shtc3.c @@ -36,42 +36,63 @@ // Constants # define LP_I2C_TRANS_TIMEOUT_CYCLES 5000 # define LP_I2C_TRANS_WAIT_FOREVER -1 +# define I2C_BUS_SPEED 400000 // 400 KHz // I2C Buffers static uint8_t data_wr[2]; static uint8_t data_rd[6]; +static bool initialized = false; +# if ULP_COMP == 0 +static i2c_master_bus_handle_t bus_handle; +static i2c_master_dev_handle_t dev_handle_shtc3; +# endif -#ifdef IS_ULP_COCPU +#if ULP_COMP == 1 # define SHTC3_I2C_NUM_0 LP_I2C_NUM_0 -#else +# define I2C_BUS_HANDLE_S 0 +# define I2C_HANDLE_PORT_S HTC3_I2C_NUM_0 +#elif ULP_COMP == 0 # define SHTC3_I2C_NUM_0 I2C_NUM_0 +# define I2C_BUS_HANDLE_S &bus_handle +# define I2C_HANDLE_PORT_S dev_handle_shtc3 #endif -bool initialized = false; // Helper function to send a 16-bit command -static void send_command_16bit(uint16_t cmd, uint8_t slave_addr) { +static esp_err_t send_command_16bit(uint16_t cmd, uint8_t slave_addr) { data_wr[0] = (cmd >> 8) & 0xFF; // High byte data_wr[1] = cmd & 0xFF; // Low byte - esp_err_t ret = i2c_write(SHTC3_I2C_NUM_0, slave_addr, data_wr, + + esp_err_t err = i2c_write(I2C_HANDLE_PORT_S, slave_addr, data_wr, sizeof(data_wr), LP_I2C_TRANS_WAIT_FOREVER); - if (ret != ESP_OK) { + + if (err != ESP_OK) { // Bail and try again - return; + return err; } -} -// Helper function to send an 8-bit command -static void send_command_8bit(uint8_t cmd, uint8_t slave_addr) { - data_wr[0] = cmd; - i2c_write(SHTC3_I2C_NUM_0, slave_addr, data_wr, 1, LP_I2C_TRANS_WAIT_FOREVER); + return ESP_OK; } bool Init() { - // 1. INSTALL I2C DRIVER - if (i2c_init(SHTC3_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN) != ESP_OK) { + + // 2. Install I2C driver + if (i2c_init(I2C_BUS_HANDLE_S, SHTC3_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN, I2C_BUS_SPEED) != ESP_OK) { return false; } + +#if ULP_COMP == 0 + // Configuration of a specific device on the bus + i2c_device_config_t dev_cfg_shtc3 = {}; + dev_cfg_shtc3.dev_addr_length = I2C_ADDR_BIT_LEN_7; + dev_cfg_shtc3.device_address = SHTC3_SLAVE_ADDR; // Address SHTC3 + dev_cfg_shtc3.scl_speed_hz = I2C_BUS_SPEED; + + if(i2c_master_bus_add_device(bus_handle, &dev_cfg_shtc3, &dev_handle_shtc3) != ESP_OK){ + return false; + } +#endif + return true; } @@ -97,8 +118,9 @@ void ReadSensors(int16_t* temperature, uint32_t* humidity, uint32_t* pressure, // Read 6 bytes: [TempMSB, TempLSB, TempCRC, HumMSB, HumLSB, HumCRC] // In this example, we ignore CRC for simplicity. - ret = i2c_write_read(SHTC3_I2C_NUM_0, SHTC3_SLAVE_ADDR, data_rd, - sizeof(data_rd), LP_I2C_TRANS_TIMEOUT_CYCLES); + ret = i2c_read(I2C_HANDLE_PORT_S, SHTC3_SLAVE_ADDR, data_rd, sizeof(data_rd), + LP_I2C_TRANS_TIMEOUT_CYCLES); + if (ret == ESP_OK) { // 5. Raw values uint16_t raw_temp = (data_rd[0] << 8) | data_rd[1]; diff --git a/main/sensors/stcc4.c b/main/sensors/stcc4.c index d88ae2f..e96d23c 100644 --- a/main/sensors/stcc4.c +++ b/main/sensors/stcc4.c @@ -16,95 +16,204 @@ #include "user_config.h" -#if BOARD_HAS_STTC4 == 1 +#if BOARD_HAS_STCC4 == 1 #if ((ULP_COMP == 1) && (BOARD_HAS_ULP == 1)) || ((ULP_COMP == 0) && (BOARD_HAS_ULP == 0)) #pragma message("STTC4 is enabled") # include # include +# if ULP_COMP == 1 +# include "ulp_lp_core_gpio.h" +# elif ULP_COMP == 0 +# include "driver/gpio.h" +# endif + # include "sensors/sensors.h" # include "sensors/utils.h" // Constants for STCC4 -# define STCC4_SLAVE_ADDR 0x65 // Typical address for Sensirion sensors +# define STCC4_SLAVE_ADDR 0x64 // Typical address for Sensirion sensors +# define CRC8_POLYNOMIAL 0x31 // Commands (16-bit, transmitted MSB first) -# define STCC4_CMD_MEASURE_SINGLE_SHOT \ - 0x2C1F // Command for single shot measurement -# define STCC4_CMD_MEASURE_CONTINUOUS \ - 0x21B1 // Command for continuous measurement -# define STCC4_CMD_READ_DATA 0xE000 // Command to read data -# define STCC4_CMD_SLEEP 0xB009 // Command to enter sleep +# define STCC4_CMD_START_CONTINUOUS 0x218B // Command for continuous measurement +# define STCC4_CMD_STOP_CONTINUOUS 0x3F86 // Stop for continuous measurement +# define STCC4_CMD_MEASURE_SINGLE_SHOT 0x219D // Command for single shot measurement +# define STCC4_CMD_READ_DATA 0xEC05 // Command to read data +# define STCC4_CMD_SLEEP 0x3650 // Command to enter sleep // Constants # define LP_I2C_TRANS_TIMEOUT_CYCLES 5000 # define LP_I2C_TRANS_WAIT_FOREVER -1 +# define I2C_BUS_SPEED 100000 // 100 KHz // I2C Buffers static uint8_t data_wr[2]; -static uint8_t data_rd[6]; +static uint8_t data_rd[12]; +static bool initialized = false; +# if ULP_COMP == 0 +static i2c_master_bus_handle_t bus_handle; +static i2c_master_dev_handle_t dev_handle_stcc4; +# endif + -#ifdef IS_ULP_COCPU +#if ULP_COMP == 1 # define STCC4_I2C_NUM_0 LP_I2C_NUM_0 -#else +# define I2C_BUS_HANDLE_S 0 +# define I2C_HANDLE_PORT_S STCC4_I2C_NUM_0 +#elif ULP_COMP == 0 # define STCC4_I2C_NUM_0 I2C_NUM_0 +# define I2C_BUS_HANDLE_S &bus_handle +# define I2C_HANDLE_PORT_S dev_handle_stcc4 #endif -bool initialized = false; +bool check_crc(const uint8_t *data, uint8_t crc); // Helper function to send a 16-bit command -static void send_command_16bit(uint16_t cmd, uint8_t slave_addr) { +static esp_err_t send_command_16bit(uint16_t cmd, uint8_t slave_addr) { data_wr[0] = (cmd >> 8) & 0xFF; // High byte data_wr[1] = cmd & 0xFF; // Low byte - esp_err_t ret = i2c_write(STCC4_I2C_NUM_0, slave_addr, data_wr, + + esp_err_t err = i2c_write(I2C_HANDLE_PORT_S, slave_addr, data_wr, sizeof(data_wr), LP_I2C_TRANS_WAIT_FOREVER); - if (ret != ESP_OK) { + + if (err != ESP_OK) { // Bail and try again - return; + return err; } -} -// Helper function to send an 8-bit command -static void send_command_8bit(uint8_t cmd, uint8_t slave_addr) { - data_wr[0] = cmd; - i2c_write(STCC4_I2C_NUM_0, slave_addr, data_wr, 1, LP_I2C_TRANS_WAIT_FOREVER); + return ESP_OK; } bool Init() { - // 1. INSTALL I2C DRIVER - if (i2c_init(STCC4_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN) != ESP_OK) { + // 1. power ON +#if BOARD_HAS_PWR_ON == 1 +# if ULP_COMP == 1 + ulp_lp_core_gpio_init(LP_PWR_ON_GPIO); + ulp_lp_core_gpio_output_enable(LP_PWR_ON_GPIO); + ulp_lp_core_gpio_set_level(LP_PWR_ON_GPIO, 1); +# elif ULP_COMP == 0 + gpio_set_direction((gpio_num_t)PWR_ON_GPIO, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)PWR_ON_GPIO, 1); +# endif +#endif + + // 2. Install I2C driver + if (i2c_init(I2C_BUS_HANDLE_S, STCC4_I2C_NUM_0, SENSOR_SDA_PIN, SENSOR_SCL_PIN, I2C_BUS_SPEED) != ESP_OK) { return false; } -return true; + +#if ULP_COMP == 0 + // Configuration of a specific device on the bus + i2c_device_config_t dev_cfg_stcc4 = {}; + dev_cfg_stcc4.dev_addr_length = I2C_ADDR_BIT_LEN_7; + dev_cfg_stcc4.device_address = STCC4_SLAVE_ADDR; + dev_cfg_stcc4.scl_speed_hz = I2C_BUS_SPEED; + + if(i2c_master_bus_add_device(bus_handle, &dev_cfg_stcc4, &dev_handle_stcc4) != ESP_OK){ + return false; + } +#endif + + wait_for(125000); // 125 ms + + esp_err_t err = send_command_16bit(STCC4_CMD_SLEEP, STCC4_SLAVE_ADDR); + if (err != ESP_OK) { + return false; + } + + return true; } void ReadSensors(int16_t* temperature, uint32_t* humidity, uint32_t* pressure, uint32_t* co2, uint32_t* gas_resistance) { esp_err_t ret; + uint16_t tmp; if (!initialized) { initialized = Init(); } - send_command_16bit(STCC4_CMD_MEASURE_SINGLE_SHOT, STCC4_SLAVE_ADDR); + ret = send_command_16bit(STCC4_CMD_MEASURE_SINGLE_SHOT, STCC4_SLAVE_ADDR); + if (ret != ESP_OK) { + return; + } // Wait for measurement completion (according to STCC4 datasheet ~500-720ms) - wait_for(500000); // 500 ms + wait_for(750000); // 750 ms // Read 3 bytes: CO2 with CRC - ret = i2c_read(STCC4_I2C_NUM_0, STCC4_SLAVE_ADDR, data_rd, 3, - LP_I2C_TRANS_TIMEOUT_CYCLES); + ret = i2c_read(I2C_HANDLE_PORT_S, STCC4_SLAVE_ADDR, data_rd, sizeof(data_rd), + LP_I2C_TRANS_WAIT_FOREVER); if (ret != ESP_OK) { return; } + + // Read CO2 + // Checking CRC + if (!check_crc(data_rd, data_rd[2])) { + return; + } // Convert to CO2 value (format depends on sensor, typically 16 bits) uint16_t co2_ppm = (data_rd[0] << 8) | data_rd[1]; if (co2) { *co2 = (uint32_t)co2_ppm; } + + // Read Temperature + // Checking CRC +#if ULP_COMP == 0 + if (!check_crc(&data_rd[3], data_rd[5])) { + return; + } +#endif + + // Temperature: T = -45 + 175 * raw_temp / 65535 + tmp = (data_rd[3] << 8) | data_rd[4]; + int32_t temp_x100 = (17500ULL * tmp) / 65535 - 4500; + if (temperature) { + *temperature = (uint32_t)temp_x100; + } + + // Read Humidity + // Checking CRC +#if ULP_COMP == 0 + if (!check_crc(&data_rd[6], data_rd[8])) { + return; + } +#endif + + // Humidity: RH = 100 * raw_hum / 65535 + tmp = (data_rd[6] << 8) | data_rd[7]; + int32_t hum_x100 = (10000ULL * tmp) / 65535; + + // Humidity limitation within 0..100% + if (hum_x100 > 10000) hum_x100 = 10000; + if (hum_x100 < 0) hum_x100 = 0; + + if (humidity) { + *humidity = (uint32_t)hum_x100; + } +} + +bool check_crc(const uint8_t *data, uint8_t crc) { + // CRC-8 algorithm for Sensirion (polynomial 0x31, initial value 0xFF) + uint8_t crc_calc = 0xFF; + for (int i = 0; i < 2; i++) { + crc_calc ^= data[i]; + for (int bit = 0; bit < 8; bit++) { + if (crc_calc & 0x80) { + crc_calc = (crc_calc << 1) ^ CRC8_POLYNOMIAL; + } else { + crc_calc <<= 1; + } + } + } + return (crc_calc == crc); } + #endif #endif diff --git a/main/sensors/ulp_saved_val.c b/main/sensors/ulp_saved_val.c index 0368190..c42af12 100644 --- a/main/sensors/ulp_saved_val.c +++ b/main/sensors/ulp_saved_val.c @@ -26,6 +26,10 @@ void ReadSensors(int16_t* temperature, uint32_t* humidity, uint32_t* pressure, uint32_t* co2, uint32_t* gas_resistance) { printf(" >>> ULP Temperature: [%d]\n", (int16_t)ulp_temperature); + printf(" >>> ULP Humidity: [%d]\n", (int16_t)ulp_humidity); + printf(" >>> ULP Pressure: [%d]\n", (int16_t)ulp_pressure); + printf(" >>> ULP Co2: [%d]\n", (int16_t)ulp_co2); + printf(" >>> ULP Gas_resistance: [%d]\n", (int16_t)ulp_gas_resistance); if (temperature) { *temperature = (int16_t)ulp_temperature; diff --git a/main/sensors/ulp_utils.c b/main/sensors/ulp_utils.c index b49786d..7b237c1 100644 --- a/main/sensors/ulp_utils.c +++ b/main/sensors/ulp_utils.c @@ -16,7 +16,7 @@ #include "user_config.h" -#if ULP_COMP == 1 +#if defined ESP_PLATFORM && ULP_COMP == 1 # include "utils.h" @@ -24,23 +24,23 @@ # include "ulp_lp_core_i2c.h" # include "ulp_lp_core_utils.h" -esp_err_t i2c_init(i2c_port_t port, int sda_pin, int scl_pin) { return ESP_OK; } +esp_err_t i2c_init(int /*bus_handle*/, i2c_port_t i2c_handle_port, int sda_pin, int scl_pin, int i2c_speed) { return ESP_OK; } -esp_err_t i2c_write(i2c_port_t port, uint8_t address, uint8_t const* data, +esp_err_t i2c_write(i2c_port_t i2c_handle_port, uint8_t address, uint8_t const* data, uint8_t len, int32_t ms_dur) { - return lp_core_i2c_master_write_to_device(port, address, data, len, ms_dur); + return lp_core_i2c_master_write_to_device(i2c_handle_port, address, data, len, ms_dur); } -esp_err_t i2c_read(i2c_port_t port, uint8_t address, uint8_t* data, uint8_t len, +esp_err_t i2c_read(i2c_port_t i2c_handle_port, uint8_t address, uint8_t* data, uint8_t len, int32_t ms_dur) { - return lp_core_i2c_master_read_from_device(port, address, data, len, ms_dur); + return lp_core_i2c_master_read_from_device(i2c_handle_port, address, data, len, ms_dur); } -esp_err_t i2c_write_read(i2c_port_t port, uint8_t address, +esp_err_t i2c_write_read(i2c_port_t i2c_handle_port, uint8_t address, uint8_t const* write_data, uint8_t write_len, uint8_t* read_data, uint8_t read_len, int32_t ms_dur) { return lp_core_i2c_master_write_read_device( - port, address, write_data, write_len, read_data, read_len, ms_dur); + i2c_handle_port, address, write_data, write_len, read_data, read_len, ms_dur); } void wait_for(int32_t us_dur) { ulp_lp_core_delay_us(us_dur); } diff --git a/main/sensors/utils.h b/main/sensors/utils.h index 4757403..9aa03f2 100644 --- a/main/sensors/utils.h +++ b/main/sensors/utils.h @@ -16,23 +16,34 @@ #if defined ESP_PLATFORM +#include "user_config.h" + # include -# include # include +# if ULP_COMP == 1 +# include +# define I2C_BUS_HANDLE int +# define I2C_HANDLE_PORT i2c_port_t +# elif ULP_COMP == 0 +# include +# define I2C_BUS_HANDLE i2c_master_bus_handle_t* +# define I2C_HANDLE_PORT i2c_master_dev_handle_t +# endif # ifdef __cplusplus extern "C" { # endif -esp_err_t i2c_init(i2c_port_t port, int sda_pin, int scl_pin); +esp_err_t i2c_init(I2C_BUS_HANDLE bus_handle, I2C_HANDLE_PORT i2c_handle_port, int sda_pin, int scl_pin, int i2c_speed); -esp_err_t i2c_write(i2c_port_t port, uint8_t address, uint8_t const* data, +esp_err_t i2c_write(I2C_HANDLE_PORT i2c_handle_port, uint8_t address, uint8_t const* data, uint8_t len, int32_t ms_dur); -esp_err_t i2c_read(i2c_port_t port, uint8_t address, uint8_t* data, uint8_t len, +esp_err_t i2c_read(I2C_HANDLE_PORT i2c_handle_port, uint8_t address, uint8_t* data, uint8_t len, int32_t ms_dur); -esp_err_t i2c_write_read(i2c_port_t port, uint8_t address, +esp_err_t i2c_write_read(I2C_HANDLE_PORT i2c_handle_port, uint8_t address, uint8_t const* write_data, uint8_t write_len, uint8_t* read_data, uint8_t read_len, int32_t ms_dur); + void wait_for(int32_t us_dur); # ifdef __cplusplus diff --git a/main/sleeping/ulp_sleep.cpp b/main/sleeping/ulp_sleep.cpp index 303178d..5e1c08b 100644 --- a/main/sleeping/ulp_sleep.cpp +++ b/main/sleeping/ulp_sleep.cpp @@ -33,6 +33,8 @@ # include # include "ulp_main.h" +# define I2C_BUS_SPEED 100000 // 100 KHz + extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); @@ -73,12 +75,12 @@ static void lp_i2c_init(void) { lp_core_i2c_cfg_t i2c_cfg{}; lp_core_i2c_timing_cfg_t i2c_timing_cfg{}; - i2c_timing_cfg.clk_speed_hz = 100000; + i2c_timing_cfg.clk_speed_hz = I2C_BUS_SPEED; i2c_cfg.i2c_pin_cfg.sda_io_num = LP_I2C_SDA_IO; i2c_cfg.i2c_pin_cfg.scl_io_num = LP_I2C_SCL_IO; - i2c_cfg.i2c_pin_cfg.sda_pullup_en = true; - i2c_cfg.i2c_pin_cfg.scl_pullup_en = true; + i2c_cfg.i2c_pin_cfg.sda_pullup_en = false; + i2c_cfg.i2c_pin_cfg.scl_pullup_en = false; i2c_cfg.i2c_timing_cfg = i2c_timing_cfg; i2c_cfg.i2c_src_clk = LP_I2C_SCLK_LP_FAST; diff --git a/main/user_config.h b/main/user_config.h index 8579c3e..1fc810a 100644 --- a/main/user_config.h +++ b/main/user_config.h @@ -54,7 +54,7 @@ # define BOARD_M5STACK_ATOM_LITE 4 # ifndef BOARD -# define BOARD BOARD_NANO_ESP32_C6 +# define BOARD BOARD_AETHER_ESP32_C6 # endif # if BOARD == BOARD_AETHER_ESP32_C6 @@ -76,10 +76,16 @@ #if BOARD_HAS_ULP == 1 # define ULP_SLEEP 1 +# define THREAD_SLEEP 0 +# define ESP_MAIN_SLEEP 0 #elif defined ESP_PLATFORM +# define ULP_SLEEP 0 +# define THREAD_SLEEP 0 # define ESP_MAIN_SLEEP 1 #else +# define ULP_SLEEP 0 # define THREAD_SLEEP 1 +# define ESP_MAIN_SLEEP 0 #endif #if defined IS_ULP_COCPU diff --git a/ulp/CMakeLists.txt b/ulp/CMakeLists.txt index 1e63d3e..94ce3c8 100644 --- a/ulp/CMakeLists.txt +++ b/ulp/CMakeLists.txt @@ -58,3 +58,26 @@ CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#main") target_include_directories(${ULP_APP_NAME} PUBLIC "${aether-client-cpp_SOURCE_DIR}") target_compile_definitions(${ULP_APP_NAME} PRIVATE "ULP_MODE=1") + +# Calculate where the build folder of the main project is located +# ExternalProject is usually built inside build/ulp_main-prefix/src/ulp_main-build +# We need to go up to the root of the build folder +set(MAIN_BUILD_DIR "${CMAKE_BINARY_DIR}/../../..") +set(ULP_BOARD_FILE "${MAIN_BUILD_DIR}/ulp_board_config.cmake") + +# If the configuration file exists, connect it +if(EXISTS "${ULP_BOARD_FILE}") + include("${ULP_BOARD_FILE}") +endif() + +# Checking if the BOARD variable value appears after including +if(NOT "${BOARD}" STREQUAL "") + message(STATUS "--------------------------------------------------") + message(STATUS "ULP Project SUCCESS! Board loaded from file: ${BOARD}") + message(STATUS "--------------------------------------------------") + + # Checking if the BOARD variable has been included + add_compile_definitions(BOARD=${BOARD}) +else() + message(WARNING "ULP Project: BOARD is not defined!") +endif()