Add BSEC, show IAQ on display

This commit is contained in:
MG-95 2021-10-31 12:08:02 +01:00
commit 1f322a8221
7 changed files with 1289 additions and 105 deletions

View file

@ -8,34 +8,51 @@
#include <cstring>
#include "BME68x-Sensor-API/bme68x.h"
#include "BSEC/bsec_interface.h"
#include "oled-driver/Renderer.hpp"
extern QueueHandle_t spiMutex;
extern void waitForSpiFinished();
extern Renderer renderer;
extern void initDisplay();
constexpr auto MaximumChars = 22 * 4;
char buffer[MaximumChars];
constexpr auto SPI_DEVICE = &hspi2;
uint8_t txBuffer[512];
constexpr auto SpiPeripherie = &hspi2;
uint8_t txBuffer[512 + 1];
constexpr auto temperatureOffset = 7.0f;
struct bme68x_dev bmeSensor;
volatile int8_t res;
struct bme68x_conf bmeConf;
struct bme68x_heatr_conf bmeHeaterConf;
struct bme68x_data bmeData[3];
uint16_t del_period;
uint32_t time_ms = 0;
uint8_t n_fields;
uint16_t sampleCount = 1;
uint32_t delayInUs;
uint8_t numberOfData;
/* Heater temperature in degree Celsius */
uint16_t temp_prof[10] = {200, 240, 280, 320, 360, 360, 320, 280, 240, 200};
constexpr auto ProfileLength = 1;
/* Heating duration in milliseconds */
uint16_t dur_prof[10] = {100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
// Heater temperature in degree Celsius
uint16_t temperatureProfile[ProfileLength] = {320};
// Heating duration in milliseconds
uint16_t durationProfile[ProfileLength] = {150};
constexpr uint8_t numberRequestedVirtualSensors = 4;
bsec_sensor_configuration_t requestedVirtualSensors[numberRequestedVirtualSensors];
float iaq, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus,
temperature, humidity, staticIaq, co2Equivalent, breathVocEquivalent, compGasValue,
gasPercentage;
uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy,
gasPercentageAcccuracy;
// uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE];
// uint8_t workBuffer[BSEC_MAX_WORKBUFFER_SIZE];
void setChipSelect(bool state)
{
@ -49,9 +66,9 @@ BME68X_INTF_RET_TYPE bme68x_spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32
xSemaphoreTake(spiMutex, portMAX_DELAY);
setChipSelect(true);
HAL_SPI_Transmit_DMA(SPI_DEVICE, &reg_addr, 1);
HAL_SPI_Transmit_DMA(SpiPeripherie, &reg_addr, 1);
waitForSpiFinished();
HAL_SPI_Receive_DMA(SPI_DEVICE, reg_data, len);
HAL_SPI_Receive_DMA(SpiPeripherie, reg_data, len);
waitForSpiFinished();
setChipSelect(false);
@ -73,7 +90,7 @@ BME68X_INTF_RET_TYPE bme68x_spi_write(uint8_t reg_addr, const uint8_t *reg_data,
xSemaphoreTake(spiMutex, portMAX_DELAY);
setChipSelect(true);
HAL_SPI_Transmit_DMA(SPI_DEVICE, const_cast<uint8_t *>(txBuffer), len + 1);
HAL_SPI_Transmit_DMA(SpiPeripherie, const_cast<uint8_t *>(txBuffer), len + 1);
waitForSpiFinished();
setChipSelect(false);
@ -85,7 +102,7 @@ BME68X_INTF_RET_TYPE bme68x_spi_write(uint8_t reg_addr, const uint8_t *reg_data,
// Delay function maps
void bme68x_delay_us(uint32_t period, void *)
{
HAL_Delay(period / 1000);
vTaskDelay(period / 1000);
}
int8_t bme68x_spi_init(struct bme68x_dev *bme)
@ -94,13 +111,11 @@ int8_t bme68x_spi_init(struct bme68x_dev *bme)
if (bme != NULL)
{
// printf("SPI Interface\n");
bme->read = bme68x_spi_read;
bme->write = bme68x_spi_write;
bme->intf = BME68X_SPI_INTF;
bme->delay_us = bme68x_delay_us;
bme->intf_ptr = SPI_DEVICE;
bme->amb_temp =
25; /* The ambient temperature in deg C is used for defining the heater temperature */
}
@ -112,90 +127,216 @@ int8_t bme68x_spi_init(struct bme68x_dev *bme)
return rslt;
}
void bme68x_check_rslt(const char *, int8_t)
void bmeSensorInit()
{
bme68x_spi_init(&bmeSensor);
bme68x_init(&bmeSensor);
bme68x_get_conf(&bmeConf, &bmeSensor);
bmeConf.os_hum = BME68X_OS_16X;
bmeConf.os_temp = BME68X_OS_2X;
bmeConf.os_pres = BME68X_OS_1X;
bmeConf.filter = BME68X_FILTER_OFF;
bmeConf.odr = BME68X_ODR_NONE;
bme68x_set_conf(&bmeConf, &bmeSensor);
bmeHeaterConf.enable = BME68X_ENABLE;
bmeHeaterConf.heatr_temp_prof = temperatureProfile;
bmeHeaterConf.heatr_dur_prof = durationProfile;
bmeHeaterConf.profile_len = ProfileLength;
bme68x_set_heatr_conf(BME68X_SEQUENTIAL_MODE, &bmeHeaterConf, &bmeSensor);
bme68x_set_op_mode(BME68X_SEQUENTIAL_MODE, &bmeSensor);
bsec_init();
// Change 3 virtual sensors (switch IAQ and raw temperature -> on / pressure -> off
requestedVirtualSensors[0].sensor_id = BSEC_OUTPUT_IAQ;
requestedVirtualSensors[0].sample_rate = BSEC_SAMPLE_RATE_CONTINUOUS;
requestedVirtualSensors[1].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT;
requestedVirtualSensors[1].sample_rate = BSEC_SAMPLE_RATE_CONTINUOUS;
requestedVirtualSensors[2].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
requestedVirtualSensors[2].sample_rate = BSEC_SAMPLE_RATE_CONTINUOUS;
requestedVirtualSensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
requestedVirtualSensors[3].sample_rate = BSEC_SAMPLE_RATE_CONTINUOUS;
// Allocate a struct for the returned physical sensor settings
bsec_sensor_configuration_t requiredSensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t numberRequiredSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
// Call bsec_update_subscription() to enable/disable the requested virtual sensors
bsec_update_subscription(requestedVirtualSensors, numberRequestedVirtualSensors,
requiredSensorSettings, &numberRequiredSensorSettings);
}
void bmeRun()
{
res = bme68x_spi_init(&bmeSensor);
bme68x_check_rslt("bme68x_interface_init", res);
delayInUs = bme68x_get_meas_dur(BME68X_SEQUENTIAL_MODE, &bmeConf, &bmeSensor) +
(bmeHeaterConf.heatr_dur_prof[0] * 1000);
vTaskDelay(delayInUs / 1000);
res = bme68x_init(&bmeSensor);
bme68x_check_rslt("bme68x_init", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
res = bme68x_get_conf(&bmeConf, &bmeSensor);
bme68x_check_rslt("bme68x_get_conf", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
bmeConf.filter = BME68X_FILTER_OFF;
bmeConf.odr =
BME68X_ODR_NONE; /* This parameter defines the sleep duration after each profile */
bmeConf.os_hum = BME68X_OS_16X;
bmeConf.os_pres = BME68X_OS_1X;
bmeConf.os_temp = BME68X_OS_2X;
res = bme68x_set_conf(&bmeConf, &bmeSensor);
bme68x_check_rslt("bme68x_set_conf", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
bmeHeaterConf.enable = BME68X_ENABLE;
bmeHeaterConf.heatr_temp_prof = temp_prof;
bmeHeaterConf.heatr_dur_prof = dur_prof;
bmeHeaterConf.profile_len = 10;
res = bme68x_set_heatr_conf(BME68X_SEQUENTIAL_MODE, &bmeHeaterConf, &bmeSensor);
bme68x_check_rslt("bme68x_set_heatr_conf", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
res = bme68x_set_op_mode(BME68X_SEQUENTIAL_MODE, &bmeSensor);
bme68x_check_rslt("bme68x_set_op_mode", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
// printf("Sample, TimeStamp(ms), Temperature(deg C), Pressure(Pa), Humidity(%%), Gas "
// "resistance(ohm), Status, Profile index, Measurement index\n");
while (1)
auto status = bme68x_get_data(BME68X_SEQUENTIAL_MODE, bmeData, &numberOfData, &bmeSensor);
if (status != 0)
{
del_period =
bme68x_get_meas_dur(BME68X_SEQUENTIAL_MODE, &bmeConf) + bmeHeaterConf.heatr_dur_prof[0];
vTaskDelay(del_period);
__asm("bkpt");
}
}
// time_ms = HAL_GetTick();
void bsecRun()
{
/*
auto status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, sizeof(workBuffer));
res = bme68x_get_data(BME68X_SEQUENTIAL_MODE, bmeData, &n_fields, &bmeSensor);
bme68x_check_rslt("bme68x_get_data", res);
/* Check if res == BME68X_OK, report or handle if otherwise */
for (uint8_t i = 0; i < n_fields; i++)
if (status == BSEC_OK)
{
for (uint32_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++)
{
renderer.clearAll();
snprintf(buffer, MaximumChars,
"%d°C, %luhPa, %lu%%\n%lukOhm, status: 0x%x\ngas_index: %d\nmeas_index: %d",
bmeData[i].temperature / 100, //
bmeData[i].pressure / 100, //
bmeData[i].humidity / 1000, //
bmeData[i].gas_resistance / 1000, //
bmeData[i].status, //
bmeData[i].gas_index, //
bmeData[i].meas_index);
renderer.print({0, 0}, buffer);
renderer.render();
/*
snprintf(buffer, MaximumChars, "sampleCount: %u\n, time_ms: %u\n \
temperature; %d°C\n \
pressure: %u\n \
humidity: %u\n \
gas_resistance: %u\n \
// status: 0x%x\n \
//gas_index: %d\n \
meas_index: %d\n",
sampleCount, time_ms, (bmeData[i].temperature / 100), bmeData[i].pressure,
(bmeData[i].humidity / 1000), bmeData[i].gas_resistance, bmeData[i].status,
bmeData[i].gas_index, bmeData[i].meas_index);
*/
bsecState[i] = state[i];
}
validBsecState = true;
}
*/
if (!(bmeData[numberOfData - 1].status & BME68X_NEW_DATA_MSK))
{
__asm("bkpt");
return;
}
return;
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t nInputs = 0, nOutputs = 0;
int64_t currentTimeInNs = xTaskGetTickCount() * int64_t(1000) * int64_t(1000);
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
inputs[nInputs].signal = bmeData[numberOfData - 1].temperature / 100.0f;
inputs[nInputs].time_stamp = currentTimeInNs;
nInputs++;
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
inputs[nInputs].signal = bmeData[numberOfData - 1].humidity / 1000.0f;
inputs[nInputs].time_stamp = currentTimeInNs;
nInputs++;
inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
inputs[nInputs].signal = bmeData[numberOfData - 1].pressure;
inputs[nInputs].time_stamp = currentTimeInNs;
nInputs++;
inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
inputs[nInputs].signal = bmeData[numberOfData - 1].gas_resistance;
inputs[nInputs].time_stamp = currentTimeInNs;
nInputs++;
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[nInputs].signal = temperatureOffset;
inputs[nInputs].time_stamp = currentTimeInNs;
nInputs++;
nOutputs = BSEC_NUMBER_OUTPUTS;
bsec_output_t outputs[BSEC_NUMBER_OUTPUTS];
auto status = bsec_do_steps(inputs, nInputs, outputs, &nOutputs);
if (status != BSEC_OK)
{
return;
}
// zeroOutputs();
if (nOutputs > 0)
{
auto outputTimestamp = outputs[0].time_stamp / 1000000; /* Convert from ns to ms */
for (uint8_t i = 0; i < nOutputs; i++)
{
switch (outputs[i].sensor_id)
{
case BSEC_OUTPUT_IAQ:
iaq = outputs[i].signal;
iaqAccuracy = outputs[i].accuracy;
break;
case BSEC_OUTPUT_STATIC_IAQ:
staticIaq = outputs[i].signal;
staticIaqAccuracy = outputs[i].accuracy;
break;
case BSEC_OUTPUT_CO2_EQUIVALENT:
co2Equivalent = outputs[i].signal;
co2Accuracy = outputs[i].accuracy;
break;
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
breathVocEquivalent = outputs[i].signal;
breathVocAccuracy = outputs[i].accuracy;
break;
case BSEC_OUTPUT_RAW_TEMPERATURE:
rawTemperature = outputs[i].signal;
break;
case BSEC_OUTPUT_RAW_PRESSURE:
pressure = outputs[i].signal;
break;
case BSEC_OUTPUT_RAW_HUMIDITY:
rawHumidity = outputs[i].signal;
break;
case BSEC_OUTPUT_RAW_GAS:
gasResistance = outputs[i].signal;
break;
case BSEC_OUTPUT_STABILIZATION_STATUS:
stabStatus = outputs[i].signal;
break;
case BSEC_OUTPUT_RUN_IN_STATUS:
runInStatus = outputs[i].signal;
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
temperature = outputs[i].signal;
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
humidity = outputs[i].signal;
break;
case BSEC_OUTPUT_COMPENSATED_GAS:
compGasValue = outputs[i].signal;
compGasAccuracy = outputs[i].accuracy;
break;
case BSEC_OUTPUT_GAS_PERCENTAGE:
gasPercentage = outputs[i].signal;
gasPercentageAcccuracy = outputs[i].accuracy;
break;
default:
break;
}
}
}
}
void printBmeSensorData()
{
renderer.clearAll();
snprintf(buffer, MaximumChars,
"%d°C, %luhPa, %d%%\nIAQ: %d, Accuracy: %d\nCO2: %dppm\n%d, %d, %d - %lukOhm",
static_cast<int>(temperature), //
bmeData[numberOfData - 1].pressure / 100, //
static_cast<int>(humidity), //
static_cast<int>(iaq), //
iaqAccuracy, //
static_cast<int>(co2Equivalent), //
bmeData[numberOfData - 1].status, //
bmeData[numberOfData - 1].gas_index, //
bmeData[numberOfData - 1].gas_wait, //
bmeData[numberOfData - 1].gas_resistance / 1000);
renderer.print({0, 0}, buffer);
renderer.render();
}
//--------------------------------------------------------------------------------------------------
extern "C" void sensorTask(void *)
{
initDisplay();
bmeSensorInit();
while (1)
{
bmeRun();
bsecRun();
printBmeSensorData();
}
}