RocketLogger  2.0.0
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 
55 int bme280_get_id(void);
56 
63 int bme280_read_calibration(int sensor_identifier);
64 
71 int bme280_set_parameters(int sensor_identifier);
72 
79 int bme280_get_index(int sensor_identifier);
80 
88 static int32_t bme280_compensate_temperature_fine(int sensor_identifier,
89  int32_t temperature_raw);
90 
98 static int32_t bme280_compensate_temperature(int sensor_identifier,
99  int32_t temperature_raw);
100 
109 static uint32_t bme280_compensate_pressure(int sensor_identifier,
110  int32_t pressure_raw,
111  int32_t temperature_raw);
112 
121 static uint32_t bme280_compensate_humidity(int sensor_identifier,
122  int32_t humidity_raw,
123  int32_t temperature_raw);
124 
128 int32_t bme280_temperature[sizeof(bme280_sensors)] = {0};
129 
133 int32_t bme280_humidity[sizeof(bme280_sensors)] = {0};
134 
138 int32_t bme280_pressure[sizeof(bme280_sensors)] = {0};
139 
144 
145 int bme280_init(int sensor_identifier) {
146  int sensor_bus = sensors_get_bus();
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 
190 void bme280_deinit(int sensor_identifier) {
191  (void)sensor_identifier; // suppress unused parameter warning
192 }
193 
194 int bme280_read(int sensor_identifier) {
195  int sensor_bus = sensors_get_bus();
196  int sensor_index = bme280_get_index(sensor_identifier);
197  uint8_t data[BME280_DATA_BLOCK_SIZE];
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 
238 int32_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 
256 int bme280_get_id(void) {
257  int sensor_bus = sensors_get_bus();
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 
269 int bme280_read_calibration(int sensor_identifier) {
270  int sensor_bus = sensors_get_bus();
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 
336 int bme280_set_parameters(int sensor_identifier) {
337  (void)sensor_identifier; // suppress unused parameter warning
338  int sensor_bus = sensors_get_bus();
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(
358  RL_LOG_ERROR,
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 
379 int 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 
390 static 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 
411 static 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 
419 static 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 
458 static 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
uint16_t T1
Definition: bme280.h:119
uint16_t P1
Definition: bme280.h:124