1 // Copyright (c) 2015, Tobias Mueller tm(at)tm3d.de
\r
2 // All rights reserved.
\r
4 // Redistribution and use in source and binary forms, with or without
\r
5 // modification, are permitted provided that the following conditions are
\r
8 // * Redistributions of source code must retain the above copyright
\r
9 // notice, this list of conditions and the following disclaimer.
\r
10 // * Redistributions in binary form must reproduce the above copyright
\r
11 // notice, this list of conditions and the following disclaimer in the
\r
12 // documentation and/or other materials provided with the
\r
14 // * All advertising materials mentioning features or use of this
\r
15 // software must display the following acknowledgement: This product
\r
16 // includes software developed by tm3d.de and its contributors.
\r
17 // * Neither the name of tm3d.de nor the names of its contributors may
\r
18 // be used to endorse or promote products derived from this software
\r
19 // without specific prior written permission.
\r
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
\r
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
\r
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
\r
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
\r
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
\r
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
\r
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
33 #define F_CPU 4000000UL
\r
35 #define F_CPU 8000000UL
\r
40 /** Array Index to Field data mapping for Calibration Data*/
\r
41 #define BME680_T2_LSB_REG (1)
\r
42 #define BME680_T2_MSB_REG (2)
\r
43 #define BME680_T3_REG (3)
\r
44 #define BME680_P1_LSB_REG (5)
\r
45 #define BME680_P1_MSB_REG (6)
\r
46 #define BME680_P2_LSB_REG (7)
\r
47 #define BME680_P2_MSB_REG (8)
\r
48 #define BME680_P3_REG (9)
\r
49 #define BME680_P4_LSB_REG (11)
\r
50 #define BME680_P4_MSB_REG (12)
\r
51 #define BME680_P5_LSB_REG (13)
\r
52 #define BME680_P5_MSB_REG (14)
\r
53 #define BME680_P7_REG (15)
\r
54 #define BME680_P6_REG (16)
\r
55 #define BME680_P8_LSB_REG (19)
\r
56 #define BME680_P8_MSB_REG (20)
\r
57 #define BME680_P9_LSB_REG (21)
\r
58 #define BME680_P9_MSB_REG (22)
\r
59 #define BME680_P10_REG (23)
\r
60 #define BME680_H2_MSB_REG (25)
\r
61 #define BME680_H2_LSB_REG (26)
\r
62 #define BME680_H1_LSB_REG (26)
\r
63 #define BME680_H1_MSB_REG (27)
\r
64 #define BME680_H3_REG (28)
\r
65 #define BME680_H4_REG (29)
\r
66 #define BME680_H5_REG (30)
\r
67 #define BME680_H6_REG (31)
\r
68 #define BME680_H7_REG (32)
\r
69 #define BME680_T1_LSB_REG (33)
\r
70 #define BME680_T1_MSB_REG (34)
\r
71 #define BME680_GH2_LSB_REG (35)
\r
72 #define BME680_GH2_MSB_REG (36)
\r
73 #define BME680_GH1_REG (37)
\r
74 #define BME680_GH3_REG (38)
\r
77 #include <util/delay.h>
\r
78 #include <avr/pgmspace.h>
\r
79 #include <avr/interrupt.h>
\r
81 #include "TWI_Master.h"
\r
84 #define WC 0b11101100
\r
85 #define RC 0b11101101
\r
87 volatile uint8_t d[41];
\r
101 uint8_t fr4[2]; //17-18
\r
106 uint16_t h2_; //25 +26
\r
107 uint8_t h1_; //halb und halb 26+27
\r
119 uint16_t h2; //Berechnung
\r
120 uint16_t h1; //Berechnung
\r
121 int32_t t_fine; //Berechnung bei Temperaturmessung
\r
122 uint8_t res_heat_range;/**<resistance calculation*/
123 int8_t res_heat_val; /**<correction factor*/
124 int8_t range_switching_error;/**<range switching error*/
\r
125 int8_t ltemp; //letzte Temperatur
\r
129 volatile calib_t calib;
\r
132 #define BME680_CALIB_I2C_ADDR_1 (0x89)
\r
133 #define BME680_CALIB_I2C_ADDR_2 (0xE1)
\r
134 #define BME680_PAGE0_I2C_ID_REG (0xD0)
\r
135 #define BME680_CALIB_DATA_LENGTH_GAS (25)
\r
136 #define BME680_CALIB_DATA_LENGTH (16)
\r
139 #define BME680_MAX_HUMIDITY_VALUE (102400)
\r
140 #define BME680_MIN_HUMIDITY_VALUE (0)
\r
143 //ME680_CALIB_I2C_ADDR_1,
\r
145 // BME680_CALIB_DATA_LENGTH_GAS);
\r
146 /* read the humidity and gas
\r
148 /* com_status = (enum bme680_return_type)
\r
149 bme680->bme680_bus_read(
\r
151 BME680_CALIB_I2C_ADDR_2,
\r
153 BME680_CALIB_DATA_LENGTH_GAS),
\r
154 BME680_CALIB_DATA_LENGTH);
\r
161 void setup_read(uint8_t addr) {
\r
162 I2c_StartCondition();
\r
164 I2c_WriteByte(addr); //Ctrl hum
\r
165 I2c_StartCondition();
\r
166 I2c_WriteByte (RC);
\r
170 void setup_write(uint8_t addr) {
\r
171 I2c_StartCondition();
\r
173 I2c_WriteByte(addr); //Ctrl hum
\r
177 uint8_t readone(uint8_t addr) {
\r
179 uint8_t b=I2c_ReadByte(NO_ACK);
\r
180 I2c_StopCondition();
\r
184 void writeone(uint8_t addr,uint8_t b) {
\r
186 I2c_WriteByte(b); //Ctrl hum
\r
187 I2c_StopCondition();
\r
190 int8_t initBME680() {
\r
191 uint8_t b1=readone(0xD0);
\r
192 setup_read(BME680_CALIB_I2C_ADDR_1);
\r
193 for(uint8_t i=0;i<BME680_CALIB_DATA_LENGTH_GAS-1;i++) {
\r
194 calib.d[i]=I2c_ReadByte(ACK);
\r
196 calib.d[BME680_CALIB_DATA_LENGTH_GAS-1]=I2c_ReadByte(NO_ACK);
\r
197 I2c_StopCondition();
\r
199 setup_read(BME680_CALIB_I2C_ADDR_2);
\r
200 for(uint8_t i=BME680_CALIB_DATA_LENGTH_GAS;i<BME680_CALIB_DATA_LENGTH_GAS+BME680_CALIB_DATA_LENGTH-1;i++) {
\r
201 calib.d[i]=I2c_ReadByte(ACK);
\r
203 calib.d[BME680_CALIB_DATA_LENGTH_GAS+BME680_CALIB_DATA_LENGTH-1]=I2c_ReadByte(NO_ACK);
\r
204 I2c_StopCondition();
\r
205 calib.res_heat_range=(readone(0x02)&0x30)>>4;
\r
206 calib.res_heat_val=readone(0);
\r
207 calib.range_switching_error=(readone(0x04)& 0xF0)>>4;
\r
210 calib.h1 = (uint16_t)(((((uint16_t)calib.d[ BME680_H1_MSB_REG]))
\r
211 << 4) | (calib.d[ BME680_H1_LSB_REG] &0x0F));
\r
212 calib.h2 = (uint16_t)(((((uint16_t)calib.d[ BME680_H2_MSB_REG]))
\r
213 << 4) | ((calib.d[ BME680_H2_LSB_REG]) >> 4));
\r
218 I2c_StartCondition();
\r
220 I2c_WriteByte(0x72); //Ctrl hum
\r
221 I2c_WriteByte(0x01); //1x oversembling hum
\r
222 I2c_WriteByte(0x74); //Ctrl hum
\r
223 I2c_WriteByte(0b01010101); //2x oversembling t - 16x oversemmping p - mode cont
\r
224 I2c_StopCondition();
\r
234 const float lookup_k1_range[16] PROGMEM = {
235 1, 1, 1, 1, 1,0.99, 1, 0.992,
236 1, 1, 0.998, 0.995, 1, 0.99, 1, 1};
237 const float lookup_k2_range[16] PROGMEM = {
238 8e6, 4e6, 2e6, 1e6,499500.4995, 248262.1648, 125000, 63004.03226,
239 31281.28128, 15625, 7812.5, 3906.25,1953.125,976.5625, 488.28125, 244.140625};
\r
241 const float lookup_k1_range1[16] = {
242 1, 1, 1, 1, 1,0.99, 1, 0.992,
243 1, 1, 0.998, 0.995, 1, 0.99, 1, 1};
244 const float lookup_k2_range1[16] = {
245 8e6, 4e6, 2e6, 1e6,499500.4995, 248262.1648, 125000, 63004.03226,
246 31281.28128, 15625, 7812.5, 3906.25,1953.125,976.5625, 488.28125, 244.140625};
\r
249 double bme680_compensate_gas_double(uint16_t gas_adc_u16, uint8_t gas_range_u8)
251 double gas_res_d = 0;
255 int8_t range_switching_error_val = 0;
258 float a1= pgm_read_float(&(lookup_k1_range[gas_range_u8]));
259 float a2= pgm_read_float(&(lookup_k2_range[gas_range_u8]));
260 //float a1=lookup_k1_range1[gas_range_u8];
261 //float a2=lookup_k2_range1[gas_range_u8];
263 range_switching_error_val = calib.range_switching_error;
266 var1 = (1340.0 + (5.0 * range_switching_error_val))*a1;
268 gas_res_d = var1*a2/(gas_adc_u16-512.0+var1);
273 void readBMP680(int16_t *T,uint16_t *H,uint32_t *P,uint16_t *G){
\r
282 int32_t res_heat_x100 = 0;
283 uint8_t res_heat = 0;
284 uint16_t heater_temp_u16=350;
285 int16_t ambient_temp_s16=calib.ltemp;
286 if ((heater_temp_u16 >= 200) && (heater_temp_u16 <= 400)) {
287 var1 = (((int32_t)ambient_temp_s16 *
288 calib.gh3) / 10) << 8;
289 var2 = (calib.gh1 + 784) *
290 (((((calib.gh2 + 154009) *
291 heater_temp_u16 * 5) / 100) + 3276800) / 10);
292 var3 = var1 + (var2 >> 1);
293 var4 = (var3 / (calib.res_heat_range + 4));
295 var5 = (131 * calib.res_heat_val) + 65536;
297 res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
298 res_heat = (uint8_t) ((res_heat_x100 + 50) / 100);
300 uint16_t duration=100;
\r
303 while ((duration) > 0x3F) {
304 (duration) = (duration) >> 2;
307 (duration) = (duration) + (factor * 64);
309 //I2c_WriteByte(0x74); //Ctrl hum
\r
310 //I2c_WriteByte(0b01010101); //2x oversembling t - 16x oversemmping p - mode cont
\r
311 // [71] <- 10; [72] <- 04; [73] <- 0C; [74] <- 91; [75] <- 00;
\r
312 // [70] <- 00 [71] <- 10; [72] <- 04; [73] <- 0C; [74] <- 91; [75] <- 00;
\r
314 I2c_WriteByte(0x00);
\r
315 I2c_WriteByte(0x71);
\r
316 I2c_WriteByte(0x10);
\r
317 I2c_WriteByte(0x72);
\r
318 I2c_WriteByte(0x04);
\r
319 I2c_WriteByte(0x73);
\r
320 I2c_WriteByte(0x0C);
\r
321 I2c_WriteByte(0x74);
\r
322 I2c_WriteByte(0x90);
\r
323 I2c_WriteByte(0x75);
\r
324 I2c_WriteByte(0x00);
\r
326 I2c_WriteByte(0x5A);
\r
327 I2c_WriteByte(res_heat);
\r
328 I2c_WriteByte(0x64);
\r
329 I2c_WriteByte(duration);
\r
330 I2c_StopCondition();
\r
333 writeone(0x74,0x91);
\r
337 while ((bx&0x01)==0x01) {
\r
342 //volatile uint8_t rs=readone(0x2B);
\r
345 Ph=I2c_ReadByte(ACK);Ph=Ph<<8;
\r
346 Ph|=I2c_ReadByte(ACK);Ph=Ph<<4;
\r
347 Ph|=I2c_ReadByte(ACK)>>4;
\r
348 Th=I2c_ReadByte(ACK);Th=Th<<8;
\r
349 Th|=I2c_ReadByte(ACK);Th=Th<<4;
\r
350 Th|=I2c_ReadByte(ACK)>>4;
\r
351 Hh=I2c_ReadByte(ACK);Hh=Hh<<8;
\r
352 Hh|=I2c_ReadByte(NO_ACK);
\r
353 I2c_StopCondition();
\r
355 volatile uint8_t g1=I2c_ReadByte(ACK);
\r
356 volatile uint8_t g2=I2c_ReadByte(NO_ACK);
\r
357 I2c_StopCondition();
\r
358 *G=(((uint16_t)g1)<<2)|(g2>>6);
\r
361 *G= bme680_compensate_gas_double(*G,g2&0xF)/10.0;
\r
363 int32_t temp_comp = 0;
\r
365 var1 = ((int32_t)Th >> 3) -
\r
366 ((int32_t)calib.t1 << 1);
\r
367 var2 = (var1 * (int32_t)calib.t2) >> 11;
\r
368 var3 = ((((var1 >> 1) * (var1 >> 1)) >> 12) *
\r
369 ((int32_t)calib.t3 << 4)) >> 14;
\r
370 calib.t_fine = var2 + var3;
\r
371 temp_comp = ((calib.t_fine * 5) + 128) >> 8;
\r
373 int32_t temp_scaled = 0;
\r
375 int32_t humidity_comp = 0;
\r
377 temp_scaled = (((int32_t)calib.t_fine * 5) + 128) >> 8;
\r
378 var1 = (int32_t)Hh -
\r
379 ((int32_t)((int32_t)calib.h1 << 4)) -
\r
380 (((temp_scaled * (int32_t)calib.h3) /
\r
381 ((int32_t)100)) >> 1);
\r
383 var2 = ((int32_t)calib.h2 *
\r
384 (((temp_scaled * (int32_t)calib.h4) /
\r
385 ((int32_t)100)) + (((temp_scaled *
\r
386 ((temp_scaled * (int32_t)calib.h5) /
\r
387 ((int32_t)100))) >> 6) / ((int32_t)100)) + (int32_t)(1 << 14))) >> 10;
\r
389 var3 = var1 * var2;
\r
391 var4 = ((((int32_t)calib.h6) << 7) +
\r
392 ((temp_scaled * (int32_t)calib.h7) /
\r
393 ((int32_t)100))) >> 4;
\r
395 var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
\r
396 var6 = (var4 * var5) >> 1;
\r
398 humidity_comp = (var3 + var6) >> 12;
\r
399 if (humidity_comp > BME680_MAX_HUMIDITY_VALUE)
\r
400 humidity_comp = BME680_MAX_HUMIDITY_VALUE;
\r
401 else if (humidity_comp < BME680_MIN_HUMIDITY_VALUE)
\r
402 humidity_comp = BME680_MIN_HUMIDITY_VALUE;
\r
404 int32_t pressure_comp = 0;//int -> 5684
\r
406 var1 = (((int32_t)calib.t_fine) >> 1) - (int32_t)64000;
\r
407 var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *
\r
408 (int32_t)calib.p6) >> 2;
\r
409 var2 = var2 + ((var1 * (int32_t)calib.p5) << 1);
\r
410 var2 = (var2 >> 2) + ((int32_t)calib.p4 << 16);
\r
411 var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
\r
412 ((int32_t)calib.p3 << 5)) >> 3) +
\r
413 (((int32_t)calib.p2 * var1) >> 1);
\r
415 var1 = (((int32_t)32768 + var1) * (int32_t)calib.p1) >> 15;
\r
416 pressure_comp = (int32_t)1048576 - Ph;
\r
417 pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));
\r
418 var4 = ((int32_t)1 << 31);
\r
419 if (pressure_comp >= var4)
\r
420 pressure_comp = ((pressure_comp / (uint32_t)var1) << 1);
\r
422 pressure_comp = ((pressure_comp << 1) / (uint32_t)var1);
\r
423 var1 = ((int32_t)calib.p9 * (int32_t)(((pressure_comp >> 3) *
\r
424 (pressure_comp >> 3)) >> 13)) >> 12;
\r
425 var2 = ((int32_t)(pressure_comp >> 2) *
\r
426 (int32_t)calib.p8) >> 13;
\r
427 var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *
\r
428 (int32_t)(pressure_comp >> 8) *
\r
429 (int32_t)calib.p10) >> 17;
\r
431 pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +
\r
432 ((int32_t)calib.p7 << 7)) >> 4);
\r
438 *T=(int16_t)temp_comp;
\r
439 calib.ltemp=temp_comp/100;
\r
440 //*P=pressure_comp;
\r
441 *H=(uint16_t)(humidity_comp/10);
\r