Contiki-NG
bmp-280-sensor.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup sensortag-cc26xx-bmp-sensor
33  * @{
34  *
35  * \file
36  * Driver for the Sensortag BMP280 Altimeter / Pressure Sensor
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki.h"
40 #include "lib/sensors.h"
41 #include "bmp-280-sensor.h"
42 #include "sys/ctimer.h"
43 #include "sensor-common.h"
44 #include "board-i2c.h"
45 #include "ti-lib.h"
46 
47 #include <stdint.h>
48 #include <string.h>
49 #include <stdio.h>
50 /*---------------------------------------------------------------------------*/
51 #define DEBUG 0
52 #if DEBUG
53 #define PRINTF(...) printf(__VA_ARGS__)
54 #else
55 #define PRINTF(...)
56 #endif
57 /*---------------------------------------------------------------------------*/
58 #define BMP280_I2C_ADDRESS 0x77
59 /*---------------------------------------------------------------------------*/
60 /* Registers */
61 #define ADDR_CALIB 0x88
62 #define ADDR_PROD_ID 0xD0
63 #define ADDR_RESET 0xE0
64 #define ADDR_STATUS 0xF3
65 #define ADDR_CTRL_MEAS 0xF4
66 #define ADDR_CONFIG 0xF5
67 #define ADDR_PRESS_MSB 0xF7
68 #define ADDR_PRESS_LSB 0xF8
69 #define ADDR_PRESS_XLSB 0xF9
70 #define ADDR_TEMP_MSB 0xFA
71 #define ADDR_TEMP_LSB 0xFB
72 #define ADDR_TEMP_XLSB 0xFC
73 /*---------------------------------------------------------------------------*/
74 /* Reset values */
75 #define VAL_PROD_ID 0x58
76 #define VAL_RESET 0x00
77 #define VAL_STATUS 0x00
78 #define VAL_CTRL_MEAS 0x00
79 #define VAL_CONFIG 0x00
80 #define VAL_PRESS_MSB 0x80
81 #define VAL_PRESS_LSB 0x00
82 #define VAL_TEMP_MSB 0x80
83 #define VAL_TEMP_LSB 0x00
84 /*---------------------------------------------------------------------------*/
85 /* Test values */
86 #define VAL_RESET_EXECUTE 0xB6
87 #define VAL_CTRL_MEAS_TEST 0x55
88 /*---------------------------------------------------------------------------*/
89 /* Misc. */
90 #define MEAS_DATA_SIZE 6
91 #define CALIB_DATA_SIZE 24
92 /*---------------------------------------------------------------------------*/
93 #define RES_OFF 0
94 #define RES_ULTRA_LOW_POWER 1
95 #define RES_LOW_POWER 2
96 #define RES_STANDARD 3
97 #define RES_HIGH 5
98 #define RES_ULTRA_HIGH 6
99 /*---------------------------------------------------------------------------*/
100 /* Bit fields in CTRL_MEAS register */
101 #define PM_OFF 0
102 #define PM_FORCED 1
103 #define PM_NORMAL 3
104 /*---------------------------------------------------------------------------*/
105 #define OSRST(v) ((v) << 5)
106 #define OSRSP(v) ((v) << 2)
107 /*---------------------------------------------------------------------------*/
108 typedef struct bmp_280_calibration {
109  uint16_t dig_t1;
110  int16_t dig_t2;
111  int16_t dig_t3;
112  uint16_t dig_p1;
113  int16_t dig_p2;
114  int16_t dig_p3;
115  int16_t dig_p4;
116  int16_t dig_p5;
117  int16_t dig_p6;
118  int16_t dig_p7;
119  int16_t dig_p8;
120  int16_t dig_p9;
121  int32_t t_fine;
122 } bmp_280_calibration_t;
123 /*---------------------------------------------------------------------------*/
124 static uint8_t calibration_data[CALIB_DATA_SIZE];
125 /*---------------------------------------------------------------------------*/
126 #define SENSOR_STATUS_DISABLED 0
127 #define SENSOR_STATUS_INITIALISED 1
128 #define SENSOR_STATUS_NOT_READY 2
129 #define SENSOR_STATUS_READY 3
130 
131 static int enabled = SENSOR_STATUS_DISABLED;
132 /*---------------------------------------------------------------------------*/
133 /* A buffer for the raw reading from the sensor */
134 #define SENSOR_DATA_BUF_SIZE 6
135 
136 static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE];
137 /*---------------------------------------------------------------------------*/
138 /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */
139 #define SENSOR_STARTUP_DELAY 3
140 
141 static struct ctimer startup_timer;
142 /*---------------------------------------------------------------------------*/
143 static void
144 notify_ready(void *not_used)
145 {
146  enabled = SENSOR_STATUS_READY;
147  sensors_changed(&bmp_280_sensor);
148 }
149 /*---------------------------------------------------------------------------*/
150 static void
151 select_on_bus(void)
152 {
153  /* Set up I2C */
154  board_i2c_select(BOARD_I2C_INTERFACE_0, BMP280_I2C_ADDRESS);
155 }
156 /*---------------------------------------------------------------------------*/
157 /**
158  * \brief Initalise the sensor
159  */
160 static void
161 init(void)
162 {
163  uint8_t val;
164 
165  select_on_bus();
166 
167  /* Read and store calibration data */
168  sensor_common_read_reg(ADDR_CALIB, calibration_data, CALIB_DATA_SIZE);
169 
170  /* Reset the sensor */
171  val = VAL_RESET_EXECUTE;
172  sensor_common_write_reg(ADDR_RESET, &val, sizeof(val));
173 }
174 /*---------------------------------------------------------------------------*/
175 /**
176  * \brief Enable/disable measurements
177  * \param enable 0: disable, enable otherwise
178  *
179  * @return none
180  */
181 static void
182 enable_sensor(bool enable)
183 {
184  uint8_t val;
185 
186  select_on_bus();
187 
188  if(enable) {
189  /* Enable forced mode */
190  val = PM_FORCED | OSRSP(1) | OSRST(1);
191  } else {
192  val = PM_OFF;
193  }
194  sensor_common_write_reg(ADDR_CTRL_MEAS, &val, sizeof(val));
195 }
196 /*---------------------------------------------------------------------------*/
197 /**
198  * \brief Read temperature and pressure data
199  * \param data Pointer to a buffer where temperature and pressure will be
200  * written (6 bytes)
201  * \return True if valid data could be retrieved
202  */
203 static bool
204 read_data(uint8_t *data)
205 {
206  bool success;
207 
208  select_on_bus();
209 
210  success = sensor_common_read_reg(ADDR_PRESS_MSB, data, MEAS_DATA_SIZE);
211  if(!success) {
212  sensor_common_set_error_data(data, MEAS_DATA_SIZE);
213  }
214 
215  return success;
216 }
217 /*---------------------------------------------------------------------------*/
218 /**
219  * \brief Convert raw data to values in degrees C (temp) and Pascal (pressure)
220  * \param data Pointer to a buffer that holds raw sensor data
221  * \param temp Pointer to a variable where the converted temperature will be
222  * written
223  * \param press Pointer to a variable where the converted pressure will be
224  * written
225  */
226 static void
227 convert(uint8_t *data, int32_t *temp, uint32_t *press)
228 {
229  int32_t utemp, upress;
230  bmp_280_calibration_t *p = (bmp_280_calibration_t *)calibration_data;
231  int32_t v_x1_u32r;
232  int32_t v_x2_u32r;
233  int32_t temperature;
234  uint32_t pressure;
235 
236  /* Pressure */
237  upress = (int32_t)((((uint32_t)(data[0])) << 12)
238  | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4));
239 
240  /* Temperature */
241  utemp = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4)
242  | ((uint32_t)data[5] >> 4));
243 
244  /* Compensate temperature */
245  v_x1_u32r = ((((utemp >> 3) - ((int32_t)p->dig_t1 << 1)))
246  * ((int32_t)p->dig_t2)) >> 11;
247  v_x2_u32r = (((((utemp >> 4) - ((int32_t)p->dig_t1))
248  * ((utemp >> 4) - ((int32_t)p->dig_t1))) >> 12)
249  * ((int32_t)p->dig_t3))
250  >> 14;
251  p->t_fine = v_x1_u32r + v_x2_u32r;
252  temperature = (p->t_fine * 5 + 128) >> 8;
253  *temp = temperature;
254 
255  /* Compensate pressure */
256  v_x1_u32r = (((int32_t)p->t_fine) >> 1) - (int32_t)64000;
257  v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11)
258  * ((int32_t)p->dig_p6);
259  v_x2_u32r = v_x2_u32r + ((v_x1_u32r * ((int32_t)p->dig_p5)) << 1);
260  v_x2_u32r = (v_x2_u32r >> 2) + (((int32_t)p->dig_p4) << 16);
261  v_x1_u32r =
262  (((p->dig_p3 * (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13)) >> 3)
263  + ((((int32_t)p->dig_p2) * v_x1_u32r) >> 1)) >> 18;
264  v_x1_u32r = ((((32768 + v_x1_u32r)) * ((int32_t)p->dig_p1)) >> 15);
265 
266  if(v_x1_u32r == 0) {
267  return; /* Avoid exception caused by division by zero */
268  }
269 
270  pressure = (((uint32_t)(((int32_t)1048576) - upress) - (v_x2_u32r >> 12)))
271  * 3125;
272  if(pressure < 0x80000000) {
273  pressure = (pressure << 1) / ((uint32_t)v_x1_u32r);
274  } else {
275  pressure = (pressure / (uint32_t)v_x1_u32r) * 2;
276  }
277 
278  v_x1_u32r = (((int32_t)p->dig_p9)
279  * ((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13))) >> 12;
280  v_x2_u32r = (((int32_t)(pressure >> 2)) * ((int32_t)p->dig_p8)) >> 13;
281  pressure = (uint32_t)((int32_t)pressure
282  + ((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4));
283 
284  *press = pressure;
285 }
286 /*---------------------------------------------------------------------------*/
287 /**
288  * \brief Returns a reading from the sensor
289  * \param type BMP_280_SENSOR_TYPE_TEMP or BMP_280_SENSOR_TYPE_PRESS
290  * \return Temperature (centi degrees C) or Pressure (Pascal).
291  */
292 static int
293 value(int type)
294 {
295  int rv;
296  int32_t temp = 0;
297  uint32_t pres = 0;
298 
299  if(enabled != SENSOR_STATUS_READY) {
300  PRINTF("Sensor disabled or starting up (%d)\n", enabled);
301  return CC26XX_SENSOR_READING_ERROR;
302  }
303 
304  if((type != BMP_280_SENSOR_TYPE_TEMP) && type != BMP_280_SENSOR_TYPE_PRESS) {
305  PRINTF("Invalid type\n");
306  return CC26XX_SENSOR_READING_ERROR;
307  } else {
308  memset(sensor_value, 0, SENSOR_DATA_BUF_SIZE);
309 
310  rv = read_data(sensor_value);
311 
312  if(rv == 0) {
313  return CC26XX_SENSOR_READING_ERROR;
314  }
315 
316  PRINTF("val: %02x%02x%02x %02x%02x%02x\n",
317  sensor_value[0], sensor_value[1], sensor_value[2],
318  sensor_value[3], sensor_value[4], sensor_value[5]);
319 
320  convert(sensor_value, &temp, &pres);
321 
322  if(type == BMP_280_SENSOR_TYPE_TEMP) {
323  rv = (int)temp;
324  } else if(type == BMP_280_SENSOR_TYPE_PRESS) {
325  rv = (int)pres;
326  }
327  }
328  return rv;
329 }
330 /*---------------------------------------------------------------------------*/
331 /**
332  * \brief Configuration function for the BMP280 sensor.
333  *
334  * \param type Activate, enable or disable the sensor. See below
335  * \param enable
336  *
337  * When type == SENSORS_HW_INIT we turn on the hardware
338  * When type == SENSORS_ACTIVE and enable==1 we enable the sensor
339  * When type == SENSORS_ACTIVE and enable==0 we disable the sensor
340  */
341 static int
342 configure(int type, int enable)
343 {
344  switch(type) {
345  case SENSORS_HW_INIT:
346  enabled = SENSOR_STATUS_INITIALISED;
347  init();
348  enable_sensor(0);
349  break;
350  case SENSORS_ACTIVE:
351  /* Must be initialised first */
352  if(enabled == SENSOR_STATUS_DISABLED) {
353  return SENSOR_STATUS_DISABLED;
354  }
355  if(enable) {
356  enable_sensor(1);
357  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
358  enabled = SENSOR_STATUS_NOT_READY;
359  } else {
360  ctimer_stop(&startup_timer);
361  enable_sensor(0);
362  enabled = SENSOR_STATUS_INITIALISED;
363  }
364  break;
365  default:
366  break;
367  }
368  return enabled;
369 }
370 /*---------------------------------------------------------------------------*/
371 /**
372  * \brief Returns the status of the sensor
373  * \param type SENSORS_ACTIVE or SENSORS_READY
374  * \return 1 if the sensor is enabled
375  */
376 static int
377 status(int type)
378 {
379  switch(type) {
380  case SENSORS_ACTIVE:
381  case SENSORS_READY:
382  return enabled;
383  break;
384  default:
385  break;
386  }
387  return SENSOR_STATUS_DISABLED;
388 }
389 /*---------------------------------------------------------------------------*/
390 SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status);
391 /*---------------------------------------------------------------------------*/
392 /** @} */
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static int value(int type)
Returns a reading from the sensor.
Header file with macros which rename TI CC26xxware functions.
Header file for the Sensortag I2C Driver.
static int status(int type)
Returns the status of the sensor.
static void enable_sensor(bool enable)
Enable/disable measurements.
static int configure(int type, int enable)
Configuration function for the BMP280 sensor.
void sensor_common_set_error_data(uint8_t *buf, uint8_t len)
Fill a result buffer with dummy error data.
Definition: sensor-common.c:71
static void convert(uint8_t *data, int32_t *temp, uint32_t *press)
Convert raw data to values in degrees C (temp) and Pascal (pressure)
bool sensor_common_read_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Reads a sensor&#39;s register over I2C.
Definition: sensor-common.c:48
Header file for the callback timer
Header file for the Sensortag Common sensor utilities.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition: board-i2c.c:310
bool sensor_common_write_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Write to a sensor&#39;s register over I2C.
Definition: sensor-common.c:54
Header file for the Sensortag BMP280 Altimeter / Pressure Sensor.
static void init(void)
Initalise the sensor.
static void notify_ready(void *unused)
Callback when sensor is ready to read data from.
static bool read_data(uint8_t *data)
Read temperature and pressure data.
const struct sensors_sensor bmp_280_sensor
Exports a global symbol to be used by the sensor API.