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