Driver for Bosch Sensortec BME680 added (#469)
* Driver for Bosch Sensortec BME680 added
This commit is contained in:
		
							parent
							
								
									e0410b2c5d
								
							
						
					
					
						commit
						691cf4ed62
					
				
					 12 changed files with 3081 additions and 0 deletions
				
			
		
							
								
								
									
										555
									
								
								extras/bme680/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								extras/bme680/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,555 @@
 | 
			
		|||
# Driver for **BME680** digital **environmental sensor**
 | 
			
		||||
 | 
			
		||||
This driver is written for usage with the ESP8266 and FreeRTOS. It supports multiple BME680 sensors which are either connected to the SPI or to different I2C interfaces with different addresses.
 | 
			
		||||
 | 
			
		||||
## About the sensor
 | 
			
		||||
 | 
			
		||||
BME680 is an ultra-low-power environmental sensor that integrates temperature, pressure, humidity and gas sensors in only one unit.
 | 
			
		||||
 | 
			
		||||
## Communication interfaces
 | 
			
		||||
 | 
			
		||||
The BME680 sensor can be connected using I2C or SPI.
 | 
			
		||||
 | 
			
		||||
The I2C interface supports data rates up to 3.4 Mbps. It is possible to connect multiple BME680 sensors with different I2C slave addresses to the same I2C bus or to different I2C buses. Possible I2C slave addresses are 0x76 and 0x77.
 | 
			
		||||
 | 
			
		||||
The SPI interface allows clock rates up to 10 MHz and the SPI modes '00' (CPOL=CPHA=0) and '11' (CPOL=CPHA=1).
 | 
			
		||||
 | 
			
		||||
Interface selection is done automatically by the sensor using the SPI CS signal. As long as the CS signal keeps high after power-on reset, the I2C interface is used. Once the CS signal has been pulled down, SPI interface is used until next power-on reset.
 | 
			
		||||
 | 
			
		||||
## Measurement process
 | 
			
		||||
 | 
			
		||||
Once the BME680 has been initialized, it can be used for measurements. The BME680 operates in two different modes, the **sleep mode** and the **forced mode**.
 | 
			
		||||
 | 
			
		||||
The sensor starts after power-up automatically in the *sleep mode* where it does not perform any measurement and consumes only 0.15 μA. Measurements are only done in *forced mode*.
 | 
			
		||||
 | 
			
		||||
**Please note:** There are two further undocumented modes, the *parallel* and the *sequential* mode. They can't be supported by the driver, since it is not clear what they do and how to use them.
 | 
			
		||||
 | 
			
		||||
#### Measurement cylce
 | 
			
		||||
 | 
			
		||||
To perform measurements, the BME680 sensor has to be triggered to switch to the **forced mode**. In this mode, it performs exactly one measurement of temperature, pressure, humidity, and gas in that order, the so-called **TPHG measurement cycle**. After the execution of this TPHG measurement cycle, **raw sensor data** become available and the sensor returns automatically back to sleep mode.
 | 
			
		||||
 | 
			
		||||
Each of the individual measurements can be configured or skipped separately via the sensor settings, see section **Measurement settings**. Dependent on the configuration, the **duration of a TPHG measurement cycle** can vary from some milliseconds up to about 4.5 seconds, especially if gas measurement is enabled.
 | 
			
		||||
 | 
			
		||||
To avoid the blocking of the user task during measurements, the measurement process is therefore separated into the following steps:
 | 
			
		||||
 | 
			
		||||
1. Trigger the sensor with function ```bme680_force_measurement``` to switch to *forced mode* in which it performs exactly one THPG measurement cycle.
 | 
			
		||||
 | 
			
		||||
2. Wait the measurement duration using function ```vTaskDelay``` and the value returned from function ```bme680_get_measurement_duration``` or wait as long as function ```bme680_is_measuring``` returns true.
 | 
			
		||||
 | 
			
		||||
3. Fetch the results as fixed point values with function ```bme680_get_results_fixed``` or as floating point values with function ```bme680_get_results_float```.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
// as long as sensor configuration isn't changed, the duration can be considered as constant
 | 
			
		||||
uint32_t duration = bme680_get_measurement_duration(sensor);
 | 
			
		||||
...
 | 
			
		||||
if (bme680_force_measurement (sensor)) // STEP 1
 | 
			
		||||
{
 | 
			
		||||
    // STEP 2: passive waiting until measurement results are available
 | 
			
		||||
    vTaskDelay (duration);
 | 
			
		||||
 | 
			
		||||
    // STEP 3: get the results and do something with them
 | 
			
		||||
    if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
        ...
 | 
			
		||||
}
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
Alternatively, busy waiting can be realized using function ```bme680_is_measuring```.
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
if (bme680_force_measurement (sensor)) // STEP 1
 | 
			
		||||
{
 | 
			
		||||
    // STEP 2: busy waiting until measurement results are available
 | 
			
		||||
    while (bme680_is_measuring (sensor)) ;
 | 
			
		||||
 | 
			
		||||
    // STEP 3: get the results and do something with them
 | 
			
		||||
    if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
        ...
 | 
			
		||||
}
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For convenience, it is also possible to use the high-level functions ```bme680_measure_float``` or ```bme680_measure_fixed```. These functions combine all 3 steps above within a single function and are therefore very easy to use. **Please note** that these functions must not be used when they are called from a software timer callback function since the calling task is delayed using function *vTaskDelay*.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
// ONE STEP: measure, wait, get the results and do something with them
 | 
			
		||||
if (bme680_measure_float (sensor, &values))
 | 
			
		||||
    ...
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Measurement results
 | 
			
		||||
 | 
			
		||||
Once the sensor has finished the measurement raw data are available at the sensor. Either function ```bme680_get_results_fixed``` or function ```bme680_get_results_float``` can be used to fetch the results. Both functions read raw data from the sensor and converts them into utilizable fixed point or floating point sensor values.
 | 
			
		||||
 | 
			
		||||
**Please note:** Conversion of raw sensor data into the final sensor values is based on very complex calculations that use a large number of calibration parameters. Therefore, the driver does not provide functions that only return the raw sensor data.
 | 
			
		||||
 | 
			
		||||
Dependent on sensor value representation, measurement results contain different dimensions:
 | 
			
		||||
 | 
			
		||||
| Value | Fixed Point | Floating Point | Conversion
 | 
			
		||||
| ----------- | ------------- | -------- |-----------
 | 
			
		||||
| temperature | 1/100 °C | °C | float = fixed / 100
 | 
			
		||||
| pressure | Pascal | hPascal | float = fixed / 100
 | 
			
		||||
| humidity | 1/1000 % | % | float = fixed / 1000
 | 
			
		||||
| gas_resistance | Ohm | Ohm | float = fixed
 | 
			
		||||
 | 
			
		||||
The gas resistance value in Ohm represents the resistance of sensor's gas sensitive layer.
 | 
			
		||||
 | 
			
		||||
If the TPHG measurement cycle or fetching the results fails, invalid sensor values are returned:
 | 
			
		||||
 | 
			
		||||
| Invalid Value | Fixed Point | Floating Point |
 | 
			
		||||
| ----------- | ------------- | -------- |
 | 
			
		||||
| temperature | INT16_MIN | -327.68 |
 | 
			
		||||
| pressure | 0 | 0.0 |
 | 
			
		||||
| humidity | 0 | 0.0 |
 | 
			
		||||
| gas_resistance | 0 | 0.0 |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Measurement settings
 | 
			
		||||
 | 
			
		||||
The sensor allows to change a lot of measurement parameters.
 | 
			
		||||
 | 
			
		||||
#### Oversampling rates
 | 
			
		||||
 | 
			
		||||
To increase the resolution of raw sensor data, the sensor supports oversampling for temperature,  pressure, and humidity measurements. Using function ```bme680_set_oversampling_rates```, individual **oversampling rates** can be defined for these measurements. With an oversampling rate *osr*, the resolution of the according raw sensor data can be increased from 16 bit to 16+ld(*osr*) bit.
 | 
			
		||||
 | 
			
		||||
Possible oversampling rates are 1x (default by the driver) 2x, 4x, 8x and 16x. It is also possible to define an oversampling rate of 0. This **deactivates** the corresponding measurement and the output values become invalid.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
// Changes the oversampling rate for temperature to 4x and for pressure to 2x. Humidity measurement is skipped.
 | 
			
		||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_2x, osr_none);
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### IIR Filter
 | 
			
		||||
 | 
			
		||||
