Compare commits
10 Commits
b3783a13da
...
72572e2f9a
Author | SHA1 | Date | |
---|---|---|---|
72572e2f9a | |||
cc3cd94374 | |||
a5a125482c | |||
d942cd8d9e | |||
06baae7e04 | |||
42ab393dce | |||
73b4262ea3 | |||
20b8c8c0f0 | |||
644f99985e | |||
23de126d97 |
BIN
.gitea/gas.png
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 112 KiB |
BIN
.gitea/hum.png
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 148 KiB |
BIN
.gitea/press.png
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 110 KiB |
BIN
.gitea/temp.png
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 152 KiB |
7
.gitignore
vendored
@ -1,2 +1,7 @@
|
|||||||
*.o
|
*.o
|
||||||
bme680
|
bme680
|
||||||
|
bme680_i2c
|
||||||
|
bme680_spi
|
||||||
|
bme680_log*
|
||||||
|
plot/*.png
|
||||||
|
plot/*.txt
|
41
Makefile
@ -1,17 +1,38 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
OPT=-O2 -std=c99 -Wall -Wextra -W -pedantic
|
CFLAGS = -g -O0 -Wall -Wextra -Wpedantic -Wshadow -Wformat=2 -Wfloat-equal \
|
||||||
CFLAGS=-I. $(OPT)
|
-Wconversion -Wcast-align -Wpointer-arith -Wstrict-overflow=5 \
|
||||||
CFILES=$(wildcard ./*.c)
|
-Wwrite-strings -Wcast-qual -Wswitch-default -Wswitch-enum \
|
||||||
OBJECTS=$(patsubst %.c,%.o, $(CFILES))
|
-Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes \
|
||||||
BINARY=bme680
|
-Wmissing-declarations -Wredundant-decls -Wold-style-definition \
|
||||||
|
-Winline -Wlogical-op -Wjump-misses-init -Wdouble-promotion \
|
||||||
|
-Wformat-overflow=2 -Wformat-signedness -Wmissing-include-dirs \
|
||||||
|
-Wnull-dereference -Wstack-usage=1024 -Wpacked -Woverlength-strings \
|
||||||
|
-Wvla -Walloc-zero -Wduplicated-cond -Wduplicated-branches -Wrestrict \
|
||||||
|
-fanalyzer -I. -std=c89
|
||||||
|
|
||||||
all: $(BINARY)
|
CFILES = $(wildcard *.c)
|
||||||
|
OBJECTS = $(CFILES:.c=.o)
|
||||||
|
BIN = bme680
|
||||||
|
|
||||||
$(BINARY): $(OBJECTS)
|
all: spi i2c log
|
||||||
$(CC) $^ -o $@
|
|
||||||
|
log: $(OBJECTS)
|
||||||
|
@echo ">>> $(BIN)_log_spi"
|
||||||
|
@$(CC) $(CFLAGS) -DUSE_SPI -std=gnu99 $^ cmd/log.c -o "$(BIN)_log_spi"
|
||||||
|
@echo ">>> $(BIN)_log_i2c"
|
||||||
|
@$(CC) $(CFLAGS) -DUSE_I2C -std=gnu99 $^ cmd/log.c -o "$(BIN)_log_i2c"
|
||||||
|
|
||||||
|
spi: $(OBJECTS)
|
||||||
|
@echo ">>> $(BIN)_spi"
|
||||||
|
@$(CC) $(CFLAGS) -DUSE_SPI $^ cmd/main.c -o "$(BIN)_spi"
|
||||||
|
|
||||||
|
i2c: $(OBJECTS)
|
||||||
|
@echo ">>> $(BIN)_i2c"
|
||||||
|
@$(CC) $(CFLAGS) -DUSE_I2C $^ cmd/main.c -o "$(BIN)_i2c"
|
||||||
|
|
||||||
%.o:%.c
|
%.o:%.c
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
@echo "cc $<"
|
||||||
|
@$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(OBJECTS) $(BINARY)
|
@rm -rf $(OBJECTS)
|
126
README.md
@ -14,7 +14,21 @@ Connecting the purple BME680 module board to SPI:
|
|||||||
| SCLK | "SCL" | GPIO 11 (Pin 23) |
|
| SCLK | "SCL" | GPIO 11 (Pin 23) |
|
||||||
| CS | "CS" | GPIO 8 (Pin 24) |
|
| CS | "CS" | GPIO 8 (Pin 24) |
|
||||||
|
|
||||||
## spi demo
|
### build
|
||||||
|
```sh
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
This will create demo programs `bme680_i2c` and `bme680_spi`, and logging programs `bme680_log_i2c` and `bme680_log_spi`. They all expect the pin/devices specified in `spi.c` and `i2c.c`.
|
||||||
|
|
||||||
|
The loggers spit out the following every minute:
|
||||||
|
```
|
||||||
|
2024-08-19T18:20:00+0100 22.2358 101068 65.8092 11054.4 1
|
||||||
|
```
|
||||||
|
`Date`, `Temperature °C`, `Pressure Pa`, `% RH`, `Measured Gas resistance Ω`, `Heat stability bit`
|
||||||
|
|
||||||
|
>Note: disregard measured gas resistance if the heat stability bit is not 1.
|
||||||
|
|
||||||
|
## bme680_{i2c,spi} demo output
|
||||||
```
|
```
|
||||||
par_t1: 26203
|
par_t1: 26203
|
||||||
par_t2: 26519
|
par_t2: 26519
|
||||||
@ -53,50 +67,9 @@ gas resistance: 12100.310308 Ohm
|
|||||||
=== heat_stab_r: 1
|
=== heat_stab_r: 1
|
||||||
```
|
```
|
||||||
|
|
||||||
## i2c demo
|
|
||||||
```
|
|
||||||
par_t1: 26125
|
|
||||||
par_t2: 26370
|
|
||||||
par_t3: 3
|
|
||||||
par_p1: 36262
|
|
||||||
par_p2: -10371
|
|
||||||
par_p3: 88
|
|
||||||
par_p4: 6713
|
|
||||||
par_p5: -103
|
|
||||||
par_p6: 30
|
|
||||||
par_p7: 31
|
|
||||||
par_p8: -251
|
|
||||||
par_p9: -3158
|
|
||||||
par_p10: 30
|
|
||||||
par_h1: 776
|
|
||||||
par_h2: 1010
|
|
||||||
par_h3: 0
|
|
||||||
par_h4: 45
|
|
||||||
par_h5: 20
|
|
||||||
par_h6: 120
|
|
||||||
par_h7: -100
|
|
||||||
par_g1: 183
|
|
||||||
par_g2: 59281
|
|
||||||
par_g3: 18
|
|
||||||
range_switching_error: 19
|
|
||||||
res_heat_range: 1
|
|
||||||
res_heat_val: 39
|
|
||||||
float mode
|
|
||||||
tfine: 97289.819111
|
|
||||||
temp: 19.001918 degC
|
|
||||||
press: 100226.479673 Pa
|
|
||||||
humidity: 67.022216 % RH
|
|
||||||
gas resistance: 14702.868852 Ohm
|
|
||||||
== for heater target=300.0 and ambient temp=19.0 (degC)
|
|
||||||
=== gas_valid_r: 1
|
|
||||||
=== heat_stab_r: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: Do not trust the gas resistance measurement if `heat_stab_r` is not `1`.
|
|
||||||
|
|
||||||
## Burn-in / logging
|
## Burn-in / logging
|
||||||
|
|
||||||
See file `example/log.c`
|
See file `cmd/log.c`
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@ -105,64 +78,11 @@ See file `example/log.c`
|
|||||||
|
|
||||||
Compile and run
|
Compile and run
|
||||||
```sh
|
```sh
|
||||||
stdbuf -o0 ./bme680 2>&1 | tee -a log.txt
|
$ make
|
||||||
```
|
$ mkdir data
|
||||||
|
$ stdbuf -o0 ./bme680_log_i2c 2>&1 | tee -a data/i2c.txt &
|
||||||
This will give an output similar to this:
|
$ stdbuf -o0 ./bme680_log_spi 2>&1 | tee -a data/spi.txt &
|
||||||
```
|
# wait a couple of hours or days ..
|
||||||
2024-05-14T13:03:02+0100 20.8916 99836.7 68.6594 7180.73 1
|
$ cd plot
|
||||||
2024-05-14T13:04:03+0100 20.8658 99840.3 68.7844 7171.53 1
|
$ ./plot.sh
|
||||||
2024-05-14T13:05:03+0100 20.8979 99838.6 68.7759 7162.35 1
|
|
||||||
2024-05-14T13:06:03+0100 20.9208 99843.8 68.6436 7166.93 1
|
|
||||||
2024-05-14T13:07:03+0100 20.9303 99845.4 68.747 7144.05 1
|
|
||||||
2024-05-14T13:08:03+0100 20.9249 99846 68.7122 7139.49 0
|
|
||||||
2024-05-14T13:09:04+0100 20.9036 99845.2 68.7224 7157.76 1
|
|
||||||
2024-05-14T13:10:04+0100 20.8737 99850.5 68.575 7144.05 1
|
|
||||||
2024-05-14T13:11:04+0100 20.8753 99850.6 68.8879 7139.49 1
|
|
||||||
2024-05-14T13:12:04+0100 20.9152 99849.3 68.8602 7134.94 1
|
|
||||||
```
|
|
||||||
|
|
||||||
If last field is not 1 then the measurement, at least for gas resistance, cannot be trusted.
|
|
||||||
```sh
|
|
||||||
sed -n '/1$/p' log.txt > test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Then graph with gnuplot
|
|
||||||
```
|
|
||||||
# gnuplot
|
|
||||||
reset
|
|
||||||
|
|
||||||
set key autotitle columnhead
|
|
||||||
set terminal pngcairo enhanced size 2*1920/3,2*1080/3
|
|
||||||
set grid
|
|
||||||
set xdata time
|
|
||||||
set timefmt "%Y-%m-%dT%H:%M:%S%z"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# gas res vs time
|
|
||||||
set title "[I_{dac}=100, 100ms, target=300 C] GasRes over time"
|
|
||||||
set xlabel "Time"
|
|
||||||
set ylabel "Gas Resistance (OHM)"
|
|
||||||
set output "gas.png"
|
|
||||||
plot 'test.txt' u 1:5 w p pt 3 ps 1 t "BME680"
|
|
||||||
|
|
||||||
|
|
||||||
set title "[I_{dac}=100, 100ms, target=300 C] Temperature over time"
|
|
||||||
set xlabel "Time"
|
|
||||||
set ylabel "Temperature (C)"
|
|
||||||
set output "temp.png"
|
|
||||||
plot 'test.txt' u 1:2 w p pt 3 ps 1 t "BME680"
|
|
||||||
|
|
||||||
set title "[I_{dac}=100, 100ms, target=300 C] Pressure over time"
|
|
||||||
set xlabel "Time"
|
|
||||||
set ylabel "Pressure (Pa)"
|
|
||||||
set output "press.png"
|
|
||||||
plot 'test.txt' u 1:3 w p pt 3 ps 1 t "BME680"
|
|
||||||
|
|
||||||
set title "[I_{dac}=100, 100ms, target=300 C] Humidity over time"
|
|
||||||
set xlabel "Time"
|
|
||||||
set ylabel "Humidity (%RH)"
|
|
||||||
set output "hum.png"
|
|
||||||
plot 'test.txt' u 1:4 w p pt 3 ps 1 t "BME680"
|
|
||||||
```
|
```
|
||||||
|
242
bme680.c
@ -1,8 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "bme680.h"
|
#include "bme680.h"
|
||||||
#include "registers.h"
|
|
||||||
|
|
||||||
|
|
||||||
static void calc_temp_comp(bme680_t *bme680);
|
static void calc_temp_comp(bme680_t *bme680);
|
||||||
static void calc_press_comp(bme680_t *bme680);
|
static void calc_press_comp(bme680_t *bme680);
|
||||||
@ -152,9 +150,9 @@ int bme680_reset(bme680_t *bme680) {
|
|||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
/* configure device */
|
/* configure device */
|
||||||
int bme680_configure(bme680_t *bme680) {
|
int bme680_configure(bme680_t *bme680) {
|
||||||
uint8_t meas, hum, filter, ctrl_gas1, ctrl_gas0, err;
|
uint8_t meas, hum, filter, ctrl_gas1, ctrl_gas0, i;
|
||||||
int i;
|
int err = 0;
|
||||||
meas = hum = filter = err = 0;
|
meas = hum = filter = 0;
|
||||||
|
|
||||||
/* ctrl_meas. the last 0 is ticked on to enable forced mode,
|
/* ctrl_meas. the last 0 is ticked on to enable forced mode,
|
||||||
* but the config has to be written first. strange behaviour.
|
* but the config has to be written first. strange behaviour.
|
||||||
@ -281,6 +279,16 @@ int bme680_read(bme680_t *bme680) {
|
|||||||
/* These arrays are used to compute a sensor heating value `res_heat' */
|
/* These arrays are used to compute a sensor heating value `res_heat' */
|
||||||
/* for a specified heating target, specified in degree C. */
|
/* for a specified heating target, specified in degree C. */
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
/*
|
||||||
|
* Below functions are out of the datasheet
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Woverflow"
|
||||||
|
#pragma GCC diagnostic ignored "-Wstrict-overflow"
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||||
|
|
||||||
static double const_array1[16] = {
|
static double const_array1[16] = {
|
||||||
1, 1, 1, 1, 1, 0.99, 1, 0.992, 1,
|
1, 1, 1, 1, 1, 0.99, 1, 0.992, 1,
|
||||||
1, 0.998, 0.995, 1, 0.99, 1, 1
|
1, 0.998, 0.995, 1, 0.99, 1, 1
|
||||||
@ -299,7 +307,6 @@ static int const_array1_int[16] = {
|
|||||||
2147483647
|
2147483647
|
||||||
};
|
};
|
||||||
|
|
||||||
/* long int maybe */
|
|
||||||
static int const_array2_int[16] = {
|
static int const_array2_int[16] = {
|
||||||
4096000000, 2048000000, 1024000000, 512000000, 255744255,
|
4096000000, 2048000000, 1024000000, 512000000, 255744255,
|
||||||
127110228, 64000000, 32258064, 16016016, 8000000, 4000000,
|
127110228, 64000000, 32258064, 16016016, 8000000, 4000000,
|
||||||
@ -375,7 +382,7 @@ static void calc_press_comp_2 (bme680_t *bme680 ) {
|
|||||||
((int32_t)bme680->cal.par_p3 << 5)) >> 3) + (((int32_t)bme680->cal.par_p2 * var1) >> 1);
|
((int32_t)bme680->cal.par_p3 << 5)) >> 3) + (((int32_t)bme680->cal.par_p2 * var1) >> 1);
|
||||||
var1 = var1 >> 18;
|
var1 = var1 >> 18;
|
||||||
var1 = ((32768 + var1) * (int32_t)bme680->cal.par_p1) >> 15;
|
var1 = ((32768 + var1) * (int32_t)bme680->cal.par_p1) >> 15;
|
||||||
press_comp = 1048576 - bme680->adc.press; // bosch code pg 19 says "press_raw" here ???
|
press_comp = 1048576 - bme680->adc.press; /* bosch code pg 19 says "press_raw" here ??? */
|
||||||
press_comp = (uint32_t)((press_comp - (var2 >> 12)) * ((uint32_t)3125));
|
press_comp = (uint32_t)((press_comp - (var2 >> 12)) * ((uint32_t)3125));
|
||||||
if (press_comp >= (1 << 30))
|
if (press_comp >= (1 << 30))
|
||||||
press_comp = ((press_comp / (uint32_t)var1) << 1);
|
press_comp = ((press_comp / (uint32_t)var1) << 1);
|
||||||
@ -444,100 +451,6 @@ static void calc_hum_comp (bme680_t *bme680) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************/
|
|
||||||
// TODO: read one big contiguous block
|
|
||||||
int bme680_calibrate(bme680_t *bme680) {
|
|
||||||
uint8_t buffer[3] = {0, 0 ,0};
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
/* temperature */
|
|
||||||
err |= read_dev(bme680, 0xE9, buffer, 2);
|
|
||||||
bme680->cal.par_t1 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x8A, buffer, 2);
|
|
||||||
bme680->cal.par_t2 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x8C, buffer, 1);
|
|
||||||
bme680->cal.par_t3 = buffer[0];
|
|
||||||
|
|
||||||
|
|
||||||
/* pressure */
|
|
||||||
err |= read_dev(bme680, 0x8E, buffer, 2);
|
|
||||||
bme680->cal.par_p1 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x90, buffer, 2);
|
|
||||||
bme680->cal.par_p2 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x92, buffer, 1);
|
|
||||||
bme680->cal.par_p3 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x94, buffer, 2);
|
|
||||||
bme680->cal.par_p4 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x96, buffer, 2);
|
|
||||||
bme680->cal.par_p5 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x99, buffer, 1);
|
|
||||||
bme680->cal.par_p6 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x98, buffer, 1);
|
|
||||||
bme680->cal.par_p7 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x9C, buffer, 1);
|
|
||||||
bme680->cal.par_p8 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x9E, buffer, 2);
|
|
||||||
bme680->cal.par_p9 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xA0, buffer, 1);
|
|
||||||
bme680->cal.par_p10 = buffer[0];
|
|
||||||
|
|
||||||
|
|
||||||
/* humidity */
|
|
||||||
err |= read_dev(bme680, 0xE2, buffer, 2);
|
|
||||||
bme680->cal.par_h1 = (buffer[1] << 4) | (buffer[0] & 0xF);
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE1, buffer, 2);
|
|
||||||
bme680->cal.par_h2 = (buffer[0] << 4) | ((buffer[1] >> 4) & 0xF);
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE4, buffer, 1);
|
|
||||||
bme680->cal.par_h3 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE5, buffer, 1);
|
|
||||||
bme680->cal.par_h4 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE6, buffer, 1);
|
|
||||||
bme680->cal.par_h5 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE7, buffer, 1);
|
|
||||||
bme680->cal.par_h6 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xE8, buffer, 1);
|
|
||||||
bme680->cal.par_h7 = buffer[0];
|
|
||||||
|
|
||||||
|
|
||||||
/* gas */
|
|
||||||
err |= read_dev(bme680, 0xED, buffer, 1);
|
|
||||||
bme680->cal.par_g1 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xEB, buffer, 2);
|
|
||||||
bme680->cal.par_g2 = (buffer[1] << 8) | buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0xEE, buffer, 1);
|
|
||||||
bme680->cal.par_g3 = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x04, buffer, 1);
|
|
||||||
bme680->cal.range_switching_error = buffer[0];
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x02, buffer, 1);
|
|
||||||
bme680->cal.res_heat_range = (buffer[0] >> 4) & 3;
|
|
||||||
|
|
||||||
err |= read_dev(bme680, 0x00, buffer, 1);
|
|
||||||
bme680->cal.res_heat_val = buffer[0];
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
static void calc_gas_res_1(bme680_t *bme680) {
|
static void calc_gas_res_1(bme680_t *bme680) {
|
||||||
double var1, gas_res;
|
double var1, gas_res;
|
||||||
@ -568,36 +481,6 @@ static void calc_gas_res(bme680_t *bme680) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************/
|
|
||||||
void bme680_print_calibration (bme680_t *bme680) {
|
|
||||||
printf("par_t1: %d\n", bme680->cal.par_t1);
|
|
||||||
printf("par_t2: %d\n", bme680->cal.par_t2);
|
|
||||||
printf("par_t3: %d\n", bme680->cal.par_t3);
|
|
||||||
printf("par_p1: %d\n", bme680->cal.par_p1);
|
|
||||||
printf("par_p2: %d\n", bme680->cal.par_p2);
|
|
||||||
printf("par_p3: %d\n", bme680->cal.par_p3);
|
|
||||||
printf("par_p4: %d\n", bme680->cal.par_p4);
|
|
||||||
printf("par_p5: %d\n", bme680->cal.par_p5);
|
|
||||||
printf("par_p6: %d\n", bme680->cal.par_p6);
|
|
||||||
printf("par_p7: %d\n", bme680->cal.par_p7);
|
|
||||||
printf("par_p8: %d\n", bme680->cal.par_p8);
|
|
||||||
printf("par_p9: %d\n", bme680->cal.par_p9);
|
|
||||||
printf("par_p10: %d\n", bme680->cal.par_p10);
|
|
||||||
printf("par_h1: %d\n", bme680->cal.par_h1);
|
|
||||||
printf("par_h2: %d\n", bme680->cal.par_h2);
|
|
||||||
printf("par_h3: %d\n", bme680->cal.par_h3);
|
|
||||||
printf("par_h4: %d\n", bme680->cal.par_h4);
|
|
||||||
printf("par_h5: %d\n", bme680->cal.par_h5);
|
|
||||||
printf("par_h6: %d\n", bme680->cal.par_h6);
|
|
||||||
printf("par_h7: %d\n", bme680->cal.par_h7);
|
|
||||||
printf("par_g1: %d\n", bme680->cal.par_g1);
|
|
||||||
printf("par_g2: %d\n", bme680->cal.par_g2);
|
|
||||||
printf("par_g3: %d\n", bme680->cal.par_g3);
|
|
||||||
printf("range_switching_error: %d\n", bme680->cal.range_switching_error);
|
|
||||||
printf("res_heat_range: %d\n", bme680->cal.res_heat_range);
|
|
||||||
printf("res_heat_val: %d\n", bme680->cal.res_heat_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
static uint8_t calc_target_1(bme680_t *bme680, double target, double ambient) {
|
static uint8_t calc_target_1(bme680_t *bme680, double target, double ambient) {
|
||||||
double var1, var2, var3, var4, var5;
|
double var1, var2, var3, var4, var5;
|
||||||
@ -606,7 +489,7 @@ static uint8_t calc_target_1(bme680_t *bme680, double target, double ambient) {
|
|||||||
var1 = ((double)bme680->cal.par_g1 / 16.0) + 49.0;
|
var1 = ((double)bme680->cal.par_g1 / 16.0) + 49.0;
|
||||||
var2 = (((double)bme680->cal.par_g2 / 32768.0) * 0.0005) + 0.00235;
|
var2 = (((double)bme680->cal.par_g2 / 32768.0) * 0.0005) + 0.00235;
|
||||||
var3 = (double)bme680->cal.par_g3 / 1024.0;
|
var3 = (double)bme680->cal.par_g3 / 1024.0;
|
||||||
var4 = var1 * (1.0 + (var2 * (double)target)); /* */
|
var4 = var1 * (1.0 + (var2 * (double)target));
|
||||||
var5 = var4 + (var3 * (double)ambient);
|
var5 = var4 + (var3 * (double)ambient);
|
||||||
res_heat = (uint8_t)(3.4 * ((var5 * (4.0 / (4.0 + (double)bme680->cal.res_heat_range)) *
|
res_heat = (uint8_t)(3.4 * ((var5 * (4.0 / (4.0 + (double)bme680->cal.res_heat_range)) *
|
||||||
(1.0 / (1.0 + ((double)bme680->cal.res_heat_val * 0.002)))) - 25));
|
(1.0 / (1.0 + ((double)bme680->cal.res_heat_val * 0.002)))) - 25));
|
||||||
@ -638,3 +521,98 @@ uint8_t bme680_calc_target(bme680_t *bme680, double target, double ambient) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
/********************************************************************/
|
||||||
|
/* TODO: read one big contiguous block */
|
||||||
|
int bme680_calibrate(bme680_t *bme680) {
|
||||||
|
uint8_t buffer[3] = {0, 0 ,0};
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/* temperature */
|
||||||
|
err |= read_dev(bme680, 0xE9, buffer, 2);
|
||||||
|
bme680->cal.par_t1 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x8A, buffer, 2);
|
||||||
|
bme680->cal.par_t2 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x8C, buffer, 1);
|
||||||
|
bme680->cal.par_t3 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
|
||||||
|
/* pressure */
|
||||||
|
err |= read_dev(bme680, 0x8E, buffer, 2);
|
||||||
|
bme680->cal.par_p1 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x90, buffer, 2);
|
||||||
|
bme680->cal.par_p2 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x92, buffer, 1);
|
||||||
|
bme680->cal.par_p3 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x94, buffer, 2);
|
||||||
|
bme680->cal.par_p4 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x96, buffer, 2);
|
||||||
|
bme680->cal.par_p5 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x99, buffer, 1);
|
||||||
|
bme680->cal.par_p6 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x98, buffer, 1);
|
||||||
|
bme680->cal.par_p7 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x9C, buffer, 1);
|
||||||
|
bme680->cal.par_p8 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x9E, buffer, 2);
|
||||||
|
bme680->cal.par_p9 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xA0, buffer, 1);
|
||||||
|
bme680->cal.par_p10 = buffer[0];
|
||||||
|
|
||||||
|
|
||||||
|
/* humidity */
|
||||||
|
err |= read_dev(bme680, 0xE2, buffer, 2);
|
||||||
|
bme680->cal.par_h1 = (buffer[1] << 4) | (buffer[0] & 0xF);
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE1, buffer, 2);
|
||||||
|
bme680->cal.par_h2 = (buffer[0] << 4) | ((buffer[1] >> 4) & 0xF);
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE4, buffer, 1);
|
||||||
|
bme680->cal.par_h3 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE5, buffer, 1);
|
||||||
|
bme680->cal.par_h4 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE6, buffer, 1);
|
||||||
|
bme680->cal.par_h5 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE7, buffer, 1);
|
||||||
|
bme680->cal.par_h6 = buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xE8, buffer, 1);
|
||||||
|
bme680->cal.par_h7 = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
|
||||||
|
/* gas */
|
||||||
|
err |= read_dev(bme680, 0xED, buffer, 1);
|
||||||
|
bme680->cal.par_g1 = buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xEB, buffer, 2);
|
||||||
|
bme680->cal.par_g2 = (buffer[1] << 8) | buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0xEE, buffer, 1);
|
||||||
|
bme680->cal.par_g3 = buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x04, buffer, 1);
|
||||||
|
bme680->cal.range_switching_error = buffer[0];
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x02, buffer, 1);
|
||||||
|
bme680->cal.res_heat_range = (buffer[0] >> 4) & 3;
|
||||||
|
|
||||||
|
err |= read_dev(bme680, 0x00, buffer, 1);
|
||||||
|
bme680->cal.res_heat_val = (int8_t)buffer[0];
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
72
bme680.h
@ -3,6 +3,75 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* REGISTERS */
|
||||||
|
|
||||||
|
/* confuses me too ! */
|
||||||
|
/* SPI page number 0 => 0x00 to 0x7F */
|
||||||
|
/* SPI page number 1 => 0x80 to 0xFF */
|
||||||
|
#define REG_SPI_PAGE(v) ((v > 0x7F) ? 0 : 1)
|
||||||
|
#define REG_SPI_PAGE_MAP(v) (v == 0 ? "LOW" : "HIGH")
|
||||||
|
|
||||||
|
#define REG_STATUS 0x73
|
||||||
|
#define REG_RESET 0xE0
|
||||||
|
#define REG_ID 0xD0
|
||||||
|
#define REG_CONFIG 0x75
|
||||||
|
#define REG_CTRL_MEAS 0x74
|
||||||
|
#define REG_CTRL_HUM 0x72
|
||||||
|
|
||||||
|
#define REG_CTRL_GAS_1 0x71
|
||||||
|
#define REG_CTRL_GAS_0 0x70
|
||||||
|
|
||||||
|
#define REG_GAS_WAIT_9 0x6D
|
||||||
|
#define REG_GAS_WAIT_8 0x6C
|
||||||
|
#define REG_GAS_WAIT_7 0x6B
|
||||||
|
#define REG_GAS_WAIT_6 0x6A
|
||||||
|
#define REG_GAS_WAIT_5 0x69
|
||||||
|
#define REG_GAS_WAIT_4 0x68
|
||||||
|
#define REG_GAS_WAIT_3 0x67
|
||||||
|
#define REG_GAS_WAIT_2 0x66
|
||||||
|
#define REG_GAS_WAIT_1 0x65
|
||||||
|
#define REG_GAS_WAIT_0 0x64
|
||||||
|
|
||||||
|
#define REG_RES_HEAT_9 0x63
|
||||||
|
#define REG_RES_HEAT_8 0x62
|
||||||
|
#define REG_RES_HEAT_7 0x61
|
||||||
|
#define REG_RES_HEAT_6 0x60
|
||||||
|
#define REG_RES_HEAT_5 0x5F
|
||||||
|
#define REG_RES_HEAT_4 0x5E
|
||||||
|
#define REG_RES_HEAT_3 0x5D
|
||||||
|
#define REG_RES_HEAT_2 0x5C
|
||||||
|
#define REG_RES_HEAT_1 0x5B
|
||||||
|
#define REG_RES_HEAT_0 0x5A
|
||||||
|
|
||||||
|
#define REG_IDAC_HEAT_9 0x59
|
||||||
|
#define REG_IDAC_HEAT_8 0x58
|
||||||
|
#define REG_IDAC_HEAT_7 0x57
|
||||||
|
#define REG_IDAC_HEAT_6 0x56
|
||||||
|
#define REG_IDAC_HEAT_5 0x55
|
||||||
|
#define REG_IDAC_HEAT_4 0x54
|
||||||
|
#define REG_IDAC_HEAT_3 0x53
|
||||||
|
#define REG_IDAC_HEAT_2 0x52
|
||||||
|
#define REG_IDAC_HEAT_1 0x51
|
||||||
|
#define REG_IDAC_HEAT_0 0x50
|
||||||
|
|
||||||
|
#define REG_GAS_R_LSB 0x2B
|
||||||
|
#define REG_GAS_R_MSB 0x2A
|
||||||
|
|
||||||
|
#define REG_HUM_LSB 0x26
|
||||||
|
#define REG_HUM_MSB 0x25
|
||||||
|
|
||||||
|
#define REG_TEMP_XLSB 0x24
|
||||||
|
#define REG_TEMP_LSB 0x23
|
||||||
|
#define REG_TEMP_MSB 0x22
|
||||||
|
|
||||||
|
#define REG_PRESS_XLSB 0x21
|
||||||
|
#define REG_PRESS_LSB 0x20
|
||||||
|
#define REG_PRESS_MSB 0x1F
|
||||||
|
|
||||||
|
#define REG_MEAS_STATUS 0x1D
|
||||||
|
|
||||||
|
/* END OF REGISTERS */
|
||||||
|
|
||||||
#define BME680_IS_SPI(m) ((m & 1) == 1)
|
#define BME680_IS_SPI(m) ((m & 1) == 1)
|
||||||
#define BME680_IS_FLOAT(m) (((m >> 1) & 1) == 0)
|
#define BME680_IS_FLOAT(m) (((m >> 1) & 1) == 0)
|
||||||
#define BME680_GAS_ENABLED(m) (((m >> 2) & 1) == 1)
|
#define BME680_GAS_ENABLED(m) (((m >> 2) & 1) == 1)
|
||||||
@ -142,7 +211,6 @@ struct bme680 {
|
|||||||
|
|
||||||
typedef struct bme680 bme680_t;
|
typedef struct bme680 bme680_t;
|
||||||
|
|
||||||
|
|
||||||
int bme680_init(bme680_t *bme680, uint8_t mode);
|
int bme680_init(bme680_t *bme680, uint8_t mode);
|
||||||
int bme680_deinit(bme680_t *bme680);
|
int bme680_deinit(bme680_t *bme680);
|
||||||
int bme680_reset(bme680_t *bme680);
|
int bme680_reset(bme680_t *bme680);
|
||||||
@ -156,6 +224,4 @@ int bme680_read_setpoint_index(bme680_t *bme680, uint8_t *index);
|
|||||||
|
|
||||||
uint8_t bme680_calc_target(bme680_t *bme680, double target, double ambient);
|
uint8_t bme680_calc_target(bme680_t *bme680, double target, double ambient);
|
||||||
|
|
||||||
void bme680_print_calibration(bme680_t *bme680);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
31
bme680_util.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "bme680_util.h"
|
||||||
|
|
||||||
|
void bme680_print_calibration (bme680_t *bme680) {
|
||||||
|
printf("par_t1: %d\n", bme680->cal.par_t1);
|
||||||
|
printf("par_t2: %d\n", bme680->cal.par_t2);
|
||||||
|
printf("par_t3: %d\n", bme680->cal.par_t3);
|
||||||
|
printf("par_p1: %d\n", bme680->cal.par_p1);
|
||||||
|
printf("par_p2: %d\n", bme680->cal.par_p2);
|
||||||
|
printf("par_p3: %d\n", bme680->cal.par_p3);
|
||||||
|
printf("par_p4: %d\n", bme680->cal.par_p4);
|
||||||
|
printf("par_p5: %d\n", bme680->cal.par_p5);
|
||||||
|
printf("par_p6: %d\n", bme680->cal.par_p6);
|
||||||
|
printf("par_p7: %d\n", bme680->cal.par_p7);
|
||||||
|
printf("par_p8: %d\n", bme680->cal.par_p8);
|
||||||
|
printf("par_p9: %d\n", bme680->cal.par_p9);
|
||||||
|
printf("par_p10: %d\n", bme680->cal.par_p10);
|
||||||
|
printf("par_h1: %d\n", bme680->cal.par_h1);
|
||||||
|
printf("par_h2: %d\n", bme680->cal.par_h2);
|
||||||
|
printf("par_h3: %d\n", bme680->cal.par_h3);
|
||||||
|
printf("par_h4: %d\n", bme680->cal.par_h4);
|
||||||
|
printf("par_h5: %d\n", bme680->cal.par_h5);
|
||||||
|
printf("par_h6: %d\n", bme680->cal.par_h6);
|
||||||
|
printf("par_h7: %d\n", bme680->cal.par_h7);
|
||||||
|
printf("par_g1: %d\n", bme680->cal.par_g1);
|
||||||
|
printf("par_g2: %d\n", bme680->cal.par_g2);
|
||||||
|
printf("par_g3: %d\n", bme680->cal.par_g3);
|
||||||
|
printf("range_switching_error: %d\n", bme680->cal.range_switching_error);
|
||||||
|
printf("res_heat_range: %d\n", bme680->cal.res_heat_range);
|
||||||
|
printf("res_heat_val: %d\n", bme680->cal.res_heat_val);
|
||||||
|
}
|
8
bme680_util.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef BME680_UTIL_H
|
||||||
|
#define BME680_UTIL_H
|
||||||
|
|
||||||
|
#include "bme680.h"
|
||||||
|
|
||||||
|
void bme680_print_calibration (bme680_t *bme680);
|
||||||
|
|
||||||
|
#endif
|
@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
#include "bme680.h"
|
#include "bme680.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
#define AMBIENT_TEMP_GUESS 19.0
|
#define AMBIENT_TEMP_GUESS 19.0
|
||||||
#define HEATER_TARGET 300.0
|
#define HEATER_TARGET 300.0
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
bme680_t bme680;
|
bme680_t bme680;
|
||||||
@ -20,14 +20,29 @@ int main(void) {
|
|||||||
time_t curr_time;
|
time_t curr_time;
|
||||||
char date[100];
|
char date[100];
|
||||||
|
|
||||||
|
#if defined(USE_SPI) && defined(USE_I2C)
|
||||||
|
#error "Both USE_SPI and USE_I2C are defined. Please define only one."
|
||||||
|
#elif !defined(USE_SPI) && !defined(USE_I2C)
|
||||||
|
#error "Neither USE_SPI nor USE_I2C is defined. Please define one."
|
||||||
|
#elif defined(USE_SPI)
|
||||||
|
bme680.dev.init = spi_init;
|
||||||
|
bme680.dev.read = spi_read;
|
||||||
|
bme680.dev.write = spi_write;
|
||||||
|
bme680.dev.deinit = spi_deinit;
|
||||||
|
#elif defined(USE_I2C)
|
||||||
bme680.dev.init = i2c_init;
|
bme680.dev.init = i2c_init;
|
||||||
bme680.dev.read = i2c_read;
|
bme680.dev.read = i2c_read;
|
||||||
bme680.dev.write = i2c_write;
|
bme680.dev.write = i2c_write;
|
||||||
bme680.dev.deinit = i2c_deinit;
|
bme680.dev.deinit = i2c_deinit;
|
||||||
bme680.dev.sleep = usleep;
|
#endif
|
||||||
|
bme680.dev.sleep = usleep;
|
||||||
mode = BME680_MODE_FLOAT | BME680_I2C | BME680_ENABLE_GAS;
|
|
||||||
|
|
||||||
|
mode = BME680_MODE_FLOAT | BME680_ENABLE_GAS;
|
||||||
|
#if defined(USE_SPI)
|
||||||
|
mode |= BME680_SPI;
|
||||||
|
#elif defined(USE_I2C)
|
||||||
|
mode |= BME680_I2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (bme680_init(&bme680, mode) != 0) {
|
if (bme680_init(&bme680, mode) != 0) {
|
||||||
fprintf(stderr, "bme680_init()\n");
|
fprintf(stderr, "bme680_init()\n");
|
||||||
@ -35,7 +50,11 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
START:
|
START:
|
||||||
bme680_reset(&bme680);
|
if (bme680_reset(&bme680) != 0) {
|
||||||
|
fprintf(stderr, "bme680_reset()\n");
|
||||||
|
bme680_deinit(&bme680);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
if (bme680_calibrate(&bme680) != 0) {
|
if (bme680_calibrate(&bme680) != 0) {
|
||||||
fprintf(stderr, "bme680_calibrate()\n");
|
fprintf(stderr, "bme680_calibrate()\n");
|
||||||
@ -90,7 +109,7 @@ START:
|
|||||||
|
|
||||||
temperature = bme680.fcomp.temp;
|
temperature = bme680.fcomp.temp;
|
||||||
|
|
||||||
// 60 secs
|
/* 60 secs */
|
||||||
usleep(1000*1000*60);
|
usleep(1000*1000*60);
|
||||||
goto START;
|
goto START;
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "bme680.h"
|
#include "bme680.h"
|
||||||
|
#include "bme680_util.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
|
||||||
@ -20,21 +21,33 @@ int main(void) {
|
|||||||
|
|
||||||
/* 1. Assign functions for interacting with the device */
|
/* 1. Assign functions for interacting with the device */
|
||||||
|
|
||||||
// bme680.dev.init = i2c_init;
|
#if defined(USE_SPI) && defined(USE_I2C)
|
||||||
// bme680.dev.read = i2c_read;
|
#error "Both USE_SPI and USE_I2C are defined. Please define only one."
|
||||||
// bme680.dev.write = i2c_write;
|
#elif !defined(USE_SPI) && !defined(USE_I2C)
|
||||||
// bme680.dev.deinit = i2c_deinit;
|
#error "Neither USE_SPI nor USE_I2C is defined. Please define one."
|
||||||
|
#elif defined(USE_SPI)
|
||||||
bme680.dev.init = spi_init;
|
bme680.dev.init = spi_init;
|
||||||
bme680.dev.read = spi_read;
|
bme680.dev.read = spi_read;
|
||||||
bme680.dev.write = spi_write;
|
bme680.dev.write = spi_write;
|
||||||
bme680.dev.deinit = spi_deinit;
|
bme680.dev.deinit = spi_deinit;
|
||||||
|
#elif defined(USE_I2C)
|
||||||
|
bme680.dev.init = i2c_init;
|
||||||
|
bme680.dev.read = i2c_read;
|
||||||
|
bme680.dev.write = i2c_write;
|
||||||
|
bme680.dev.deinit = i2c_deinit;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bme680.dev.sleep = usleep;
|
bme680.dev.sleep = usleep;
|
||||||
|
|
||||||
/* 2. set the device mode */
|
/* 2. set the device mode */
|
||||||
mode = BME680_MODE_FLOAT | BME680_SPI | BME680_ENABLE_GAS;
|
mode = BME680_MODE_FLOAT | BME680_ENABLE_GAS;
|
||||||
/* BME680_MODE_INT | BME680_I2C; */
|
#if defined(USE_SPI)
|
||||||
|
mode |= BME680_SPI;
|
||||||
|
#elif defined(USE_I2C)
|
||||||
|
mode |= BME680_I2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 3. initialise dev func's, and check device id */
|
/* 3. initialise dev func's, and check device id */
|
31
i2c.c
@ -1,8 +1,4 @@
|
|||||||
/*
|
/* Raspberry Pi i2c */
|
||||||
|
|
||||||
Example I2C use on linux/raspberry pi
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -24,42 +20,47 @@ int i2c_init(void) {
|
|||||||
fd = open(I2C_DEVICE, O_RDWR);
|
fd = open(I2C_DEVICE, O_RDWR);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "could not open device: %s\n", I2C_DEVICE);
|
fprintf(stderr, "could not open device: %s\n", I2C_DEVICE);
|
||||||
return I2C_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, I2C_SLAVE, I2C_BME680_ADDRESS) < 0) {
|
if (ioctl(fd, I2C_SLAVE, I2C_BME680_ADDRESS) < 0) {
|
||||||
fprintf(stderr, "failed to acquire bus/talk to slave\n");
|
fprintf(stderr, "failed to acquire bus/talk to slave\n");
|
||||||
close(fd);
|
close(fd);
|
||||||
return I2C_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return I2C_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
|
int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
|
||||||
uint8_t cmd[2] = {reg, 0x00};
|
uint8_t cmd[2];
|
||||||
|
cmd[0] = reg;
|
||||||
|
cmd[1] = 0x00;
|
||||||
|
|
||||||
write(fd, cmd, 2);
|
write(fd, cmd, 2);
|
||||||
|
|
||||||
if (read(fd, dst, size) != (ssize_t)size) {
|
if (read(fd, dst, size) != (ssize_t)size) {
|
||||||
fprintf(stderr, "error read()\n");
|
fprintf(stderr, "error read()\n");
|
||||||
return I2C_ERR;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return I2C_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int i2c_write(uint8_t reg, uint8_t value) {
|
int i2c_write(uint8_t reg, uint8_t value) {
|
||||||
uint8_t cmd[2] = {reg, value};
|
uint8_t cmd[2];
|
||||||
|
cmd[0] = reg;
|
||||||
|
cmd[1] = value;
|
||||||
|
|
||||||
if (write(fd, cmd, 2) != 2) {
|
if (write(fd, cmd, 2) != 2) {
|
||||||
fprintf(stderr, "error write()\n");
|
fprintf(stderr, "error write()\n");
|
||||||
return I2C_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return I2C_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_deinit(void) {
|
int i2c_deinit(void) {
|
||||||
@ -67,6 +68,6 @@ int i2c_deinit(void) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return I2C_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
i2c.h
@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define I2C_OK 0
|
|
||||||
#define I2C_ERR 1
|
|
||||||
|
|
||||||
int i2c_init (void);
|
int i2c_init (void);
|
||||||
int i2c_read (uint8_t reg, uint8_t *dst, uint32_t size);
|
int i2c_read (uint8_t reg, uint8_t *dst, uint32_t size);
|
||||||
int i2c_write (uint8_t reg, uint8_t value);
|
int i2c_write (uint8_t reg, uint8_t value);
|
||||||
|
38
plot/gnuplot.gpt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# gnuplot
|
||||||
|
reset
|
||||||
|
|
||||||
|
set key autotitle columnhead top left spacing 2
|
||||||
|
set terminal pngcairo enhanced size 2*1920/3,2*1080/3
|
||||||
|
set grid linewidth 2
|
||||||
|
set xdata time
|
||||||
|
set timefmt "%Y-%m-%dT%H:%M:%S%z"
|
||||||
|
set xtics format "%d/%m\n%H:%M"
|
||||||
|
|
||||||
|
# gas res vs time
|
||||||
|
set title "[I_{dac}=100, 100ms, target=300 C] GasRes over time"
|
||||||
|
set xlabel "Time"
|
||||||
|
set ylabel "Gas Resistance (OHM)"
|
||||||
|
set output "gas.png"
|
||||||
|
plot 'i2c.txt' u 1:5 w p pt 3 ps 1 t "bme680-i2c", \
|
||||||
|
'spi.txt' u 1:5 w p pt 3 ps 1 t "bme680-spi"
|
||||||
|
|
||||||
|
set title "Temperature over time"
|
||||||
|
set xlabel "Time"
|
||||||
|
set ylabel "Temperature (C)"
|
||||||
|
set output "temp.png"
|
||||||
|
plot '../data/i2c.txt' u 1:2 w p pt 3 ps 1 t "bme680-i2c", \
|
||||||
|
'../data/spi.txt' u 1:2 w p pt 3 ps 1 t "bme680-spi"
|
||||||
|
|
||||||
|
set title "Pressure over time"
|
||||||
|
set xlabel "Time"
|
||||||
|
set ylabel "Pressure (Pa)"
|
||||||
|
set output "press.png"
|
||||||
|
plot '../data/i2c.txt' u 1:3 w p pt 3 ps 1 t "bme680-i2c", \
|
||||||
|
'../data/spi.txt' u 1:3 w p pt 3 ps 1 t "bme680-spi"
|
||||||
|
|
||||||
|
set title "Humidity over time"
|
||||||
|
set xlabel "Time"
|
||||||
|
set ylabel "Humidity (%RH)"
|
||||||
|
set output "hum.png"
|
||||||
|
plot '../data/i2c.txt' u 1:4 w p pt 3 ps 1 t "bme680-i2c", \
|
||||||
|
'../data/spi.txt' u 1:4 w p pt 3 ps 1 t "bme680-spi"
|
5
plot/plot.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
sed -n '/1$/p' ../data/spi.txt > spi.txt
|
||||||
|
sed -n '/1$/p' ../data/i2c.txt > i2c.txt
|
||||||
|
gnuplot gnuplot.gpt
|
70
registers.h
@ -1,70 +0,0 @@
|
|||||||
#ifndef REGISTERS_H
|
|
||||||
#define REGISTERS_H
|
|
||||||
|
|
||||||
/* SPI page number 0 => 0x00 to 0x7F */
|
|
||||||
/* SPI page number 1 => 0x80 to 0xFF */
|
|
||||||
#define REG_SPI_PAGE(v) ((v > 0x7F) ? 0 : 1)
|
|
||||||
#define REG_SPI_PAGE_MAP(v) (v == 0 ? "LOW" : "HIGH")
|
|
||||||
|
|
||||||
#define REG_STATUS 0x73
|
|
||||||
#define REG_RESET 0xE0
|
|
||||||
#define REG_ID 0xD0
|
|
||||||
#define REG_CONFIG 0x75
|
|
||||||
#define REG_CTRL_MEAS 0x74
|
|
||||||
#define REG_CTRL_HUM 0x72
|
|
||||||
|
|
||||||
#define REG_CTRL_GAS_1 0x71
|
|
||||||
#define REG_CTRL_GAS_0 0x70
|
|
||||||
|
|
||||||
#define REG_GAS_WAIT_9 0x6D
|
|
||||||
#define REG_GAS_WAIT_8 0x6C
|
|
||||||
#define REG_GAS_WAIT_7 0x6B
|
|
||||||
#define REG_GAS_WAIT_6 0x6A
|
|
||||||
#define REG_GAS_WAIT_5 0x69
|
|
||||||
#define REG_GAS_WAIT_4 0x68
|
|
||||||
#define REG_GAS_WAIT_3 0x67
|
|
||||||
#define REG_GAS_WAIT_2 0x66
|
|
||||||
#define REG_GAS_WAIT_1 0x65
|
|
||||||
#define REG_GAS_WAIT_0 0x64
|
|
||||||
|
|
||||||
#define REG_RES_HEAT_9 0x63
|
|
||||||
#define REG_RES_HEAT_8 0x62
|
|
||||||
#define REG_RES_HEAT_7 0x61
|
|
||||||
#define REG_RES_HEAT_6 0x60
|
|
||||||
#define REG_RES_HEAT_5 0x5F
|
|
||||||
#define REG_RES_HEAT_4 0x5E
|
|
||||||
#define REG_RES_HEAT_3 0x5D
|
|
||||||
#define REG_RES_HEAT_2 0x5C
|
|
||||||
#define REG_RES_HEAT_1 0x5B
|
|
||||||
#define REG_RES_HEAT_0 0x5A
|
|
||||||
|
|
||||||
#define REG_IDAC_HEAT_9 0x59
|
|
||||||
#define REG_IDAC_HEAT_8 0x58
|
|
||||||
#define REG_IDAC_HEAT_7 0x57
|
|
||||||
#define REG_IDAC_HEAT_6 0x56
|
|
||||||
#define REG_IDAC_HEAT_5 0x55
|
|
||||||
#define REG_IDAC_HEAT_4 0x54
|
|
||||||
#define REG_IDAC_HEAT_3 0x53
|
|
||||||
#define REG_IDAC_HEAT_2 0x52
|
|
||||||
#define REG_IDAC_HEAT_1 0x51
|
|
||||||
#define REG_IDAC_HEAT_0 0x50
|
|
||||||
|
|
||||||
#define REG_GAS_R_LSB 0x2B
|
|
||||||
#define REG_GAS_R_MSB 0x2A
|
|
||||||
|
|
||||||
#define REG_HUM_LSB 0x26
|
|
||||||
#define REG_HUM_MSB 0x25
|
|
||||||
|
|
||||||
#define REG_TEMP_XLSB 0x24
|
|
||||||
#define REG_TEMP_LSB 0x23
|
|
||||||
#define REG_TEMP_MSB 0x22
|
|
||||||
|
|
||||||
#define REG_PRESS_XLSB 0x21
|
|
||||||
#define REG_PRESS_LSB 0x20
|
|
||||||
#define REG_PRESS_MSB 0x1F
|
|
||||||
|
|
||||||
#define REG_MEAS_STATUS 0x1D
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
53
spi.c
@ -1,8 +1,4 @@
|
|||||||
/*
|
/* Raspberry Pi SPI */
|
||||||
|
|
||||||
Example SPI use on linux/raspberry pi
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -35,52 +31,48 @@ Example SPI use on linux/raspberry pi
|
|||||||
|
|
||||||
static int fd;
|
static int fd;
|
||||||
|
|
||||||
//static void print_access(const char *name, uint8_t reg, uint8_t *dst, uint32_t size);
|
|
||||||
|
|
||||||
int spi_init(void) {
|
int spi_init(void) {
|
||||||
|
|
||||||
uint8_t mode = SPI_MODE;
|
uint8_t mode = SPI_MODE;
|
||||||
uint8_t bits = SPI_BITS;
|
uint8_t bits = SPI_BITS;
|
||||||
uint32_t speed = SPI_SPEED;
|
uint32_t speed = SPI_SPEED;
|
||||||
|
|
||||||
if ((fd = open(SPI_DEVICE, O_RDWR)) < 0) {
|
if ((fd = open(SPI_DEVICE, O_RDWR)) < 0) {
|
||||||
fprintf(stderr, "spi open(%s)\n", SPI_DEVICE);
|
fprintf(stderr, "spi open(%s)\n", SPI_DEVICE);
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_RD_MODE, &mode) == -1) {
|
if (ioctl(fd, SPI_IOC_RD_MODE, &mode) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_RD_MODE\n");
|
fprintf(stderr, "SPI_IOC_RD_MODE\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
|
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_WR_MODE\n");
|
fprintf(stderr, "SPI_IOC_WR_MODE\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
|
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_WR_BITS_PER_WORD\n");
|
fprintf(stderr, "SPI_IOC_WR_BITS_PER_WORD\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) {
|
if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_RD_BITS_PER_WORD\n");
|
fprintf(stderr, "SPI_IOC_RD_BITS_PER_WORD\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
|
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_WR_MAX_SPEED_HZ\n");
|
fprintf(stderr, "SPI_IOC_WR_MAX_SPEED_HZ\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) {
|
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) {
|
||||||
fprintf(stderr, "SPI_IOC_RD_MAX_SPEED_HZ\n");
|
fprintf(stderr, "SPI_IOC_RD_MAX_SPEED_HZ\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// puts("spi_init");
|
return 0;
|
||||||
return SPI_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bme680 auto-increments for spi reads */
|
/* bme680 auto-increments for spi reads */
|
||||||
@ -101,11 +93,10 @@ int spi_read(uint8_t reg, uint8_t *dst, uint32_t size) {
|
|||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
|
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
|
||||||
fprintf(stderr, "spi_read()\n");
|
fprintf(stderr, "spi_read()\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print_access("spi_read", reg, dst, size);
|
return 0;
|
||||||
return SPI_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bme680 does NOT auto-increment for spi writes, so one at a time */
|
/* bme680 does NOT auto-increment for spi writes, so one at a time */
|
||||||
@ -126,32 +117,16 @@ int spi_write(uint8_t reg, uint8_t value) {
|
|||||||
|
|
||||||
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
|
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
|
||||||
fprintf(stderr, "spi_write()\n");
|
fprintf(stderr, "spi_write()\n");
|
||||||
return SPI_ERR;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print_access("spi_write", reg, &value, 1);
|
return 0;
|
||||||
return SPI_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int spi_deinit(void) {
|
int spi_deinit(void) {
|
||||||
// puts("spi_deinit");
|
|
||||||
if (fd) {
|
if (fd) {
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SPI_OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static void print_access(const char *name, uint8_t reg, uint8_t *dst, uint32_t size) {
|
|
||||||
printf("%s: %.2X (%d) [", name, reg, size);
|
|
||||||
for(uint32_t i=0; i<size; i++) {
|
|
||||||
printf("%.2X", dst[i]);
|
|
||||||
if (i < (size - 1)) {
|
|
||||||
printf(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("]\n");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
3
spi.h
@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define SPI_OK 0
|
|
||||||
#define SPI_ERR 1
|
|
||||||
|
|
||||||
int spi_init (void);
|
int spi_init (void);
|
||||||
int spi_read (uint8_t reg, uint8_t *dst, uint32_t size);
|
int spi_read (uint8_t reg, uint8_t *dst, uint32_t size);
|
||||||
int spi_write (uint8_t reg, uint8_t value);
|
int spi_write (uint8_t reg, uint8_t value);
|
||||||
|