dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_bmp280.c
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  *
26  * Additional note on redistribution: The copyright and license notices above
27  * must be maintained in each individual source file that is a derivative work
28  * of this source file; otherwise redistribution is prohibited.
29  */
30 
31 /* Project Includes */
32 #include "pios.h"
33 
34 #if defined(PIOS_INCLUDE_BMP280) || defined(PIOS_INCLUDE_BMP280_SPI)
35 
36 #include "pios_bmp280_priv.h"
37 #include "pios_semaphore.h"
38 #include "pios_thread.h"
39 #include "pios_queue.h"
40 
41 /* Private constants */
42 
43 /* BMP280 Addresses */
44 #define BMP280_I2C_ADDR 0x76 // 0x77
45 #define BMP280_ID 0xD0
46 #define BMP280_RESET 0xE0
47 #define BMP280_STATUS 0xF3
48 #define BMP280_CTRL_MEAS 0xF4
49 #define BMP280_CONFIG 0xF5
50 #define BMP280_PRESS_MSB 0xF7
51 #define BMP280_PRESS_LSB 0xF8
52 #define BMP280_PRESS_XLSB 0xF9
53 #define BMP280_TEMP_MSB 0xFA
54 #define BMP280_TEMP_LSB 0xFB
55 #define BMP280_TEMP_XLSB 0xFC
56 
57 #define BMP280_CAL_ADDR 0x88
58 
59 #define BMP280_P0 101.3250f
60 
61 #define BMP280_MODE_CONTINUOUS 0x03
62 
63 #define PIOS_BMP_SPI_SPEED 9500000 /* Just shy of 10MHz */
64 
65 /* Private methods */
66 static int32_t PIOS_BMP280_Read(uint8_t address, uint8_t *buffer, uint8_t len);
67 static int32_t PIOS_BMP280_WriteCommand(uint8_t address, uint8_t buffer);
68 
69 static bool PIOS_BMP280_callback(void *ctx, void *output,
70  int ms_to_wait, int *next_call);
71 
72 /* Private types */
73 
74 /* Local Types */
75 
76 enum pios_bmp280_dev_magic {
77  PIOS_BMP280_DEV_MAGIC = 0x32504d42, /* 'BMP2' */
78 };
79 
80 struct bmp280_dev {
81  const struct pios_bmp280_cfg *cfg;
82 #ifndef PIOS_EXCLUDE_BMP280_I2C
83  pios_i2c_t i2c_id;
84 #endif
85 #ifdef PIOS_INCLUDE_BMP280_SPI
86  pios_spi_t spi_id;
87  uint32_t spi_slave;
88 #endif
89 
90  uint32_t compensatedPressure;
91  int32_t compensatedTemperature;
92 
93  uint16_t digT1;
94  int16_t digT2;
95  int16_t digT3;
96  uint16_t digP1;
97  int16_t digP2;
98  int16_t digP3;
99  int16_t digP4;
100  int16_t digP5;
101  int16_t digP6;
102  int16_t digP7;
103  int16_t digP8;
104  int16_t digP9;
105 
106  uint8_t oversampling;
107  enum pios_bmp280_dev_magic magic;
108 
109  struct pios_semaphore *busy;
110 };
111 
112 static struct bmp280_dev *dev;
113 
117 static struct bmp280_dev *PIOS_BMP280_alloc(void)
118 {
119  struct bmp280_dev *bmp280_dev;
120 
121  bmp280_dev = (struct bmp280_dev *)PIOS_malloc(sizeof(*bmp280_dev));
122 
123  if (!bmp280_dev) {
124  return NULL;
125  }
126 
127  *bmp280_dev = (struct bmp280_dev) {
128  .magic = PIOS_BMP280_DEV_MAGIC
129  };
130 
131  bmp280_dev->busy = PIOS_Semaphore_Create();
132 
133  bmp280_dev->magic = PIOS_BMP280_DEV_MAGIC;
134 
135  return(bmp280_dev);
136 }
137 
142 static int32_t PIOS_BMP280_Validate(struct bmp280_dev *dev)
143 {
144  if (dev == NULL)
145  return -1;
146  if (dev->magic != PIOS_BMP280_DEV_MAGIC)
147  return -2;
148  return 0;
149 }
150 
151 static int32_t PIOS_BMP280_Common_Init(const struct pios_bmp280_cfg *cfg)
152 {
153  dev->oversampling = cfg->oversampling;
154  dev->cfg = cfg;
155 
156  uint8_t data[24];
157 
158  if (PIOS_BMP280_Read(BMP280_CAL_ADDR, data, 24) != 0)
159  return -2;
160 
161  dev->digT1 = (data[ 1] << 8) | data[ 0];
162  dev->digT2 = (data[ 3] << 8) | data[ 2];
163  dev->digT3 = (data[ 5] << 8) | data[ 4];
164  dev->digP1 = (data[ 7] << 8) | data[ 6];
165  dev->digP2 = (data[ 9] << 8) | data[ 8];
166  dev->digP3 = (data[11] << 8) | data[10];
167  dev->digP4 = (data[13] << 8) | data[12];
168  dev->digP5 = (data[15] << 8) | data[14];
169  dev->digP6 = (data[17] << 8) | data[16];
170  dev->digP7 = (data[19] << 8) | data[18];
171  dev->digP8 = (data[21] << 8) | data[20];
172  dev->digP9 = (data[23] << 8) | data[22];
173 
174  if ((dev->digT1 == dev->digT2) &&
175  (dev->digT1 == dev->digP1)) {
176  /* Values invariant, so no good device detect */
177  return -11;
178  }
179 
180  if (PIOS_BMP280_WriteCommand(BMP280_CONFIG, 0x00) != 0)
181  return -2;
182 
183  PIOS_SENSORS_RegisterCallback(PIOS_SENSOR_BARO, PIOS_BMP280_callback, dev);
184 
185  return 0;
186 }
187 
193 static int32_t PIOS_BMP280_ClaimDevice(void)
194 {
195  PIOS_Assert(PIOS_BMP280_Validate(dev) == 0);
196 
197  return PIOS_Semaphore_Take(dev->busy, PIOS_SEMAPHORE_TIMEOUT_MAX) == true ? 0 : 1;
198 }
199 
204 static int32_t PIOS_BMP280_ReleaseDevice(void)
205 {
206  PIOS_Assert(PIOS_BMP280_Validate(dev) == 0);
207 
208  return PIOS_Semaphore_Give(dev->busy) == true ? 0 : 1;
209 }
210 
211 
216 static int32_t PIOS_BMP280_StartADC(void)
217 {
218  if (PIOS_BMP280_Validate(dev) != 0)
219  return -1;
220 
221  /* Start the conversion */
222  return(PIOS_BMP280_WriteCommand(BMP280_CTRL_MEAS,
223  dev->oversampling | BMP280_MODE_CONTINUOUS));
224 
225  return 0;
226 }
227 
231 static int32_t PIOS_BMP280_GetDelay() {
232  if (PIOS_BMP280_Validate(dev) != 0)
233  return 100;
234 
235  switch(dev->oversampling) {
237  return 16;
239  return 25;
240  default:
242  return 46;
243  }
244 }
245 
250 static int32_t PIOS_BMP280_ReadADC()
251 {
252  if (PIOS_BMP280_Validate(dev) != 0)
253  return -1;
254 
255  uint8_t data[6];
256 
257  /* Read and store results */
258 
259  if (PIOS_BMP280_Read(BMP280_PRESS_MSB, data, 6) != 0)
260  return -1;
261 
262  static int32_t T = 0;
263 
264  int32_t raw_temperature = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | ((uint32_t)data[5] >> 4));
265 
266  int32_t varT1, varT2;
267 
268  varT1 = ((((raw_temperature >> 3) - ((int32_t)dev->digT1 << 1))) * ((int32_t)dev->digT2)) >> 11;
269  varT2 = (((((raw_temperature >> 4) - ((int32_t)dev->digT1)) * ((raw_temperature >> 4) - ((int32_t)dev->digT1))) >> 12) * ((int32_t)dev->digT3)) >> 14;
270 
271  /* Filter T ourselves */
272  if (!T) {
273  T = (varT1 + varT2) * 5;
274  } else {
275  T = (varT1 + varT2) + (T * 4) / 5; // IIR Gain=5
276  }
277 
278  dev->compensatedTemperature = T;
279 
280  int32_t raw_pressure = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4));
281 
282  if (raw_pressure == 0x80000) {
283  return -1;
284  }
285 
286  int64_t varP1, varP2, P;
287 
288  varP1 = ((int64_t)T / 5) - 128000;
289  varP2 = varP1 * varP1 * (int64_t)dev->digP6;
290  varP2 = varP2 + ((varP1 * (int64_t)dev->digP5) << 17);
291  varP2 = varP2 + (((int64_t)dev->digP4) << 35);
292  varP1= ((varP1 * varP1 * (int64_t)dev->digP3) >> 8) + ((varP1 * (int64_t)dev->digP2) << 12);
293  varP1 = (((((int64_t)1) << 47) + varP1)) * ((int64_t)dev->digP1) >> 33;
294  if (varP1 == 0)
295  {
296  return -1; // avoid exception caused by division by zero
297  }
298  P = 1048576 - raw_pressure;
299  P = (((P << 31) - varP2) * 3125) / varP1;
300  varP1 = (((int64_t)dev->digP9) * (P >> 13) * (P >> 13)) >> 25;
301  varP2 = (((int64_t)dev->digP8) * P) >> 19;
302  dev->compensatedPressure = (uint32_t)((P + varP1 + varP2) >> 8) + (((int64_t)dev->digP7) << 4);
303  return 0;
304 }
305 
306 static inline int32_t PIOS_BMP280_CheckData(const uint8_t *data,
307  const uint8_t *data_b)
308 {
309  int i;
310 
311  /* Verify we got consistent results */
312  for (i = 0; i < 6; i++) {
313  if (data[i] != data_b[i]) {
314  return -3;
315  }
316  }
317 
318  /* Verify the probed data varies */
319  for (i = 1; i < 6; i++) {
320  if (data[i] != data[0]) {
321  return 0;
322  }
323  }
324 
325  return -4;
326 }
327 
328 #ifndef PIOS_EXCLUDE_BMP280_I2C
329 static int32_t PIOS_BMP280_I2C_Read(pios_i2c_t i2c_id,
330  uint8_t address, uint8_t *buffer, uint8_t len)
331 {
332  const struct pios_i2c_txn txn_list[] = {
333  {
334  .info = __func__,
335  .addr = BMP280_I2C_ADDR,
336  .rw = PIOS_I2C_TXN_WRITE,
337  .len = 1,
338  .buf = &address,
339  },
340  {
341  .info = __func__,
342  .addr = BMP280_I2C_ADDR,
343  .rw = PIOS_I2C_TXN_READ,
344  .len = len,
345  .buf = buffer,
346  }
347  };
348 
349  return PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list));
350 }
351 
352 static int32_t PIOS_BMP280_I2C_Write(pios_i2c_t i2c_id,
353  uint8_t *buffer, uint8_t len) {
354  const struct pios_i2c_txn txn_list[] = {
355  {
356  .info = __func__,
357  .addr = BMP280_I2C_ADDR,
358  .rw = PIOS_I2C_TXN_WRITE,
359  .len = len,
360  .buf = buffer,
361  }
362  };
363 
364  return PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list));
365 }
366 
370 int32_t PIOS_BMP280_Init(const struct pios_bmp280_cfg *cfg, pios_i2c_t i2c_device)
371 {
372  uint8_t data[6];
373  uint8_t data_b[6];
374 
375  /* Ignore first result */
376  if (PIOS_BMP280_I2C_Read(i2c_device, BMP280_CAL_ADDR, data, 6) != 0)
377  return -2;
378 
379  if (PIOS_BMP280_I2C_Read(i2c_device, BMP280_CAL_ADDR, data, 6) != 0)
380  return -2;
381 
382  if (PIOS_BMP280_I2C_Read(i2c_device, BMP280_CAL_ADDR, data_b, 6) != 0)
383  return -2;
384 
385  int ret = PIOS_BMP280_CheckData(data, data_b);
386 
387  if (ret) {
388  return ret;
389  }
390 
391  dev = (struct bmp280_dev *) PIOS_BMP280_alloc();
392  if (dev == NULL)
393  return -1;
394 
395  dev->i2c_id = i2c_device;
396 
397  return PIOS_BMP280_Common_Init(cfg);
398 }
399 #endif /* PIOS_EXCLUDE_BMP280_I2C */
400 
401 #ifdef PIOS_INCLUDE_BMP280_SPI
402 static int32_t PIOS_BMP280_ClaimBus(pios_spi_t spi_id, uint32_t spi_slave)
403 {
404  if (PIOS_SPI_ClaimBus(spi_id) != 0)
405  return -2;
406 
408  PIOS_SPI_RC_PinSet(spi_id, spi_slave, false);
410 
411  PIOS_SPI_SetClockSpeed(spi_id, PIOS_BMP_SPI_SPEED);
412 
413  return 0;
414 }
415 
416 static void PIOS_BMP280_ReleaseBus(pios_spi_t spi_id, uint32_t spi_slave)
417 {
418  PIOS_SPI_RC_PinSet(spi_id, spi_slave, true);
419 
420  PIOS_SPI_ReleaseBus(spi_id);
421 }
422 
423 static int32_t PIOS_BMP280_SPI_Read(pios_spi_t spi_id, uint32_t spi_slave,
424  uint8_t address, uint8_t *buffer, uint8_t len) {
425  if (PIOS_BMP280_ClaimBus(spi_id, spi_slave) != 0)
426  return -1;
427 
428  PIOS_SPI_TransferByte(spi_id, 0x80 | address);
429 
430  int ret = PIOS_SPI_TransferBlock(spi_id, NULL, buffer, len);
431 
432  PIOS_BMP280_ReleaseBus(spi_id, spi_slave);
433 
434  return ret;
435 }
436 
437 static int32_t PIOS_BMP280_SPI_Write(pios_spi_t spi_id, uint32_t spi_slave,
438  uint8_t *buffer, uint8_t len) {
439  if (PIOS_BMP280_ClaimBus(spi_id, spi_slave) != 0)
440  return -1;
441 
442  int ret = PIOS_SPI_TransferBlock(spi_id, buffer, NULL, len);
443 
444  PIOS_BMP280_ReleaseBus(spi_id, spi_slave);
445 
446  return ret;
447 }
448 
449 int32_t PIOS_BMP280_SPI_Init(const struct pios_bmp280_cfg *cfg, pios_spi_t spi_device,
450  uint32_t spi_slave)
451 {
452  uint8_t data[6];
453  uint8_t data_b[6];
454 
455  /* Ignore first result */
456  if (PIOS_BMP280_SPI_Read(spi_device, spi_slave,
457  BMP280_CAL_ADDR, data, 6) != 0)
458  return -2;
459 
460  if (PIOS_BMP280_SPI_Read(spi_device, spi_slave,
461  BMP280_CAL_ADDR, data, 6) != 0)
462  return -2;
463 
464  if (PIOS_BMP280_SPI_Read(spi_device, spi_slave,
465  BMP280_CAL_ADDR, data_b, 6) != 0)
466  return -2;
467 
468  int ret = PIOS_BMP280_CheckData(data, data_b);
469 
470  if (ret) {
471  return ret;
472  }
473 
474  dev = (struct bmp280_dev *) PIOS_BMP280_alloc();
475  if (dev == NULL)
476  return -1;
477 
478  dev->spi_id = spi_device;
479  dev->spi_slave = spi_slave;
480 
481  return PIOS_BMP280_Common_Init(cfg);
482 }
483 
484 #endif /* PIOS_INCLUDE_BMP280_SPI */
485 
486 /*
487 * Reads one or more bytes into a buffer
488 * \param[in] the command indicating the address to read
489 * \param[out] buffer destination buffer
490 * \param[in] len number of bytes which should be read
491 * \return 0 if operation was successful
492 * \return -1 if error during I2C transfer
493 */
494 static int32_t PIOS_BMP280_Read(uint8_t address, uint8_t *buffer, uint8_t len)
495 {
496  PIOS_Assert(PIOS_BMP280_Validate(dev) == 0);
497 
498  if (0) {
499 #ifndef PIOS_EXCLUDE_BMP280_I2C
500  } else if (dev->i2c_id) {
501  return PIOS_BMP280_I2C_Read(dev->i2c_id, address, buffer, len);
502 #endif
503 #ifdef PIOS_INCLUDE_BMP280_SPI
504  } else if (dev->spi_id) {
505  return PIOS_BMP280_SPI_Read(dev->spi_id, dev->spi_slave,
506  address, buffer, len);
507 #endif
508  }
509 
510  PIOS_Assert(0);
511  return -1;
512 }
513 
521 static int32_t PIOS_BMP280_WriteCommand(uint8_t address, uint8_t buffer)
522 {
523  uint8_t data[] = {
524  address,
525  buffer,
526  };
527 
528  PIOS_Assert(PIOS_BMP280_Validate(dev) == 0);
529 
530  if (0) {
531 #ifndef PIOS_EXCLUDE_BMP280_I2C
532  } else if (dev->i2c_id) {
533  return PIOS_BMP280_I2C_Write(dev->i2c_id,
534  data, sizeof(data));
535 #endif
536 #ifdef PIOS_INCLUDE_BMP280_SPI
537  } else if (dev->spi_id) {
538  data[0] &= 0x7f; /* Clear high bit */
539  return PIOS_BMP280_SPI_Write(dev->spi_id, dev->spi_slave,
540  data, sizeof(data));
541 #endif
542  }
543 
544  PIOS_Assert(0);
545  return -1;
546 }
547 
552 int32_t PIOS_BMP280_Test()
553 {
554  if (PIOS_BMP280_Validate(dev) != 0)
555  return -1;
556 
557  // TODO: Is there a better way to test this than just checking that pressure/temperature has changed?
558  int32_t currentTemperature = 0;
559  int32_t currentPressure = 0;
560 
561  PIOS_BMP280_ClaimDevice();
562 
563  currentTemperature = dev->compensatedTemperature;
564  currentPressure = dev->compensatedPressure;
565 
566  PIOS_BMP280_StartADC();
567  PIOS_DELAY_WaitmS(PIOS_BMP280_GetDelay());
568  PIOS_BMP280_ReadADC();
569  PIOS_BMP280_ReleaseDevice();
570 
571  if (currentTemperature == dev->compensatedTemperature)
572  return -1;
573 
574  if (currentPressure == dev->compensatedPressure)
575  return -1;
576 
577  return 0;
578 }
579 
580 static bool PIOS_BMP280_callback(void *ctx, void *output,
581  int ms_to_wait, int *next_call)
582 {
583  struct bmp280_dev *dev = (struct bmp280_dev *)ctx;
584 
585  PIOS_Assert(dev);
586  PIOS_Assert(output);
587 
588  // Poll a bit faster than sampling rate
589  *next_call = PIOS_BMP280_GetDelay() * 3 / 5;
590 
591  int32_t read_adc_result = 0;
592 
593  PIOS_BMP280_StartADC();
594 
595  PIOS_BMP280_ClaimDevice();
596  read_adc_result = PIOS_BMP280_ReadADC();
597  PIOS_BMP280_ReleaseDevice();
598 
599  if (read_adc_result) {
600  return false;
601  }
602 
603  struct pios_sensor_baro_data *data = (struct pios_sensor_baro_data *)output;
604 
605  // Compute the altitude from the pressure and temperature and send it out
606  data->pressure = ((float) dev->compensatedPressure) / 256.0f / 1000.0f;
607  float calc_alt = 44330.0f * (1.0f - powf(data->pressure / BMP280_P0, (1.0f / 5.255f)));
608  data->temperature = ((float) dev->compensatedTemperature) / 256.0f / 100.0f;
609  data->altitude = calc_alt;
610 
611  return true;
612 }
613 
614 #endif /* PIOS_INCLUDE_BMP280 */
615 
#define PIOS_SEMAPHORE_TIMEOUT_MAX
Main PiOS header to include all the compiled in PiOS options.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
#define NELEMENTS(x)
Definition: pios.h:192
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
float P[NUMX][NUMX]
Definition: insgps14state.c:66
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
Configuration structure for the BMP280 driver.
#define BMP280_STANDARD_RESOLUTION
static float T[3]
Scales used in NED transform (local tangent plane approx).
Definition: attitude.c:210
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
struct pios_i2c_adapter * pios_i2c_t
Definition: pios_i2c.h:48
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t speed)
int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
Pios sensor structure for generic baro data.
Definition: pios_sensors.h:78
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
int32_t PIOS_BMP280_SPI_Init(const struct pios_bmp280_cfg *cfg, pios_spi_t spi_device, uint32_t spi_slave)
int32_t PIOS_I2C_Transfer(pios_i2c_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns)
int32_t PIOS_SENSORS_RegisterCallback(enum pios_sensor_type type, PIOS_SENSOR_Callback_t callback, void *ctx)
Register a callback-based sensor with the PIOS_SENSORS interface.
Definition: pios_sensors.c:68
uint32_t magic
int32_t PIOS_BMP280_Init(const struct pios_bmp280_cfg *cfg, pios_i2c_t i2c_device)
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
#define BMP280_ULTRA_HIGH_RESOLUTION
const char * info
Definition: pios_i2c.h:41
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
uint32_t len
Definition: pios_i2c.h:44
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
Definition: pios_delay.c:140
#define BMP280_HIGH_RESOLUTION
int32_t PIOS_DELAY_WaituS(uint32_t uS)
Definition: pios_delay.c:116