// // Created by MightyPork on 2017/11/17. // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include #include #include #include #include #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)); } }