Contiki-NG
Loading...
Searching...
No Matches
bmp-280-sensor.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, 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 * \addtogroup sensortag-bmp-sensor
32 * @{
33 *
34 * \file
35 * Driver for the Sensortag BMP280 Altimeter / Pressure Sensor
36 * \author
37 * Edvard Pettersen <e.pettersen@ti.com>
38 */
39/*---------------------------------------------------------------------------*/
40#include "contiki.h"
41#include "lib/sensors.h"
42#include "sys/ctimer.h"
43#include "dev/i2c-arch.h"
44/*---------------------------------------------------------------------------*/
45#include "board-conf.h"
46#include "bmp-280-sensor.h"
47/*---------------------------------------------------------------------------*/
48#include <Board.h>
49
50#include <ti/drivers/I2C.h>
51/*---------------------------------------------------------------------------*/
52#include <stdbool.h>
53#include <stdint.h>
54#include <string.h>
55/*---------------------------------------------------------------------------*/
56#define DEBUG 0
57#if DEBUG
58#define PRINTF(...) printf(__VA_ARGS__)
59#else
60#define PRINTF(...)
61#endif
62/*---------------------------------------------------------------------------*/
63/*
64 * Disable the entire file if sensors are disabled, as it could potentially
65 * create compile errors with missing defines from either the Board file or
66 * configuration defines.
67 */
68#if BOARD_SENSORS_ENABLE
69/*---------------------------------------------------------------------------*/
70#ifndef Board_BMP280_ADDR
71#error "Board file doesn't define I2C address Board_BMP280_ADDR"
72#endif
73/* Sensor I2C address */
74#define BMP280_I2C_ADDRESS Board_BMP280_ADDR
75/*---------------------------------------------------------------------------*/
76/* Registers */
77#define ADDR_CALIB 0x88
78#define ADDR_PROD_ID 0xD0
79#define ADDR_RESET 0xE0
80#define ADDR_STATUS 0xF3
81#define ADDR_CTRL_MEAS 0xF4
82#define ADDR_CONFIG 0xF5
83#define ADDR_PRESS_MSB 0xF7
84#define ADDR_PRESS_LSB 0xF8
85#define ADDR_PRESS_XLSB 0xF9
86#define ADDR_TEMP_MSB 0xFA
87#define ADDR_TEMP_LSB 0xFB
88#define ADDR_TEMP_XLSB 0xFC
89/*---------------------------------------------------------------------------*/
90/* Reset values */
91#define VAL_PROD_ID 0x58
92#define VAL_RESET 0x00
93#define VAL_STATUS 0x00
94#define VAL_CTRL_MEAS 0x00
95#define VAL_CONFIG 0x00
96#define VAL_PRESS_MSB 0x80
97#define VAL_PRESS_LSB 0x00
98#define VAL_TEMP_MSB 0x80
99#define VAL_TEMP_LSB 0x00
100/*---------------------------------------------------------------------------*/
101/* Test values */
102#define VAL_RESET_EXECUTE 0xB6
103#define VAL_CTRL_MEAS_TEST 0x55
104/*---------------------------------------------------------------------------*/
105/* Misc. */
106#define SENSOR_DATA_BUF_SIZE 6
107/*---------------------------------------------------------------------------*/
108#define RES_OFF 0
109#define RES_ULTRA_LOW_POWER 1
110#define RES_LOW_POWER 2
111#define RES_STANDARD 3
112#define RES_HIGH 5
113#define RES_ULTRA_HIGH 6
114/*---------------------------------------------------------------------------*/
115/* Bit fields in CTRL_MEAS register */
116#define PM_OFF 0
117#define PM_FORCED 1
118#define PM_NORMAL 3
119/*---------------------------------------------------------------------------*/
120#define OSRST(v) ((v) << 5)
121#define OSRSP(v) ((v) << 2)
122/*---------------------------------------------------------------------------*/
123typedef struct {
124 uint16_t dig_t1;
125 int16_t dig_t2;
126 int16_t dig_t3;
127 uint16_t dig_p1;
128 int16_t dig_p2;
129 int16_t dig_p3;
130 int16_t dig_p4;
131 int16_t dig_p5;
132 int16_t dig_p6;
133 int16_t dig_p7;
134 int16_t dig_p8;
135 int16_t dig_p9;
136} BMP_280_Calibration;
137/*---------------------------------------------------------------------------*/
138static BMP_280_Calibration calib_data;
139/*---------------------------------------------------------------------------*/
140static I2C_Handle i2c_handle;
141/*---------------------------------------------------------------------------*/
142typedef enum {
143 SENSOR_STATUS_DISABLED,
144 SENSOR_STATUS_INITIALISED,
145 SENSOR_STATUS_NOT_READY,
146 SENSOR_STATUS_READY
147} SENSOR_STATUS;
148
149static volatile SENSOR_STATUS sensor_status = SENSOR_STATUS_DISABLED;
150/*---------------------------------------------------------------------------*/
151/* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */
152#define SENSOR_STARTUP_DELAY 3
153
154static struct ctimer startup_timer;
155/*---------------------------------------------------------------------------*/
156static void
157notify_ready(void *unused)
158{
159 (void)unused;
160
161 sensor_status = SENSOR_STATUS_READY;
162 sensors_changed(&bmp_280_sensor);
163}
164/*---------------------------------------------------------------------------*/
165/**
166 * \brief Initalise the sensor.
167 * \return Boolean Value descibing whether initialization were
168 * successful or not.
169 * \retval true Successful initialization
170 * \retval false Error during initialization
171 */
172static bool
173init(void)
174{
176
177 i2c_handle = i2c_arch_acquire(Board_I2C0);
178
179 if(!i2c_handle) {
180 sensor_status = SENSOR_STATUS_DISABLED;
181 return false;
182 }
183
184 uint8_t reset_data[] = { ADDR_RESET, VAL_RESET_EXECUTE };
185
186 uint8_t calib_reg = ADDR_CALIB;
187 /* Read and store calibration data */
188 rv_write_read = i2c_arch_write_read(i2c_handle, BMP280_I2C_ADDRESS,
189 &calib_reg, sizeof(calib_reg),
190 &calib_data, sizeof(calib_data));
191 /* then reset the sensor */
192 rv_write = i2c_arch_write(i2c_handle, BMP280_I2C_ADDRESS, reset_data,
193 sizeof(reset_data));
194
195 i2c_arch_release(i2c_handle);
196
197 return rv_write_read && rv_write;
198}
199/*---------------------------------------------------------------------------*/
200/**
201 * \brief Enable/disable measurements.
202 * \param enable Enable if true; else, disable.
203 * \return Boolean Value descibing whether initialization were
204 * successful or not.
205 * \retval true Successful initialization
206 * \retval false Error during initialization
207 */
208static bool
209enable_sensor(bool enable)
210{
211 bool rv;
212
213 uint8_t val = (enable)
214 ? PM_FORCED | OSRSP(1) | OSRST(1)
215 : PM_OFF;
216
217 uint8_t ctrl_meas_data[] = { ADDR_CTRL_MEAS, val };
218
219 i2c_handle = i2c_arch_acquire(Board_I2C0);
220
221 if(!i2c_handle) {
222 sensor_status = SENSOR_STATUS_DISABLED;
223 return false;
224 }
225
226 rv = i2c_arch_write(i2c_handle, BMP280_I2C_ADDRESS, &ctrl_meas_data,
227 sizeof(ctrl_meas_data));
228
229 i2c_arch_release(i2c_handle);
230 return rv;
231}
232/*---------------------------------------------------------------------------*/
233/**
234 * \brief Read temperature and pressure data.
235 * \param data Pointer to a buffer where temperature and pressure will be
236 * written.
237 * \param count Number of byes to read.
238 * \return Boolean Value descibing whether initialization were
239 * successful or not.
240 * \retval true Successful initialization
241 * \retval false Error during initialization
242 */
243static bool
244read_data(uint8_t *data, size_t count)
245{
246 bool rv;
247 uint8_t press_msb_reg = ADDR_PRESS_MSB;
248
249 i2c_handle = i2c_arch_acquire(Board_I2C0);
250
251 if(!i2c_handle) {
252 sensor_status = SENSOR_STATUS_DISABLED;
253 return false;
254 }
255
256 rv = i2c_arch_write_read(i2c_handle, BMP280_I2C_ADDRESS, &press_msb_reg,
257 sizeof(press_msb_reg), data, count);
258
259 i2c_arch_release(i2c_handle);
260
261 return rv;
262}
263/*---------------------------------------------------------------------------*/
264/**
265 * \brief Convert raw data to values in degrees C (temp) and Pascal
266 * (pressure).
267 * \param data Pointer to a buffer that holds raw sensor data.
268 * \param temp Pointer to a variable where the converted temperature will
269 * be written.
270 * \param press Pointer to a variable where the converted pressure will be
271 * written.
272 */
273static void
275{
276 BMP_280_Calibration *p = &calib_data;
277
278 /* Pressure */
279 const int32_t upress = (int32_t)(
280 (((uint32_t)data[0]) << 12) |
281 (((uint32_t)data[1]) << 4) |
282 (((uint32_t)data[2]) >> 4)
283 );
284 /* Temperature */
285 const int32_t utemp = (int32_t)(
286 (((uint32_t)data[3]) << 12) |
287 (((uint32_t)data[4]) << 4) |
288 (((uint32_t)data[5]) >> 4)
289 );
290
291 /* Compensate temperature */
292 int32_t v_x1_u32r = (((utemp >> 3) - ((int32_t)p->dig_t1 << 1)) * (int32_t)p->dig_t2) >> 11;
293 int32_t v_x2_u32r = (((((utemp >> 4) - (int32_t)p->dig_t1) * ((utemp >> 4) - (int32_t)p->dig_t1)) >> 12) * (int32_t)p->dig_t3) >> 14;
294
295 const uint32_t t_fine = v_x1_u32r + v_x2_u32r;
296 const int32_t temperature = (t_fine * 5 + 128) >> 8;
297 *temp = temperature;
298
299 /* Compensate pressure */
300 v_x1_u32r = ((int32_t)t_fine >> 1) - (int32_t)64000;
301 v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) * (int32_t)p->dig_p6;
302 v_x2_u32r = ((v_x1_u32r * (int32_t)p->dig_p5) << 1) + v_x2_u32r;
303 v_x2_u32r = (v_x2_u32r >> 2) + ((int32_t)p->dig_p4 << 16);
304 v_x1_u32r = ((((((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 13) * p->dig_p3) >> 3) + (((int32_t)p->dig_p2 * v_x1_u32r) >> 1)) >> 18;
305 v_x1_u32r = ((32768 + v_x1_u32r) * (int32_t)p->dig_p1) >> 15;
306
307 if(v_x1_u32r == 0) {
308 /* Avoid exception caused by division by zero */
309 *press = 0;
310 return;
311 }
312
313 uint32_t pressure = (((uint32_t)((int32_t)1048576 - upress)) - (v_x2_u32r >> 12)) * 3125;
314 if((int32_t)pressure < 0) {
316 } else {
318 }
319
320 v_x1_u32r = (((int32_t)(((pressure >> 3) * (pressure >> 3)) >> 13)) * (int32_t)p->dig_p9) >> 12;
321 v_x2_u32r = ((int32_t)(pressure >> 2) * (int32_t)p->dig_p8) >> 13;
322 pressure = (uint32_t)(((v_x1_u32r + v_x2_u32r + p->dig_p7) >> 4) + (int32_t)pressure);
323
324 *press = pressure;
325}
326/*---------------------------------------------------------------------------*/
327/**
328 * \brief Returns a reading from the sensor.
329 * \param type Parameter of type BMP_280_SENSOR_TYPE, choosing between either
330 * measuring temperature or pressure.
331 * \return Sensor data of either Temperature (centi degrees C) or
332 * Pressure (Pascal).
333 */
334static int
335value(int type)
336{
337 int32_t temp = 0;
338 uint32_t pres = 0;
339
340 /* A buffer for the raw reading from the sensor */
341 uint8_t sensor_value[SENSOR_DATA_BUF_SIZE];
342
343 if(sensor_status != SENSOR_STATUS_READY) {
344 PRINTF("Sensor disabled or starting up (%d)\n", sensor_status);
345 return BMP_280_READING_ERROR;
346 }
347
348 switch(type) {
349 case BMP_280_SENSOR_TYPE_TEMP:
350 case BMP_280_SENSOR_TYPE_PRESS:
351 memset(sensor_value, 0, SENSOR_DATA_BUF_SIZE);
352 if(!read_data(sensor_value, SENSOR_DATA_BUF_SIZE)) {
353 return BMP_280_READING_ERROR;
354 }
355
356 PRINTF("val: %02x%02x%02x %02x%02x%02x\n",
357 sensor_value[0], sensor_value[1], sensor_value[2],
358 sensor_value[3], sensor_value[4], sensor_value[5]);
359
360 convert(sensor_value, &temp, &pres);
361
362 if(type == BMP_280_SENSOR_TYPE_TEMP) {
363 return (int)temp;
364 } else if(type == BMP_280_SENSOR_TYPE_PRESS) {
365 return (int)pres;
366 } else {
367 return 0;
368 }
369
370 default:
371 PRINTF("Invalid BMP 208 Sensor Type\n");
372 return BMP_280_READING_ERROR;
373 }
374}
375/*---------------------------------------------------------------------------*/
376/**
377 * \brief Configuration function for the BMP280 sensor.
378 * \param type Activate, enable or disable the sensor. See below
379 * \param enable Disable sensor if 0; else, enable sensor otherwise.
380 * When type == SENSORS_HW_INIT we turn on the hardware.
381 * When type == SENSORS_ACTIVE and enable==1 we enable the sensor.
382 * When type == SENSORS_ACTIVE and enable==0 we disable the sensor.
383 */
384static int
385configure(int type, int enable)
386{
387 switch(type) {
388 case SENSORS_HW_INIT:
389 if(init()) {
390 enable_sensor(false);
391 sensor_status = SENSOR_STATUS_INITIALISED;
392 } else {
393 sensor_status = SENSOR_STATUS_DISABLED;
394 }
395 break;
396
397 case SENSORS_ACTIVE:
398 /* Must be initialised first */
399 if(sensor_status == SENSOR_STATUS_DISABLED) {
400 break;
401 }
402 if(enable) {
403 enable_sensor(true);
404 ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
405 sensor_status = SENSOR_STATUS_NOT_READY;
406 } else {
407 ctimer_stop(&startup_timer);
408 enable_sensor(false);
409 sensor_status = SENSOR_STATUS_INITIALISED;
410 }
411 break;
412
413 default:
414 break;
415 }
416 return sensor_status;
417}
418/*---------------------------------------------------------------------------*/
419/**
420 * \brief Returns the status of the sensor.
421 * \param type SENSORS_ACTIVE or SENSORS_READY.
422 * \return Current status of the sensor.
423 */
424static int
425status(int type)
426{
427 switch(type) {
428 case SENSORS_ACTIVE:
429 case SENSORS_READY:
430 return sensor_status;
431 default:
432 return SENSOR_STATUS_DISABLED;
433 }
434}
435/*---------------------------------------------------------------------------*/
436SENSORS_SENSOR(bmp_280_sensor, "BMP280", value, configure, status);
437/*---------------------------------------------------------------------------*/
438#endif /* BOARD_SENSORS_ENABLE */
439/*---------------------------------------------------------------------------*/
440/** @} */
Header file for the callback timer.
bool i2c_arch_write_read(I2C_Handle i2c_handle, uint_least8_t slave_addr, void *wbuf, size_t wcount, void *rbuf, size_t rcount)
Setup and peform an I2C transaction.
Definition i2c-arch.c:53
static bool i2c_arch_write(I2C_Handle i2c_handle, uint_least8_t slave_addr, void *wbuf, size_t wcount)
Perform a write-only I2C transaction.
Definition i2c-arch.h:128
I2C_Handle i2c_arch_acquire(uint_least8_t index)
Open and lock the I2C Peripheral for use.
Definition i2c-arch.c:84
void i2c_arch_release(I2C_Handle i2c_handle)
Release the I2C Peripheral for other modules to use.
Definition i2c-arch.c:74
static volatile uint64_t count
Num.
Definition clock.c:50
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition ctimer.c:138
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition ctimer.h:137
static int value(int type)
Returns a reading from the sensor.
static int configure(int type, int enable)
Configuration function for the BMP280 sensor.
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 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 bool read_data()
Take readings from the sensor.
Implementation of the I2C HAL driver for CC13xx/CC26xx.
Header file with definitions related to the sensors on the Sensortags.