The sensor also integrates an internal IIR filter (low pass filter) to reduce short-term changes in sensor output values caused by external disturbances. It effectively reduces the bandwidth of the sensor output values.
 | 
			
		||||
 | 
			
		||||
The filter can optionally be used for pressure and temperature data that are subject to many short-term changes. With the IIR filter the resolution of pressure and temperature data increases to 20 bit. Humidity and gas inside the sensor does not fluctuate rapidly and does not require such a low pass filtering.
 | 
			
		||||
 | 
			
		||||
Using function ```bme680_set_filter_size```, the user task can change the **size of the filter**. The default size is 3. If the size of the filter becomes 0, the filter is **not used**.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
// Change the IIR filter size for temperature and pressure to 7.
 | 
			
		||||
bme680_set_filter_size(sensor, iir_size_7);
 | 
			
		||||
...
 | 
			
		||||
// Don't use IIR filter
 | 
			
		||||
bme680_set_filter_size(sensor, iir_size_0);
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Heater profile
 | 
			
		||||
 | 
			
		||||
For the gas measurement, the sensor integrates a heater. Parameters for this heater are defined by **heater profiles**. The sensor supports up to 10 such heater profiles, which are numbered from 0 to 9. Each profile consists of a temperature set-point (the target temperature) and a heating duration. By default, only the heater profile 0 with 320 degree Celsius as target temperature and 150 ms heating duration is defined.
 | 
			
		||||
 | 
			
		||||
**Please note:** According to the data sheet, target temperatures between 200 and 400 degrees Celsius are typical and about 20 to 30 ms are necessary for the heater to reach the desired target temperature.
 | 
			
		||||
 | 
			
		||||
Function ```bme680_set_heater_profile``` can be used to set the parameters for one of the heater profiles 0 ... 9. Once the parameters of a heater profile are defined, the gas measurement can be activated with that heater profile using function ```bme680_use_heater_profile```. If -1 or ```BME680_HEATER_NOT_USED``` is used as heater profile, gas measurement is deactivated completely.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
// Change the heater profile 1 to 300 degree Celsius for 100 ms and activate it
 | 
			
		||||
bme680_set_heater_profile (sensor, 1, 300, 100);
 | 
			
		||||
bme680_use_heater_profile (sensor, 1);
 | 
			
		||||
...
 | 
			
		||||
// Deactivate gas measurement completely
 | 
			
		||||
bme680_use_heater_profile (sensor, BME680_HEATER_NOT_USED);
 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If several heater profiles have been defined with function ```bme680_set_heater_profile```, a sequence of gas measurements with different heater parameters can be realized by a sequence of activations of different heater profiles for successive TPHG measurements using function ```bme680_use_heater_profile```.
 | 
			
		||||
 | 
			
		||||
For example, if there were 5 heater profiles defined with following code during the setup
 | 
			
		||||
