From 657ee06eed7718a443570e12f70fbefd325a43ca Mon Sep 17 00:00:00 2001 From: "A.M. Rowsell" Date: Sat, 27 Jun 2026 21:28:41 -0400 Subject: [PATCH] files: split sensors out into their own source files --- aht.c | 2 +- bmp.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++------ bmp.h | 23 ++++++----- ens.c | 2 +- main.c | 45 ++++++++++++++++---- 5 files changed, 167 insertions(+), 32 deletions(-) diff --git a/aht.c b/aht.c index 8286054..41e1c2c 100644 --- a/aht.c +++ b/aht.c @@ -1,7 +1,7 @@ #include "aht.h" #include "hardware/i2c.h" -#include "pico/stdlib.h" +#include "pico/stdlib.h" // IWYU pragma: keep static const uint8_t AHT_MEASURE[3] = {0xAC, 0x33, 0x00}; diff --git a/bmp.c b/bmp.c index fe41d2f..cb89fc6 100644 --- a/bmp.c +++ b/bmp.c @@ -1,18 +1,121 @@ -#include "bmp.h" +// Copyright 2026 A.M. Rowsell +// SPDX-License-Identifier: MIT +#include "./bmp.h" -uint8_t BMP_RESET[2] = {0x7E, 0xB6}; -uint8_t BMP_CAL_DATA[21]; -uint8_t BMP_SETUP[6] = {0x1C, 0x0B, 0x1D, 0x08, 0x1F, 0x0A}; -uint8_t BMP_START[2] = {0x1B, 0x33}; +static const uint8_t BMP_RESET[2] = {0x7E, 0xB6}; +static const uint8_t BMP_CAL_DATA[21]; +static const uint8_t BMP_SETUP[6] = {0x1C, 0x0B, 0x1D, 0x08, 0x1F, 0x0A}; +static const uint8_t BMP_START[2] = {0x1B, 0x33}; -double bmp_cal_data_fp[15]; +float bmp_cal_data_fp[15]; -int getBMPCalData(bmp_cal_data_t *cal) { - // TODO: Implement calibration data retrieval - return 0; +int getBMPData(i2c_inst_t *i2c, float *temperature, float *pressure) { + uint8_t rawMeasurements[7]; + uint32_t rawTemp; + uint32_t rawPress; + i2c_write_blocking(i2c, BMP_ADDR, &BMP_STATUS, 1, true); + i2c_read_blocking(i2c, BMP_ADDR, rawMeasurements, 7, + false); // read status & 6 data bytes + if ((rawMeasurements[0] & 0x60) != 0x60) { + // no measurements ready + return 1; + } + rawPress = (rawMeasurements[3] << 16) | (rawMeasurements[2] << 8) | + rawMeasurements[1]; + rawTemp = (rawMeasurements[6] << 16) | (rawMeasurements[5] << 8) | + rawMeasurements[4]; + // now for the crazy math + + float partial_data1; + float partial_data2; + float t_lin; + + partial_data1 = (float)(rawTemp - bmp_cal_data_fp[PAR_T1]); + partial_data2 = (float)(partial_data1 * bmp_cal_data_fp[PAR_T2]); + t_lin = + partial_data2 + (partial_data1 * partial_data1) * bmp_cal_data_fp[PAR_T3]; + // t_lin is compensated temperature + + float comp_press; + float partial_data3; + float partial_data4; + float partial_out1; + float partial_out2; + + partial_data1 = bmp_cal_data_fp[PAR_P6] * t_lin; + partial_data2 = bmp_cal_data_fp[PAR_P7] * (t_lin * t_lin); + partial_data3 = bmp_cal_data_fp[PAR_P8] * (t_lin * t_lin * t_lin); + partial_out1 = + bmp_cal_data_fp[PAR_P5] + partial_data1 + partial_data2 + partial_data3; + + partial_data1 = bmp_cal_data_fp[PAR_P2] * t_lin; + partial_data2 = bmp_cal_data_fp[PAR_P3] * (t_lin * t_lin); + partial_data3 = bmp_cal_data_fp[PAR_P4] * (t_lin * t_lin * t_lin); + partial_out2 = (float)rawPress * (bmp_cal_data_fp[PAR_P1] + partial_data1 + + partial_data2 + partial_data3); + + partial_data1 = (float)rawPress * (float)rawPress; + partial_data2 = bmp_cal_data_fp[PAR_P9] + bmp_cal_data_fp[PAR_P10] * t_lin; + partial_data3 = partial_data1 * partial_data2; + partial_data4 = + partial_data3 + ((float)rawPress * (float)rawPress * (float)rawPress) * + bmp_cal_data_fp[PAR_P11]; + comp_press = partial_out1 + partial_out2 + partial_data4; + + *temperature = t_lin; + *pressure = comp_press; + return 0; } -int initBMP(void) { - // TODO: Implement BMP initialization - return 0; +int getBMPCalData(i2c_inst_t *i2c, bmp_cal_data_t *calData) { + uint8_t rawValues[21]; + i2c_write_blocking(i2c, BMP_ADDR, &BMP_CAL_ADDR, 1, true); + i2c_read_blocking(i2c, BMP_ADDR, rawValues, BMP_CAL_LEN, false); + + calData->NVM_PAR_T1 = (uint16_t)((rawValues[1] << 8) | rawValues[0]); + calData->NVM_PAR_T2 = (uint16_t)((rawValues[3] << 8) | rawValues[2]); + calData->NVM_PAR_T3 = (int8_t)(rawValues[4]); + calData->NVM_PAR_P1 = (int16_t)((rawValues[6] << 8) | rawValues[5]); + calData->NVM_PAR_P2 = (int16_t)((rawValues[8] << 8) | rawValues[7]); + calData->NVM_PAR_P3 = (int8_t)(rawValues[9]); + calData->NVM_PAR_P4 = (int8_t)(rawValues[10]); + calData->NVM_PAR_P5 = (uint16_t)((rawValues[12] << 8) | rawValues[11]); + calData->NVM_PAR_P6 = (uint16_t)((rawValues[14] << 8) | rawValues[13]); + calData->NVM_PAR_P7 = (int8_t)(rawValues[15]); + calData->NVM_PAR_P8 = (int8_t)(rawValues[16]); + calData->NVM_PAR_P9 = (int16_t)((rawValues[18] << 8) | rawValues[17]); + calData->NVM_PAR_P10 = (int8_t)(rawValues[19]); + calData->NVM_PAR_P11 = (int8_t)(rawValues[20]); + + // convert cal values to floating point, adjusted values + bmp_cal_data_fp[PAR_T1] = (float)calData->NVM_PAR_T1 / pow(2, -8); + bmp_cal_data_fp[PAR_T2] = (float)calData->NVM_PAR_T2 / pow(2, 30); + bmp_cal_data_fp[PAR_T3] = (float)calData->NVM_PAR_T3 / pow(2, 48); + bmp_cal_data_fp[PAR_P1] = + ((float)calData->NVM_PAR_P1 - pow(2, 14)) / pow(2, 20); + bmp_cal_data_fp[PAR_P2] = + ((float)calData->NVM_PAR_P2 - pow(2, 14)) / pow(2, 29); + bmp_cal_data_fp[PAR_P3] = (float)calData->NVM_PAR_P3 / pow(2, 32); + bmp_cal_data_fp[PAR_P4] = (float)calData->NVM_PAR_P4 / pow(2, 37); + bmp_cal_data_fp[PAR_P5] = (float)calData->NVM_PAR_P5 / pow(2, -3); + bmp_cal_data_fp[PAR_P6] = (float)calData->NVM_PAR_P6 / pow(2, 6); + bmp_cal_data_fp[PAR_P7] = (float)calData->NVM_PAR_P7 / pow(2, 8); + bmp_cal_data_fp[PAR_P8] = (float)calData->NVM_PAR_P8 / pow(2, 15); + bmp_cal_data_fp[PAR_P9] = (float)calData->NVM_PAR_P9 / pow(2, 48); + bmp_cal_data_fp[PAR_P10] = (float)calData->NVM_PAR_P10 / pow(2, 48); + bmp_cal_data_fp[PAR_P11] = (float)calData->NVM_PAR_P11 / pow(2, 65); + + return 0; +} + +int initBMP(i2c_inst_t *i2c) { + bmp_cal_data_t bmpRawCalValues, *bmpRawCalValues_t = &bmpRawCalValues; + i2c_write_blocking(i2c, BMP_ADDR, BMP_RESET, 2, false); // send reset + sleep_ms(2); // wait for reset to complete + getBMPCalData(i2c, bmpRawCalValues_t); + i2c_write_blocking(i2c, BMP_ADDR, BMP_SETUP, 6, + false); // set up sampling parameters + i2c_write_blocking(i2c, BMP_ADDR, BMP_START, 2, + false); // start automatic measurements + return 0; } diff --git a/bmp.h b/bmp.h index 7fc45e4..87faa92 100644 --- a/bmp.h +++ b/bmp.h @@ -1,17 +1,19 @@ #ifndef BMP_H #define BMP_H +#include "hardware/i2c.h" +#include #include #define BMP_ADDR 0x77 -#define BMP_STATUS 0x03 -#define BMP_DATA 0x04 -#define BMP_CAL_ADDR 0x31 +static const uint8_t BMP_STATUS = 0x03; +static const uint8_t BMP_DATA = 0x04; +static const uint8_t BMP_CAL_ADDR = 0x31; #define BMP_CAL_LEN 21 -extern uint8_t BMP_RESET[2]; -extern uint8_t BMP_CAL_DATA[21]; -extern uint8_t BMP_SETUP[6]; -extern uint8_t BMP_START[2]; +static const uint8_t BMP_RESET[2]; +static const uint8_t BMP_CAL_DATA[21]; +static const uint8_t BMP_SETUP[6]; +static const uint8_t BMP_START[2]; // instead of a bunch of defines enum { @@ -49,9 +51,10 @@ typedef struct { } bmp_cal_data_t; // floating point conversions -extern double bmp_cal_data_fp[15]; +extern float bmp_cal_data_fp[15]; -int getBMPCalData(bmp_cal_data_t *cal); -int initBMP(void); +int getBMPData(i2c_inst_t *i2c, float *temperature, float *pressure); +int getBMPCalData(i2c_inst_t *i2c, bmp_cal_data_t *cal); +int initBMP(i2c_inst_t *i2c); #endif // BMP_H diff --git a/ens.c b/ens.c index 0a6f460..0b97db8 100644 --- a/ens.c +++ b/ens.c @@ -1,7 +1,7 @@ #include "ens.h" #include "hardware/i2c.h" -#include "pico/stdlib.h" +#include "pico/stdlib.h" // IWYU pragma: keep static const uint8_t ENS_ACTIVATE[2] = {0x10, 0x02}; static const uint8_t ENS_IDLE[2] = {0x10, 0x01}; diff --git a/main.c b/main.c index 10c0f1f..e9c4cf6 100644 --- a/main.c +++ b/main.c @@ -18,8 +18,9 @@ * the readings to Adafruit IO over MQTT using the Pico W. ******************************************************************************/ -#include "aht.h" -#include "ens.h" +#include "./aht.h" +#include "./bmp.h" +#include "./ens.h" #include "./mqtt.h" #include "hardware/gpio.h" #include "hardware/i2c.h" @@ -32,8 +33,9 @@ #include #include -#define AVERAGES 4 - +#define AVERAGES 8 +#define I2C1_SCL_PIN 19 +#define I2C1_SDA_PIN 18 // MQTT and WiFi defines #define ADAFRUIT_IO_HOST "io.adafruit.com" #define ADAFRUIT_IO_USERNAME "ADAFRUIT_IO_USERNAME" @@ -58,6 +60,14 @@ static void mqtt_connection_cb(mqtt_client_t *client, void *arg, printf("MQTT status: %d\n", status); } +static float average_float(const float *samples, uint8_t count) { + float sum = 0.0; + for (uint8_t i = 0; i < count; i++) { + sum += samples[i]; + } + return sum / count; +} + static double average_double(const double *samples, uint8_t count) { double sum = 0.0; for (uint8_t i = 0; i < count; i++) { @@ -74,14 +84,17 @@ static uint16_t average_uint16(const uint16_t *samples, uint8_t count) { return (uint16_t)((sum + (uint32_t)count / 2) / (uint32_t)count); } - int main() { uint16_t tvoc, eco2, etoh, avg_tvoc, avg_eco2, avg_etoh; uint8_t aqi, validData; - double t, h, avg_t, avg_h; + double t, h, avg_t, avg_h, avg_bmp_t, avg_bmp_p; uint16_t tvoc_avg[AVERAGES], eco2_avg[AVERAGES], etoh_avg[AVERAGES]; double t_avg[AVERAGES], h_avg[AVERAGES]; + float bmpt_avg[AVERAGES]; + float bmpp_avg[AVERAGES]; char payload[32]; + float bmpT; + float bmpP; // MQTT setup ensaht_mqtt_t mqtt; struct mqtt_connect_client_info_t mqtt_client_info = { @@ -134,6 +147,15 @@ int main() { bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C)); + + i2c_init(i2c1, + 100 * 1000); // start i2c1 at 100kHz -- this is the stemma chain + gpio_set_function(I2C1_SDA_PIN, GPIO_FUNC_I2C); + gpio_set_function(I2C1_SCL_PIN, GPIO_FUNC_I2C); + gpio_pull_up(I2C1_SDA_PIN); + gpio_pull_up(I2C1_SCL_PIN); + bi_decl(bi_2pins_with_func(I2C1_SDA_PIN, I2C1_SCL_PIN, GPIO_FUNC_I2C)); + initBMP(i2c1); printf("\x1b[2J"); // clear screen uint8_t i = 0; uint8_t sample_count = 0; @@ -141,15 +163,22 @@ int main() { while (1) { // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); getAHTData(&t, &h); + getBMPData(i2c1, &bmpT, &bmpP); t_avg[i] = t; h_avg[i] = h; + bmpt_avg[i] = bmpT; + bmpp_avg[i] = bmpP; if (sample_count < AVERAGES) { sample_count++; } avg_t = average_double(t_avg, sample_count); avg_h = average_double(h_avg, sample_count); - printf("\x1b[H\x1b[JTemperature %0.2f Humidity %0.2f\n", avg_t, avg_h); - validData = getENSData(&avg_t, &avg_h, &aqi, &tvoc, &eco2, &etoh); + avg_bmp_t = average_float(bmpt_avg, sample_count); + avg_bmp_p = average_float(bmpp_avg, sample_count); + printf("\x1b[H\x1b[JTemperature %0.2f C Humidity %0.2f%%\n", avg_t, avg_h); + printf("BMP Temperature %0.2f C Pressure %0.2f kPa\n", avg_bmp_t, + avg_bmp_p / 100.0); + validData = getENSData(&avg_bmp_t, &avg_h, &aqi, &tvoc, &eco2, &etoh); tvoc_avg[i] = tvoc; eco2_avg[i] = eco2; etoh_avg[i] = etoh;