From b1224528aae4c4d789f90d2f2509323ab7c6ffe0 Mon Sep 17 00:00:00 2001 From: "A.M. Rowsell" Date: Mon, 15 Jun 2026 15:03:54 -0400 Subject: [PATCH] initial commit of project --- .gitignore | 25 ++++++++++++ CMakeLists.txt | 59 ++++++++++++++++++++++++++++ LICENSE | 21 ++++++++++ ensaht.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 ensaht.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e778bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Created by https://www.toptal.com/developers/gitignore/api/cmake +# Edit at https://www.toptal.com/developers/gitignore?templates=cmake + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +pico_sdk_import.cmake +### CMake Patch ### +CMakeUserPresets.json + +# External projects +*-prefix/ + +# build folder +build/ +# End of https://www.toptal.com/developers/gitignore/api/cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b5b34b5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) +set(PICO_SDK_PATH "/home/amr/workspace/rp2040/pico-sdk") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(PICO_BOARD pico_w CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0") + message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") +endif() + +project(ensaht C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(ensaht ensaht.c ) + +pico_set_program_name(ensaht "ensaht") +pico_set_program_version(ensaht "0.1") +pico_enable_stdio_usb(ensaht 1) +pico_enable_stdio_uart(ensaht 0) +# Add the standard library to the build +target_link_libraries(ensaht + hardware_i2c + hardware_gpio + hardware_divider + pico_double + pico_stdlib) +if (PICO_CYW43_SUPPORTED) + target_link_libraries(ensaht pico_cyw43_arch_none) +endif() +# Add the standard include files to the build +target_include_directories(ensaht PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required +) + +pico_add_extra_outputs(ensaht) + +add_custom_target(flash + COMMAND openocd + -f interface/cmsis-dap.cfg + -f target/rp2350.cfg + -c "adapter speed 5000" + -c "program ${CMAKE_CURRENT_BINARY_DIR}/ensaht.elf verify reset exit" + DEPENDS ensaht +) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8265059 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 A.M. Rowsell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ensaht.c b/ensaht.c new file mode 100644 index 0000000..ffbccd7 --- /dev/null +++ b/ensaht.c @@ -0,0 +1,102 @@ +#include "hardware/gpio.h" +#include "hardware/i2c.h" +#include "pico/cyw43_arch.h" +#include "pico/stdlib.h" +#include +#include +#include +#include +#include + +#define AHT_ADDR 0x38 +#define ENS_ADDR 0x53 +uint8_t AHT_MEASURE[3] = {0xAC, 0x33, 0x00}; +uint8_t ENS_ACTIVATE[2] = {0x10, 0x02}; +uint8_t ENS_IDLE[2] = {0x10, 0x01}; +#define ENS_TEMP_IN 0x13 +#define ENS_HUM_IN 0x15 +#define ENS_STATUS 0x20 +#define ENS_STATUS_MASK 0x0C +#define ENS_AQI 0x21 +#define ENS_TVOC 0x22 +#define ENS_ECO2 0x24 +#define ENS_ETOH 0x26 + +void getAHTData(double *t, double *h) { + uint8_t result[6]; + uint32_t temperature, humidity; + i2c_write_blocking(i2c_default, AHT_ADDR, AHT_MEASURE, 3, + false); // trigger measurement + // now we must delay ~100ms + sleep_ms(100); + i2c_read_blocking(i2c_default, AHT_ADDR, result, 6, + false); // read 6 bytes back + humidity = (result[1] << 12) | (result[2] << 4) | (result[3] & 0xF0) >> 4; + temperature = (result[3] & 0x0F) << 16 | (result[4] << 8) | result[5]; + *t = ((double)temperature / 1048576.0f) * 200.0f - 50.0f; + *h = ((double)humidity / 1048576.0f) * 100.0f; + return; +} + +void activateENS(void) { + i2c_write_blocking(i2c_default, ENS_ADDR, ENS_ACTIVATE, 2, false); + return; +} +void deactivateENS(void) { + i2c_write_blocking(i2c_default, ENS_ADDR, ENS_IDLE, 2, false); + return; +} +uint8_t getENSData(double *t, double *h, uint8_t *AQI, uint16_t *TVOC, + uint16_t *ECO2, uint16_t *ETOH) { + uint16_t K = (uint16_t)(*t + 273.15) * 64; // convert to ENS format + uint16_t RH = (uint16_t)*h * 512; + uint8_t inputData[5] = {0x13, (uint8_t)(K & 0x00FF), (uint8_t)(K >> 8), + (uint8_t)(RH & 0x00FF), (uint8_t)(RH >> 8)}; + uint8_t result[7], dataReg = ENS_AQI, valid; + i2c_write_blocking(i2c_default, ENS_ADDR, inputData, 5, false); + activateENS(); + sleep_ms(100); + i2c_write_blocking(i2c_default, ENS_ADDR, &dataReg, 1, true); + i2c_read_blocking(i2c_default, ENS_ADDR, result, 7, false); + *AQI = result[0]; + *TVOC = (result[2] << 8) | result[1]; + *ECO2 = (result[4] << 8) | result[3]; + *ETOH = (result[6] << 8) | result[5]; + dataReg = 0x20; // status register + i2c_write_blocking(i2c_default, ENS_ADDR, &dataReg, 1, true); + i2c_read_blocking(i2c_default, ENS_ADDR, result, 1, false); + printf("Status register is 0x%0X\n", result[0]); + valid = (result[0] & ENS_STATUS_MASK) == 0 + ? 1 + : 0; // check if we are in warm-up or normal mode + // deactivateENS(); + return valid; +} + +int main() { + uint16_t tvoc, eco2, etoh; + uint8_t aqi, validData; + double t, h; + stdio_init_all(); + i2c_init(i2c_default, 100 * 1000); // start i2c at 100khz + gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C); + gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C); + gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN); + gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN); + + bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, + GPIO_FUNC_I2C)); + + while (1) { + getAHTData(&t, &h); + printf("Temperature %f Humidity %f\n", t, h); + validData = getENSData(&t, &h, &aqi, &tvoc, &eco2, &etoh); + if (!validData) { + printf("ENS Data not yet valid\n"); + } + printf("AQI: %d TVOC: %d eCO2: %d EtOH: %d\n", aqi, tvoc, eco2, etoh); + sleep_ms(2000); + } + + return 0; +}