```
 | 
			
		||||
bme680_set_heater_profile (sensor, 0, 200, 100);
 | 
			
		||||
bme680_set_heater_profile (sensor, 1, 250, 120);
 | 
			
		||||
bme680_set_heater_profile (sensor, 2, 300, 140);
 | 
			
		||||
bme680_set_heater_profile (sensor, 3, 350, 160);
 | 
			
		||||
bme680_set_heater_profile (sensor, 4, 400, 180);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
the user task could use them as a sequence like following:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
while (1)
 | 
			
		||||
{
 | 
			
		||||
    switch (count++ % 5)
 | 
			
		||||
    {
 | 
			
		||||
        case 0: bme680_use_heater_profile (sensor, 0); break;
 | 
			
		||||
        case 1: bme680_use_heater_profile (sensor, 1); break;
 | 
			
		||||
        case 2: bme680_use_heater_profile (sensor, 2); break;
 | 
			
		||||
        case 3: bme680_use_heater_profile (sensor, 3); break;
 | 
			
		||||
        case 4: bme680_use_heater_profile (sensor, 4); break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // measurement duration changes in each cycle
 | 
			
		||||
    uint32_t duration = bme680_get_measurement_duration(sensor);
 | 
			
		||||
 | 
			
		||||
    // trigger the sensor to start one TPHG measurement cycle
 | 
			
		||||
    if (bme680_force_measurement (sensor))
 | 
			
		||||
    {
 | 
			
		||||
        vTaskDelay (duration);
 | 
			
		||||
 | 
			
		||||
        // get the results and do something with them
 | 
			
		||||
        if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
            ...
 | 
			
		||||
    }
 | 
			
		||||
    ...
 | 
			
		||||
}
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Ambient temperature
 | 
			
		||||
 | 
			
		||||
The heater resistance calculation algorithm takes into account the ambient temperature of the sensor. Using function ```bme680_set_ambient_temperature```, the ambient temperature either determined from the sensor itself or from another temperature sensor can be set.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
...
 | 
			
		||||
bme680_set_ambient_temperature (sensor, ambient);
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Error Handling
 | 
			
		||||
 | 
			
		||||
Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In the latter case, the member ```error_code``` of the sensor device data structure is set which indicates what error happened.
 | 
			
		||||
 | 
			
		||||
There are two different error levels that are ORed into one single *error_code*, errors in the I2C or SPI communication and errors of the BME680 sensor itself.  To test for a certain error, first you can AND the *error_code* with one of the error masks, ```BME680_INT_ERROR_MASK``` for I2C or SPI errors and ```BME680_DRV_ERROR_MASK``` for other errors. Then you can test the result for a certain error code.
 | 
			
		||||
 | 
			
		||||
For example, error handling for ```bme680_get_results_float``` could look like:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
{
 | 
			
		||||
    // no error happened
 | 
			
		||||
    ...
 | 
			
		||||
}
 | 
			
		||||
else
 | 
			
		||||
{
 | 
			
		||||
    // error happened
 | 
			
		||||
 | 
			
		||||
    switch (sensor->error_code & BME680_INT_ERROR_MASK)
 | 
			
		||||
    {
 | 
			
		||||
        case BME680_INT_BUSY:        ...
 | 
			
		||||
        case BME680_INT_READ_FAILED: ...
 | 
			
		||||
        ...
 | 
			
		||||
    }
 | 
			
		||||
    switch (sensor->error_code & BME680_DRV_ERROR_MASK)
 | 
			
		||||
    {
 | 
			
		||||
        case BME680_MEAS_STILL_RUNNING: ...
 | 
			
		||||
        case BME680_NO_NEW_DATA:        ...
 | 
			
		||||
        ...
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
First, the hardware configuration has to be established. This can differ dependent on the communication interface and the number of sensors used.
 | 
			
		||||
 | 
			
		||||
### Hardware configurations
 | 
			
		||||
 | 
			
		||||
The driver supports multiple BME680 sensors at the same time that are connected either to I2C or SPI. Following figures show some possible hardware configurations.
 | 
			
		||||
 | 
			
		||||
First figure shows the configuration with only one sensor at I2C bus 0.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 +-------------------------+     +--------+
 | 
			
		||||
 | ESP8266  Bus 0          |     | BME680 |
 | 
			
		||||
 |          GPIO 5 (SCL)   +---->+ SCL    |
 | 
			
		||||
 |          GPIO 4 (SDA)   +-----+ SDA    |
 | 
			
		||||
 |                         |     +--------+
 | 
			
		||||
 +-------------------------+
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Next figure shows the configuration with only one sensor at SPI bus using GPIO2 as CS signal.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 +-------------------------+     +--------+
 | 
			
		||||
 |          Bus 1          |     | BME680 |
 | 
			
		||||
 |          GPIO 12 (MISO) <------ SDO    |
 | 
			
		||||
 |          GPIO 13 (MOSI) >-----> SDI    |
 | 
			
		||||
 |          GPIO 14 (SCK)  >-----> SCK    |
 | 
			
		||||
 |          GPIO 2  (CS)   >-----> CS     |
 | 
			
		||||
 +-------------------------+     +--------+
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Please note:**
 | 
			
		||||
 | 
			
		||||
1. Since the system flash memory is connected to SPI bus 0, the sensor has to be connected to SPI bus 1.
 | 
			
		||||
 | 
			
		||||
2. GPIO15 which is used as CS signal of SPI bus 1 does not work correctly together with the BME680. Therefore, the user has to specify another GPIO pin as CS signal, e.g., GPIO2.
 | 
			
		||||
Next figure shows a possible configuration with two I2C buses. In that case, the sensors can have same or different I2C slave addresses.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 +-------------------------+     +----------+
 | 
			
		||||
 | ESP8266  Bus 0          |     | BME680_1 |
 | 
			
		||||
 |          GPIO 5 (SCL)   ------> SCL      |
 | 
			
		||||
 |          GPIO 4 (SDA)   ------- SDA      |
 | 
			
		||||
 |                         |     +----------+
 | 
			
		||||
 |          Bus 1          |     | BME680_2 |
 | 
			
		||||
 |          GPIO 14 (SCL)  ------> SCL      |
 | 
			
		||||
 |          GPIO 12 (SDA)  ------- SDA      |
 | 
			
		||||
 +-------------------------+     +----------+
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Last figure shows a possible configuration using I2C bus 0 and SPI bus 1 at the same time.
 | 
			
		||||
```
 | 
			
		||||
 +-------------------------+     +----------+
 | 
			
		||||
 | ESP8266  Bus 0          |     | BME680_1 |
 | 
			
		||||
 |          GPIO 5 (SCL)   ------> SCL      |
 | 
			
		||||
 |          GPIO 4 (SDA)   ------- SDA      |
 | 
			
		||||
 |                         |     +----------+
 | 
			
		||||
 |          Bus 1          |     | BME680_2 |
 | 
			
		||||
 |          GPIO 12 (MISO) <------ SDO      |
 | 
			
		||||
 |          GPIO 13 (MOSI) >-----> SDI      |
 | 
			
		||||
 |          GPIO 14 (SCK)  >-----> SCK      |
 | 
			
		||||
 |          GPIO 2  (CS)   >-----> CS       |
 | 
			
		||||
 +-------------------------+     +----------+
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Further configurations are possible, e.g., two sensors that are connected at the same I2C bus with different slave addresses.
 | 
			
		||||
 | 
			
		||||
### Communication interface settings
 | 
			
		||||
 | 
			
		||||
Dependent on the hardware configuration, the communication interface settings have to be defined.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
// define SPI interface for BME680 sensors
 | 
			
		||||
#define SPI_BUS         1
 | 
			
		||||
#define SPI_CS_GPIO     2   // GPIO 15, the default CS of SPI bus 1, can't be used
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
// define I2C interface for BME680 sensors
 | 
			
		||||
#define I2C_BUS         0
 | 
			
		||||
#define I2C_SCL_PIN     5
 | 
			
		||||
#define I2C_SDA_PIN     4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Main program
 | 
			
		||||
 | 
			
		||||
If I2C interfaces are used, they have to be initialized first.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
SPI interface has not to be initialized explicitly.
 | 
			
		||||
 | 
			
		||||
Once the I2C interfaces are initialized, function ```bme680_init_sensor``` has to be called for each BME680 sensor in order to initialize the sensor and to check its availability as well as its error state. This function returns a pointer to a sensor device data structure or NULL in case of error.
 | 
			
		||||
 | 
			
		||||
The parameter *bus* specifies the ID of the I2C or SPI bus to which the sensor is connected.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
static bme680_sensor_t* sensor;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For sensors connected to an I2C interface, a valid I2C slave address has to be defined as parameter *addr*. In that case parameter *cs* is ignored.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
sensor = bme680_init_sensor (I2C_BUS, BME680_I2C_ADDRESS_2, 0);
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If parameter *addr* is 0, the sensor is connected to a SPI bus. In that case, parameter *cs* defines the GPIO used as CS signal.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The remaining part of the program is independent on the communication interface.
 | 
			
		||||
 | 
			
		||||
