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
33static void parse_sensor_data(struct bmp280_t *bmp, uint8_t *data);
34static void parse_calib_data(struct bmp280_t *bmp, uint8_t *data);
35PRINT_CONFIG_MSG("BMP280 uses double precision compensation")
38static bool bmp280_config(struct bmp280_t *bmp);
39static void bmp280_register_write(struct bmp280_t *bmp, uint8_t reg, uint8_t value);
41
42
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
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
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
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
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]);
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) {
218 bmp->status = BMP280_STATUS_UNINIT;
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
231static void parse_sensor_data(struct bmp280_t *bmp, uint8_t *data)
232{
233 /* Temporary variables to store the sensor data */
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
258static 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
281static 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
300static 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
329static 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
359static 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
384static 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.
@ 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
@ BMP_280
Definition bmp280.h:59
#define BMP280_DATA_START_REG_ADDR
Definition bmp280_regs.h:63
#define BMP280_IIR_FILTER_COEFF_16
#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
#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)
#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
#define BMP280_POWER_NORMAL_MODE
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:202
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:222
@ 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")
uint16_t foo
Definition main_demo5.c:58
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.