990786770464b92e8706c6a813f296482ce8b184
[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 \r
80 #include "USI_TWI_Master.h"\r
81 #include "BME680.h"\r
82 \r
83 #define WC 0b11101100\r
84 #define RC 0b11101101\r
85 typedef union {\r
86         volatile uint8_t d[41];\r
87         struct {\r
88                 uint8_t fr1;\r
89                 int16_t t2;\r
90                 int8_t t3;\r
91                 uint8_t fr2; //4\r
92                 uint16_t p1;\r
93                 int16_t p2; //7\r
94                 int8_t p3;\r
95                 uint8_t fr3; //10\r
96                 int16_t p4;\r
97                 int16_t p5;\r
98                 int8_t p7;\r
99                 int8_t p6;\r
100                 uint8_t fr4[2]; //17-18\r
101                 int16_t p8;\r
102                 int16_t p9;\r
103                 uint8_t p10;\r
104                 uint8_t fr5; //24\r
105                 uint16_t h2_; //25 +26\r
106                 uint8_t h1_;  //halb und halb 26+27\r
107                 int8_t h3;\r
108                 int8_t h4;\r
109                 int8_t h5;\r
110                 uint8_t h6;\r
111                 int8_t h7;//32\r
112                 uint16_t t1;\r
113                 int16_t gh2;\r
114                 int8_t gh1;\r
115                 int8_t gh3; //38\r
116                 int8_t fr6;// 39;\r
117                 int8_t fr7; //40;\r
118                 uint16_t h2; //Berechnung\r
119                 uint16_t h1; //Berechnung       \r
120                 int32_t t_fine; //Berechnung bei Temperaturmessung      \r
121                 uint8_t  res_heat_range;/**<resistance calculation*/
122                 int8_t  res_heat_val; /**<correction factor*/
123                 int8_t  range_switching_error;/**<range switching error*/\r
124                 int8_t ltemp; //letzte Temperatur\r
125         };\r
126 } calib_t;\r
127 \r
128 volatile calib_t calib;\r
129 \r
130 \r
131 #define BME680_CALIB_I2C_ADDR_1                         (0x89)\r
132 #define BME680_CALIB_I2C_ADDR_2                         (0xE1)\r
133 #define BME680_PAGE0_I2C_ID_REG                         (0xD0)\r
134 #define BME680_CALIB_DATA_LENGTH_GAS                    (25)\r
135 #define BME680_CALIB_DATA_LENGTH                        (16)\r
136 \r
137 \r
138 #define BME680_MAX_HUMIDITY_VALUE               (102400)\r
139 #define BME680_MIN_HUMIDITY_VALUE               (0)\r
140 \r
141 \r
142 //ME680_CALIB_I2C_ADDR_1,\r
143 //                                              a_data_u8,\r
144 //                                              BME680_CALIB_DATA_LENGTH_GAS);\r
145                                 /* read the humidity and gas\r
146                                 calibration data*/\r
147 /*                              com_status = (enum bme680_return_type)\r
148                                              bme680->bme680_bus_read(\r
149                                              bme680->dev_addr,\r
150                                              BME680_CALIB_I2C_ADDR_2,\r
151                                             (a_data_u8 +\r
152                                             BME680_CALIB_DATA_LENGTH_GAS),\r
153                                             BME680_CALIB_DATA_LENGTH);\r
154 \r
155 \r
156 \r
157                                                 */\r
158 \r
159 \r
160 void setup_read(uint8_t addr) {\r
161         I2c_StartCondition();\r
162         I2c_WriteByte(WC);\r
163         I2c_WriteByte(addr);  //Ctrl hum\r
164         I2c_StartCondition();\r
165         I2c_WriteByte (RC);\r
166         \r
167 }\r
168 \r
169 void setup_write(uint8_t addr) {\r
170         I2c_StartCondition();\r
171         I2c_WriteByte(WC);\r
172         I2c_WriteByte(addr);  //Ctrl hum\r
173 }\r
174 \r
175 \r
176 uint8_t readone(uint8_t addr) {\r
177         setup_read(addr);\r
178         uint8_t b=I2c_ReadByte(NO_ACK);\r
179         I2c_StopCondition();\r
180         return b;\r
181 }\r
182 \r
183 void writeone(uint8_t addr,uint8_t b) {\r
184         setup_write(addr);\r
185         I2c_WriteByte(b);  //Ctrl hum\r
186         I2c_StopCondition();\r
187 }\r
188 \r
189 int8_t initBME680() {\r
190         uint8_t b1=readone(0xD0);\r
191         setup_read(BME680_CALIB_I2C_ADDR_1);\r
192         for(uint8_t i=0;i<BME680_CALIB_DATA_LENGTH_GAS-1;i++) {\r
193                 calib.d[i]=I2c_ReadByte(ACK);\r
194         }\r
195         calib.d[BME680_CALIB_DATA_LENGTH_GAS-1]=I2c_ReadByte(NO_ACK);\r
196         I2c_StopCondition();\r
197 \r
198         setup_read(BME680_CALIB_I2C_ADDR_2);\r
199         for(uint8_t i=BME680_CALIB_DATA_LENGTH_GAS;i<BME680_CALIB_DATA_LENGTH_GAS+BME680_CALIB_DATA_LENGTH-1;i++) {\r
200                 calib.d[i]=I2c_ReadByte(ACK);\r
201         }\r
202         calib.d[BME680_CALIB_DATA_LENGTH_GAS+BME680_CALIB_DATA_LENGTH-1]=I2c_ReadByte(NO_ACK);\r
203         I2c_StopCondition();\r
204         calib.res_heat_range=(readone(0x02)&0x30)>>4;\r
205         calib.res_heat_val=readone(0);\r
206         calib.range_switching_error=(readone(0x04)& 0xF0)>>4;\r
207 \r
208 \r
209     calib.h1 = (uint16_t)(((((uint16_t)calib.d[ BME680_H1_MSB_REG]))\r
210                 << 4) | (calib.d[ BME680_H1_LSB_REG] &0x0F));\r
211         calib.h2 = (uint16_t)(((((uint16_t)calib.d[ BME680_H2_MSB_REG]))\r
212                 << 4) | ((calib.d[ BME680_H2_LSB_REG]) >> 4));\r
213 \r
214         \r
215         /*\r
216         \r
217         I2c_StartCondition();\r
218         I2c_WriteByte(WC);\r
219         I2c_WriteByte(0x72);  //Ctrl hum\r
220         I2c_WriteByte(0x01); //1x oversembling hum\r
221         I2c_WriteByte(0x74);  //Ctrl hum\r
222         I2c_WriteByte(0b01010101); //2x oversembling t - 16x oversemmping p - mode cont\r
223         I2c_StopCondition();    \r
224 \r
225         */\r
226         calib.ltemp=25;\r
227 \r
228         return b1==0x61;\r
229 \r
230 }\r
231 \r
232 \r
233 const float lookup_k1_range[16] PROGMEM = {
234         1, 1, 1, 1, 1,0.99, 1, 0.992,
235 1, 1, 0.998, 0.995, 1, 0.99, 1, 1};
236 const float lookup_k2_range[16] PROGMEM = {
237         8e6, 4e6, 2e6, 1e6,499500.4995, 248262.1648, 125000, 63004.03226,
238 31281.28128, 15625, 7812.5, 3906.25,1953.125,976.5625, 488.28125, 244.140625};\r
239 \r
240 double bme680_compensate_gas_double(uint16_t gas_adc_u16, uint8_t gas_range_u8)
241 {
242         double gas_res_d = 0;
243
244         
245         
246         int8_t range_switching_error_val = 0;
247
248         double var1 = 0;
249         float a1= pgm_read_float(&(lookup_k1_range[gas_range_u8]));
250         float a2= pgm_read_float(&(lookup_k2_range[gas_range_u8]));
251
252         range_switching_error_val =     calib.range_switching_error;
253
254
255         var1 = (1340.0 + (5.0 * range_switching_error_val))*a1;
256         gas_res_d = var1*a2/(gas_adc_u16-512.0+var1);
257         return gas_res_d;
258 }
259 \r
260 \r
261 void readBMP680(int16_t *T,uint16_t *H,uint32_t *P,uint16_t *G){\r
262 \r
263 \r
264         \r
265         int32_t var1 ;
266         int32_t var2 ;
267         int32_t var3 ;
268         int32_t var4 ;
269         int32_t var5 ;
270         int32_t res_heat_x100 = 0;
271         uint8_t res_heat = 0;
272         uint16_t heater_temp_u16=350;
273         int16_t ambient_temp_s16=calib.ltemp;
274         if ((heater_temp_u16 >= 200) && (heater_temp_u16 <= 400)) {
275                 var1 = (((int32_t)ambient_temp_s16 *
276                 calib.gh3) / 10) << 8;
277                 var2 = (calib.gh1 + 784) *
278                 (((((calib.gh2 + 154009) *
279                 heater_temp_u16 * 5) / 100) + 3276800) / 10);
280                 var3 = var1 + (var2 >> 1);
281                 var4 = (var3 / (calib.res_heat_range + 4));
282
283                 var5 = (131 * calib.res_heat_val) + 65536;
284
285                 res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
286                 res_heat = (uint8_t) ((res_heat_x100 + 50) / 100);
287         }\r
288         uint16_t duration=100;\r
289         uint8_t factor = 0;
290
291         while ((duration) > 0x3F) {
292                 (duration) = (duration) >> 2;
293                 factor += 1;
294         }
295         (duration) = (duration) + (factor * 64);
296 \r
297         //I2c_WriteByte(0x74);  //Ctrl hum\r
298         //I2c_WriteByte(0b01010101); //2x oversembling t - 16x oversemmping p - mode cont\r
299         // [71] <- 10;  [72] <- 04;  [73] <- 0C;  [74] <- 91;  [75] <- 00;\r
300         // [70] <- 00     [71] <- 10;  [72] <- 04;  [73] <- 0C;  [74] <- 91;  [75] <- 00;\r
301         setup_write(0x70);\r
302         I2c_WriteByte(0x00);\r
303         I2c_WriteByte(0x71);\r
304         I2c_WriteByte(0x10);\r
305         I2c_WriteByte(0x72);\r
306         I2c_WriteByte(0x04);\r
307         I2c_WriteByte(0x73);\r
308         I2c_WriteByte(0x0C);\r
309         I2c_WriteByte(0x74);\r
310         I2c_WriteByte(0x90);\r
311         I2c_WriteByte(0x75);\r
312         I2c_WriteByte(0x00);\r
313 \r
314         I2c_WriteByte(0x5A);\r
315         I2c_WriteByte(res_heat);\r
316         I2c_WriteByte(0x64);\r
317         I2c_WriteByte(duration);\r
318         I2c_StopCondition();\r
319 \r
320 \r
321         writeone(0x74,0x91);\r
322         _delay_ms(1000);\r
323         \r
324         uint8_t bx=0x91;\r
325         while ((bx&0x01)==0x01) {\r
326                 bx=readone(0x74);\r
327                 _delay_ms(5);\r
328         }\r
329 \r
330         //volatile uint8_t rs=readone(0x2B);\r
331         uint32_t Th,Hh,Ph;\r
332         setup_read(0x1F);\r
333         Ph=I2c_ReadByte(ACK);Ph=Ph<<8;\r
334         Ph|=I2c_ReadByte(ACK);Ph=Ph<<4;\r
335         Ph|=I2c_ReadByte(ACK)>>4;\r
336         Th=I2c_ReadByte(ACK);Th=Th<<8;\r
337         Th|=I2c_ReadByte(ACK);Th=Th<<4;\r
338         Th|=I2c_ReadByte(ACK)>>4;       \r
339         Hh=I2c_ReadByte(ACK);Hh=Hh<<8;\r
340         Hh|=I2c_ReadByte(NO_ACK);\r
341         I2c_StopCondition();\r
342         setup_read(0x2A);\r
343         volatile uint8_t g1=I2c_ReadByte(ACK);\r
344         volatile uint8_t g2=I2c_ReadByte(NO_ACK);\r
345         I2c_StopCondition();\r
346         *G=(((uint16_t)g1)<<2)|(g2>>6);\r
347         *P=*G;\r
348         *G= bme680_compensate_gas_double(*G,g2&0xF)/10.0;\r
349 \r
350         int32_t temp_comp = 0;\r
351 \r
352         var1 = ((int32_t)Th >> 3) -\r
353         ((int32_t)calib.t1 << 1);\r
354         var2 = (var1 * (int32_t)calib.t2) >> 11;\r
355         var3 = ((((var1 >> 1) * (var1 >> 1)) >> 12) *\r
356         ((int32_t)calib.t3 << 4)) >> 14;\r
357         calib.t_fine = var2 + var3;\r
358         temp_comp = ((calib.t_fine * 5) + 128) >> 8;\r
359 \r
360         int32_t temp_scaled = 0;\r
361         int32_t var6    = 0;\r
362         int32_t humidity_comp = 0;\r
363 \r
364         temp_scaled = (((int32_t)calib.t_fine * 5) + 128) >> 8;\r
365         var1 = (int32_t)Hh -\r
366                 ((int32_t)((int32_t)calib.h1 << 4)) -\r
367                 (((temp_scaled * (int32_t)calib.h3) /\r
368                 ((int32_t)100)) >> 1);\r
369 \r
370         var2 = ((int32_t)calib.h2 *\r
371                 (((temp_scaled * (int32_t)calib.h4) /\r
372                 ((int32_t)100)) + (((temp_scaled *\r
373                 ((temp_scaled * (int32_t)calib.h5) /\r
374                 ((int32_t)100))) >> 6) / ((int32_t)100)) + (int32_t)(1 << 14))) >> 10;\r
375 \r
376         var3 = var1 * var2;\r
377 \r
378         var4 = ((((int32_t)calib.h6) << 7) +\r
379                 ((temp_scaled * (int32_t)calib.h7) /\r
380                 ((int32_t)100))) >> 4;\r
381 \r
382         var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;\r
383         var6 = (var4 * var5) >> 1;\r
384 \r
385         humidity_comp = (var3 + var6) >> 12;\r
386         if (humidity_comp > BME680_MAX_HUMIDITY_VALUE)\r
387                 humidity_comp = BME680_MAX_HUMIDITY_VALUE;\r
388                 else if (humidity_comp < BME680_MIN_HUMIDITY_VALUE)\r
389                 humidity_comp = BME680_MIN_HUMIDITY_VALUE;\r
390 \r
391     int32_t pressure_comp = 0;//int -> 5684\r
392 \r
393     var1 = (((int32_t)calib.t_fine) >> 1) - (int32_t)64000;\r
394     var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *\r
395     (int32_t)calib.p6) >> 2;\r
396     var2 = var2 + ((var1 * (int32_t)calib.p5) << 1);\r
397     var2 = (var2 >> 2) + ((int32_t)calib.p4 << 16);\r
398     var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *\r
399     ((int32_t)calib.p3 << 5)) >> 3) +\r
400     (((int32_t)calib.p2 * var1) >> 1);\r
401     var1 = var1 >> 18;\r
402     var1 = (((int32_t)32768 + var1) * (int32_t)calib.p1) >> 15;\r
403     pressure_comp = (int32_t)1048576 - Ph;\r
404     pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));\r
405     var4 = ((int32_t)1 << 31);\r
406     if (pressure_comp >= var4)\r
407     pressure_comp = ((pressure_comp / (uint32_t)var1) << 1);\r
408     else\r
409     pressure_comp = ((pressure_comp << 1) / (uint32_t)var1);\r
410     var1 = ((int32_t)calib.p9 * (int32_t)(((pressure_comp >> 3) *\r
411     (pressure_comp >> 3)) >> 13)) >> 12;\r
412     var2 = ((int32_t)(pressure_comp >> 2) *\r
413     (int32_t)calib.p8) >> 13;\r
414     var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *\r
415     (int32_t)(pressure_comp >> 8) *\r
416     (int32_t)calib.p10) >> 17;\r
417 \r
418     pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +\r
419     ((int32_t)calib.p7 << 7)) >> 4);\r
420 \r
421 \r
422 \r
423 \r
424         \r
425         *T=(int16_t)temp_comp;\r
426         calib.ltemp=temp_comp/100;\r
427         //*P=pressure_comp;\r
428         *H=(uint16_t)(humidity_comp/10);\r
429         //*P=rs;\r
430         *T=g1;\r
431         *H=g2;\r
432         //*P=\r
433 \r
434 \r
435 }\r
436 \r