You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
9.0 KiB
268 lines
9.0 KiB
//
|
|
// Created by MightyPork on 2017/11/17.
|
|
//
|
|
|
|
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
|
|
#include <esp_log.h>
|
|
#include <esp_err.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/task.h>
|
|
#include <driver/i2c.h>
|
|
#include "voc_sensor.h"
|
|
|
|
struct bme680_dev gas_sensor;
|
|
|
|
static const char *TAG = "vocsensor";
|
|
|
|
#define i2c_num I2C_NUM_0
|
|
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
|
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
|
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
|
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
|
#define ACK_VAL 0x0 /*!< I2C ack value */
|
|
#define NACK_VAL 0x1 /*!< I2C nack value */
|
|
|
|
static void user_delay_ms(uint32_t period) {
|
|
/*
|
|
* Return control or wait,
|
|
* for a period amount of milliseconds
|
|
*/
|
|
vTaskDelay(pdMS_TO_TICKS(period));
|
|
}
|
|
|
|
#if 0
|
|
static int8_t user_spi_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
|
{
|
|
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
|
|
|
/*
|
|
* The parameter dev_id can be used as a variable to select which Chip Select pin has
|
|
* to be set low to activate the relevant device on the SPI bus
|
|
*/
|
|
|
|
/*
|
|
* Data on the bus should be like
|
|
* |----------------+---------------------+-------------|
|
|
* | MOSI | MISO | Chip Select |
|
|
* |----------------+---------------------|-------------|
|
|
* | (don't care) | (don't care) | HIGH |
|
|
* | (reg_addr) | (don't care) | LOW |
|
|
* | (don't care) | (reg_data[0]) | LOW |
|
|
* | (....) | (....) | LOW |
|
|
* | (don't care) | (reg_data[len - 1]) | LOW |
|
|
* | (don't care) | (don't care) | HIGH |
|
|
* |----------------+---------------------|-------------|
|
|
*/
|
|
|
|
return rslt;
|
|
}
|
|
|
|
static int8_t user_spi_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
|
{
|
|
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
|
|
|
/*
|
|
* The parameter dev_id can be used as a variable to select which Chip Select pin has
|
|
* to be set low to activate the relevant device on the SPI bus
|
|
*/
|
|
|
|
/*
|
|
* Data on the bus should be like
|
|
* |---------------------+--------------+-------------|
|
|
* | MOSI | MISO | Chip Select |
|
|
* |---------------------+--------------|-------------|
|
|
* | (don't care) | (don't care) | HIGH |
|
|
* | (reg_addr) | (don't care) | LOW |
|
|
* | (reg_data[0]) | (don't care) | LOW |
|
|
* | (....) | (....) | LOW |
|
|
* | (reg_data[len - 1]) | (don't care) | LOW |
|
|
* | (don't care) | (don't care) | HIGH |
|
|
* |---------------------+--------------|-------------|
|
|
*/
|
|
|
|
return rslt;
|
|
}
|
|
#endif
|
|
|
|
static int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data_rd, uint16_t size) {
|
|
ESP_LOGD(TAG, "BME680 i2c read");
|
|
|
|
/*
|
|
* The parameter dev_id can be used as a variable to store the I2C address of the device
|
|
*/
|
|
|
|
/*
|
|
* Data on the bus should be like
|
|
* |------------+---------------------|
|
|
* | I2C action | Data |
|
|
* |------------+---------------------|
|
|
* | Start | - |
|
|
* | Write | (reg_addr) |
|
|
* | Stop | - |
|
|
* | Start | - |
|
|
* | Read | (reg_data[0]) |
|
|
* | Read | (....) |
|
|
* | Read | (reg_data[len - 1]) |
|
|
* | Stop | - |
|
|
* |------------+---------------------|
|
|
*/
|
|
|
|
if (size == 0) {
|
|
return 0;
|
|
}
|
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (dev_id << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
|
|
i2c_master_write_byte(cmd, reg_addr, ACK_CHECK_EN);
|
|
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (dev_id << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
|
|
i2c_master_read(cmd, data_rd, size, I2C_MASTER_LAST_NACK);
|
|
i2c_master_stop(cmd);
|
|
|
|
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, pdMS_TO_TICKS(1000));
|
|
i2c_cmd_link_delete(cmd);
|
|
|
|
// HAL_I2C_Master_Transmit(&hi2c1, dev_id<<1, ®_addr, 1, 100);
|
|
// HAL_I2C_Master_Receive(&hi2c1, dev_id<<1, reg_data, len, 100);
|
|
|
|
return ret == ESP_OK ? BME680_OK : BME680_E_COM_FAIL;
|
|
}
|
|
|
|
static int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) {
|
|
ESP_LOGD(TAG, "BME680 i2c write");
|
|
/*
|
|
* The parameter dev_id can be used as a variable to store the I2C address of the device
|
|
*/
|
|
|
|
/*
|
|
* Data on the bus should be like
|
|
* |------------+---------------------|
|
|
* | I2C action | Data |
|
|
* |------------+---------------------|
|
|
* | Start | - |
|
|
* | Write | (reg_addr) |
|
|
* | Write | (reg_data[0]) |
|
|
* | Write | (....) |
|
|
* | Write | (reg_data[len - 1]) |
|
|
* | Stop | - |
|
|
* |------------+---------------------|
|
|
*/
|
|
//HAL_I2C_Master_Transmit(&hi2c1, dev_id<<1, &data[0], (uint16_t) (len + 1), 100);
|
|
|
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
i2c_master_start(cmd);
|
|
i2c_master_write_byte(cmd, (dev_id << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
|
|
i2c_master_write_byte(cmd, reg_addr, ACK_CHECK_EN);
|
|
i2c_master_write(cmd, reg_data, len, ACK_CHECK_EN);
|
|
i2c_master_stop(cmd);
|
|
|
|
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, pdMS_TO_TICKS(1000));
|
|
i2c_cmd_link_delete(cmd);
|
|
|
|
return ret == ESP_OK ? BME680_OK : BME680_E_COM_FAIL;
|
|
}
|
|
|
|
|
|
esp_err_t voc_init(void) {
|
|
int8_t rslt;
|
|
gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY;
|
|
gas_sensor.intf = BME680_I2C_INTF;
|
|
gas_sensor.read = user_i2c_read;
|
|
gas_sensor.write = user_i2c_write;
|
|
gas_sensor.delay_ms = user_delay_ms;
|
|
|
|
ESP_LOGD(TAG, "BME680 initializing");
|
|
rslt = bme680_init(&gas_sensor);
|
|
if (rslt != BME680_OK) {
|
|
ESP_LOGE(TAG, "Error from bme680_init: %d", rslt);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ESP_LOGD(TAG, "BME680 configuring");
|
|
/* Set the temperature, pressure and humidity settings */
|
|
gas_sensor.tph_sett.os_hum = BME680_OS_2X;
|
|
gas_sensor.tph_sett.os_pres = BME680_OS_4X;
|
|
gas_sensor.tph_sett.os_temp = BME680_OS_8X;
|
|
gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3;
|
|
|
|
/* Set the remaining gas sensor settings and link the heating profile */
|
|
gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
|
|
/* Create a ramp heat waveform in 3 steps */
|
|
gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */
|
|
gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */
|
|
|
|
/* Select the power mode */
|
|
/* Must be set before writing the sensor configuration */
|
|
gas_sensor.power_mode = BME680_FORCED_MODE;
|
|
|
|
/* Set the required sensor settings needed */
|
|
uint8_t set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
|
|
|
|
/* Set the desired sensor configuration */
|
|
rslt = bme680_set_sensor_settings(set_required_settings, &gas_sensor);
|
|
if (rslt != BME680_OK) {
|
|
ESP_LOGE(TAG, "Error from bme680_set_sensor_settings: %d", rslt);
|
|
return ESP_FAIL;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
uint32_t voc_start_measure(void) {
|
|
/* Set the power mode */
|
|
int8_t rslt;
|
|
|
|
rslt = bme680_set_sensor_mode(&gas_sensor);
|
|
if (rslt != BME680_OK) {
|
|
ESP_LOGE(TAG, "Error from bme680_set_sensor_mode: %d", rslt);
|
|
return 0;
|
|
}
|
|
|
|
/* Get the total measurement duration so as to sleep or wait till the
|
|
* measurement is complete */
|
|
uint16_t meas_period;
|
|
bme680_get_profile_dur(&meas_period, &gas_sensor);
|
|
meas_period += 10; // add some extra safety margin
|
|
|
|
ESP_LOGD(TAG, "Measurement will take %d ms\r\n", meas_period);
|
|
|
|
return meas_period;
|
|
}
|
|
|
|
esp_err_t voc_read(struct bme680_field_data *data) {
|
|
/* Set the power mode */
|
|
int8_t rslt;
|
|
rslt = bme680_get_sensor_data(data, &gas_sensor);
|
|
if (rslt != BME680_OK) {
|
|
ESP_LOGE(TAG, "Error from bme680_get_sensor_data: %d", rslt);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "T: %d/100 degC, P: %d/100 hPa, H %d/1000 %%rH ", data->temperature, data->pressure, data->humidity);
|
|
/* Avoid using measurements from an unstable heating setup */
|
|
if (data->status & BME680_GASM_VALID_MSK) {
|
|
ESP_LOGI(TAG, "G: %d ohms", data->gas_resistance);
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
void voc_read_task(void *param) {
|
|
ESP_LOGI(TAG, "VOC sensor init");
|
|
voc_init();
|
|
|
|
struct bme680_field_data data;
|
|
|
|
while (1) {
|
|
ESP_LOGI(TAG, "VOC sensor meas");
|
|
uint32_t mswait = voc_start_measure();
|
|
vTaskDelay(pdMS_TO_TICKS(mswait));
|
|
|
|
ESP_LOGI(TAG, "VOC sensor read");
|
|
voc_read(&data);
|
|
|
|
// TODO do something with it
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
}
|
|
}
|
|
|