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/*---------------------------------------------------------------------------*/
92#define RES_OFF 0
93#define RES_ULTRA_LOW_POWER 1
94#define RES_LOW_POWER 2
95#define RES_STANDARD 3
96#define RES_HIGH 5
97#define RES_ULTRA_HIGH 6
98/*---------------------------------------------------------------------------*/
99/* Bit fields in CTRL_MEAS register */
100#define PM_OFF 0
101#define PM_FORCED 1
102#define PM_NORMAL 3
103/*---------------------------------------------------------------------------*/
104#define OSRST(v) ((v) << 5)
105#define OSRSP(v) ((v) << 2)
106/*---------------------------------------------------------------------------*/
107typedef struct bmp_280_calibration {
108 uint16_t dig_t1;
109 int16_t dig_t2;
110 int16_t dig_t3;
111 uint16_t dig_p1;
112 int16_t dig_p2;
113 int16_t dig_p3;
114 int16_t dig_p4;
115 int16_t dig_p5;
116 int16_t dig_p6;
117 int16_t dig_p7;
118 int16_t dig_p8;
119 int16_t dig_p9;
120 int32_t t_fine;
121} bmp_280_calibration_t;
122
123static bmp_280_calibration_t calibration_data;
124/*---------------------------------------------------------------------------*/
125#define SENSOR_STATUS_DISABLED 0
126#define SENSOR_STATUS_INITIALISED 1
127#define SENSOR_STATUS_NOT_READY 2
128#define SENSOR_STATUS_READY 3
129
130static int enabled = SENSOR_STATUS_DISABLED;
131/*---------------------------------------------------------------------------*/
132/* A buffer for the raw reading from the sensor */
133#define SENSOR_DATA_BUF_SIZE 6
134
135static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE];
136/*---------------------------------------------------------------------------*/
137/* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */
138#define SENSOR_STARTUP_DELAY 3
139
140static struct ctimer startup_timer;
141/*---------------------------------------------------------------------------*/
142static void
143notify_ready(void *not_used)
144{
145 enabled = SENSOR_STATUS_READY;
146 sensors_changed(&bmp_280_sensor);
147}
148/*---------------------------------------------------------------------------*/
149static void
150select_on_bus(void)
151{
152 /* Set up I2C */
153 board_i2c_select(BOARD_I2C_INTERFACE_0, BMP280_I2C_ADDRESS);
154}
155/*---------------------------------------------------------------------------*/
156/**
157 * \brief Initalise the sensor
158 */
159static void
160init(void)
161{
162 uint8_t val;
163
164 select_on_bus();
165
166 /* Read and store calibration data */
167 sensor_common_read_reg(ADDR_CALIB, (uint8_t *)&calibration_data,
168 sizeof(calibration_data));
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 */
179static void
180enable_sensor(bool enable)
181{
182 uint8_t val;
183
184 select_on_bus();
185
186 if(enable) {
187 /* Enable forced mode */
188 val = PM_FORCED | OSRSP(1) | OSRST(1);
189 } else {
190 val = PM_OFF;
191 }
192 sensor_common_write_reg(ADDR_CTRL_MEAS, &val, sizeof(val));
193}
194/*---------------------------------------------------------------------------*/
195/**
196 * \brief Read temperature and pressure data
197 * \param data Pointer to a buffer where temperature and pressure will be
198 * written (6 bytes)
199 * \return True if valid data could be retrieved
200 */
201static bool
202read_data(uint8_t *data)
203{
204 bool success;
205
206 select_on_bus();
207
208 success = sensor_common_read_reg(ADDR_PRESS_MSB, data, MEAS_DATA_SIZE);
209 if(!success) {
210 sensor_common_set_error_data(data, MEAS_DATA_SIZE);
211 }
212
213 return success;
214}
215/*---------------------------------------------------------------------------*/
216/**
217 * \brief Convert raw data to values in degrees C (temp) and Pascal (pressure)
218 * \param data Pointer to a buffer that holds raw sensor data
219 * \param temp Pointer to a variable where the converted temperature will be
220 * written
221 * \param press Pointer to a variable where the converted pressure will be
222 * written
223 */
224static void
225convert(uint8_t *data, int32_t *temp, uint32_t *press)
226{
227 int32_t utemp, upress;
228 bmp_280_calibration_t *p = &calibration_data;
229 int32_t v_x1_u32r;
230 int32_t v_x2_u32r;
231 int32_t temperature;
232 uint32_t pressure;
233
234 /* Pressure */
235 upress = (int32_t)((((uint32_t)(data[0])) << 12)
236 | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4));
237
238 /* Temperature */
239 utemp = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4)
240 | ((uint32_t)data[5] >> 4));
241
242 /* Compensate temperature */
243 v_x1_u32r = ((((utemp >> 3) - ((int32_t)p->dig_t1 << 1)))
244 * ((int32_t)p->dig_t2)) >> 11;
245 v_x2_u32r = (((((utemp >> 4) - ((int32_t)p->dig_t1))
246 * ((utemp >> 4) - ((int32_t)p->dig_t1))) >> 12)
247 * ((int32_t)p->dig_t3))
248 >> 14;
249 p->t_fine = v_x1_u32r + v_x2_u32r;
250 temperature = (p->t_fine * 5 + 128) >> 8;
251 *temp = temperature;
252
253 /* Compensate pressure */
254 v_x1_u32r = (((int32_t)p->t_fine) >> 1) - (int32_t)64000;
255 v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11)
256 * ((int32_t)p->dig_p6);
257 v_x2_u32r = v_x2_u32r + ((v_x1_u32r * ((int32_t)p->dig_p5)) << 1);
258 v_x2_u32r = (v_x2_u32r >> 2) + (((int32_t)p->dig_p4) << 16);
259 v_x1_u32r =
260 (((p->dig_p3 * (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13)) >> 3)
261 + ((((int32_t)p->dig_p2) * v_x1_u32r) >> 1)) >> 18;
262 v_x1_u32r = ((((32768 + v_x1_u32r)) * ((int32_t)p->dig_p1)) >> 15);
263
264 if(v_x1_u32r == 0) {
265 return; /* Avoid exception caused by division by zero */
266 }
267
268 pressure = (((uint32_t)(((int32_t)1048576) - upress) - (v_x2_u32r >> 12)))
269 * 3125;
270 if(pressure < 0x80000000) {
271 pressure = (pressure << 1) / ((uint32_t)v_x1_u32r);
272 } else {
273 pressure = (pressure / (uint32_t)v_x1_u32r) * 2;
274 }
275
276 v_x1_u32r = (((int32_t)p->dig_p9)
277 * ((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13))) >> 12;
278 v_x2_u32r = (((int32_t)(pressure >> 2)) * ((int32_t)p->dig_p8)) >> 13;
279 pressure = (uint32_t)((int32_t)pressure
280 + ((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4));
281
282 *press = pressure;
283}
284/*---------------------------------------------------------------------------*/
285/**
286 * \brief Returns a reading from the sensor
287 * \param type BMP_280_SENSOR_TYPE_TEMP or BMP_280_SENSOR_TYPE_PRESS
288 * \return Temperature (centi degrees C) or Pressure (Pascal).
289 */
290static int
291value(int type)
292{
293 int rv;
294 int32_t temp = 0;
295 uint32_t pres = 0;
296
297 if(enabled != SENSOR_STATUS_READY) {
298 PRINTF("Sensor disabled or starting up (%d)\n", enabled);
299 return CC26XX_SENSOR_READING_ERROR;
300 }
301
302 if((type != BMP_280_SENSOR_TYPE_TEMP) && type != BMP_280_SENSOR_TYPE_PRESS) {
303 PRINTF("Invalid type\n");
304 return CC26XX_SENSOR_READING_ERROR;
305 } else {
306 memset(sensor_value, 0, SENSOR_DATA_BUF_SIZE);
307
308 rv = read_data(sensor_value);
309
310 if(rv == 0) {
311 return CC26XX_SENSOR_READING_ERROR;
312 }
313
314 PRINTF("val: %02x%02x%02x %02x%02x%02x\n",
315 sensor_value[0], sensor_value[1], sensor_value[2],
316 sensor_value[3], sensor_value[4], sensor_value[5]);
317
318 convert(sensor_value, &temp, &pres);
319
320 if(type == BMP_280_SENSOR_TYPE_TEMP) {
321 rv = (int)temp;
322 } else if(type == BMP_280_SENSOR_TYPE_PRESS) {
323 rv = (int)pres;
324 }
325 }
326 return rv;
327}
328/*---------------------------------------------------------------------------*/
329/**
330 * \brief Configuration function for the BMP280 sensor.
331 *
332 * \param type Activate, enable or disable the sensor. See below
333 * \param enable
334 *
335 * When type == SENSORS_HW_INIT we turn on the hardware
336 * When type == SENSORS_ACTIVE and enable==1 we enable the sensor
337 * When type == SENSORS_ACTIVE and enable==0 we disable the sensor
338 */
339static int
340configure(int type, int enable)
341{
342 switch(type) {
343 case SENSORS_HW_INIT:
344 enabled = SENSOR_STATUS_INITIALISED;
345 init();
346 enable_sensor(0);
347 break;
348 case SENSORS_ACTIVE:
349 /* Must be initialised first */
350 if(enabled == SENSOR_STATUS_DISABLED) {
351 return SENSOR_STATUS_DISABLED;
352 }
353 if(enable) {
354 enable_sensor(1);
355 ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
356 enabled = SENSOR_STATUS_NOT_READY;
357 } else {
358 ctimer_stop(&startup_timer);
359 enable_sensor(0);
360 enabled = SENSOR_STATUS_INITIALISED;
361 }
362 break;
363 default:
364 break;
365 }
366 return enabled;
367}
368/*---------------------------------------------------------------------------*/
369/**
370 * \brief Returns the status of the sensor
371 * \param type SENSORS_ACTIVE or SENSORS_READY
372 * \return 1 if the sensor is enabled
373 */
374static int
375status(int type)
376{
377 switch(type) {
378 case SENSORS_ACTIVE:
379 case SENSORS_READY:
380 return enabled;
381 break;
382 default:
383 break;
384 }
385 return SENSOR_STATUS_DISABLED;
386}
387/*---------------------------------------------------------------------------*/
388SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status);
389/*---------------------------------------------------------------------------*/
390/** @} */
Header file for the Sensortag I2C Driver.
Header file for the callback timer.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
static void init(void)
Initalise the sensor.
const struct sensors_sensor bmp_280_sensor
Exports a global symbol to be used by the sensor API.
static int value(int type)
Returns a reading from the sensor.
static bool read_data(uint8_t *data)
Read temperature and pressure data.
static int status(int type)
Returns the status of the sensor.
static void enable_sensor(bool enable)
Enable/disable measurements.
static void convert(uint8_t *data, int32_t *temp, uint32_t *press)
Convert raw data to values in degrees C (temp) and Pascal (pressure)
static int configure(int type, int enable)
Configuration function for the BMP280 sensor.
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition: board-i2c.c:310
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
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
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
static void notify_ready(void *unused)
Callback when sensor is ready to read data from.
Header file for the Sensortag Common sensor utilities.
Header file with macros which rename TI CC26xxware functions.