Contiki 3.x
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-CC26XX BMP280 Altimeter / Pressure Sensor
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki-conf.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 /** @} */
static bool read_data(uint8_t *data)
Read temperature and pressure data.
Header file with macros which rename TI CC26xxware functions.
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 enable_sensor(bool enable)
Enable/disable measurements.
static void init(void)
Initalise the sensor.
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition: board-i2c.c:301
static int status(int type)
Returns the status of the sensor.
Header file for the callback timer
#define NULL
The null pointer.
static int value(int type)
Returns a reading from the sensor.
Header file for the Sensortag-CC26xx Common sensor utilities.
Header file for the Sensortag-CC26xx I2C Driver.
static int configure(int type, int enable)
Configuration function for the BMP280 sensor.
Header file for the Sensortag-CC26xx BMP280 Altimeter / Pressure Sensor.
bool sensor_common_read_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Reads a sensor's register over I2C.
Definition: sensor-common.c:48
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
bool sensor_common_write_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Write to a sensor's register over I2C.
Definition: sensor-common.c:54
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static void convert(uint8_t *data, int32_t *temp, uint32_t *press)
Convert raw data to values in degrees C (temp) and Pascal (pressure)