Optionally, you could wish to set some measurement parameters. For details see the section **Measurement settings** above, the header file of the driver ```bme680.h```, and of course the data sheet of the sensor.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
if (sensor)
 | 
			
		||||
{
 | 
			
		||||
    // Create a task that uses the sensor
 | 
			
		||||
    xTaskCreate(user_task, "user_task", 256, NULL, 2, NULL);
 | 
			
		||||
 | 
			
		||||
    /** -- OPTIONAL PART -- */
 | 
			
		||||
 | 
			
		||||
    // Changes the oversampling rates to 4x oversampling for temperature
 | 
			
		||||
    // and 2x oversampling for humidity. Pressure measurement is skipped.
 | 
			
		||||
    bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
 | 
			
		||||
 | 
			
		||||
    // Change the IIR filter size for temperature and pressure to 7.
 | 
			
		||||
    bme680_set_filter_size(sensor, iir_size_7);
 | 
			
		||||
 | 
			
		||||
    // Change the heater profile 0 to 200 degree Celsius for 100 ms.
 | 
			
		||||
    bme680_set_heater_profile (sensor, 0, 200, 100);
 | 
			
		||||
    bme680_use_heater_profile (sensor, 0);
 | 
			
		||||
 | 
			
		||||
    ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Last, the user task that uses the sensor has to be created.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### User task
 | 
			
		||||
 | 
			
		||||
BME680 supports only the *forced mode* that performs exactly one measurement. Therefore, the measurement has to be triggered in each cycle. The waiting for measurement results is also required in each cycle, before the results can be fetched.
 | 
			
		||||
 | 
			
		||||
Thus the user task could look like the following:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
void user_task(void *pvParameters)
 | 
			
		||||
{
 | 
			
		||||
    bme680_values_float_t values;
 | 
			
		||||
 | 
			
		||||
    TickType_t last_wakeup = xTaskGetTickCount();
 | 
			
		||||
 | 
			
		||||
    // as long as sensor configuration isn't changed, duration is constant
 | 
			
		||||
    uint32_t duration = bme680_get_measurement_duration(sensor);
 | 
			
		||||
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        // trigger the sensor to start one TPHG measurement cycle
 | 
			
		||||
        bme680_force_measurement (sensor);
 | 
			
		||||
 | 
			
		||||
        // passive waiting until measurement results are available
 | 
			
		||||
        vTaskDelay (duration);
 | 
			
		||||
 | 
			
		||||
        // alternatively: busy waiting until measurement results are available
 | 
			
		||||
        // while (bme680_is_measuring (sensor)) ;
 | 
			
		||||
 | 
			
		||||
        // get the results and do something with them
 | 
			
		||||
        if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
            printf("%.3f BME680 Sensor: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
 | 
			
		||||
                   (double)sdk_system_get_time()*1e-3,
 | 
			
		||||
                   values.temperature, values.humidity,
 | 
			
		||||
                   values.pressure, values.gas_resistance);
 | 
			
		||||
 | 
			
		||||
        // passive waiting until 1 second is over
 | 
			
		||||
        vTaskDelayUntil(&last_wakeup, 1000 / portTICK_PERIOD_MS);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Function ```bme680_force_measurement``` is called inside the task loop to perform exactly one measurement in each cycle.
 | 
			
		||||
 | 
			
		||||
The task is then delayed using function ```vTaskDelay``` and the value returned from function ```bme680_get_measurement_duration``` or as long as function ```bme680_is_measuring``` returns true.
 | 
			
		||||
 | 
			
		||||
Since the measurement duration only depends on the current sensor configuration, it changes only when sensor configuration is changed. Therefore, it can be considered as constant as long as the sensor configuration isn't changed and can be determined with function ```bme680_get_measurement_duration``` outside the task loop. If the sensor configuration changes, the function has to be executed again.
 | 
			
		||||
 | 
			
		||||
Once the measurement results are available, they can be fetched as fixed point oder floating point sensor values using function ```bme680_get_results_float``` and ```bme680_get_results_fixed```, respectively.
 | 
			
		||||
 | 
			
		||||
## Full Example
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
// Uncomment to use SPI
 | 
			
		||||
// #define SPI_USED
 | 
			
		||||
 | 
			
		||||
#include "espressif/esp_common.h"
 | 
			
		||||
#include "esp/uart.h"
 | 
			
		||||
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "task.h"
 | 
			
		||||
 | 
			
		||||
// include communication interface driver
 | 
			
		||||
#include "esp/spi.h"
 | 
			
		||||
#include "i2c/i2c.h"
 | 
			
		||||
 | 
			
		||||
// include BME680 driver
 | 
			
		||||
#include "bme680/bme680.h"
 | 
			
		||||
 | 
			
		||||
#ifdef SPI_USED
 | 
			
		||||
// define SPI interface for BME680 sensors
 | 
			
		||||
#define SPI_BUS         1
 | 
			
		||||
#define SPI_CS_GPIO     2   // GPIO 15, the default CS of SPI bus 1, can't be used
 | 
			
		||||
#else
 | 
			
		||||
// define I2C interface for BME680 sensors
 | 
			
		||||
#define I2C_BUS         0
 | 
			
		||||
#define I2C_SCL_PIN     5
 | 
			
		||||
#define I2C_SDA_PIN     4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bme680_sensor_t* sensor;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * User task that triggers measurements of sensor every seconds. It uses
 | 
			
		||||
 * function *vTaskDelay* to wait for measurement results. Busy waiting
 | 
			
		||||
 * alternative is shown in comments
 | 
			
		||||
 */
 | 
			
		||||
void user_task(void *pvParameters)
 | 
			
		||||
{
 | 
			
		||||
    bme680_values_float_t values;
 | 
			
		||||
 | 
			
		||||
    TickType_t last_wakeup = xTaskGetTickCount();
 | 
			
		||||
 | 
			
		||||
    // as long as sensor configuration isn't changed, duration is constant
 | 
			
		||||
    uint32_t duration = bme680_get_measurement_duration(sensor);
 | 
			
		||||
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        // trigger the sensor to start one TPHG measurement cycle
 | 
			
		||||
        bme680_force_measurement (sensor);
 | 
			
		||||
 | 
			
		||||
        // passive waiting until measurement results are available
 | 
			
		||||
        vTaskDelay (duration);
 | 
			
		||||
 | 
			
		||||
        // alternatively: busy waiting until measurement results are available
 | 
			
		||||
        // while (bme680_is_measuring (sensor)) ;
 | 
			
		||||
 | 
			
		||||
        // get the results and do something with them
 | 
			
		||||
        if (bme680_get_results_float (sensor, &values))
 | 
			
		||||
            printf("%.3f BME680 Sensor: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
 | 
			
		||||
                   (double)sdk_system_get_time()*1e-3,
 | 
			
		||||
                   values.temperature, values.humidity,
 | 
			
		||||
                   values.pressure, values.gas_resistance);
 | 
			
		||||
 | 
			
		||||
        // passive waiting until 1 second is over
 | 
			
		||||
        vTaskDelayUntil(&last_wakeup, 1000 / portTICK_PERIOD_MS);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void user_init(void)
 | 
			
		||||
{
 | 
			
		||||
    // Set UART Parameter
 | 
			
		||||
    uart_set_baud(0, 115200);
 | 
			
		||||
    // Give the UART some time to settle
 | 
			
		||||
    sdk_os_delay_us(500);
 | 
			
		||||
 | 
			
		||||
    /** -- MANDATORY PART -- */
 | 
			
		||||
 | 
			
		||||
    #ifdef SPI_USED
 | 
			
		||||
    // Init the sensor connected either to SPI.
 | 
			
		||||
    sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
 | 
			
		||||
    #else
 | 
			
		||||
    // Init all I2C bus interfaces at which BME680 sensors are connected
 | 
			
		||||
    i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K);
 | 
			
		||||
 | 
			
		||||
    // Init the sensor connected either to I2C.
 | 
			
		||||
    sensor = bme680_init_sensor (I2C_BUS, BME680_I2C_ADDRESS_2, 0);
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    if (sensor)
 | 
			
		||||
    {
 | 
			
		||||
        // Create a task that uses the sensor
 | 
			
		||||
        xTaskCreate(user_task, "user_task", 256, NULL, 2, NULL);
 | 
			
		||||
 | 
			
		||||
        /** -- OPTIONAL PART -- */
 | 
			
		||||
 | 
			
		||||
        // Changes the oversampling rates to 4x oversampling for temperature
 | 
			
		||||
        // and 2x oversampling for humidity. Pressure measurement is skipped.
 | 
			
		||||
        bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
 | 
			
		||||
 | 
			
		||||
        // Change the IIR filter size for temperature and pressure to 7.
 | 
			
		||||
        bme680_set_filter_size(sensor, iir_size_7);
 | 
			
		||||
 | 
			
		||||
        // Change the heater profile 0 to 200 degree Celcius for 100 ms.
 | 
			
		||||
        bme680_set_heater_profile (sensor, 0, 200, 100);
 | 
			
		||||
        bme680_use_heater_profile (sensor, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										1475
									
								
								extras/bme680/bme680.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1475
									
								
								extras/bme680/bme680.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										384
									
								
								extras/bme680/bme680.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								extras/bme680/bme680.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,384 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Driver for Bosch Sensortec BME680 digital temperature, humidity, pressure and
 | 
			
		||||
 * gas sensor connected to I2C or SPI
 | 
			
		||||
 *
 | 
			
		||||
 * Part of esp-open-rtos [https://github.com/SuperHouse/esp-open-rtos]
 | 
			
		||||
 *
 | 
			
		||||
 * ---------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * The BSD License (3-clause license)
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht]
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 * this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 * notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 * documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of the copyright holder nor the names of its
 | 
			
		||||
 * contributors may be used to endorse or promote products derived from this
 | 
			
		||||
 * software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BME680_H__
 | 
			
		||||
#define __BME680_H__
 | 
			
		||||
 | 
			
		||||
#include "bme680/bme680_types.h"
 | 
			
		||||
 | 
			
		||||
// Uncomment one of the following defines to enable debug output
 | 
			
		||||
// #define BME680_DEBUG_LEVEL_1    // only error messages
 | 
			
		||||
// #define BME680_DEBUG_LEVEL_2    // debug and error messages
 | 
			
		||||
 | 
			
		||||
// BME680 addresses
 | 
			
		||||
#define BME680_I2C_ADDRESS_1           0x76  // SDO pin is low
 | 
			
		||||
#define BME680_I2C_ADDRESS_2           0x77  // SDO pin is high
 | 
			
		||||
 | 
			
		||||
// BME680 chip id
 | 
			
		||||
#define BME680_CHIP_ID                 0x61    // BME680_REG_ID<7:0>
 | 
			
		||||
 | 
			
		||||
// Definition of error codes
 | 
			
		||||
#define BME680_OK                      0
 | 
			
		||||
#define BME680_NOK                     -1
 | 
			
		||||
 | 
			
		||||
#define BME680_INT_ERROR_MASK          0x000f
 | 
			
		||||
#define BME680_DRV_ERROR_MASK          0xfff0
 | 
			
		||||
 | 
			
		||||
// Error codes for I2C and SPI interfaces ORed with BME680 driver error codes
 | 
			
		||||
#define BME680_I2C_READ_FAILED         1
 | 
			
		||||
#define BME680_I2C_WRITE_FAILED        2
 | 
			
		||||
#define BME680_I2C_BUSY                3
 | 
			
		||||
#define BME680_SPI_WRITE_FAILED        4
 | 
			
		||||
#define BME680_SPI_READ_FAILED         5
 | 
			
		||||
#define BME680_SPI_BUFFER_OVERFLOW     6
 | 
			
		||||
#define BME680_SPI_SET_PAGE_FAILED     7
 | 
			
		||||
 | 
			
		||||
// BME680 driver error codes ORed with error codes for I2C and SPI interfaces
 | 
			
		||||
#define BME680_RESET_CMD_FAILED        ( 1 << 8)
 | 
			
		||||
#define BME680_WRONG_CHIP_ID           ( 2 << 8)
 | 
			
		||||
#define BME680_READ_CALIB_DATA_FAILED  ( 3 << 8)
 | 
			
		||||
#define BME680_MEAS_ALREADY_RUNNING    ( 4 << 8)
 | 
			
		||||
#define BME680_MEAS_NOT_RUNNING        ( 5 << 8)
 | 
			
		||||
#define BME680_MEAS_STILL_RUNNING      ( 6 << 8)
 | 
			
		||||
#define BME680_FORCE_MODE_FAILED       ( 7 << 8)
 | 
			
		||||
#define BME680_NO_NEW_DATA             ( 8 << 8)
 | 
			
		||||
#define BME680_WRONG_HEAT_PROFILE      ( 9 << 8)
 | 
			
		||||
#define BME680_MEAS_GAS_NOT_VALID      (10 << 8)
 | 
			
		||||
#define BME680_HEATER_NOT_STABLE       (11 << 8)
 | 
			
		||||
 | 
			
		||||
// Driver range definitions
 | 
			
		||||
#define BME680_HEATER_TEMP_MIN         200  // min. 200 degree Celsius
 | 
			
		||||
#define BME680_HEATER_TEMP_MAX         400  // max. 200 degree Celsius
 | 
			
		||||
#define BME680_HEATER_PROFILES         10   // max. 10 heater profiles 0 ... 9
 | 
			
		||||
#define BME680_HEATER_NOT_USED         -1   // heater not used profile
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** --------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * Functional Description of the BME680 sensor
 | 
			
		||||
 *
 | 
			
		||||
 * The BME680 sensor only support two modes, the sleep mode and the forced
 | 
			
		||||
 * mode in which measurements are done. After power-up sequence, the sensor
 | 
			
		||||
 * automatically starts in sleep mode. To start a measurement, the sensor has
 | 
			
		||||
 * to switch in the forced mode. In this mode it performs exactly one
 | 
			
		||||
 * measurement of temperature, pressure, humidity, and gas in that order,
 | 
			
		||||
 * the so-called TPHG measurement cycle. After the execution of this TPHG
 | 
			
		||||
 * measurement cycle, raw sensor data are available and the sensor returns
 | 
			
		||||
 * automatically back to sleep mode.
 | 
			
		||||
 *
 | 
			
		||||
 * Using the BME680 consists of the following steps
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Trigger the sensor to switch into forced mode to perform one THPG cycle
 | 
			
		||||
 * 2. Wait until the THPG cycle has been finished (measurement duration)
 | 
			
		||||
 * 3. Fetch raw sensor data, compensate and convert them to sensor values
 | 
			
		||||
 *
 | 
			
		||||
 * ---------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Initialize a BME680 sensor
 | 
			
		||||
 *
 | 
			
		||||
 * The function initializes the sensor device data structure, probes the
 | 
			
		||||
 * sensor, soft resets the sensor, and configures the sensor with the
 | 
			
		||||
 * the following default settings:
 | 
			
		||||
 *
 | 
			
		||||
 * - Oversampling rate for temperature, pressure, humidity is osr_1x
 | 
			
		||||
 * - Filter size for pressure and temperature is iir_size 3
 | 
			
		||||
 * - Heater profile 0 with 320 degree C and 150 ms duration
 | 
			
		||||
 *
 | 
			
		||||
 * The sensor can be connected either to an I2C or a SPI bus. In both cases,
 | 
			
		||||
 * the parameter *bus* specifies the ID of the corresponding bus. Please note
 | 
			
		||||
 * that in case of SPI, bus 1 has to be used since bus 0 is used for system
 | 
			
		||||
 * flash memory.
 | 
			
		||||
 *
 | 
			
		||||
 * If parameter *addr* is greater than 0, it defines a valid I2C slave address
 | 
			
		||||
 * and the sensor is connected to an I2C bus. In that case parameter *cs* is
 | 
			
		||||
 * ignored.
 | 
			
		||||
 *
 | 
			
		||||
 * If parameter *addr* is 0, the sensor is connected to a SPI bus. In that
 | 
			
		||||
 * case, parameter *cs* defines the GPIO used as CS signal
 | 
			
		||||
 *
 | 
			
		||||
 * @param   bus     I2C or SPI bus at which BME680 sensor is connected
 | 
			
		||||
 * @param   addr    I2C addr of the BME680 sensor, 0 for SPI
 | 
			
		||||
 * @param   cs      SPI CS GPIO, ignored for I2C
 | 
			
		||||
 * @return          pointer to sensor data structure, or NULL on error
 | 
			
		||||
 */
 | 
			
		||||
bme680_sensor_t* bme680_init_sensor (uint8_t bus, uint8_t addr, uint8_t cs_pin);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Force one single TPHG measurement
 | 
			
		||||
 *
 | 
			
		||||
 * The function triggers the sensor to start one THPG measurement cycle.
 | 
			
		||||
 * Parameters for the measurement like oversampling rates, IIR filter sizes
 | 
			
		||||
 * and heater profile can be configured before.
 | 
			
		||||
 *
 | 
			
		||||
 * Once the TPHG measurement is started, the user task has to wait for the
 | 
			
		||||
 * results. The duration of the TPHG measurement can be determined with
 | 
			
		||||
 * function *bme680_get_measurement_duration*.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev   pointer to the sensor device data structure
 | 
			
		||||
 * @return        true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_force_measurement (bme680_sensor_t* dev);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Get estimated duration of a TPHG measurement
 | 
			
		||||
 *
 | 
			
		||||
 * The function returns an estimated duration of the TPHG measurement cycle
 | 
			
		||||
 * in RTOS ticks for the current configuration of the sensor.
 | 
			
		||||
 *
 | 
			
		||||
 * This duration is the time required by the sensor for one TPHG measurement
 | 
			
		||||
 * until the results are available. It strongly depends on which measurements
 | 
			
		||||
 * are performed in the THPG measurement cycle and what configuration
 | 
			
		||||
 * parameters were set. It can vary from 1 RTOS (10 ms) tick up to 4500 RTOS
 | 
			
		||||
 * ticks (4.5 seconds).
 | 
			
		||||
 *
 | 
			
		||||
 * If the measurement configuration is not changed, the duration can be
 | 
			
		||||
 * considered as constant.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev   pointer to the sensor device data structure
 | 
			
		||||
 * @return        duration of TPHG measurement cycle in ticks or 0 on error
 | 
			
		||||
 */
 | 
			
		||||
uint32_t bme680_get_measurement_duration (const bme680_sensor_t *dev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get the measurement status
 | 
			
		||||
 *
 | 
			
		||||
 * The function can be used to test whether a measurement that was started
 | 
			
		||||
 * before is still running.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev   pointer to the sensor device data structure
 | 
			
		||||
 * @return        true if measurement is still running or false otherwise
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_is_measuring (bme680_sensor_t* dev);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get results of a measurement in fixed point representation
 | 
			
		||||
 *
 | 
			
		||||
 * The function returns the results of a TPHG measurement that has been
 | 
			
		||||
 * started before. If the measurement is still running, the function fails
 | 
			
		||||
 * and returns invalid values (see type declaration).
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   results pointer to a data structure that is filled with results
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_get_results_fixed (bme680_sensor_t* dev,
 | 
			
		||||
                               bme680_values_fixed_t* results);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Get results of a measurement in floating point representation
 | 
			
		||||
 *
 | 
			
		||||
 * The function returns the results of a TPHG measurement that has been
 | 
			
		||||
 * started before. If the measurement is still running, the function fails
 | 
			
		||||
 * and returns invalid values (see type declaration).
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   results pointer to a data structure that is filled with results
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_get_results_float (bme680_sensor_t* dev,
 | 
			
		||||
                               bme680_values_float_t* results);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Start a measurement, wait and return the results (fixed point)
 | 
			
		||||
 *
 | 
			
		||||
 * This function is a combination of functions above. For convenience it
 | 
			
		||||
 * starts a TPHG measurement using *bme680_force_measurement*, then it waits
 | 
			
		||||
 * the measurement duration for the results using *vTaskDelay* and finally it
 | 
			
		||||
 * returns the results using function *bme680_get_results_fixed*.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: Since the calling task is delayed using function *vTaskDelay*, this
 | 
			
		||||
 * function must not be used when it is called from a software timer callback
 | 
			
		||||
 * function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   results pointer to a data structure that is filled with results
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_measure_fixed (bme680_sensor_t* dev,
 | 
			
		||||
                           bme680_values_fixed_t* results);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Start a measurement, wait and return the results (floating point)
 | 
			
		||||
 *
 | 
			
		||||
 * This function is a combination of functions above. For convenience it
 | 
			
		||||
 * starts a TPHG measurement using *bme680_force_measurement*, then it waits
 | 
			
		||||
 * the measurement duration for the results using *vTaskDelay* and finally it
 | 
			
		||||
 * returns the results using function *bme680_get_results_float*.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: Since the calling task is delayed using function *vTaskDelay*, this
 | 
			
		||||
 * function must not be used when it is called from a software timer callback
 | 
			
		||||
 * function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   results pointer to a data structure that is filled with results
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_measure_float (bme680_sensor_t* dev,
 | 
			
		||||
                           bme680_values_float_t* results);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Set the oversampling rates for measurements
 | 
			
		||||
 *
 | 
			
		||||
 * The BME680 sensor allows to define individual oversampling rates for
 | 
			
		||||
 * the measurements of temperature, pressure and humidity. Using an
 | 
			
		||||
 * oversampling rate of *osr*, the resolution of raw sensor data can be
 | 
			
		||||
 * increased by ld(*osr*) bits.
 | 
			
		||||
 *
 | 
			
		||||
 * Possible oversampling rates are 1x (default), 2x, 4x, 8x, 16x, see type
 | 
			
		||||
 * *bme680_oversampling_rate_t*. The default oversampling rate is 1.
 | 
			
		||||
 *
 | 
			
		||||
 * Please note: Use *osr_none* to skip the corresponding measurement.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   ost     oversampling rate for temperature measurements
 | 
			
		||||
 * @param   osp     oversampling rate for pressure measurements
 | 
			
		||||
 * @param   osh     oversampling rate for humidity measurements
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_set_oversampling_rates (bme680_sensor_t* dev,
 | 
			
		||||
                                    bme680_oversampling_rate_t osr_t,
 | 
			
		||||
                                    bme680_oversampling_rate_t osr_p,
 | 
			
		||||
                                    bme680_oversampling_rate_t osr_h);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Set the size of the IIR filter
 | 
			
		||||
 *
 | 
			
		||||
 * The sensor integrates an internal IIR filter (low pass filter) to reduce
 | 
			
		||||
 * short-term changes in sensor output values caused by external disturbances.
 | 
			
		||||
 * It effectively reduces the bandwidth of the sensor output values.
 | 
			
		||||
 *
 | 
			
		||||
 * The filter can optionally be used for pressure and temperature data that
 | 
			
		||||
 * are subject to many short-term changes. Using the IIR filter, increases the
 | 
			
		||||
 * resolution of pressure and temperature data to 20 bit. Humidity and gas
 | 
			
		||||
 * inside the sensor does not fluctuate rapidly and does not require such a
 | 
			
		||||
 * low pass filtering.
 | 
			
		||||
 *
 | 
			
		||||
 * The default filter size is 3 (*iir_size_3*).
 | 
			
		||||
 *
 | 
			
		||||
 * Please note: If the size of the filter is 0, the filter is not used.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev     pointer to the sensor device data structure
 | 
			
		||||
 * @param   size    IIR filter size
 | 
			
		||||
 * @return          true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_set_filter_size(bme680_sensor_t* dev, bme680_filter_size_t size);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Set a heater profile for gas measurements
 | 
			
		||||
 *
 | 
			
		||||
 * The sensor integrates a heater for the gas measurement. Parameters for this
 | 
			
		||||
 * heater are defined by so called heater profiles. The sensor supports up to
 | 
			
		||||
 * 10 heater profiles, which are numbered from 0 to 9. Each profile consists of
 | 
			
		||||
 * a temperature set-point (the target temperature) and a heating duration.
 | 
			
		||||
 *
 | 
			
		||||
 * This function sets the parameters for one of the heater profiles 0 ... 9.
 | 
			
		||||
 * To activate the gas measurement with this profile, use function
 | 
			
		||||
 * *bme680_use_heater_profile*, see below.
 | 
			
		||||
 *
 | 
			
		||||
 * Please note: According to the data sheet, a target temperatures of between
 | 
			
		||||
 * 200 and 400 degrees Celsius are typical and about 20 to 30 ms are necessary
 | 
			
		||||
 * for the heater to reach the desired target temperature.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev           pointer to the sensor device data structure
 | 
			
		||||
 * @param   profile       heater profile 0 ... 9
 | 
			
		||||
 * @param   temperature   target temperature in degree Celsius
 | 
			
		||||
 * @param   duration      heating duration in milliseconds
 | 
			
		||||
 * @return                true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_set_heater_profile (bme680_sensor_t* dev,
 | 
			
		||||
                                uint8_t  profile,
 | 
			
		||||
                                uint16_t temperature,
 | 
			
		||||
                                uint16_t duration);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Activate gas measurement with a given heater profile
 | 
			
		||||
 *
 | 
			
		||||
 * The function activates the gas measurement with one of the heater
 | 
			
		||||
 * profiles 0 ... 9 or deactivates the gas measurement completely when
 | 
			
		||||
 * -1 or BME680_HEATER_NOT_USED is used as heater profile.
 | 
			
		||||
 *
 | 
			
		||||
 * Parameters of the activated heater profile have to be set before with
 | 
			
		||||
 * function *bme680_set_heater_profile* otherwise the function fails.
 | 
			
		||||
 *
 | 
			
		||||
 * If several heater profiles have been defined with function
 | 
			
		||||
 * *bme680_set_heater_profile*, a sequence of gas measurements with different
 | 
			
		||||
 * heater parameters can be realized by a sequence of activations of different
 | 
			
		||||
 * heater profiles for successive TPHG measurements using this function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev       pointer to the sensor device data structure0 *
 | 
			
		||||
 * @param   profile   0 ... 9 to activate or -1 to deactivate gas measure
 | 
			
		||||
 * @return            true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_use_heater_profile (bme680_sensor_t* dev, int8_t profile);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Set ambient temperature
 | 
			
		||||
 *
 | 
			
		||||
 * The heater resistance calculation algorithm takes into account the ambient
 | 
			
		||||
 * temperature of the sensor. This function can be used to set this ambient
 | 
			
		||||
 * temperature. Either values determined from the sensor itself or from
 | 
			
		||||
 * another temperature sensor can be used. The default ambient temperature
 | 
			
		||||
 * is 25 degree Celsius.
 | 
			
		||||
 *
 | 
			
		||||
 * @param   dev           pointer to the sensor device data structure
 | 
			
		||||
 * @param   temperature   ambient temperature in degree Celsius
 | 
			
		||||
 * @return                true on success, false on error
 | 
			
		||||
 */
 | 
			
		||||
bool bme680_set_ambient_temperature (bme680_sensor_t* dev,
 | 
			
		||||
                                     int16_t temperature);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif /* End of CPP guard */
 | 
			
		||||
 | 
			
		||||
#endif /* __BME680_H__ */
 | 
			
		||||
							
								
								
									
										192
									
								
								extras/bme680/bme680_types.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								extras/bme680/bme680_types.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,192 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Driver for Bosch Sensortec BME680 digital temperature, humity, pressure and
 | 
			
		||||
 * gas sensor connected to I2C or SPI
 | 
			
		||||
 *
 | 
			
		||||
 * Part of esp-open-rtos [https://github.com/SuperHouse/esp-open-rtos]
 | 
			
		||||
 *
 | 
			
		||||
 * ---------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * The BSD License (3-clause license)
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht]
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 * this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 * notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 * documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of the copyright holder nor the names of its
 | 
			
		||||
 * contributors may be used to endorse or promote products derived from this
 | 
			
		||||
 * software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __BME680_TYPES_H__
 | 
			
		||||
#define __BME680_TYPES_H__
 | 
			
		||||
 | 
			
		||||
#include "stdint.h"
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C"
 | 
			
		||||
{
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Fixed point sensor values (fixed THPG values)
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {                                              // invalid value
 | 
			
		||||
    int16_t  temperature;    // temperature in degree C * 100 (INT16_MIN)
 | 
			
		||||
    uint32_t pressure;       // barometric pressure in Pascal (0)
 | 
			
		||||
    uint32_t humidity;       // relative humidity in % * 1000 (0)
 | 
			
		||||
    uint32_t gas_resistance; // gas resistance in Ohm         (0)
 | 
			
		||||
} bme680_values_fixed_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Floating point sensor values (real THPG values)
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {                                              // invalid value
 | 
			
		||||
    float   temperature;    // temperature in degree C        (-327.68)
 | 
			
		||||
    float   pressure;       // barometric pressure in hPascal (0.0)
 | 
			
		||||
    float   humidity;       // relative humidity in %         (0.0)
 | 
			
		||||
    float   gas_resistance; // gas resistance in Ohm          (0.0)
 | 
			
		||||
} bme680_values_float_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief 	Oversampling rates
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    osr_none = 0,     // measurement is skipped, output values are invalid
 | 
			
		||||
    osr_1x   = 1,     // default oversampling rates
 | 
			
		||||
    osr_2x   = 2,
 | 
			
		||||
    osr_4x   = 3,
 | 
			
		||||
    osr_8x   = 4,
 | 
			
		||||
    osr_16x  = 5
 | 
			
		||||
} bme680_oversampling_rate_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief 	Filter sizes
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    iir_size_0   = 0,   // filter is not used
 | 
			
		||||
    iir_size_1   = 1,
 | 
			
		||||
    iir_size_3   = 2,
 | 
			
		||||
    iir_size_7   = 3,
 | 
			
		||||
    iir_size_15  = 4,
 | 
			
		||||
    iir_size_31  = 5,
 | 
			
		||||
    iir_size_63  = 6,
 | 
			
		||||
    iir_size_127 = 7
 | 
			
		||||
} bme680_filter_size_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Sensor parameters that configure the TPHG measurement cycle
 | 
			
		||||
 *
 | 
			
		||||
 *  T - temperature measurement
 | 
			
		||||
 *  P - pressure measurement
 | 
			
		||||
 *  H - humidity measurement
 | 
			
		||||
 *  G - gas measurement
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
 | 
			
		||||
    uint8_t  osr_temperature;        // T oversampling rate (default osr_1x)
 | 
			
		||||
    uint8_t  osr_pressure;           // P oversampling rate (default osr_1x)
 | 
			
		||||
    uint8_t  osr_humidity;           // H oversampling rate (default osr_1x)
 | 
			
		||||
    uint8_t  filter_size;            // IIR filter size (default iir_size_3)
 | 
			
		||||
 | 
			
		||||
    int8_t   heater_profile;         // Heater profile used (default 0)
 | 
			
		||||
    uint16_t heater_temperature[10]; // Heater temperature for G (default 320)
 | 
			
		||||
    uint16_t heater_duration[10];    // Heater duration for G (default 150)
 | 
			
		||||
 | 
			
		||||
    int8_t   ambient_temperature;    // Ambient temperature for G (default 25)
 | 
			
		||||
 | 
			
		||||
} bme680_settings_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief   Data structure for calibration parameters
 | 
			
		||||
 *
 | 
			
		||||
 * These calibration parameters are used in compensation algorithms to convert
 | 
			
		||||
 * raw sensor data to measurement results.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
 | 
			
		||||
    uint16_t par_t1;         // calibration data for temperature compensation
 | 
			
		||||
    int16_t  par_t2;
 | 
			
		||||
    int8_t   par_t3;
 | 
			
		||||
 | 
			
		||||
    uint16_t par_p1;         // calibration data for pressure compensation
 | 
			
		||||
    int16_t  par_p2;
 | 
			
		||||
    int8_t   par_p3;
 | 
			
		||||
    int16_t  par_p4;
 | 
			
		||||
    int16_t  par_p5;
 | 
			
		||||
    int8_t   par_p7;
 | 
			
		||||
    int8_t   par_p6;
 | 
			
		||||
    int16_t  par_p8;
 | 
			
		||||
    int16_t  par_p9;
 | 
			
		||||
    uint8_t  par_p10;
 | 
			
		||||
 | 
			
		||||
    uint16_t par_h1;         // calibration data for humidity compensation
 | 
			
		||||
    uint16_t par_h2;
 | 
			
		||||
    int8_t   par_h3;
 | 
			
		||||
    int8_t   par_h4;
 | 
			
		||||
    int8_t   par_h5;
 | 
			
		||||
    uint8_t  par_h6;
 | 
			
		||||
    int8_t   par_h7;
 | 
			
		||||
 | 
			
		||||
    int8_t   par_gh1;        // calibration data for gas compensation
 | 
			
		||||
    int16_t  par_gh2;
 | 
			
		||||
    int8_t   par_gh3;
 | 
			
		||||
 | 
			
		||||
    int32_t  t_fine;         // temperatur correction factor for P and G
 | 
			
		||||
    uint8_t  res_heat_range;
 | 
			
		||||
    int8_t   res_heat_val;
 | 
			
		||||
    int8_t   range_sw_err;
 | 
			
		||||
 | 
			
		||||
} bme680_calib_data_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief 	BME680 sensor device data structure type
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
 | 
			
		||||
    int       error_code;      // contains the error code of last operation
 | 
			
		||||
 | 
			
		||||
    uint8_t   bus;             // I2C = x, SPI = 1
 | 
			
		||||
    uint8_t   addr;            // I2C = slave address, SPI = 0
 | 
			
		||||
    uint8_t   spi_cs_pin;      // GPIO used as SPI CS
 | 
			
		||||
 | 
			
		||||
    bool      meas_started;    // indicates whether measurement started
 | 
			
		||||
    uint32_t  meas_start_tick; // measurement start time in RTOS ticks
 | 
			
		||||
    uint8_t   meas_status;     // last sensor status (for internal use only)
 | 
			
		||||
 | 
			
		||||
    bme680_settings_t    settings;    // sensor settings
 | 
			
		||||
    bme680_calib_data_t  calib_data;  // calibration data of the sensor
 | 
			
		||||
 | 
			
		||||
} bme680_sensor_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif /* End of CPP guard */
 | 
			
		||||
 | 
			
		||||
#endif /* __BME680_TYPES_H__ */
 | 
			
		||||
							
								
								
									
										9
									
								
								extras/bme680/component.mk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								extras/bme680/component.mk
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
# Component makefile for extras/bme60
 | 
			
		||||
 | 
			
		||||
# expected anyone using bme680 driver includes it as 'bme680/bme680.h'
 | 
			
		||||
INC_DIRS += $(bme680_ROOT).. 
 | 
			
		||||
 | 
			
		||||
# args for passing into compile rule generation
 | 
			
		||||
bme680_SRC_DIR =  $(bme680_ROOT)
 | 
			
		||||
 | 
			
		||||
$(eval $(call component_compile_rules,bme680))
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue