From 674806b5356862fe9bde107d027f5ed5eab0b8b5 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sun, 24 Jul 2022 13:11:52 +0100 Subject: [PATCH 01/14] feature: add module for BME280 sensor. --- Lib/Inc/BME280.h | 17 +++++++++++++++++ Lib/Src/BME280.c | 12 ++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 Lib/Inc/BME280.h create mode 100644 Lib/Src/BME280.c diff --git a/Lib/Inc/BME280.h b/Lib/Inc/BME280.h new file mode 100644 index 00000000..1bde7816 --- /dev/null +++ b/Lib/Inc/BME280.h @@ -0,0 +1,17 @@ +/** + *@file BME280.h + *@brief This file contains the API functions for accessing BME280 sensor. + * + */ + +/* + * BME280.h + * + * Created on: 24 Jul 2022 + * Author: salavat.magazov + */ + +#ifndef INC_BME280_H_ +#define INC_BME280_H_ + +#endif /* INC_BME280_H_ */ diff --git a/Lib/Src/BME280.c b/Lib/Src/BME280.c new file mode 100644 index 00000000..c95eb52a --- /dev/null +++ b/Lib/Src/BME280.c @@ -0,0 +1,12 @@ +/** + *@file BME280.c + *@brief This file contains the BME280 sensor driver code. + * + */ + +/* + * BME280.c + * + * Created on: 24 Jul 2022 + * Author: salavat.magazov + */ From 1e3a824369aa880299b1e4ee3f0784205625f13e Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sun, 24 Jul 2022 13:30:08 +0100 Subject: [PATCH 02/14] feature: transfer Sam's code unmodified to a new module. --- Lib/Inc/BME280.h | 12 +++ Lib/Src/BME280.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) diff --git a/Lib/Inc/BME280.h b/Lib/Inc/BME280.h index 1bde7816..6fe8f3b0 100644 --- a/Lib/Inc/BME280.h +++ b/Lib/Inc/BME280.h @@ -14,4 +14,16 @@ #ifndef INC_BME280_H_ #define INC_BME280_H_ +#ifdef __cplusplus +extern "C" +{ +#endif + + // Function prototypes and all definitions that should be visible from + // outside the module go here. + +#ifdef __cplusplus +} +#endif + #endif /* INC_BME280_H_ */ diff --git a/Lib/Src/BME280.c b/Lib/Src/BME280.c index c95eb52a..8c9f526b 100644 --- a/Lib/Src/BME280.c +++ b/Lib/Src/BME280.c @@ -10,3 +10,224 @@ * Created on: 24 Jul 2022 * Author: salavat.magazov */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "gpio.h" +#include "spi.h" + + const uint8_t ctrl_meas = 0b01110100; + const uint8_t ctrl_hum = 0b01110010; + const uint8_t config = 0b01110101; + const uint8_t status = 0b11110011; + const uint8_t hum_msb = 0b11111101; + const uint8_t temp_msb = 0b11111010; + const uint8_t dig_H1_addr = 0b10100001; + const uint8_t dig_H2_addr = 0b11100001; + const uint8_t dig_H3_addr = 0b11100011; + const uint8_t dig_H4_addr = 0b11100100; + const uint8_t dig_H5_addr = 0b11100101; + const uint8_t dig_H6_addr = 0b11100111; + const uint8_t dig_T1_addr = 0b10001000; + const uint8_t dig_T2_addr = 0b10001010; + const uint8_t dig_T3_addr = 0b10001100; + + HAL_StatusTypeDef ret; + uint8_t hum_val[3]; // humidity raw value + uint8_t temp_val[3]; // temperature raw value + typedef int32_t BME280_S32_t; + typedef uint32_t BME280_U32_t; + + BME280_S32_t t_fine, adc_T, adc_H; + uint8_t spi_buff[5]; // SPI buffer not for measurements + uint8_t hum_osrs = 0b00000001; // enable humidity with x1 oversampling + uint8_t meas_val = 0b00100001; // set forced mode and turn off press + uint8_t filter_off = 0b00000000; // turn off filter + BME280_U32_t humidity; // final humidity value + uint8_t digT1[2]; + int8_t digT2[2], digT3[2], digH2[2]; + + unsigned short dig_T1; + short dig_T2, dig_T3, dig_H2, dig_H4, dig_H5, dig_H4_ls[2], dig_H5_ls[2]; + unsigned char dig_H1, dig_H3, digH6; + char dig_H6; + memset(spi_buff, 0, sizeof(spi_buff)); + // select mode 0 + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); + + // write settings + HAL_SPI_Transmit(&hspi2, (uint8_t *)&ctrl_hum, 1, 100); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&hum_osrs, 1, 100); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&ctrl_meas, 1, 100); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&meas_val, 1, 100); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&config, 1, 100); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&filter_off, 1, 100); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); + + spi_buff[0] = 1; + + // check status + while (spi_buff[0] & 0b00001000) + { // bit masking need bit 3 + + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&status, 1, 100); + HAL_SPI_Receive(&hspi2, (uint8_t *)spi_buff, 1, 100); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); + } + + // read hum data + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&hum_msb, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)hum_val, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)hum_val, 2, 100); + } + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); + adc_H = (hum_val[1] >> 8) | (hum_val[0]); + + // read temp data + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&temp_msb, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)temp_val, 1, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)temp_val, 1, 100); + } + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); + + // correct temp data + adc_T = (temp_val[2] >> 24) | (temp_val[1] >> 21) | temp_val[0]; + + // read data + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T1_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT1, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT1, 2, 100); + } + + dig_T1 = (digT1[1] << 8) | digT1[0]; + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T2_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT2, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT2, 2, 100); + } + + dig_T2 = (int)(digT2[1] << 8) | (int)digT2[0]; + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T3_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT3, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT3, 2, 100); + } + + dig_T3 = (int)((digT3[1] << 8) | digT3[0]); + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H1_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H1, 1, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H1, 1, 100); + } + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H2_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digH2, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digH2, 2, 100); + } + + dig_H2 = (int)((digH2[1] << 8) | digH2[0]); + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H3_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H3, 1, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H3, 1, 100); + } + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H4_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H4_ls, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H4_ls, 2, 100); + } + + dig_H4_ls[1] = dig_H4_ls[1] & 0b0000000000001111; + dig_H4 = (int)(dig_H4_ls[0] | dig_H4_ls[1]); + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H5_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H5_ls, 2, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H5_ls, 2, 100); + } + + dig_H5_ls[0] = (dig_H5_ls[0] & 0b1111000000000000) >> 12; + dig_H5_ls[1] = dig_H5_ls[1] << 8; + dig_H5 = (int)(dig_H5_ls[1] | dig_H5_ls[0]); + + HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H6_addr, 1, 100); + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&digH6, 1, 100); + while (ret != HAL_OK) + { + ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&digH6, 1, 100); + } + + dig_H6 = (char)digH6; + + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); + + // perform calculations + BME280_S32_t var1, var2; + var1 = ((((adc_T >> 3) - ((BME280_S32_t)dig_T1 << 1))) * + ((BME280_S32_t)dig_T2)) >> + 11; + + var2 = (((((adc_T >> 4) - ((BME280_S32_t)dig_T1)) * + ((adc_T >> 4) - ((BME280_S32_t)dig_T1))) >> + 12) * + ((BME280_S32_t)dig_T3)) >> + 14; + t_fine = var1 + var2; + + BME280_S32_t v_x1_u32r; + v_x1_u32r = (t_fine - ((BME280_S32_t)76800)); + v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - + (((BME280_S32_t)dig_H5) * v_x1_u32r)) + + ((BME280_S32_t)16384)) >> + 15) * + (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * + (((v_x1_u32r * ((BME280_S32_t)dig_H3)) >> 11) + + ((BME280_S32_t)32768))) >> + 10) + + ((BME280_S32_t)2097152)) * + ((BME280_S32_t)dig_H2) + + 8192) >> + 14)); + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((BME280_S32_t)dig_H1)) >> + 4)); + v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); + v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); + + humidity = (BME280_U32_t)(v_x1_u32r >> 12); + +#ifdef __cplusplus +} +#endif From 852b544cf8f14073be3bd022e41db6f81dc6bedd Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Mon, 25 Jul 2022 08:50:44 +0100 Subject: [PATCH 03/14] feature: add sensor initialisation method --- Lib/Inc/BME280.h | 29 ------ Lib/Inc/CBME280.h | 84 ++++++++++++++++ Lib/Src/BME280.c | 233 -------------------------------------------- Lib/Src/CBME280.cpp | 148 ++++++++++++++++++++++++++++ 4 files changed, 232 insertions(+), 262 deletions(-) delete mode 100644 Lib/Inc/BME280.h create mode 100644 Lib/Inc/CBME280.h delete mode 100644 Lib/Src/BME280.c create mode 100644 Lib/Src/CBME280.cpp diff --git a/Lib/Inc/BME280.h b/Lib/Inc/BME280.h deleted file mode 100644 index 6fe8f3b0..00000000 --- a/Lib/Inc/BME280.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - *@file BME280.h - *@brief This file contains the API functions for accessing BME280 sensor. - * - */ - -/* - * BME280.h - * - * Created on: 24 Jul 2022 - * Author: salavat.magazov - */ - -#ifndef INC_BME280_H_ -#define INC_BME280_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - - // Function prototypes and all definitions that should be visible from - // outside the module go here. - -#ifdef __cplusplus -} -#endif - -#endif /* INC_BME280_H_ */ diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h new file mode 100644 index 00000000..438905ee --- /dev/null +++ b/Lib/Inc/CBME280.h @@ -0,0 +1,84 @@ +/** + *@file CBME280.h + * + */ + +/* + * CBME280.h + * + * Created on: 24 Jul 2022 + * Author: salavat.magazov + */ + +#ifndef CBME280_H_ +#define CBME280_H_ + +#include "CGpioWrapper.h" +#include "gpio.h" +#include "spi.h" + +#define T_CALIBRATION_SIZE 3 +#define P_CALIBRATION_SIZE 9 +#define H_CALIBRATION_SIZE 6 + +class CBME280 +{ + enum REGISTER_MAP + { + /* Calibration registers. */ + DIG_T1 = 0x88, + DIG_T2 = 0x8A, + DIG_T3 = 0x8C, + DIG_P1 = 0x8E, + DIG_P2 = 0x90, + DIG_P3 = 0x92, + DIG_P4 = 0x94, + DIG_P5 = 0x96, + DIG_P6 = 0x98, + DIG_P7 = 0x9A, + DIG_P8 = 0x9C, + DIG_P9 = 0x9E, + DIG_H1 = 0xA1, + DIG_H2 = 0xE1, + DIG_H3 = 0xE3, + DIG_H4 = 0xE4, + DIG_H5 = 0xE5, + /* Sensor data registers. */ + ID = 0xD0, + RESET = 0xE0, + CTRL_HUM = 0xF2, + STATUS = 0xF3, + CTRL_MEAS = 0xF4, + CONFIG = 0xF5, + PRESS_MSB = 0xF7, + PRESS_LSB = 0xF8, + PRESS_XLSB = 0xF9, + TEMP_MSB = 0xFA, + TEMP_LSB = 0xFB, + TEMP_XLSB = 0xFC, + HUM_MSB = 0xFD, + HUM_LSB = 0xFE + }; + +public: + CBME280(SPI_HandleTypeDef *p_spi, + GPIO_TypeDef *p_slave_select_port, + uint16_t slave_select_pin); + virtual ~CBME280(); + + bool init(); + +private: + void calibrateSensor(uint8_t const *const p_calibration_data); + + SPI_HandleTypeDef *mp_spi; + CGpioWrapper m_slave_select; + + bool mb_initialised; + + uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; + uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; + uint16_t m_humidity_calibration[H_CALIBRATION_SIZE]; +}; + +#endif /* CBME280_H_ */ diff --git a/Lib/Src/BME280.c b/Lib/Src/BME280.c deleted file mode 100644 index 8c9f526b..00000000 --- a/Lib/Src/BME280.c +++ /dev/null @@ -1,233 +0,0 @@ -/** - *@file BME280.c - *@brief This file contains the BME280 sensor driver code. - * - */ - -/* - * BME280.c - * - * Created on: 24 Jul 2022 - * Author: salavat.magazov - */ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include -#include "gpio.h" -#include "spi.h" - - const uint8_t ctrl_meas = 0b01110100; - const uint8_t ctrl_hum = 0b01110010; - const uint8_t config = 0b01110101; - const uint8_t status = 0b11110011; - const uint8_t hum_msb = 0b11111101; - const uint8_t temp_msb = 0b11111010; - const uint8_t dig_H1_addr = 0b10100001; - const uint8_t dig_H2_addr = 0b11100001; - const uint8_t dig_H3_addr = 0b11100011; - const uint8_t dig_H4_addr = 0b11100100; - const uint8_t dig_H5_addr = 0b11100101; - const uint8_t dig_H6_addr = 0b11100111; - const uint8_t dig_T1_addr = 0b10001000; - const uint8_t dig_T2_addr = 0b10001010; - const uint8_t dig_T3_addr = 0b10001100; - - HAL_StatusTypeDef ret; - uint8_t hum_val[3]; // humidity raw value - uint8_t temp_val[3]; // temperature raw value - typedef int32_t BME280_S32_t; - typedef uint32_t BME280_U32_t; - - BME280_S32_t t_fine, adc_T, adc_H; - uint8_t spi_buff[5]; // SPI buffer not for measurements - uint8_t hum_osrs = 0b00000001; // enable humidity with x1 oversampling - uint8_t meas_val = 0b00100001; // set forced mode and turn off press - uint8_t filter_off = 0b00000000; // turn off filter - BME280_U32_t humidity; // final humidity value - uint8_t digT1[2]; - int8_t digT2[2], digT3[2], digH2[2]; - - unsigned short dig_T1; - short dig_T2, dig_T3, dig_H2, dig_H4, dig_H5, dig_H4_ls[2], dig_H5_ls[2]; - unsigned char dig_H1, dig_H3, digH6; - char dig_H6; - memset(spi_buff, 0, sizeof(spi_buff)); - // select mode 0 - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); - - // write settings - HAL_SPI_Transmit(&hspi2, (uint8_t *)&ctrl_hum, 1, 100); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&hum_osrs, 1, 100); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&ctrl_meas, 1, 100); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&meas_val, 1, 100); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&config, 1, 100); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&filter_off, 1, 100); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); - - spi_buff[0] = 1; - - // check status - while (spi_buff[0] & 0b00001000) - { // bit masking need bit 3 - - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&status, 1, 100); - HAL_SPI_Receive(&hspi2, (uint8_t *)spi_buff, 1, 100); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); - } - - // read hum data - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&hum_msb, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)hum_val, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)hum_val, 2, 100); - } - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); - adc_H = (hum_val[1] >> 8) | (hum_val[0]); - - // read temp data - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&temp_msb, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)temp_val, 1, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)temp_val, 1, 100); - } - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); - - // correct temp data - adc_T = (temp_val[2] >> 24) | (temp_val[1] >> 21) | temp_val[0]; - - // read data - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T1_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT1, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT1, 2, 100); - } - - dig_T1 = (digT1[1] << 8) | digT1[0]; - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T2_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT2, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT2, 2, 100); - } - - dig_T2 = (int)(digT2[1] << 8) | (int)digT2[0]; - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_T3_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT3, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digT3, 2, 100); - } - - dig_T3 = (int)((digT3[1] << 8) | digT3[0]); - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H1_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H1, 1, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H1, 1, 100); - } - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H2_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digH2, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)digH2, 2, 100); - } - - dig_H2 = (int)((digH2[1] << 8) | digH2[0]); - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H3_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H3, 1, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&dig_H3, 1, 100); - } - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H4_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H4_ls, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H4_ls, 2, 100); - } - - dig_H4_ls[1] = dig_H4_ls[1] & 0b0000000000001111; - dig_H4 = (int)(dig_H4_ls[0] | dig_H4_ls[1]); - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H5_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H5_ls, 2, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (uint8_t *)dig_H5_ls, 2, 100); - } - - dig_H5_ls[0] = (dig_H5_ls[0] & 0b1111000000000000) >> 12; - dig_H5_ls[1] = dig_H5_ls[1] << 8; - dig_H5 = (int)(dig_H5_ls[1] | dig_H5_ls[0]); - - HAL_SPI_Transmit(&hspi2, (uint8_t *)&dig_H6_addr, 1, 100); - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&digH6, 1, 100); - while (ret != HAL_OK) - { - ret = HAL_SPI_Receive(&hspi2, (unsigned char *)&digH6, 1, 100); - } - - dig_H6 = (char)digH6; - - HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); - - // perform calculations - BME280_S32_t var1, var2; - var1 = ((((adc_T >> 3) - ((BME280_S32_t)dig_T1 << 1))) * - ((BME280_S32_t)dig_T2)) >> - 11; - - var2 = (((((adc_T >> 4) - ((BME280_S32_t)dig_T1)) * - ((adc_T >> 4) - ((BME280_S32_t)dig_T1))) >> - 12) * - ((BME280_S32_t)dig_T3)) >> - 14; - t_fine = var1 + var2; - - BME280_S32_t v_x1_u32r; - v_x1_u32r = (t_fine - ((BME280_S32_t)76800)); - v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - - (((BME280_S32_t)dig_H5) * v_x1_u32r)) + - ((BME280_S32_t)16384)) >> - 15) * - (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * - (((v_x1_u32r * ((BME280_S32_t)dig_H3)) >> 11) + - ((BME280_S32_t)32768))) >> - 10) + - ((BME280_S32_t)2097152)) * - ((BME280_S32_t)dig_H2) + - 8192) >> - 14)); - v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((BME280_S32_t)dig_H1)) >> - 4)); - v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); - v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); - - humidity = (BME280_U32_t)(v_x1_u32r >> 12); - -#ifdef __cplusplus -} -#endif diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp new file mode 100644 index 00000000..bf7e6a9f --- /dev/null +++ b/Lib/Src/CBME280.cpp @@ -0,0 +1,148 @@ +/** + *@file CBME280.cpp + * + */ + +/* + * BME280.cpp + * + * Created on: 24 Jul 2022 + * Author: salavat.magazov + */ + +#include + +#define BME280_ID 0x60 +#define BMP280_ID 0x58 +#define SOFT_RESET 0xB6 +#define SPI_WRITE_MASK 0x80 +#define ID_PACKET_SIZE 2 +#define CALIB1_PACKET_SIZE 24 +#define CALIB2_PACKET_SIZE 1 +#define CALIB3_PACKET_SIZE 8 +#define SPI_TIMEOUT_MS 100 +#define SENSOR_RESET_DELAY_MS 9 + +#define CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) + +#define HIGH true +#define LOW false + +CBME280::CBME280(SPI_HandleTypeDef *p_spi, + GPIO_TypeDef *p_slave_select_port, + uint16_t slave_select_pin) + : mp_spi(p_spi), + m_slave_select(p_slave_select_port, slave_select_pin), + mb_initialised(false) +{ + if (mp_spi == nullptr) + { + Error_Handler(); + } + m_slave_select.set(true); +} + +CBME280::~CBME280() +{ + // TODO Auto-generated destructor stub +} + +bool CBME280::init() +{ + /* TODO: + * 1. Check SPI works. + * 2. Read chip ID to verify comms to sensor works. + * 3. Read calibration values and store in appropriate places. + */ + /* This communication via SPI is going to be done without interrupts.*/ + // TODO: how do we ensure SPI is available? Perhaps need a wrapper around + // SPI with a mutex. + if (HAL_SPI_GetState(mp_spi) != HAL_SPI_STATE_READY) + { + Error_Handler(); + } + uint8_t register_address; + /* Soft reset. */ + register_address = RESET; + m_slave_select.set(false); + HAL_SPI_Transmit(mp_spi, ®ister_address, 1, SPI_TIMEOUT_MS); + m_slave_select.set(true); + HAL_Delay(SENSOR_RESET_DELAY_MS); + /* Read sensor ID to see if it is responding to comms. */ + register_address = ID; + uint8_t id_register[ID_PACKET_SIZE]; + m_slave_select.set(LOW); + HAL_SPI_TransmitReceive(mp_spi, + ®ister_address, + id_register, + ID_PACKET_SIZE, + SPI_TIMEOUT_MS); + m_slave_select.set(HIGH); + if ((id_register[1] != BME280_ID) && (id_register[1] != BMP280_ID)) + { + return false; + } + /* Read sensor calibration data. */ + register_address = DIG_T1; + uint8_t calibration_register[CALIB1_PACKET_SIZE + + CALIB2_PACKET_SIZE * CALIB3_PACKET_SIZE]; + m_slave_select.set(LOW); + HAL_SPI_TransmitReceive(mp_spi, + ®ister_address, + calibration_register, + CALIB1_PACKET_SIZE, + SPI_TIMEOUT_MS); + m_slave_select.set(HIGH); + register_address = DIG_H1; + m_slave_select.set(LOW); + HAL_SPI_TransmitReceive(mp_spi, + ®ister_address, + &(calibration_register[CALIB1_PACKET_SIZE - 1]), + CALIB2_PACKET_SIZE, + SPI_TIMEOUT_MS); + m_slave_select.set(HIGH); + register_address = DIG_H2; + m_slave_select.set(LOW); + HAL_SPI_TransmitReceive(mp_spi, + ®ister_address, + &(calibration_register[CALIB1_PACKET_SIZE]), + CALIB2_PACKET_SIZE, + SPI_TIMEOUT_MS); + m_slave_select.set(HIGH); + calibrateSensor(calibration_register); + mb_initialised = true; + return true; +} + +void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) +{ + uint8_t const *p_runner = p_calibration_data; + for (int i = 0; i < T_CALIBRATION_SIZE; i++) + { + m_temperature_calibration[i] = *p_runner; + m_temperature_calibration[i] |= *(++p_runner) << 8; + ++p_runner; + } + for (int i = 0; i < P_CALIBRATION_SIZE; i++) + { + m_pressure_calibration[i] = *p_runner; + m_pressure_calibration[i] |= *(++p_runner) << 8; + ++p_runner; + } + /* Humidity calibration data is spread around and is stored in a weird + * convoluted way. See the manual. This recovery was copied with + * modifications from the Bosch github repository. + * https://github.com/BoschSensortec/BME280_driver */ + /* I am certain the engineer at Bosch who came up with this had management + * breathing down their neck. One day they stopped caring and made this + * monstrocity.*/ + m_humidity_calibration[0] = p_calibration_data[25]; + m_humidity_calibration[1] = + (p_calibration_data[27] << 8) + p_calibration_data[26]; + m_humidity_calibration[2] = p_calibration_data[28]; + m_humidity_calibration[3] = + (p_calibration_data[29] << 4) + (p_calibration_data[30] & 0x0F); + m_humidity_calibration[4] = + (p_calibration_data[31] << 4) + (p_calibration_data[30] >> 4); + m_humidity_calibration[5] = p_calibration_data[32]; +} From 7c55e7f50d4e293237d3fb72da60a2d17b5b2a68 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Mon, 25 Jul 2022 09:16:09 +0100 Subject: [PATCH 04/14] docs: add doxygen headers to methods. feature: add sensor data access methods. --- Lib/Inc/CBME280.h | 39 +++++++++++++++++++++++++++++++++++++++ Lib/Src/CBME280.cpp | 19 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index 438905ee..c4e5fa1e 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -68,8 +68,39 @@ class CBME280 bool init(); + /** + * @brief Access processed temperature data. + * + * @return Temperature in degrees Celsius. + */ + float getTemperature() const + { + return m_temperature; + }; + + /** + * @brief Access processed pressure data. + * + * @return Pressure in Pascals. + */ + float getPressure() const + { + return m_pressure; + }; + + /** + * @brief Access processed humidity data. + * + * @return Humidity in %RH. + */ + float getHumidity() const + { + return m_humidity; + }; + private: void calibrateSensor(uint8_t const *const p_calibration_data); + void convertRawData(uint8_t const *const p_raw_adc_data); SPI_HandleTypeDef *mp_spi; CGpioWrapper m_slave_select; @@ -79,6 +110,14 @@ class CBME280 uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; uint16_t m_humidity_calibration[H_CALIBRATION_SIZE]; + + uint32_t m_raw_temperature_data; + uint32_t m_raw_pressure_data; + uint32_t m_raw_humidity_data; + + float m_temperature; + float m_pressure; + float m_humidity; }; #endif /* CBME280_H_ */ diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index bf7e6a9f..bcecb682 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -28,6 +28,13 @@ #define HIGH true #define LOW false +/** + * @brief Construct a sensor driver class instance. + * + * @param p_spi Pointer to HAL handler for SPI channel. + * @param p_slave_select_port Pointer to GPIO port for SS pin. + * @param slave_select_pin Mask of the SS pin. + */ CBME280::CBME280(SPI_HandleTypeDef *p_spi, GPIO_TypeDef *p_slave_select_port, uint16_t slave_select_pin) @@ -47,6 +54,12 @@ CBME280::~CBME280() // TODO Auto-generated destructor stub } +/** + * @brief Initialise the sensor. This must be successfully completed before + * sensor can be accessed for data. + * + * @return True if initialisation is successful, false otherwise. + */ bool CBME280::init() { /* TODO: @@ -114,6 +127,12 @@ bool CBME280::init() return true; } +/** + * @brief Convert raw data from the sensor registers into usable calibration + * values. + * + * @param p_calibration_data Pointer to raw data stream of 33 8-bit values. + */ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) { uint8_t const *p_runner = p_calibration_data; From 478051074e039dae98e5fb2d6612a0172f2ecaf1 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Mon, 25 Jul 2022 10:22:59 +0100 Subject: [PATCH 05/14] feature: add conversion of raw data stream into raw structured data. --- Lib/Src/CBME280.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index bcecb682..735327d5 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -165,3 +165,28 @@ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) (p_calibration_data[31] << 4) + (p_calibration_data[30] >> 4); m_humidity_calibration[5] = p_calibration_data[32]; } + +/** + * @brief Convert raw data from sensor registers into corresponding unprocessed + * sensor values. + * + * @param p_raw_adc_data Pointer to raw data stream of 8 8-bit values. + */ +void CBME280::convertRawData(uint8_t const *const p_raw_adc_data) +{ + m_raw_pressure_data = p_raw_adc_data[0]; + m_raw_pressure_data = m_raw_pressure_data << 8; + m_raw_pressure_data += p_raw_adc_data[1]; + m_raw_pressure_data = m_raw_pressure_data << 4; + m_raw_pressure_data += p_raw_adc_data[2] >> 4; + + m_raw_temperature_data = p_raw_adc_data[0]; + m_raw_temperature_data = m_raw_temperature_data << 8; + m_raw_temperature_data += p_raw_adc_data[1]; + m_raw_temperature_data = m_raw_temperature_data << 4; + m_raw_temperature_data += p_raw_adc_data[2] >> 4; + + m_raw_humidity_data = p_raw_adc_data[6]; + m_raw_humidity_data = m_raw_humidity_data << 8; + m_raw_humidity_data += p_raw_adc_data[7]; +} From 59dfe1f2e8449c2b89c046ee64f4f069d3631627 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Mon, 25 Jul 2022 11:18:00 +0100 Subject: [PATCH 06/14] feature: add basic state machine to run sensor. --- Lib/Inc/CBME280.h | 15 +++++++-- Lib/Src/CBME280.cpp | 80 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index c4e5fa1e..4ce43578 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -20,6 +20,7 @@ #define T_CALIBRATION_SIZE 3 #define P_CALIBRATION_SIZE 9 #define H_CALIBRATION_SIZE 6 +#define RAW_ADC_DATA_SIZE 8 class CBME280 { @@ -67,6 +68,7 @@ class CBME280 virtual ~CBME280(); bool init(); + bool run(); /** * @brief Access processed temperature data. @@ -100,17 +102,26 @@ class CBME280 private: void calibrateSensor(uint8_t const *const p_calibration_data); - void convertRawData(uint8_t const *const p_raw_adc_data); + void convertRawData(); + bool startMeasument(); + void applyCalibration(); SPI_HandleTypeDef *mp_spi; CGpioWrapper m_slave_select; - bool mb_initialised; + enum STATES + { + INIT_PENDING = 0, + READY, + MEASURING, + NEW_DATA + } m_state; uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; uint16_t m_humidity_calibration[H_CALIBRATION_SIZE]; + uint8_t m_raw_adc_data[RAW_ADC_DATA_SIZE]; uint32_t m_raw_temperature_data; uint32_t m_raw_pressure_data; uint32_t m_raw_humidity_data; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index 735327d5..a4dadb0b 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -40,7 +40,7 @@ CBME280::CBME280(SPI_HandleTypeDef *p_spi, uint16_t slave_select_pin) : mp_spi(p_spi), m_slave_select(p_slave_select_port, slave_select_pin), - mb_initialised(false) + m_state(INIT_PENDING) { if (mp_spi == nullptr) { @@ -63,7 +63,7 @@ CBME280::~CBME280() bool CBME280::init() { /* TODO: - * 1. Check SPI works. + * 1. Check SPI available. * 2. Read chip ID to verify comms to sensor works. * 3. Read calibration values and store in appropriate places. */ @@ -72,7 +72,7 @@ bool CBME280::init() // SPI with a mutex. if (HAL_SPI_GetState(mp_spi) != HAL_SPI_STATE_READY) { - Error_Handler(); + return false; } uint8_t register_address; /* Soft reset. */ @@ -123,10 +123,43 @@ bool CBME280::init() SPI_TIMEOUT_MS); m_slave_select.set(HIGH); calibrateSensor(calibration_register); - mb_initialised = true; return true; } +bool CBME280::run() +{ + bool b_new_data = false; + switch (m_state) + { + case INIT_PENDING: + if (init()) + { + m_state = READY; + } + break; + case READY: + // TODO: perhaps need to have some sort of timeout here to only run + // this at regular intervals. + if (startMeasument()) + { + m_state = MEASURING; + } + break; + case MEASURING: + // N.B. This state is a wait-state to allow class to know when it is + // busy waiting for SPI interrupt to fire. + break; + case NEW_DATA: + convertRawData(); + applyCalibration(); + b_new_data = true; + break; + default: + Error_Handler(); + } + return b_new_data; +} + /** * @brief Convert raw data from the sensor registers into usable calibration * values. @@ -172,21 +205,42 @@ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) * * @param p_raw_adc_data Pointer to raw data stream of 8 8-bit values. */ -void CBME280::convertRawData(uint8_t const *const p_raw_adc_data) +void CBME280::convertRawData() { - m_raw_pressure_data = p_raw_adc_data[0]; + m_raw_pressure_data = m_raw_adc_data[0]; m_raw_pressure_data = m_raw_pressure_data << 8; - m_raw_pressure_data += p_raw_adc_data[1]; + m_raw_pressure_data += m_raw_adc_data[1]; m_raw_pressure_data = m_raw_pressure_data << 4; - m_raw_pressure_data += p_raw_adc_data[2] >> 4; + m_raw_pressure_data += m_raw_adc_data[2] >> 4; - m_raw_temperature_data = p_raw_adc_data[0]; + m_raw_temperature_data = m_raw_adc_data[0]; m_raw_temperature_data = m_raw_temperature_data << 8; - m_raw_temperature_data += p_raw_adc_data[1]; + m_raw_temperature_data += m_raw_adc_data[1]; m_raw_temperature_data = m_raw_temperature_data << 4; - m_raw_temperature_data += p_raw_adc_data[2] >> 4; + m_raw_temperature_data += m_raw_adc_data[2] >> 4; - m_raw_humidity_data = p_raw_adc_data[6]; + m_raw_humidity_data = m_raw_adc_data[6]; m_raw_humidity_data = m_raw_humidity_data << 8; - m_raw_humidity_data += p_raw_adc_data[7]; + m_raw_humidity_data += m_raw_adc_data[7]; } + +/** + * @brief Initiate measurement process. + * + * @return True if measurement started successfully. + */ +bool CBME280::startMeasument() +{ + if (HAL_SPI_GetState(mp_spi) != HAL_SPI_STATE_READY) + { + return false; + } + + return true; +} + +/** + * @brief Apply calibration to raw data. + * + */ +void CBME280::applyCalibration() {} From 65d9806c8793c7cc2e3185ee7a214e9798c88e96 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Mon, 25 Jul 2022 12:07:23 +0100 Subject: [PATCH 07/14] wip --- Lib/Inc/CBME280.h | 10 +++++++++- Lib/Src/CBME280.cpp | 22 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index 4ce43578..954c6505 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -21,6 +21,7 @@ #define P_CALIBRATION_SIZE 9 #define H_CALIBRATION_SIZE 6 #define RAW_ADC_DATA_SIZE 8 +#define MAX_SENSORS 2 class CBME280 { @@ -100,10 +101,15 @@ class CBME280 return m_humidity; }; + bool isMeasuring() const + { + return m_state == MEASURING; + } + private: void calibrateSensor(uint8_t const *const p_calibration_data); void convertRawData(); - bool startMeasument(); + bool startMeasurement(); void applyCalibration(); SPI_HandleTypeDef *mp_spi; @@ -117,6 +123,8 @@ class CBME280 NEW_DATA } m_state; + static CBME280* sp_sensors[] + uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; uint16_t m_humidity_calibration[H_CALIBRATION_SIZE]; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index a4dadb0b..2ac42259 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -140,7 +140,7 @@ bool CBME280::run() case READY: // TODO: perhaps need to have some sort of timeout here to only run // this at regular intervals. - if (startMeasument()) + if (startMeasurement()) { m_state = MEASURING; } @@ -229,12 +229,24 @@ void CBME280::convertRawData() * * @return True if measurement started successfully. */ -bool CBME280::startMeasument() +bool CBME280::startMeasurement() { if (HAL_SPI_GetState(mp_spi) != HAL_SPI_STATE_READY) { return false; } + /* Configure SPI comms as required by the sensor. */ + // TODO: this type of channel sharing with different configurations should + // be handled by a wrapper class. It can also queue up traffic and call + // callback functions. + mp_spi->Init.CLKPolarity = SPI_POLARITY_HIGH; + mp_spi->Init.CLKPhase = SPI_PHASE_2EDGE; + mp_spi->Init.NSS = SPI_NSS_SOFT; + mp_spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; + if (HAL_SPI_Init(&hspi2) != HAL_OK) + { + return false; + } return true; } @@ -244,3 +256,9 @@ bool CBME280::startMeasument() * */ void CBME280::applyCalibration() {} + +#ifdef __cplusplus +extern "C" +{ + void HAL_SPI_RxCpltCallback(hspi) {} +} From 0f2470169661ef68a76d77ae9d6a612da0a16ece Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Thu, 28 Jul 2022 13:38:45 +0100 Subject: [PATCH 08/14] wip. --- Lib/Inc/CBME280.h | 6 ++++-- Lib/Src/CBME280.cpp | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index 954c6505..e76a4bfa 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -21,7 +21,7 @@ #define P_CALIBRATION_SIZE 9 #define H_CALIBRATION_SIZE 6 #define RAW_ADC_DATA_SIZE 8 -#define MAX_SENSORS 2 +#define MAX_SENSORS 2 class CBME280 { @@ -111,6 +111,7 @@ class CBME280 void convertRawData(); bool startMeasurement(); void applyCalibration(); + void receiveNewData(); SPI_HandleTypeDef *mp_spi; CGpioWrapper m_slave_select; @@ -123,7 +124,8 @@ class CBME280 NEW_DATA } m_state; - static CBME280* sp_sensors[] + static CBME280 *sp_sensors[MAX_SENSORS]; + static uint8_t s_sensor_count; uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index 2ac42259..e516c7f8 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -28,6 +28,10 @@ #define HIGH true #define LOW false +/* Static instance control variables. */ +CBME280 *CBME280::sp_sensors[] = {nullptr}; +uint8_t CBME280::s_sensor_count = 0; + /** * @brief Construct a sensor driver class instance. * @@ -47,6 +51,15 @@ CBME280::CBME280(SPI_HandleTypeDef *p_spi, Error_Handler(); } m_slave_select.set(true); + if (s_sensor_count < MAX_SENSORS) + { + sp_sensors[s_sensor_count] = this; + s_sensor_count++; + } + else + { + Error_handler(); + } } CBME280::~CBME280() @@ -260,5 +273,7 @@ void CBME280::applyCalibration() {} #ifdef __cplusplus extern "C" { - void HAL_SPI_RxCpltCallback(hspi) {} + void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {} } + +#endif From 65218ba78f5eb92fb71d9541c339594d98ba9086 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sat, 30 Jul 2022 10:32:43 +0100 Subject: [PATCH 09/14] feature: add ADC data receive functionality. --- Lib/Inc/CBME280.h | 3 ++- Lib/Src/CBME280.cpp | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index e76a4bfa..65f1d871 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -106,12 +106,13 @@ class CBME280 return m_state == MEASURING; } + static void processIrq(); + private: void calibrateSensor(uint8_t const *const p_calibration_data); void convertRawData(); bool startMeasurement(); void applyCalibration(); - void receiveNewData(); SPI_HandleTypeDef *mp_spi; CGpioWrapper m_slave_select; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index e516c7f8..8dc0d3fe 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -58,7 +58,7 @@ CBME280::CBME280(SPI_HandleTypeDef *p_spi, } else { - Error_handler(); + Error_Handler(); } } @@ -260,7 +260,15 @@ bool CBME280::startMeasurement() { return false; } - + m_raw_adc_data[0] = PRESS_MSB; + for (int i = 1; i < RAW_ADC_DATA_SIZE; i++) + { + m_raw_adc_data[i] = 0; + } + HAL_SPI_TransmitReceive_IT(mp_spi, + m_raw_adc_data, + m_raw_adc_data, + RAW_ADC_DATA_SIZE); return true; } @@ -270,10 +278,33 @@ bool CBME280::startMeasurement() */ void CBME280::applyCalibration() {} +/** + * @brief Process IRQ call for all registered and active sensors + * + */ +void CBME280::processIrq() +{ + uint8_t sensor = 0; + while ((sp_sensors[sensor] != nullptr) && sensor < s_sensor_count) + { + if (sp_sensors[sensor]->isMeasuring()) + { + sp_sensors[sensor]->m_state = NEW_DATA; + break; + } + sensor++; + } +} + +CBME280::processIrq(); + #ifdef __cplusplus extern "C" { - void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {} + void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) + { + CBME280::processIRQ(); + } } #endif From 661c56737289a66bb0250c5309496a730f4c833c Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sat, 30 Jul 2022 10:55:24 +0100 Subject: [PATCH 10/14] feature: enable IRQ for SPI2 engine. --- Core/Inc/stm32f4xx_it.h | 1 + Core/Src/spi.c | 5 +++++ Core/Src/stm32f4xx_it.c | 15 +++++++++++++++ Multichannel temperature sensor.ioc | 3 ++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Core/Inc/stm32f4xx_it.h b/Core/Inc/stm32f4xx_it.h index deb0aa40..902a5f97 100644 --- a/Core/Inc/stm32f4xx_it.h +++ b/Core/Inc/stm32f4xx_it.h @@ -55,6 +55,7 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); +void SPI2_IRQHandler(void); void USART1_IRQHandler(void); void USART2_IRQHandler(void); void DMA2_Stream0_IRQHandler(void); diff --git a/Core/Src/spi.c b/Core/Src/spi.c index 51b2da7a..2982ec6c 100644 --- a/Core/Src/spi.c +++ b/Core/Src/spi.c @@ -85,6 +85,9 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + /* SPI2 interrupt Init */ + HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(SPI2_IRQn); /* USER CODE BEGIN SPI2_MspInit 1 */ /* USER CODE END SPI2_MspInit 1 */ @@ -110,6 +113,8 @@ void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_12|GPIO_PIN_14|GPIO_PIN_15); + /* SPI2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(SPI2_IRQn); /* USER CODE BEGIN SPI2_MspDeInit 1 */ /* USER CODE END SPI2_MspDeInit 1 */ diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index 4aae7358..f093fd62 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -56,6 +56,7 @@ /* External variables --------------------------------------------------------*/ extern DMA_HandleTypeDef hdma_adc1; +extern SPI_HandleTypeDef hspi2; extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; /* USER CODE BEGIN EV */ @@ -200,6 +201,20 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ +/** + * @brief This function handles SPI2 global interrupt. + */ +void SPI2_IRQHandler(void) +{ + /* USER CODE BEGIN SPI2_IRQn 0 */ + + /* USER CODE END SPI2_IRQn 0 */ + HAL_SPI_IRQHandler(&hspi2); + /* USER CODE BEGIN SPI2_IRQn 1 */ + + /* USER CODE END SPI2_IRQn 1 */ +} + /** * @brief This function handles USART1 global interrupt. */ diff --git a/Multichannel temperature sensor.ioc b/Multichannel temperature sensor.ioc index 0ac350fe..de1522cb 100644 --- a/Multichannel temperature sensor.ioc +++ b/Multichannel temperature sensor.ioc @@ -147,6 +147,7 @@ NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SPI2_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:true NVIC.USART1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true @@ -354,7 +355,7 @@ ProjectManager.FreePins=false ProjectManager.HalAssertFull=false ProjectManager.HeapSize=0x200 ProjectManager.KeepUserCode=true -ProjectManager.LastFirmware=true +ProjectManager.LastFirmware=false ProjectManager.LibraryCopy=1 ProjectManager.MainLocation=Core/Src ProjectManager.MultiThreaded=true From e2600934970be1bdfded375f32f8a30e8c3e6fdb Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sat, 30 Jul 2022 10:56:20 +0100 Subject: [PATCH 11/14] feature: add IRQ callback via static method. --- Lib/Src/CBME280.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index 8dc0d3fe..b62a9de2 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -279,7 +279,7 @@ bool CBME280::startMeasurement() void CBME280::applyCalibration() {} /** - * @brief Process IRQ call for all registered and active sensors + * @brief Process IRQ call for all registered and active sensors. * */ void CBME280::processIrq() @@ -296,15 +296,7 @@ void CBME280::processIrq() } } -CBME280::processIrq(); - -#ifdef __cplusplus -extern "C" +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { - void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) - { - CBME280::processIRQ(); - } + CBME280::processIrq(); } - -#endif From b1a5ac6319845144805701dbfcad3e31d857f623 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sat, 30 Jul 2022 11:00:16 +0100 Subject: [PATCH 12/14] wip. --- Lib/Src/CBME280.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index b62a9de2..b836b941 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -136,6 +136,9 @@ bool CBME280::init() SPI_TIMEOUT_MS); m_slave_select.set(HIGH); calibrateSensor(calibration_register); + // TODO: sensor requires setting up. + // set operational mode. + // set oversampling modes for all three measurements. return true; } From 4254bc617bf2be226d4510b09c70276f0da31c76 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sun, 7 Aug 2022 11:21:34 +0100 Subject: [PATCH 13/14] feature: modify calibration from integer to float. --- Lib/Inc/CBME280.h | 6 +++--- Lib/Src/CBME280.cpp | 50 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index 65f1d871..3985928a 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -128,9 +128,9 @@ class CBME280 static CBME280 *sp_sensors[MAX_SENSORS]; static uint8_t s_sensor_count; - uint16_t m_temperature_calibration[T_CALIBRATION_SIZE]; - uint16_t m_pressure_calibration[P_CALIBRATION_SIZE]; - uint16_t m_humidity_calibration[H_CALIBRATION_SIZE]; + float m_temperature_calibration[T_CALIBRATION_SIZE]; + float m_pressure_calibration[P_CALIBRATION_SIZE]; + float m_humidity_calibration[H_CALIBRATION_SIZE]; uint8_t m_raw_adc_data[RAW_ADC_DATA_SIZE]; uint32_t m_raw_temperature_data; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index b836b941..89189bae 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -11,6 +11,7 @@ */ #include +#include #define BME280_ID 0x60 #define BMP280_ID 0x58 @@ -28,6 +29,25 @@ #define HIGH true #define LOW false +/* These values were extracted from BME280 calibration source code. The original + * calibration source code was intended for use with integers to allow its use + * on resource constrained MCUs. This code will run on MCU with floating point + * unit, so converting into float calibration increases dynamic range and make + * code much more readable and maintainable. + */ +constexpr float T_CALIB_CORRECTION[] = {1, 1 / 1024, 1 / sqrt(8092)}; +constexpr float P_CALIB_CORRECTION[] = {1 / 6250, + 1 / 524288 / 32768, + 1 / 524288 / 524288 / 32768, + 65536 / 4096, + 1 / 2 / 4096, + 1 / 32768 / 4 / 4096, + 1 / 16, + 1 / 32768 / 16, + 1 / 2147483648 / 16}; +constexpr float H_CALIB_CORRECTION[] = + {-1 / 524288, 1 / 65536, 1 / 67108864, -1 / 64, 1 / 16384, 1 / 67108864}; + /* Static instance control variables. */ CBME280 *CBME280::sp_sensors[] = {nullptr}; uint8_t CBME280::s_sensor_count = 0; @@ -185,16 +205,19 @@ bool CBME280::run() void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) { uint8_t const *p_runner = p_calibration_data; + uint32_t raw_calibration; for (int i = 0; i < T_CALIBRATION_SIZE; i++) { - m_temperature_calibration[i] = *p_runner; - m_temperature_calibration[i] |= *(++p_runner) << 8; + raw_calibration = m_temperature_calibration[i] = *p_runner; + raw_calibration |= *(++p_runner) << 8; + m_temperature_calibration[i] = raw_calibration * T_CALIB_CORRECTION[i]; ++p_runner; } for (int i = 0; i < P_CALIBRATION_SIZE; i++) { - m_pressure_calibration[i] = *p_runner; - m_pressure_calibration[i] |= *(++p_runner) << 8; + raw_calibration = *p_runner; + raw_calibration |= *(++p_runner) << 8; + m_pressure_calibration[i] = raw_calibration * P_CALIB_CORRECTION[i]; ++p_runner; } /* Humidity calibration data is spread around and is stored in a weird @@ -204,15 +227,20 @@ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) /* I am certain the engineer at Bosch who came up with this had management * breathing down their neck. One day they stopped caring and made this * monstrocity.*/ - m_humidity_calibration[0] = p_calibration_data[25]; - m_humidity_calibration[1] = - (p_calibration_data[27] << 8) + p_calibration_data[26]; - m_humidity_calibration[2] = p_calibration_data[28]; - m_humidity_calibration[3] = + raw_calibration = p_calibration_data[25]; + m_humidity_calibration[0] = raw_calibration * H_CALIB_CORRECTION[0]; + raw_calibration = (p_calibration_data[27] << 8) + p_calibration_data[26]; + m_humidity_calibration[1] = raw_calibration * H_CALIB_CORRECTION[1]; + raw_calibration = p_calibration_data[28]; + m_humidity_calibration[2] = raw_calibration * H_CALIB_CORRECTION[2]; + raw_calibration = (p_calibration_data[29] << 4) + (p_calibration_data[30] & 0x0F); - m_humidity_calibration[4] = + m_humidity_calibration[3] = raw_calibration * H_CALIB_CORRECTION[3]; + raw_calibration = (p_calibration_data[31] << 4) + (p_calibration_data[30] >> 4); - m_humidity_calibration[5] = p_calibration_data[32]; + m_humidity_calibration[4] = raw_calibration * H_CALIB_CORRECTION[4]; + raw_calibration = p_calibration_data[32]; + m_humidity_calibration[5] = raw_calibration * H_CALIB_CORRECTION[5]; } /** From d37fde7d74be5a2a563f70c0f3ccb41a42aec4d2 Mon Sep 17 00:00:00 2001 From: Salavat Magazov Date: Sun, 7 Aug 2022 12:16:00 +0100 Subject: [PATCH 14/14] feature: implement raw data calibration for T, P, and H measurements. --- Lib/Inc/CBME280.h | 5 ++- Lib/Src/CBME280.cpp | 87 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/Lib/Inc/CBME280.h b/Lib/Inc/CBME280.h index 3985928a..76186f15 100644 --- a/Lib/Inc/CBME280.h +++ b/Lib/Inc/CBME280.h @@ -112,7 +112,9 @@ class CBME280 void calibrateSensor(uint8_t const *const p_calibration_data); void convertRawData(); bool startMeasurement(); - void applyCalibration(); + void calculateT(); + void calculateP(); + void calculateH(); SPI_HandleTypeDef *mp_spi; CGpioWrapper m_slave_select; @@ -137,6 +139,7 @@ class CBME280 uint32_t m_raw_pressure_data; uint32_t m_raw_humidity_data; + float m_t_fine; float m_temperature; float m_pressure; float m_humidity; diff --git a/Lib/Src/CBME280.cpp b/Lib/Src/CBME280.cpp index 89189bae..7d26ce80 100644 --- a/Lib/Src/CBME280.cpp +++ b/Lib/Src/CBME280.cpp @@ -48,6 +48,11 @@ constexpr float P_CALIB_CORRECTION[] = {1 / 6250, constexpr float H_CALIB_CORRECTION[] = {-1 / 524288, 1 / 65536, 1 / 67108864, -1 / 64, 1 / 16384, 1 / 67108864}; +constexpr float T_SCALE_FACTOR = 1 / 5120; +constexpr float P_OFFSET_1 = 64000; +constexpr float P_OFFSET_2 = 1048576; +constexpr float H_OFFSET = 76800; + /* Static instance control variables. */ CBME280 *CBME280::sp_sensors[] = {nullptr}; uint8_t CBME280::s_sensor_count = 0; @@ -186,8 +191,12 @@ bool CBME280::run() // busy waiting for SPI interrupt to fire. break; case NEW_DATA: - convertRawData(); - applyCalibration(); + /* The sequence of these method calls must be preserved since + * temperature is used in pressure and humidity calculations. + * convertRawData();*/ + calculateT(); + calculateP(); + calculateH(); b_new_data = true; break; default: @@ -220,13 +229,13 @@ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) m_pressure_calibration[i] = raw_calibration * P_CALIB_CORRECTION[i]; ++p_runner; } - /* Humidity calibration data is spread around and is stored in a weird - * convoluted way. See the manual. This recovery was copied with - * modifications from the Bosch github repository. + /* Humidity calibration data is spread around and is stored in a + * weird convoluted way. See the manual. This recovery was + * copied with modifications from the Bosch github repository. * https://github.com/BoschSensortec/BME280_driver */ - /* I am certain the engineer at Bosch who came up with this had management - * breathing down their neck. One day they stopped caring and made this - * monstrocity.*/ + /* I am certain the engineer at Bosch who came up with this had + * management breathing down their neck. One day they stopped + * caring and made this monstrocity.*/ raw_calibration = p_calibration_data[25]; m_humidity_calibration[0] = raw_calibration * H_CALIB_CORRECTION[0]; raw_calibration = (p_calibration_data[27] << 8) + p_calibration_data[26]; @@ -244,10 +253,11 @@ void CBME280::calibrateSensor(uint8_t const *const p_calibration_data) } /** - * @brief Convert raw data from sensor registers into corresponding unprocessed - * sensor values. + * @brief Convert raw data from sensor registers into corresponding + * unprocessed sensor values. * - * @param p_raw_adc_data Pointer to raw data stream of 8 8-bit values. + * @param p_raw_adc_data Pointer to raw data stream of 8 8-bit + * values. */ void CBME280::convertRawData() { @@ -280,9 +290,9 @@ bool CBME280::startMeasurement() return false; } /* Configure SPI comms as required by the sensor. */ - // TODO: this type of channel sharing with different configurations should - // be handled by a wrapper class. It can also queue up traffic and call - // callback functions. + // TODO: this type of channel sharing with different + // configurations should be handled by a wrapper class. It can + // also queue up traffic and call callback functions. mp_spi->Init.CLKPolarity = SPI_POLARITY_HIGH; mp_spi->Init.CLKPhase = SPI_PHASE_2EDGE; mp_spi->Init.NSS = SPI_NSS_SOFT; @@ -304,10 +314,55 @@ bool CBME280::startMeasurement() } /** - * @brief Apply calibration to raw data. + * @brief Apply temperature calibration to raw data. + * + */ +void CBME280::calculateT() +{ + float t; + t = (m_raw_temperature_data / 16 - m_temperature_calibration[0]); + m_t_fine = + t * m_temperature_calibration[1] + t * t * m_temperature_calibration[2]; + m_temperature = m_t_fine / T_SCALE_FACTOR; +} + +/** + * @brief Apply pressure calibration to raw data. * */ -void CBME280::applyCalibration() {} +void CBME280::calculateP() +{ + float t_p = m_t_fine / 2 - P_OFFSET_1; + float var_1 = m_pressure_calibration[3]; + var_1 += t_p * m_pressure_calibration[4]; + var_1 += t_p * t_p * m_pressure_calibration[5]; + float var_2 = 1; + var_2 += t_p * m_pressure_calibration[1]; + var_2 += t_p * t_p * m_pressure_calibration[2]; + var_2 *= m_pressure_calibration[0]; + float var_3 = P_OFFSET_2 - m_raw_pressure_data - var_1; + var_3 /= var_2; + m_pressure = m_pressure_calibration[6]; + m_pressure += var_3 * m_pressure_calibration[7]; + m_pressure += var_3 * var_3 * m_pressure_calibration[8]; +} + +/** + * @brief Apply humidity calibration to raw data. + * + */ +void CBME280::calculateH() +{ + float t_h = m_t_fine - H_OFFSET; + float var_1 = 1 + t_h * m_humidity_calibration[2]; + var_1 *= t_h * m_humidity_calibration[5]; + var_1 += 1; + var_1 *= m_humidity_calibration[1]; + var_1 *= m_raw_humidity_data + m_humidity_calibration[3] + + t_h * m_humidity_calibration[4]; + m_humidity = var_1; + m_humidity += var_1 * var_1 * m_humidity_calibration[0]; +} /** * @brief Process IRQ call for all registered and active sensors.