RocketLogger 2.1.3
bme280.c
Go to the documentation of this file.
1
32#include <errno.h>
33#include <stdint.h>
34#include <string.h>
35
36#include <i2c/smbus.h>
37
38#include "../log.h"
39#include "sensor.h"
40
41#include "bme280.h"
42
47
54int bme280_get_id(void);
55
62int bme280_read_calibration(int sensor_identifier);
63
70int bme280_set_parameters(int sensor_identifier);
71
78int bme280_get_index(int sensor_identifier);
79
87static int32_t bme280_compensate_temperature_fine(int sensor_identifier,
88 int32_t temperature_raw);
89
97static int32_t bme280_compensate_temperature(int sensor_identifier,
98 int32_t temperature_raw);
99
108static uint32_t bme280_compensate_pressure(int sensor_identifier,
109 int32_t pressure_raw,
110 int32_t temperature_raw);
111
120static uint32_t bme280_compensate_humidity(int sensor_identifier,
121 int32_t humidity_raw,
122 int32_t temperature_raw);
123
127int32_t bme280_temperature[sizeof(bme280_sensors)] = {0};
128
132int32_t bme280_humidity[sizeof(bme280_sensors)] = {0};
133
137int32_t bme280_pressure[sizeof(bme280_sensors)] = {0};
138
143
144int bme280_init(int sensor_identifier) {
146 if (sensor_bus < 0) {
148 "BME280 I2C bus not initialized properly; %d message: %s", errno,
149 strerror(errno));
150 return sensor_bus;
151 }
152
153 int result;
154
155 uint8_t device_address = (uint8_t)sensor_identifier;
156 result = sensors_init_comm(device_address);
157 if (result < 0) {
158 rl_log(RL_LOG_ERROR, "BME280 I2C initialization failed; %d message: %s",
159 errno, strerror(errno));
160 return result;
161 }
162
163 int sensor_id = bme280_get_id();
164 if (sensor_id != BME280_ID) {
165 rl_log(RL_LOG_ERROR, "BME280 with wrong sensor ID: %d; %d message: %s",
166 sensor_id, errno, strerror(errno));
167 return sensor_id;
168 }
169
170 result = bme280_read_calibration(sensor_identifier);
171 if (result < 0) {
173 "BME280 reading calibration failed; %d message: %s", errno,
174 strerror(errno));
175 return result;
176 }
177
178 result = bme280_set_parameters(sensor_identifier);
179 if (result < 0) {
181 "BME280 setting configuration failed; %d message: %s", errno,
182 strerror(errno));
183 return result;
184 }
185
186 return 0;
187}
188
189void bme280_deinit(int sensor_identifier) {
190 (void)sensor_identifier; // suppress unused parameter warning
191}
192
193int bme280_read(int sensor_identifier) {
195 int sensor_index = bme280_get_index(sensor_identifier);
197
198 // select sensor
199 uint8_t device_address = (uint8_t)sensor_identifier;
200 int result = sensors_init_comm(device_address);
201 if (result < 0) {
202 rl_log(RL_LOG_ERROR, "BME280 I2C communication failed; %d message: %s",
203 errno, strerror(errno));
204 return result;
205 }
206
207 // burst read required for data consistency
208 // i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, __u8
209 // *values)
210 int data_size = i2c_smbus_read_i2c_block_data(
212 if (data_size != BME280_DATA_BLOCK_SIZE) {
213 rl_log(RL_LOG_ERROR, "BME280 reading data block failed; %d message: %s",
214 errno, strerror(errno));
215 return data_size;
216 }
217
218 // reconstruct and compensate data
219 int32_t pressure_raw = (((int32_t)data[0]) << 12) |
220 (((int32_t)data[1]) << 4) |
221 (((int32_t)data[2]) & 0x0f);
222 int32_t temperature_raw = (((int32_t)data[3]) << 12) |
223 (((int32_t)data[4]) << 4) |
224 (((int32_t)data[5]) & 0x0f);
225 int32_t humidity_raw = (((int32_t)data[6]) << 8) | ((int32_t)data[7]);
226
227 bme280_temperature[sensor_index] =
228 bme280_compensate_temperature(sensor_identifier, temperature_raw);
229 bme280_humidity[sensor_index] = (int32_t)bme280_compensate_humidity(
230 sensor_identifier, humidity_raw, temperature_raw);
231 bme280_pressure[sensor_index] = (int32_t)bme280_compensate_pressure(
232 sensor_identifier, pressure_raw, temperature_raw);
233
234 return 0;
235}
236
237int32_t bme280_get_value(int sensor_identifier, int channel) {
238 int sensor_index = bme280_get_index(sensor_identifier);
239
240 switch (channel) {
242 return bme280_temperature[sensor_index];
243
245 return bme280_humidity[sensor_index];
246
248 return bme280_pressure[sensor_index];
249
250 default:
251 return 0;
252 }
253}
254
255int bme280_get_id(void) {
257
258 int read_result = i2c_smbus_read_byte_data(sensor_bus, BME280_REG_ID);
259
260 if (read_result < 0) {
262 "BME280 I2C error reading ID of sensor; %d message: %s", errno,
263 strerror(errno));
264 }
265 return read_result;
266}
267
268int bme280_read_calibration(int sensor_identifier) {
270 int sensor_index = bme280_get_index(sensor_identifier);
271 uint8_t data[26];
272
273 // first calibration data block (0x88...0xA1, 26 values)
274 int data_size1 =
275 i2c_smbus_read_i2c_block_data(sensor_bus, BME280_REG_CALIBRATION_BLOCK1,
277 if (data_size1 != BME280_CALIBRATION_BLOCK1_SIZE) {
279 "BME280 reading calibration block 1 failed; %d message: %s",
280 errno, strerror(errno));
281 return data_size1;
282 }
283
284 bme280_calibration[sensor_index].T1 =
285 ((uint16_t)data[1] << 8) | ((uint16_t)data[0]);
286 bme280_calibration[sensor_index].T2 =
287 ((int16_t)data[3] << 8) | ((int16_t)data[2]);
288 bme280_calibration[sensor_index].T3 =
289 ((int16_t)data[5] << 8) | ((int16_t)data[4]);
290
291 bme280_calibration[sensor_index].P1 =
292 ((uint16_t)data[7] << 8) | ((uint16_t)data[6]);
293 bme280_calibration[sensor_index].P2 =
294 ((int16_t)data[9] << 8) | ((int16_t)data[8]);
295 bme280_calibration[sensor_index].P3 =
296 ((int16_t)data[11] << 8) | ((int16_t)data[10]);
297 bme280_calibration[sensor_index].P4 =
298 ((int16_t)data[13] << 8) | ((int16_t)data[12]);
299 bme280_calibration[sensor_index].P5 =
300 ((int16_t)data[15] << 8) | ((int16_t)data[14]);
301 bme280_calibration[sensor_index].P6 =
302 ((int16_t)data[17] << 8) | ((int16_t)data[16]);
303 bme280_calibration[sensor_index].P7 =
304 ((int16_t)data[19] << 8) | ((int16_t)data[18]);
305 bme280_calibration[sensor_index].P8 =
306 ((int16_t)data[21] << 8) | ((int16_t)data[20]);
307 bme280_calibration[sensor_index].P9 =
308 ((int16_t)data[23] << 8) | ((int16_t)data[22]);
309
310 bme280_calibration[sensor_index].H1 = (uint8_t)data[25];
311
312 // second calibration data block (0xE1...0xE7 [0xF0], 7 [16] values)
313 int data_size2 =
314 i2c_smbus_read_i2c_block_data(sensor_bus, BME280_REG_CALIBRATION_BLOCK2,
316 if (data_size2 != BME280_CALIBRATION_BLOCK2_SIZE) {
318 "BME280 reading calibration block 2 failed; %d message: %s",
319 errno, strerror(errno));
320 return data_size2;
321 }
322
323 bme280_calibration[sensor_index].H2 =
324 ((int16_t)data[1] << 8) | ((int16_t)data[0]);
325 bme280_calibration[sensor_index].H3 = (uint8_t)data[2];
326 bme280_calibration[sensor_index].H4 =
327 ((int16_t)data[3] << 4) | ((int16_t)data[4] & 0x0f);
328 bme280_calibration[sensor_index].H5 =
329 ((int16_t)data[5] << 4) | ((int16_t)data[4] >> 4);
330 bme280_calibration[sensor_index].H6 = (int8_t)data[6];
331
332 return 0;
333}
334
335int bme280_set_parameters(int sensor_identifier) {
336 (void)sensor_identifier; // suppress unused parameter warning
338
339 int result;
340
341 // config: standby 250ms, filter off, no SPI, continuous measurement
342 result = i2c_smbus_write_byte_data(sensor_bus, BME280_REG_CONFIG,
345 if (result < 0) {
347 "BME280 setting config register failed; %d message: %s", errno,
348 strerror(errno));
349 return result;
350 }
351
352 // humidity control: oversampling x1
353 result = i2c_smbus_write_byte_data(sensor_bus, BME280_REG_CONTROL_HUMIDITY,
355 if (result < 0) {
356 rl_log(
358 "BME280 setting humidity control register failed; %d message: %s",
359 errno, strerror(errno));
360 return result;
361 }
362
363 // measure control: oversampling x1, continuous measurement
364 result = i2c_smbus_write_byte_data(sensor_bus, BME280_REG_CONTROL_MEASURE,
368 if (result < 0) {
370 "BME280 setting measure control register failed; %d message: %s",
371 errno, strerror(errno));
372 return result;
373 }
374
375 return 0;
376}
377
378int bme280_get_index(int sensor_identifier) {
379 unsigned int index = 0;
380 while (index < sizeof(bme280_sensors)) {
381 if (sensor_identifier == bme280_sensors[index]) {
382 return (int)index;
383 }
384 index++;
385 }
386 return -1;
387}
388
389static int32_t bme280_compensate_temperature_fine(int sensor_identifier,
390 int32_t temperature_raw) {
391 int sensor_index = bme280_get_index(sensor_identifier);
392
393 int32_t var1, var2, temperature_fine;
394 var1 = ((((temperature_raw >> 3) -
395 ((int32_t)bme280_calibration[sensor_index].T1 << 1))) *
396 ((int32_t)((int16_t)bme280_calibration[sensor_index].T2))) >>
397 11;
398 var2 = (((((temperature_raw >> 4) -
399 ((int32_t)bme280_calibration[sensor_index].T1)) *
400 ((temperature_raw >> 4) -
401 ((int32_t)bme280_calibration[sensor_index].T1))) >>
402 12) *
403 ((int32_t)((int16_t)bme280_calibration[sensor_index].T3))) >>
404 14;
405 temperature_fine = var1 + var2;
406
407 return temperature_fine;
408}
409
410static int32_t bme280_compensate_temperature(int sensor_identifier,
411 int32_t temperature_raw) {
412 int32_t temperature_fine =
413 bme280_compensate_temperature_fine(sensor_identifier, temperature_raw);
414 int32_t temperature = (temperature_fine * 50 + 1280) >> 8;
415 return temperature;
416}
417
418static uint32_t bme280_compensate_pressure(int sensor_identifier,
419 int32_t pressure_raw,
420 int32_t temperature_raw) {
421 int sensor_index = bme280_get_index(sensor_identifier);
422 int64_t var1, var2, pressure;
423
424 int64_t temperature_fine =
425 bme280_compensate_temperature_fine(sensor_identifier, temperature_raw);
426 var1 = temperature_fine - 128000;
427 var2 = var1 * var1 * (int64_t)bme280_calibration[sensor_index].P6 +
428 ((var1 * (int64_t)bme280_calibration[sensor_index].P5) << 17) +
429 (((int64_t)bme280_calibration[sensor_index].P4) << 35);
430 var1 = ((var1 * var1 * (int64_t)bme280_calibration[sensor_index].P3) >> 8) +
431 ((var1 * (int64_t)bme280_calibration[sensor_index].P2) << 12);
432 var1 = (((((int64_t)1) << 47) + var1) *
433 ((int64_t)bme280_calibration[sensor_index].P1)) >>
434 33;
435 if (var1 == 0) {
436 return 0; // avoid exception caused by division by zero
437 }
438 pressure = 1048576 - pressure_raw;
439 pressure = (((pressure << 31) - var2) * 3125) / var1;
440 var1 = (((int64_t)bme280_calibration[sensor_index].P9) * (pressure >> 13) *
441 (pressure >> 13)) >>
442 25;
443 var2 = (((int64_t)bme280_calibration[sensor_index].P8) * pressure) >> 19;
444 pressure = ((pressure + var1 + var2) >> 8) +
445 (((int64_t)bme280_calibration[sensor_index].P7) << 4);
446
447 // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24
448 // integer bits and 8 fractional bits).
449 // Output value of '24674867' represents 24674867/256 = 96386.2 Pa = 963.862
450 // hPa
451 // return (uint32_t)pressure;
452
453 int64_t pressure_rescaled = (1000 * pressure) >> 8;
454 return (uint32_t)pressure_rescaled;
455}
456
457static uint32_t bme280_compensate_humidity(int sensor_identifier,
458 int32_t humidity_raw,
459 int32_t temperature_raw) {
460 int sensor_index = bme280_get_index(sensor_identifier);
461
462 int32_t temperature_fine =
463 bme280_compensate_temperature_fine(sensor_identifier, temperature_raw);
464
465 int32_t humidity = (temperature_fine - ((int32_t)76800));
466 humidity =
467 ((((humidity_raw << 14) -
468 (((int32_t)bme280_calibration[sensor_index].H4) << 20) -
469 (((int32_t)bme280_calibration[sensor_index].H5) * humidity)) +
470 ((int32_t)16384)) >>
471 15) *
472 (((((((humidity * ((int32_t)bme280_calibration[sensor_index].H6)) >>
473 10) *
474 (((humidity * ((int32_t)bme280_calibration[sensor_index].H3)) >>
475 11) +
476 ((int32_t)32768))) >>
477 10) +
478 ((int32_t)2097152)) *
479 ((int32_t)bme280_calibration[sensor_index].H2) +
480 8192) >>
481 14);
482 humidity = (humidity - (((((humidity >> 15) * (humidity >> 15)) >> 7) *
483 ((int32_t)bme280_calibration[sensor_index].H1)) >>
484 4));
485 if (humidity < 0) {
486 humidity = 0;
487 } else if (humidity > 419430400) {
488 humidity = 419430400;
489 }
490
491 // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22
492 // integer and 10 fractional bits).
493 // Output value of '47445' represents 47445/1024 = 46.333 %RH
494 // return (uint32_t)(humidity >> 12);
495
496 uint32_t humidity_rescaled = (((uint64_t)10000 * humidity) >> 22);
497 return humidity_rescaled;
498}
int32_t bme280_humidity[sizeof(bme280_sensors)]
Definition bme280.c:132
const int bme280_sensors[]
Definition bme280.c:46
int bme280_init(int sensor_identifier)
Definition bme280.c:144
int32_t bme280_get_value(int sensor_identifier, int channel)
Definition bme280.c:237
int32_t bme280_temperature[sizeof(bme280_sensors)]
Definition bme280.c:127
int bme280_get_index(int sensor_identifier)
Definition bme280.c:378
int32_t bme280_pressure[sizeof(bme280_sensors)]
Definition bme280.c:137
int bme280_get_id(void)
Definition bme280.c:255
int bme280_read_calibration(int sensor_identifier)
Definition bme280.c:268
int bme280_read(int sensor_identifier)
Definition bme280.c:193
int bme280_set_parameters(int sensor_identifier)
Definition bme280.c:335
void bme280_deinit(int sensor_identifier)
Definition bme280.c:189
#define BME280_REG_CONTROL_MEASURE
Definition bme280.h:55
#define BME280_CALIBRATION_BLOCK1_SIZE
Definition bme280.h:66
#define BME280_OVERSAMPLE_PRESSURE_1
Definition bme280.h:90
#define BME280_REG_CALIBRATION_BLOCK1
Definition bme280.h:49
#define BME280_CHANNEL_TEMPERATURE
Definition bme280.h:42
#define BME280_STANDBY_DURATION_250
Definition bme280.h:102
#define BME280_OVERSAMPLE_HUMIDITY_1
Definition bme280.h:74
#define BME280_DATA_BLOCK_SIZE
Definition bme280.h:69
#define BME280_REG_CONFIG
Definition bme280.h:56
#define BME280_CHANNEL_PRESSURE
Definition bme280.h:44
#define BME280_REG_CALIBRATION_BLOCK2
Definition bme280.h:52
#define BME280_MODE_NORMAL
Definition bme280.h:97
#define BME280_REG_CONTROL_HUMIDITY
Definition bme280.h:53
#define BME280_ID
Definition bme280.h:47
#define BME280_REG_PRESSURE_MSB
Definition bme280.h:57
#define BME280_I2C_ADDRESSES
Definition bme280.h:39
#define BME280_CALIBRATION_BLOCK2_SIZE
Definition bme280.h:67
#define BME280_FILTER_OFF
Definition bme280.h:107
#define BME280_REG_ID
Definition bme280.h:50
#define BME280_OVERSAMPLE_TEMPERATURE_1
Definition bme280.h:84
#define BME280_CHANNEL_HUMIDITY
Definition bme280.h:43
rl_calibration_t data
The actual calibration data.
Definition calibration.h:9
int rl_log(rl_log_level_t log_level, char const *const format,...)
Definition log.c:82
@ RL_LOG_ERROR
Error.
Definition log.h:49
int sensor_bus
I2C sensor bus identifier for communication.
Definition sensor.c:53
int sensors_get_bus(void)
Definition sensor.c:150
int sensors_init_comm(uint8_t device_address)
Definition sensor.c:152