Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
bmp280.c
Go to the documentation of this file.
1 /*
2  * Chris Efstathiou hendrixgr@gmail.com
3  * Florian Sansou florian.sansou@enac.fr
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
28 #include "peripherals/bmp280.h"
29 
33 static void parse_sensor_data(struct bmp280_t *bmp, uint8_t *data);
34 static void parse_calib_data(struct bmp280_t *bmp, uint8_t *data);
35 PRINT_CONFIG_MSG("BMP280 uses double precision compensation")
36 static double compensate_pressure(struct bmp280_t *bmp);
37 static double compensate_temperature(struct bmp280_t *bmp);
38 static bool bmp280_config(struct bmp280_t *bmp);
39 static void bmp280_register_write(struct bmp280_t *bmp, uint8_t reg, uint8_t value);
40 static void bmp280_register_read(struct bmp280_t *bmp, uint8_t reg, uint16_t size);
41 
42 
48 void bmp280_init(struct bmp280_t *bmp)
49 {
50 
51  bmp->data_available = false;
52  bmp->initialized = false;
53  bmp->status = BMP280_STATUS_UNINIT;
54 
55  bmp->config_idx = 0;
56 
57  /* SPI setup */
58  if(bmp->bus == BMP280_SPI) {
59  bmp->spi.trans.cpol = SPICpolIdleHigh;
60  bmp->spi.trans.cpha = SPICphaEdge2;
61  bmp->spi.trans.dss = SPIDss8bit;
62  bmp->spi.trans.bitorder = SPIMSBFirst;
63  bmp->spi.trans.cdiv = SPIDiv16;
64 
65  bmp->spi.trans.select = SPISelectUnselect;
66  bmp->spi.trans.slave_idx = bmp->spi.slave_idx;
67  bmp->spi.trans.output_length = 0;
68  bmp->spi.trans.input_length = 0;
69  bmp->spi.trans.before_cb = NULL;
70  bmp->spi.trans.after_cb = NULL;
71  bmp->spi.trans.input_buf = bmp->spi.rx_buf;
72  bmp->spi.trans.output_buf = bmp->spi.tx_buf;
73  bmp->spi.trans.status = SPITransDone;
74 
75  // in SPI read, the first byte is garbage because writing the register address
76  bmp->rx_buffer = &bmp->spi.rx_buf[1];
77  bmp->tx_buffer = bmp->spi.tx_buf;
78  bmp->rx_length = &bmp->spi.trans.input_length;
79  }
80  /* I2C setup */
81  else {
82 
83  bmp->i2c.trans.slave_addr = bmp->i2c.slave_addr; // slave address
84  bmp->i2c.trans.status = I2CTransDone; // set initial status: Done
85 
86  bmp->rx_buffer = (uint8_t *)bmp->i2c.trans.buf;
87  bmp->tx_buffer = (uint8_t *)bmp->i2c.trans.buf;
88  bmp->rx_length = &bmp->i2c.trans.len_r;
89 
90  }
91 }
92 
101 void bmp280_periodic(struct bmp280_t *bmp)
102 {
103 
104  /* Idle */
105  if((bmp->bus == BMP280_SPI && bmp->spi.trans.status == SPITransDone) ||
106  (bmp->bus == BMP280_I2C && bmp->i2c.trans.status == I2CTransDone)) {
107 
108  switch (bmp->status) {
110  bmp->data_available = false;
111  bmp->initialized = false;
112  bmp->status = BMP280_STATUS_IDLE;
113  break;
114 
115  case BMP280_STATUS_IDLE:
116  /* Request WHO_AM_I */
118  break;
119 
121  // request calibration data
123  //process in bmp280_event()
124  break;
125 
127  /* Start configuring */
128  if(bmp280_config(bmp)) {
130  bmp->initialized = true;
131  }
132  break;
133 
135  // READ THE STATUS BYTE
137  break;
138 
140  // READ ALL 6 DATA REGISTERS
142  break;
143 
144  default:
145  break;
146  }
147  }
148 }
149 
157 void bmp280_event(struct bmp280_t *bmp)
158 {
159  /* Successful transfer */
160  if((bmp->bus == BMP280_SPI && bmp->spi.trans.status == SPITransSuccess) ||
161  (bmp->bus == BMP280_I2C && bmp->i2c.trans.status == I2CTransSuccess)) {
162  switch (bmp->status) {
163 
164  case BMP280_STATUS_IDLE:
165  /* WHO_AM_I */
166  if(bmp->rx_buffer[0] == BMP280_ID_NB) {
167  bmp->device = BMP_280;
169  } else {
170  bmp->status = BMP280_STATUS_IDLE;
171  }
172  break;
173 
175  // compute calib
176  parse_calib_data(bmp, &bmp->rx_buffer[0]);
178  break;
179 
181  if(bmp280_config(bmp)) {
183  bmp->initialized = true;
184  }
185  break;
186 
188  // check status byte
189  if ((bmp->rx_buffer[0] & (BMP280_EOC_BIT | BMP280_NVRAM_COPY_BIT)) == 0) {
191  }
192  break;
193 
195  // parse sensor data, compensate temperature first, then pressure
196  parse_sensor_data(bmp, &bmp->rx_buffer[0]);
198  compensate_pressure(bmp);
199  bmp->data_available = true;
201  break;
202 
203  default:
204  bmp->status = BMP280_STATUS_GET_CALIB; // just to avoid the compiler's warning message
205  break;
206  }
207  if(bmp->bus == BMP280_I2C){
208  bmp->i2c.trans.status = I2CTransDone;
209  }
210  else{
211  bmp->spi.trans.status = SPITransDone;
212  }
213 
214  } else if ((bmp->bus == BMP280_SPI && bmp->spi.trans.status == SPITransFailed) ||
215  (bmp->bus == BMP280_I2C && bmp->i2c.trans.status == I2CTransFailed)) {
216  /* try again */
217  if (!bmp->initialized) {
219  }
220  if(bmp->bus == BMP280_I2C){
221  bmp->i2c.trans.status = I2CTransDone;
222  }
223  else{
224  bmp->spi.trans.status = SPITransDone;
225  }
226  }
227 
228  return;
229 }
230 
231 static void parse_sensor_data(struct bmp280_t *bmp, uint8_t *data)
232 {
233  /* Temporary variables to store the sensor data */
234  uint32_t data_xlsb;
235  uint32_t data_lsb;
236  uint32_t data_msb;
237 
238  // BMP280 HAS THE 6 DATA REGISTERS START AT F7 AND GOING UP TO FC MSB FIRST THEN LSB AND LAST THE XLSB BYTE.
239  // THE FIRST THREE BYTES ARE THE PRESSURE AND THE NEXT 3 THE TEMPERATURE.
240  /* Store the parsed register values for pressure data */
241  data_msb = (uint32_t)data[0] << 16;
242  data_lsb = (uint32_t)data[1] << 8;
243  data_xlsb = (uint32_t)data[2];
244  bmp->raw_pressure = (int32_t)((data_msb | data_lsb | data_xlsb) >> 4);
245 
246  /* Store the parsed register values for temperature data */
247  data_msb = (uint32_t)data[3] << 16;
248  data_lsb = (uint32_t)data[4] << 8;
249  data_xlsb = (uint32_t)data[5];
250  bmp->raw_temperature = (int32_t)((data_msb | data_lsb | data_xlsb) >> 4);
251 }
252 
253 
258 static void parse_calib_data(struct bmp280_t *bmp, uint8_t *data)
259 {
260  bmp->calib.dig_t1 = BMP280_CONCAT_BYTES(data[1], data[0]);
261  bmp->calib.dig_t2 = (int16_t)BMP280_CONCAT_BYTES(data[3], data[2]);
262  bmp->calib.dig_t3 = (int16_t)BMP280_CONCAT_BYTES(data[5], data[4]);
263 
264  bmp->calib.dig_p1 = BMP280_CONCAT_BYTES(data[7], data[6]);
265  bmp->calib.dig_p2 = (int16_t)BMP280_CONCAT_BYTES(data[9], data[8]);
266  bmp->calib.dig_p3 = (int16_t)BMP280_CONCAT_BYTES(data[11], data[10]);
267  bmp->calib.dig_p4 = (int16_t)BMP280_CONCAT_BYTES(data[13], data[12]);
268  bmp->calib.dig_p5 = (int16_t)BMP280_CONCAT_BYTES(data[15], data[14]);
269  bmp->calib.dig_p6 = (int16_t)BMP280_CONCAT_BYTES(data[17], data[16]);
270  bmp->calib.dig_p7 = (int16_t)BMP280_CONCAT_BYTES(data[19], data[18]);
271  bmp->calib.dig_p8 = (int16_t)BMP280_CONCAT_BYTES(data[21], data[20]);
272  bmp->calib.dig_p9 = (int16_t)BMP280_CONCAT_BYTES(data[23], data[22]);
273 
274  return;
275 }
276 
281 static double compensate_temperature(struct bmp280_t *bmp)
282 {
283  double var1 = (((double)bmp->raw_temperature / 16384.0) - ((double)bmp->calib.dig_t1 / 1024.0)) * ((double)bmp->calib.dig_t2);
284  double var2 = ((double)bmp->raw_temperature / 131072.0) - ((double)bmp->calib.dig_t1 / 8192.0);
285  var2 = (var2 * var2) * (double)bmp->calib.dig_t3;
286  int64_t t_fine = (int64_t)(var1 + var2);
287 
288  /* Store t_lin in dev. structure for pressure calculation */
289  bmp->calib.t_fine = t_fine;
290  /* Store compensated temperature in float in structure */
291  bmp->temperature = (((var1 + var2) / 5120.f) * 100);
292 
293  return (double)bmp->temperature;
294 }
295 
300 static double compensate_pressure(struct bmp280_t *bmp)
301 {
302  double var1;
303  double var2;
304  double p;
305 
306  var1 = ((double)bmp->calib.t_fine / 2) - 64000.0;
307  var2 = (var1 * var1 * (double)bmp->calib.dig_p5) / 32768.0;
308  var2 = var2 + (var1 * (double)bmp->calib.dig_p5 * 2.0);
309  var2 = (var2 / 4.0) + ((double)bmp->calib.dig_p4 * 65536.0);
310  var1 = (((double)bmp->calib.dig_p3 * var1 * (var1 / 524288.0)) + ((double)bmp->calib.dig_p2 * var1)) / 524288.0;
311  var1 = (1 + (var1 / 32768.0)) * (double)bmp->calib.dig_p1;
312  p = 1048576.0 - (double)bmp->raw_pressure;
313  p = (p - (var2 / 4096.0)) * (6250.0 / var1);
314  var1 = ((double)bmp->calib.dig_p9 * p) * (p / 2147483648.0);
315  var2 = (p * ((double)bmp->calib.dig_p8)) / 32768.0;
316  p = p + ((var1 + var2 + (double)bmp->calib.dig_p7) / 16.0);
317  bmp->pressure = p;
318 
319  return (p);
320 }
321 
329 static bool bmp280_config(struct bmp280_t *bmp) {
330  // Only one transaction can be made per call to the periodic function
331  switch(bmp->config_idx) {
332  case 0:
333  // From datasheet, recommended config for drone usecase:
334  // osrs_p = 16, osrs_t = 2
336  bmp->config_idx++;
337  break;
338 
339  case 1:
340  // IIR filter = 16
342  bmp->config_idx++;
343  break;
344 
345  default:
346  return true;
347  }
348  return false;
349 }
350 
351 
359 static void bmp280_register_write(struct bmp280_t *bmp, uint8_t reg, uint8_t value) {
360 
361  bmp->tx_buffer[1] = value;
362 
363  /* SPI transaction */
364  if(bmp->bus == BMP280_SPI) {
365  bmp->tx_buffer[0] = (reg & 0x7F); //write command (bit 7 = RW = '0')
366  bmp->spi.trans.output_length = 2;
367  bmp->spi.trans.input_length = 0;
368  spi_submit(bmp->spi.p, &(bmp->spi.trans));
369  }
370  /* I2C transaction */
371  else {
372  bmp->tx_buffer[0] = reg;
373  i2c_transmit(bmp->i2c.p, &(bmp->i2c.trans), bmp->i2c.slave_addr, 2);
374  }
375 }
376 
384 static void bmp280_register_read(struct bmp280_t *bmp, uint8_t reg, uint16_t size) {
385 
386  bmp->tx_buffer[0] = reg | BMP280_READ_FLAG;
387  /* SPI transaction */
388  if(bmp->bus == BMP280_SPI) {
389  bmp->spi.trans.output_length = 2;
390  bmp->spi.trans.input_length = size+1;
391  bmp->tx_buffer[1] = 0;
392  spi_submit(bmp->spi.p, &(bmp->spi.trans));
393  }
394  /* I2C transaction */
395  else {
396  i2c_transceive(bmp->i2c.p, &(bmp->i2c.trans), bmp->i2c.slave_addr, 1, size);
397  }
398 }
399 
static bool bmp280_config(struct bmp280_t *bmp)
Configure the BMP280 device register by register.
Definition: bmp280.c:329
void bmp280_periodic(struct bmp280_t *bmp)
Should be called periodically to request sensor readings.
Definition: bmp280.c:101
static void bmp280_register_read(struct bmp280_t *bmp, uint8_t reg, uint16_t size)
Read a register.
Definition: bmp280.c:384
void bmp280_init(struct bmp280_t *bmp)
Initialize the bmp280 sensor instance.
Definition: bmp280.c:48
void bmp280_event(struct bmp280_t *bmp)
Should be called in the event thread.
Definition: bmp280.c:157
static double compensate_pressure(struct bmp280_t *bmp)
This internal API is used to compensate the raw pressure data and return the compensated pressure dat...
Definition: bmp280.c:300
static void bmp280_register_write(struct bmp280_t *bmp, uint8_t reg, uint8_t value)
Write a register with a value.
Definition: bmp280.c:359
static void parse_sensor_data(struct bmp280_t *bmp, uint8_t *data)
local function to extract raw data from i2c buffer and compute compensation with selected precision
Definition: bmp280.c:231
static void parse_calib_data(struct bmp280_t *bmp, uint8_t *data)
This internal API is used to parse the calibration data, compensates it and store it in device struct...
Definition: bmp280.c:258
static double compensate_temperature(struct bmp280_t *bmp)
This internal API is used to compensate the raw temperature data and return the compensated temperatu...
Definition: bmp280.c:281
Sensor driver for BMP280 sensor.
struct bmp280_reg_calib_data_t calib
calibration data
Definition: bmp280.h:95
enum bmp280_status_t status
state machine status
Definition: bmp280.h:91
volatile bool data_available
data ready flag
Definition: bmp280.h:94
uint8_t config_idx
The current configuration index.
Definition: bmp280.h:109
uint8_t * tx_buffer
Definition: bmp280.h:106
float temperature
temperature in deg Celcius
Definition: bmp280.h:99
uint32_t raw_temperature
uncompensated temperature
Definition: bmp280.h:97
@ BMP280_I2C
Definition: bmp280.h:54
@ BMP280_SPI
Definition: bmp280.h:53
@ BMP280_STATUS_READ_DATA_REGS
Definition: bmp280.h:69
@ BMP280_STATUS_READ_STATUS_REG
Definition: bmp280.h:68
@ BMP280_STATUS_GET_CALIB
Definition: bmp280.h:66
@ BMP280_STATUS_UNINIT
Definition: bmp280.h:64
@ BMP280_STATUS_IDLE
Definition: bmp280.h:65
@ BMP280_STATUS_CONFIGURE
Definition: bmp280.h:67
enum bmp280_bus_t bus
The communication bus used to connect the device SPI/I2C.
Definition: bmp280.h:100
enum bmp_device_t device
The device type detected.
Definition: bmp280.h:92
@ BMP_280
Definition: bmp280.h:59
float pressure
pressure in Pascal
Definition: bmp280.h:98
uint8_t * rx_buffer
Definition: bmp280.h:105
bool initialized
config done flag
Definition: bmp280.h:93
uint32_t raw_pressure
uncompensated pressure
Definition: bmp280.h:96
#define BMP280_DATA_START_REG_ADDR
Definition: bmp280_regs.h:63
#define BMP280_IIR_FILTER_COEFF_16
Definition: bmp280_regs.h:122
#define BMP280_CTRL_MEAS_REG_ADDR
Definition: bmp280_regs.h:71
#define BMP280_CHIP_ID_REG_ADDR
Definition: bmp280_regs.h:68
#define BMP280_CALIB_LSB_DATA_ADDR
Definition: bmp280_regs.h:44
#define BMP280_CONFIG_REG_ADDR
Definition: bmp280_regs.h:72
#define BMP280_READ_FLAG
Definition: bmp280_regs.h:36
#define BMP280_INACTIVITY_HALF_MS
Definition: bmp280_regs.h:109
#define BMP280_CALIB_DATA_LEN
Definition: bmp280_regs.h:45
#define BMP280_NVRAM_COPY_BIT
Definition: bmp280_regs.h:87
#define BMP280_EOC_BIT
Definition: bmp280_regs.h:86
#define BMP280_P_T_DATA_LEN
Definition: bmp280_regs.h:64
#define BMP280_CONCAT_BYTES(msb, lsb)
Definition: bmp280_regs.h:140
#define BMP280_ID_NB
Definition: bmp280_regs.h:82
#define BMP280_STATUS_REG_ADDR
Definition: bmp280_regs.h:70
#define BMP280_OVERSAMPLING_2X_T
Definition: bmp280_regs.h:92
#define BMP280_OVERSAMPLING_16X_P
Definition: bmp280_regs.h:102
#define BMP280_POWER_NORMAL_MODE
Definition: bmp280_regs.h:106
bool i2c_transmit(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len)
Submit a write only transaction.
Definition: i2c.c:324
bool i2c_transceive(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len_w, uint16_t len_r)
Submit a write/read transaction.
Definition: i2c.c:344
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
@ I2CTransDone
transaction set to done by user level
Definition: i2c.h:59
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:533
@ SPICphaEdge2
CPHA = 1.
Definition: spi.h:75
@ SPITransFailed
Definition: spi.h:100
@ SPITransSuccess
Definition: spi.h:99
@ SPITransDone
Definition: spi.h:101
@ SPICpolIdleHigh
CPOL = 1.
Definition: spi.h:84
@ SPISelectUnselect
slave is selected before transaction and unselected after
Definition: spi.h:63
@ SPIMSBFirst
Definition: spi.h:112
@ SPIDiv16
Definition: spi.h:123
@ SPIDss8bit
Definition: spi.h:90
static float p[2][2]
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
int int32_t
Typedef defining 32 bit int type.
Definition: vl53l1_types.h:83
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98