Contiki-NG
hdc-1000-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-hdc-sensor
32  * @{
33  *
34  * \file
35  * Driver for the Sensortag HDC1000 sensor.
36  * \author
37  * Edvard Pettersen <e.pettersen@ti.com>
38  */
39 /*---------------------------------------------------------------------------*/
40 #include "contiki.h"
41 #include "sys/ctimer.h"
42 #include "lib/sensors.h"
43 /*---------------------------------------------------------------------------*/
44 #include "board-conf.h"
45 #include "hdc-1000-sensor.h"
46 /*---------------------------------------------------------------------------*/
47 #include <Board.h>
48 
49 #include <ti/drivers/I2C.h>
50 /*---------------------------------------------------------------------------*/
51 #include <stdint.h>
52 #include <string.h>
53 #include <stdbool.h>
54 #include <stdio.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_HDC1000_ADDR
71 #error "Board file doesn't define the I2C address Board_HDC1000_ADDR"
72 #endif
73 /* Sensor I2C address */
74 #define HDC1000_I2C_ADDRESS Board_HDC1000_ADDR
75 /*---------------------------------------------------------------------------*/
76 /* Registers */
77 #define HDC1000_REG_TEMP 0x00 /* Temperature */
78 #define HDC1000_REG_HUM 0x01 /* Humidity */
79 #define HDC1000_REG_CONFIG 0x02 /* Configuration */
80 #define HDC1000_REG_SERID_H 0xFB /* Serial ID high */
81 #define HDC1000_REG_SERID_M 0xFC /* Serial ID middle */
82 #define HDC1000_REG_SERID_L 0xFD /* Serial ID low */
83 #define HDC1000_REG_MANF_ID 0xFE /* Manufacturer ID */
84 #define HDC1000_REG_DEV_ID 0xFF /* Device ID */
85 /*---------------------------------------------------------------------------*/
86 /* Fixed values */
87 #define HDC1000_VAL_MANF_ID 0x5449
88 #define HDC1000_VAL_DEV_ID 0x1000
89 #define HDC1000_VAL_CONFIG 0x1000 /* 14 bit, acquired in sequence */
90 /*---------------------------------------------------------------------------*/
91 /* Byte swap of 16-bit register value */
92 #define HI_UINT16(a) (((a) >> 8) & 0xFF)
93 #define LO_UINT16(a) ((a) & 0xFF)
94 
95 #define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v))
96 
97 #define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v))
98 /*---------------------------------------------------------------------------*/
99 static I2C_Handle i2c_handle;
100 /*---------------------------------------------------------------------------*/
101 /* Raw data as returned from the sensor (Big Endian) */
102 typedef struct {
103  uint16_t temp;
104  uint16_t hum;
105 } HDC_1000_SensorData;
106 
107 static HDC_1000_SensorData sensor_data;
108 /*---------------------------------------------------------------------------*/
109 static volatile HDC_1000_SENSOR_STATUS sensor_status = HDC_1000_SENSOR_STATUS_DISABLED;
110 /*---------------------------------------------------------------------------*/
111 /*
112  * Maximum measurement durations in clock ticks. We use 14bit resolution, thus:
113  * - Tmp: 6.35ms
114  * - RH: 6.5ms
115  */
116 #define MEASUREMENT_DURATION 2
117 
118 /*
119  * Wait SENSOR_STARTUP_DELAY clock ticks between activation and triggering a
120  * reading (max 15ms)
121  */
122 #define SENSOR_STARTUP_DELAY 3
123 
124 static struct ctimer startup_timer;
125 /*---------------------------------------------------------------------------*/
126 /**
127  * \brief Setup and peform an I2C transaction.
128  * \param wbuf Output buffer during the I2C transation.
129  * \param wcount How many bytes in the wbuf.
130  * \param rbuf Input buffer during the I2C transation.
131  * \param rcount How many bytes to read into rbuf.
132  * \return true if the I2C operation was successful;
133  * else, return false.
134  */
135 static bool
136 i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount)
137 {
138  I2C_Transaction i2c_transaction = {
139  .writeBuf = wbuf,
140  .writeCount = wcount,
141  .readBuf = rbuf,
142  .readCount = rcount,
143  .slaveAddress = HDC1000_I2C_ADDRESS,
144  };
145 
146  return I2C_transfer(i2c_handle, &i2c_transaction);
147 }
148 /**
149  * \brief Peform a write only I2C transaction.
150  * \param wbuf Output buffer during the I2C transation.
151  * \param wcount How many bytes in the wbuf.
152  * \return true if the I2C operation was successful;
153  * else, return false.
154  */
155 static inline bool
156 i2c_write(void *wbuf, size_t wcount)
157 {
158  return i2c_write_read(wbuf, wcount, NULL, 0);
159 }
160 /**
161  * \brief Peform a read only I2C transaction.
162  * \param rbuf Input buffer during the I2C transation.
163  * \param rcount How many bytes to read into rbuf.
164  * \return true if the I2C operation was successful;
165  * else, return false.
166  */
167 static inline bool
168 i2c_read(void *rbuf, size_t rcount)
169 {
170  return i2c_write_read(NULL, 0, rbuf, rcount);
171 }
172 /*---------------------------------------------------------------------------*/
173 /**
174  * \brief Initialize the HDC-1000 sensor driver.
175  * \return true if I2C operation successful; else, return false.
176  */
177 static bool
179 {
180  if(i2c_handle) {
181  return true;
182  }
183 
184  I2C_Params i2c_params;
185  I2C_Params_init(&i2c_params);
186 
187  i2c_params.transferMode = I2C_MODE_BLOCKING;
188  i2c_params.bitRate = I2C_400kHz;
189 
190  i2c_handle = I2C_open(Board_I2C0, &i2c_params);
191  if(i2c_handle == NULL) {
192  return false;
193  }
194 
195  /* Enable reading data in one operation */
196  uint8_t config_data[] = { HDC1000_REG_CONFIG, LSB16(HDC1000_VAL_CONFIG) };
197 
198  return i2c_write(config_data, sizeof(config_data));
199 }
200 /*---------------------------------------------------------------------------*/
201 /**
202  * \brief Start measurement.
203  * \return true if I2C operation successful; else, return false.
204  */
205 static bool
206 start(void)
207 {
208  uint8_t temp_reg[] = { HDC1000_REG_TEMP };
209 
210  return i2c_write(temp_reg, sizeof(temp_reg));
211 }
212 /*---------------------------------------------------------------------------*/
213 /**
214  * \brief Convert raw data to temperature and humidity.
215  * \param temp Output variable to store converted temperature.
216  * \param hum Output variable to store converted humidity.
217  */
218 static void
219 convert(int32_t *temp, int32_t *hum)
220 {
221  int32_t raw_temp = SWAP16(sensor_data.temp);
222  int32_t raw_hum = SWAP16(sensor_data.hum);
223 
224  /* Convert temperature to degrees C */
225  *temp = raw_temp * 100 * 165 / 65536 - 40000;
226  /* Convert relative humidity to a %RH value */
227  *hum = raw_hum * 100 * 100 / 65536;
228 }
229 /*---------------------------------------------------------------------------*/
230 /**
231  * \brief Callback when sensor is ready to read data from.
232  */
233 static void
234 notify_ready(void *unused)
235 {
236  /* Unused args */
237  (void)unused;
238 
239  /* Latch readings */
240  if(i2c_read(&sensor_data, sizeof(sensor_data))) {
242  } else {
243  sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR;
244  }
245 
246  sensors_changed(&hdc_1000_sensor);
247 }
248 /*---------------------------------------------------------------------------*/
249 /**
250  * \brief Returns a reading from the sensor.
251  * \param type HDC_1000_SENSOR_TYPE_TEMP or HDC_1000_SENSOR_TYPE_HUMID.
252  * \return Temperature (centi degrees C) or Humidity (centi %RH).
253  */
254 static int
255 value(int type)
256 {
257  int32_t temp = 0;
258  int32_t hum = 0;
259 
260  if(sensor_status != HDC_1000_SENSOR_STATUS_READINGS_READY) {
261  PRINTF("Sensor disabled or starting up (%d)\n", sensor_status);
262  return HDC_1000_READING_ERROR;
263  }
264 
265  switch(type) {
266  case HDC_1000_SENSOR_TYPE_TEMP:
267  case HDC_1000_SENSOR_TYPE_HUMID:
268  convert(&temp, &hum);
269  PRINTF("HDC: t=%d h=%d\n", (int)temp, (int)hum);
270 
271  if(type == HDC_1000_SENSOR_TYPE_TEMP) {
272  return (int)temp;
273  } else if(type == HDC_1000_SENSOR_TYPE_HUMID) {
274  return (int)hum;
275  } else {
276  return HDC_1000_READING_ERROR;
277  }
278 
279  default:
280  PRINTF("Invalid type\n");
281  return HDC_1000_READING_ERROR;
282  }
283 }
284 /*---------------------------------------------------------------------------*/
285 /**
286  * \brief Configuration function for the HDC1000 sensor.
287  * \param type Activate, enable or disable the sensor. See below.
288  * \param enable Either enable or disable the sensor.
289  * When type == SENSORS_HW_INIT we turn on the hardware.
290  * When type == SENSORS_ACTIVE and enable==1 we enable the sensor.
291  * When type == SENSORS_ACTIVE and enable==0 we disable the sensor.
292  */
293 static int
294 configure(int type, int enable)
295 {
296  switch(type) {
297  case SENSORS_HW_INIT:
298  memset(&sensor_data, 0, sizeof(sensor_data));
299 
300  if(sensor_init()) {
301  sensor_status = HDC_1000_SENSOR_STATUS_INITIALISED;
302  } else {
303  sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR;
304  }
305  break;
306 
307  case SENSORS_ACTIVE:
308  /* Must be initialised first */
309  if(sensor_status == HDC_1000_SENSOR_STATUS_DISABLED) {
310  break;
311  }
312 
313  if(enable) {
314  if(!start()) {
315  sensor_status = HDC_1000_SENSOR_STATUS_I2C_ERROR;
316  break;
317  }
318  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
320  } else {
321  ctimer_stop(&startup_timer);
322  sensor_status = HDC_1000_SENSOR_STATUS_INITIALISED;
323  }
324  break;
325 
326  default:
327  break;
328  }
329  return sensor_status;
330 }
331 /*---------------------------------------------------------------------------*/
332 /**
333  * \brief Returns the status of the sensor.
334  * \param type SENSORS_ACTIVE or SENSORS_READY.
335  * \return One of the SENSOR_STATUS_xyz defines.
336  */
337 static int
338 status(int type)
339 {
340  switch(type) {
341  case SENSORS_ACTIVE:
342  case SENSORS_READY:
343  return sensor_status;
344 
345  default:
347  }
348 }
349 /*---------------------------------------------------------------------------*/
350 SENSORS_SENSOR(hdc_1000_sensor, "HDC1000", value, configure, status);
351 /*---------------------------------------------------------------------------*/
352 #endif /* BOARD_SENSORS_ENABLE */
353 /*---------------------------------------------------------------------------*/
354 /** @} */
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static bool start(void)
Start measurement.
static int configure(int type, int enable)
Configuration function for the HDC1000 sensor.
static int status(int type)
Returns the status of the sensor.
static bool i2c_read(void *rbuf, size_t rcount)
Peform a read only I2C transaction.
Header file for the callback timer
static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount)
Setup and peform an I2C transaction.
static void convert(int32_t *temp, int32_t *hum)
Convert raw data to temperature and humidity.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
I2C transaction failed.
static int value(int type)
Returns a reading from the sensor.
static bool i2c_write(void *wbuf, size_t wcount)
Peform a write only I2C transaction.
static bool sensor_init(void)
Initialize the HDC-1000 sensor driver.
static void notify_ready(void *unused)
Callback when sensor is ready to read data from.
Header file with definitions related to the sensors on the Sensortags.
HDC_1000_SENSOR_STATUS