Many changes from 2018
[owSlave2.git] / common / I2C / BME680.c
1 // Copyright (c) 2015, Tobias Mueller tm(at)tm3d.de\r
2 // All rights reserved.\r
3 //\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
6 // met:\r
7 //\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
13 //    distribution.\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
20 //\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
32 #ifdef  __4MHZ__\r
33 #define F_CPU 4000000UL\r
34 #else\r
35 #define F_CPU 8000000UL\r
36 #endif\r
37 #include <avr/io.h>\r
38 \r
39 \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
75 \r
76 \r
77 #include <util/delay.h>\r
78 #include <avr/pgmspace.h>\r
79 #include <avr/interrupt.h>\r
80 \r
81 #include "TWI_Master.h"\r
82 #include "BME680.h"\r
83 \r
84 #define WC 0b11101100\r
85 #define RC 0b11101101\r
86 typedef union {\r
87         volatile uint8_t d[41];\r
88         struct {\r
89                 uint8_t fr1;\r
90                 int16_t t2;\r
91                 int8_t t3;\r
92                 uint8_t fr2; //4\r
93                 uint16_t p1;\r
94                 int16_t p2; //7\r
95                 int8_t p3;\r
96                 uint8_t fr3; //10\r
97                 int16_t p4;\r
98                 int16_t p5;\r
99                 int8_t p7;\r
100                 int8_t p6;\r
101                 uint8_t fr4[2]; //17-18\r
102                 int16_t p8;\r
103                 int16_t p9;\r
104                 uint8_t p10;\r
105                 uint8_t fr5; //24\r
106                 uint16_t h2_; //25 +26\r
107                 uint8_t h1_;  //halb und halb 26+27\r
108                 int8_t h3;\r
109                 int8_t h4;\r
110                 int8_t h5;\r
111                 uint8_t h6;\r
112                 int8_t h7;//32\r
113                 uint16_t t1;\r
114                 int16_t gh2;\r
115                 int8_t gh1;\r
116                 int8_t gh3; //38\r
117                 int8_t fr6;// 39;\r
118                 int8_t fr7; //40;\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
126         };\r
127 } calib_t;\r
128 \r
129 volatile calib_t calib;\r
130 \r
131 \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
137 \r
138 \r
139 #define BME680_MAX_HUMIDITY_VALUE               (102400)\r
140 #define BME680_MIN_HUMIDITY_VALUE               (0)\r
141 \r
142 \r
143 //ME680_CALIB_I2C_ADDR_1,\r
144 //                                              a_data_u8,\r
145 //                                              BME680_CALIB_DATA_LENGTH_GAS);\r
146                                 /* read the humidity and gas\r
147                                 calibration data*/\r
148 /*                              com_status = (enum bme680_return_type)\r
149                                              bme680->bme680_bus_read(\r
150                                              bme680->dev_addr,\r
151                                              BME680_CALIB_I2C_ADDR_2,\r
152                                             (a_data_u8 +\r
153                                             BME680_CALIB_DATA_LENGTH_GAS),\r
154                                             BME680_CALIB_DATA_LENGTH);\r
155 \r
156 \r
157 \r
158                                                 */\r
159 \r
160 \r
161 void setup_read(uint8_t addr) {\r
162         I2c_StartCondition();\r
163         I2c_WriteByte(WC);\r
164         I2c_WriteByte(addr);  //Ctrl hum\r
165         I2c_StartCondition();\r
166         I2c_WriteByte (RC);\r
167         \r
168 }\r
169 \r
170 void setup_write(uint8_t addr) {\r
171         I2c_StartCondition();\r
172         I2c_WriteByte(WC);\r
173         I2c_WriteByte(addr);  //Ctrl hum\r
174 }\r
175 \r
176 \r
177 uint8_t readone(uint8_t addr) {\r
178         setup_read(addr);\r
179         uint8_t b=I2c_ReadByte(NO_ACK);\r
180         I2c_StopCondition();\r
181         return b;\r
182 }\r
183 \r
184 void writeone(uint8_t addr,uint8_t b) {\r
185         setup_write(addr);\r
186         I2c_WriteByte(b);  //Ctrl hum\r
187         I2c_StopCondition();\r
188 }\r
189 \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
195         }\r
196         calib.d[BME680_CALIB_DATA_LENGTH_GAS-1]=I2c_ReadByte(NO_ACK);\r
197         I2c_StopCondition();\r
198 \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
202         }\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
208 \r
209 \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
214 \r
215         \r
216         /*\r
217         \r
218         I2c_StartCondition();\r
219         I2c_WriteByte(WC);\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
225 \r
226         */\r
227         calib.ltemp=25;\r
228 \r
229         return b1==0x61;\r
230 \r
231 }\r
232 \r
233 \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
240 \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
247 \r
248 \r
249 double bme680_compensate_gas_double(uint16_t gas_adc_u16, uint8_t gas_range_u8)
250 {
251         double gas_res_d = 0;
252
253         
254         
255         int8_t range_switching_error_val = 0;
256
257         double var1 = 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];
262
263         range_switching_error_val =     calib.range_switching_error;
264
265
266         var1 = (1340.0 + (5.0 * range_switching_error_val))*a1;
267
268         gas_res_d = var1*a2/(gas_adc_u16-512.0+var1);
269         return gas_res_d;
270 }
271 \r
272 \r
273 void readBMP680(int16_t *T,uint16_t *H,uint32_t *P,uint16_t *G){\r
274 \r
275 \r
276         \r
277         int32_t var1 ;
278         int32_t var2 ;
279         int32_t var3 ;
280         int32_t var4 ;
281         int32_t var5 ;
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));
294
295                 var5 = (131 * calib.res_heat_val) + 65536;
296
297                 res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
298                 res_heat = (uint8_t) ((res_heat_x100 + 50) / 100);
299         }\r
300         uint16_t duration=100;\r
301         uint8_t factor = 0;
302
303         while ((duration) > 0x3F) {
304                 (duration) = (duration) >> 2;
305                 factor += 1;
306         }
307         (duration) = (duration) + (factor * 64);
308 \r
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
313         setup_write(0x70);\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
325 \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
331 \r
332 \r
333         writeone(0x74,0x91);\r
334         _delay_ms(1000);\r
335         \r
336         uint8_t bx=0x91;\r
337         while ((bx&0x01)==0x01) {\r
338                 bx=readone(0x74);\r
339                 _delay_ms(5);\r
340         }\r
341 \r
342         //volatile uint8_t rs=readone(0x2B);\r
343         uint32_t Th,Hh,Ph;\r
344         setup_read(0x1F);\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
354         setup_read(0x2A);\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
359         *P=*G;\r
360         \r
361         *G= bme680_compensate_gas_double(*G,g2&0xF)/10.0;\r
362 \r
363         int32_t temp_comp = 0;\r
364 \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
372 \r
373         int32_t temp_scaled = 0;\r
374         int32_t var6    = 0;\r
375         int32_t humidity_comp = 0;\r
376 \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
382 \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
388 \r
389         var3 = var1 * var2;\r
390 \r
391         var4 = ((((int32_t)calib.h6) << 7) +\r
392                 ((temp_scaled * (int32_t)calib.h7) /\r
393                 ((int32_t)100))) >> 4;\r
394 \r
395         var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;\r
396         var6 = (var4 * var5) >> 1;\r
397 \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
403 \r
404     int32_t pressure_comp = 0;//int -> 5684\r
405 \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
414     var1 = var1 >> 18;\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
421     else\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
430 \r
431     pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +\r
432     ((int32_t)calib.p7 << 7)) >> 4);\r
433 \r
434 \r
435 \r
436 \r
437         \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
442         //*P=rs;\r
443         *T=g1;\r
444         *H=g2;\r
445         //*P=\r
446 \r
447 }\r
448 \r