Contiki-NG
bmpx8x.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Zolertia - http://www.zolertia.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 Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup zoul-bmpx8x-sensor
33  * @{
34  *
35  * BMP085/BMP180 driver implementation
36  *
37  * \file
38  * Driver for the external BMP085/BMP180 atmospheric pressure sensor
39  *
40  * \author
41  * Antonio Lignan <alinan@zolertia.com>
42  */
43 /*---------------------------------------------------------------------------*/
44 #include "contiki.h"
45 #include "dev/i2c.h"
46 #include "dev/gpio.h"
47 #include "dev/zoul-sensors.h"
48 #include "lib/sensors.h"
49 #include "bmpx8x.h"
50 /*---------------------------------------------------------------------------*/
51 #define DEBUG 0
52 #if DEBUG
53 #define PRINTF(...) printf(__VA_ARGS__)
54 #else
55 #define PRINTF(...)
56 #endif
57 /*---------------------------------------------------------------------------*/
58 static uint8_t enabled = 0;
59 /*---------------------------------------------------------------------------*/
60 typedef struct {
61  int16_t ac1;
62  int16_t ac2;
63  int16_t ac3;
64  uint16_t ac4;
65  uint16_t ac5;
66  uint16_t ac6;
67  int16_t b1;
68  int16_t b2;
69  int16_t mb;
70  int16_t mc;
71  int16_t md;
72 } bmpx8x_calibration_values;
73 
74 typedef struct {
75  uint8_t oversampling_mode;
76  int32_t b5;
77  bmpx8x_calibration_values calib;
78 } bmpx8x_config;
79 
80 static bmpx8x_config bmpx8x_values;
81 /*---------------------------------------------------------------------------*/
82 static int
83 bmpx8x_read_reg(uint8_t reg, uint8_t *buf, uint8_t num)
84 {
85  if((buf == NULL) || (num <= 0)) {
86  PRINTF("BMPx8x: invalid read values\n");
87  return BMPx8x_ERROR;
88  }
89 
91  if(i2c_single_send(BMPx8x_ADDR, reg) == I2C_MASTER_ERR_NONE) {
92  while(i2c_master_busy());
93  if(i2c_burst_receive(BMPx8x_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
94  return BMPx8x_SUCCESS;
95  }
96  }
97  return BMPx8x_ERROR;
98 }
99 /*---------------------------------------------------------------------------*/
100 static int
101 bmpx8x_write_reg(uint8_t *buf, uint8_t num)
102 {
103  if((buf == NULL) || (num <= 0)) {
104  PRINTF("BMPx8x: invalid write values\n");
105  return BMPx8x_ERROR;
106  }
107 
109  if(i2c_burst_send(BMPx8x_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
110  return BMPx8x_SUCCESS;
111  }
112  return BMPx8x_ERROR;
113 }
114 /*---------------------------------------------------------------------------*/
115 static int
116 bmpx8x_read_calib(void)
117 {
118  uint8_t buf[BMPx8x_CALIB_TABLE_SIZE];
119 
120  if(bmpx8x_read_reg(BMPx8x_AC1_CALIB, buf,
121  BMPx8x_CALIB_TABLE_SIZE) == BMPx8x_SUCCESS) {
122 
123  /* MSB first */
124  bmpx8x_values.calib.ac1 = ((buf[0] << 8) + buf[1]);
125  bmpx8x_values.calib.ac2 = ((buf[2] << 8) + buf[3]);
126  bmpx8x_values.calib.ac3 = ((buf[4] << 8) + buf[5]);
127  bmpx8x_values.calib.ac4 = ((buf[6] << 8) + buf[7]);
128  bmpx8x_values.calib.ac5 = ((buf[8] << 8) + buf[9]);
129  bmpx8x_values.calib.ac6 = ((buf[10] << 8) + buf[11]);
130  bmpx8x_values.calib.b1 = ((buf[12] << 8) + buf[13]);
131  bmpx8x_values.calib.b2 = ((buf[14] << 8) + buf[15]);
132  bmpx8x_values.calib.mb = ((buf[16] << 8) + buf[17]);
133  bmpx8x_values.calib.mc = ((buf[18] << 8) + buf[19]);
134  bmpx8x_values.calib.md = ((buf[20] << 8) + buf[21]);
135 
136  return BMPx8x_SUCCESS;
137  }
138 
139  PRINTF("BMPx8x: failed to read calibration\n");
140  return BMPx8x_ERROR;
141 }
142 /*---------------------------------------------------------------------------*/
143 static int
144 bmpx8x_read_uncompensated_pressure(int32_t *pressure)
145 {
146  uint8_t buf[3];
147  uint16_t delay;
148  int32_t upres;
149 
150  buf[0] = BMPx8x_CTRL_REG;
151 
152  switch(bmpx8x_values.oversampling_mode) {
153  case BMPx8x_MODE_ULTRA_LOW_POWER:
154  buf[1] = BMPx8x_CTRL_REG_PRESS_4_5MS;
155  delay = BMPx8x_DELAY_4_5MS;
156  break;
157  case BMPx8x_MODE_STANDARD:
158  buf[1] = BMPx8x_CTRL_REG_PRESS_7_5MS;
159  delay = BMPx8x_DELAY_7_5MS;
160  break;
161  case BMPx8x_MODE_HIGH_RES:
162  buf[1] = BMPx8x_CTRL_REG_PRESS_13_5MS;
163  delay = BMPx8x_DELAY_13_5MS;
164  break;
165  case BMPx8x_MODE_ULTRA_HIGH_RES:
166  buf[1] = BMPx8x_CTRL_REG_PRESS_25_5MS;
167  delay = BMPx8x_DELAY_25_5MS;
168  break;
169  default:
170  return BMPx8x_ERROR;
171  }
172 
173  if(bmpx8x_write_reg(buf, 2) == BMPx8x_SUCCESS) {
174  clock_delay_usec(delay);
175  if(bmpx8x_read_reg(BMPx8x_DATA_MSB, buf, 3) == BMPx8x_SUCCESS) {
176  upres = (buf[0] << 16) + (buf[1] << 8) + buf[2];
177  *pressure = (upres >> (8 - bmpx8x_values.oversampling_mode));
178  return BMPx8x_SUCCESS;
179  }
180  }
181  return BMPx8x_ERROR;
182 }
183 /*---------------------------------------------------------------------------*/
184 static int
185 bmpx8x_read_uncompensated_temperature(int32_t *temp)
186 {
187  uint8_t buf[2];
188  buf[0] = BMPx8x_CTRL_REG;
189  buf[1] = BMPx8x_CTRL_REG_TEMP;
190 
191  if(bmpx8x_write_reg(buf, 2) == BMPx8x_SUCCESS) {
192  clock_delay_usec(BMPx8x_DELAY_4_5MS);
193  if(bmpx8x_read_reg(BMPx8x_DATA_MSB, buf, 2) == BMPx8x_SUCCESS) {
194  *temp = (int32_t)((buf[0] << 8) + buf[1]);
195  return BMPx8x_SUCCESS;
196  }
197  }
198  return BMPx8x_ERROR;
199 }
200 /*---------------------------------------------------------------------------*/
201 static int
202 bmpx8x_read_temperature(int16_t *temp)
203 {
204  int32_t ut = 0;
205  int32_t x1, x2;
206 
207  if(bmpx8x_read_uncompensated_temperature(&ut) == BMPx8x_ERROR) {
208  return BMPx8x_ERROR;
209  }
210 
211  x1 = ((int32_t)ut - (int32_t)bmpx8x_values.calib.ac6)
212  * (int32_t)bmpx8x_values.calib.ac5 >> 15;
213  x2 = ((int32_t)bmpx8x_values.calib.mc << 11) / (x1 + bmpx8x_values.calib.md);
214  bmpx8x_values.b5 = x1 + x2;
215  *temp = (int16_t)((bmpx8x_values.b5 + 8) >> 4);
216  return BMPx8x_SUCCESS;
217 }
218 /*---------------------------------------------------------------------------*/
219 static int
220 bmpx8x_read_pressure(int32_t *pressure)
221 {
222  int32_t ut = 0;
223  int32_t up = 0;
224  int32_t x1, x2, b6, x3, b3, p;
225  uint32_t b4, b7;
226 
227  if(bmpx8x_read_uncompensated_pressure(&up) == BMPx8x_ERROR) {
228  return BMPx8x_ERROR;
229  }
230 
231  if(bmpx8x_read_uncompensated_temperature(&ut) == BMPx8x_ERROR) {
232  return BMPx8x_ERROR;
233  }
234 
235  b6 = bmpx8x_values.b5 - 4000;
236  x1 = (bmpx8x_values.calib.b2 * (b6 * b6 >> 12)) >> 11;
237  x2 = bmpx8x_values.calib.ac2 * b6 >> 11;
238  x3 = x1 + x2;
239  b3 = ((((int32_t)bmpx8x_values.calib.ac1) * 4 + x3) + 2) >> 2;
240 
241  x1 = (bmpx8x_values.calib.ac3 * b6) >> 13;
242  x2 = (bmpx8x_values.calib.b1 * ((b6 * b6) >> 12)) >> 16;
243  x3 = ((x1 + x2) + 2) >> 2;
244  b4 = (bmpx8x_values.calib.ac4 * ((uint32_t)(x3 + 32768))) >> 15;
245  b7 = ((uint32_t)up - b3) * 50000;
246 
247  if(b7 < 0x80000000) {
248  p = (b7 << 1) / b4;
249  } else {
250  p = (b7 / b4) << 1;
251  }
252 
253  x1 = (p >> 8) * (p >> 8);
254  x1 = (x1 * 3038) >> 16;
255  x2 = (-7357 * p) >> 16;
256  *pressure = (p + ((x1 + x2 + 3791) >> 4));
257  *pressure /= 10;
258 
259  return BMPx8x_SUCCESS;
260 }
261 /*---------------------------------------------------------------------------*/
262 static int
263 configure(int type, int value)
264 {
265  if((type != BMPx8x_ACTIVE) && (type != BMPx8x_OVERSAMPLING)) {
266  PRINTF("BMPx8x: invalid start value\n");
267  return BMPx8x_ERROR;
268  }
269 
270  if(type == BMPx8x_ACTIVE) {
271  if(value) {
272  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
273  I2C_SCL_NORMAL_BUS_SPEED);
274 
275  /* Read the calibration values */
276  if(bmpx8x_read_calib() != BMPx8x_ERROR) {
277  PRINTF("BMPx8x: sensor started\n");
278  enabled = 1;
279  bmpx8x_values.oversampling_mode = BMPx8x_MODE_ULTRA_LOW_POWER;
280  return BMPx8x_SUCCESS;
281  }
282 
283  PRINTF("BMPx8x: failed to enable\n");
284  return BMPx8x_ERROR;
285  } else {
286  enabled = 0;
287  return BMPx8x_SUCCESS;
288  }
289  } else if(type == BMPx8x_OVERSAMPLING) {
290  if((value < BMPx8x_MODE_ULTRA_LOW_POWER) ||
291  (value > BMPx8x_MODE_ULTRA_HIGH_RES)) {
292  PRINTF("BMPx8x: invalid oversampling value\n");
293  return BMPx8x_ERROR;
294  }
295  bmpx8x_values.oversampling_mode = value;
296  return BMPx8x_SUCCESS;
297  }
298 
299  return BMPx8x_ERROR;
300 }
301 /*---------------------------------------------------------------------------*/
302 static int
303 status(int type)
304 {
305  switch(type) {
306  case SENSORS_ACTIVE:
307  case SENSORS_READY:
308  return enabled;
309  }
310  return 0;
311 }
312 /*---------------------------------------------------------------------------*/
313 static int
314 bmpx8x_read_sensor(int32_t *value, uint8_t type)
315 {
316  int16_t temp = 0;
317 
318  /* The temperature is required to compensate the pressure value */
319  if(bmpx8x_read_temperature(&temp) != BMPx8x_SUCCESS) {
320  return BMPx8x_ERROR;
321  }
322 
323  switch(type) {
324  case BMPx8x_READ_PRESSURE:
325  return bmpx8x_read_pressure(value);
326 
327  case BMPx8x_READ_TEMP:
328  *value = (int16_t) temp;
329  return BMPx8x_SUCCESS;
330  }
331 
332  return BMPx8x_ERROR;
333 }
334 /*---------------------------------------------------------------------------*/
335 static int
336 value(int type)
337 {
338  int32_t value;
339 
340  if(!enabled) {
341  PRINTF("BMPx8x: sensor not started\n");
342  return BMPx8x_ERROR;
343  }
344 
345  if((type != BMPx8x_READ_PRESSURE) && (type != BMPx8x_READ_TEMP)) {
346  PRINTF("BMPx8x: invalid read value\n");
347  return BMPx8x_ERROR;
348  }
349 
350  if(bmpx8x_read_sensor(&value, type) == BMPx8x_SUCCESS) {
351  return (int)value;
352  }
353 
354  PRINTF("BMPx8x: fail to read\n");
355  return BMPx8x_ERROR;
356 }
357 /*---------------------------------------------------------------------------*/
358 SENSORS_SENSOR(bmpx8x, BMPx8x_SENSOR, value, configure, status);
359 /*---------------------------------------------------------------------------*/
360 /** @} */
uint8_t i2c_master_busy(void)
Return the busy state of I2C module.
Definition: i2c.c:141
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
Header file with register and macro declarations for the cc2538 GPIO module.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
Implementation of a generic module controlling Zoul sensors.
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition: i2c.c:49
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
#define BMPx8x_CALIB_TABLE_SIZE
size in bytes
Definition: bmpx8x.h:95
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91
Header file for the external BMP085/BMP180 Sensor Driver.