Contiki-NG
tmp-007-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-tmp-sensor
32  * @{
33  *
34  * \file
35  * Driver for the Sensortag TI TMP-007 IR Thermophile 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 /*---------------------------------------------------------------------------*/
44 #include "board-conf.h"
45 #include "tmp-007-sensor.h"
46 /*---------------------------------------------------------------------------*/
47 #include <Board.h>
48 
49 #include <ti/drivers/I2C.h>
50 #include <ti/drivers/PIN.h>
51 /*---------------------------------------------------------------------------*/
52 #include <stdint.h>
53 #include <string.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 /* Slave address */
71 #ifndef Board_TMP_ADDR
72 #error "Board file doesn't define I2C address Board_TMP_ADDR"
73 #endif
74 #define TMP_007_I2C_ADDRESS Board_TMP_ADDR
75 
76 /* Sensor Interrupt pin */
77 #ifndef Board_TMP_RDY
78 #error "Board file doesn't define interrupt pin Board_TMP_RDY"
79 #endif
80 #define TMP_007_TMP_RDY Board_TMP_RDY
81 /*---------------------------------------------------------------------------*/
82 /* TMP-007 register addresses */
83 #define REG_VOLTAGE 0x00
84 #define REG_LOCAL_TEMP 0x01
85 #define REG_CONFIG 0x02
86 #define REG_OBJ_TEMP 0x03
87 #define REG_STATUS 0x04
88 #define REG_PROD_ID 0x1F
89 /*---------------------------------------------------------------------------*/
90 /* TMP-007 register values */
91 #define VAL_CONFIG_ON 0x1000 /**< Sensor on state */
92 #define VAL_CONFIG_OFF 0x0000 /**< Sensor off state */
93 #define VAL_CONFIG_RESET 0x8000
94 #define VAL_PROD_ID 0x0078 /**< Product ID */
95 /*---------------------------------------------------------------------------*/
96 /* Conversion ready (status register) bit values */
97 #define CONV_RDY_BIT 0x4000
98 /*---------------------------------------------------------------------------*/
99 /* Register length */
100 #define REGISTER_LENGTH 2
101 /*---------------------------------------------------------------------------*/
102 /* Sensor data size */
103 #define DATA_SIZE 4
104 /*---------------------------------------------------------------------------*/
105 /* Byte swap of 16-bit register value */
106 #define HI_UINT16(a) (((a) >> 8) & 0xFF)
107 #define LO_UINT16(a) (((a) >> 0) & 0xFF)
108 
109 #define SWAP16(v) ((LO_UINT16(v) << 8) | (HI_UINT16(v) << 0))
110 
111 #define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v))
112 #define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v))
113 /*---------------------------------------------------------------------------*/
114 static const PIN_Config pin_table[] = {
115  TMP_007_TMP_RDY | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS | PIN_IRQ_NEGEDGE,
116  PIN_TERMINATE
117 };
118 
119 static PIN_State pin_state;
120 static PIN_Handle pin_handle;
121 
122 static I2C_Handle i2c_handle;
123 /*---------------------------------------------------------------------------*/
124 typedef struct {
125  TMP_007_TYPE type;
126  volatile TMP_007_STATUS status;
127  uint16_t local_tmp_latched;
128  uint16_t obj_tmp_latched;
129 } TMP_007_Object;
130 
131 static TMP_007_Object tmp_007;
132 /*---------------------------------------------------------------------------*/
133 /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - 275ms */
134 #define SENSOR_STARTUP_DELAY 36
135 
136 static struct ctimer startup_timer;
137 /*---------------------------------------------------------------------------*/
138 /**
139  * \brief Setup and peform an I2C transaction.
140  * \param wbuf Output buffer during the I2C transation.
141  * \param wcount How many bytes in the wbuf.
142  * \param rbuf Input buffer during the I2C transation.
143  * \param rcount How many bytes to read into rbuf.
144  * \return true if the I2C operation was successful;
145  * else, return false.
146  */
147 static bool
148 i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount)
149 {
150  I2C_Transaction i2c_transaction = {
151  .writeBuf = wbuf,
152  .writeCount = wcount,
153  .readBuf = rbuf,
154  .readCount = rcount,
155  .slaveAddress = TMP_007_I2C_ADDRESS,
156  };
157 
158  return I2C_transfer(i2c_handle, &i2c_transaction);
159 }
160 /**
161  * \brief Peform a write only I2C transaction.
162  * \param wbuf Output buffer during the I2C transation.
163  * \param wcount How many bytes in the wbuf.
164  * \return true if the I2C operation was successful;
165  * else, return false.
166  */
167 static inline bool
168 i2c_write(void *wbuf, size_t wcount)
169 {
170  return i2c_write_read(wbuf, wcount, NULL, 0);
171 }
172 /**
173  * \brief Peform a read only I2C transaction.
174  * \param rbuf Input buffer during the I2C transation.
175  * \param rcount How many bytes to read into rbuf.
176  * \return true if the I2C operation was successful;
177  * else, return false.
178  */
179 static inline bool
180 i2c_read(void *rbuf, size_t rcount)
181 {
182  return i2c_write_read(NULL, 0, rbuf, rcount);
183 }
184 /*---------------------------------------------------------------------------*/
185 /**
186  * \brief Initialize the TMP-007 sensor driver.
187  * \return true if I2C operation successful; else, return false.
188  */
189 static bool
191 {
192  if(pin_handle && i2c_handle) {
193  return true;
194  }
195 
196  pin_handle = PIN_open(&pin_state, pin_table);
197  if(!pin_handle) {
198  return false;
199  }
200 
201  I2C_Params i2c_params;
202  I2C_Params_init(&i2c_params);
203 
204  i2c_params.transferMode = I2C_MODE_BLOCKING;
205  i2c_params.bitRate = I2C_400kHz;
206 
207  i2c_handle = I2C_open(Board_I2C0, &i2c_params);
208  if(i2c_handle == NULL) {
209  PIN_close(pin_handle);
210  return false;
211  }
212 
213  tmp_007.status = TMP_007_STATUS_DISABLED;
214 
215  return true;
216 }
217 /*---------------------------------------------------------------------------*/
218 /**
219  * \brief Callback when sensor is ready to read data from.
220  */
221 static void
222 notify_ready_cb(void *not_used)
223 {
224  tmp_007.status = TMP_007_STATUS_READY;
225  sensors_changed(&tmp_007_sensor);
226 }
227 /*---------------------------------------------------------------------------*/
228 /**
229  * \brief Turn the sensor on or off.
230  */
231 static bool
232 enable_sensor(bool enable)
233 {
234  uint16_t cfg_value = (enable)
235  ? VAL_CONFIG_ON
236  : VAL_CONFIG_OFF;
237 
238  uint8_t cfg_data[] = { REG_CONFIG, LSB16(cfg_value) };
239 
240  return i2c_write(cfg_data, sizeof(cfg_data));
241 }
242 /*---------------------------------------------------------------------------*/
243 /**
244  * \brief Read the sensor value registers.
245  * \param local_tmp Output variable holding the Temperature in
246  * 16-bit format.
247  * \param obj_tmp Output variable holding the Object temperature in
248  * 16-bit format.
249  * \return true if valid data could be retrieved; else, false.
250  */
251 static bool
252 read_data(uint16_t *local_tmp, uint16_t *obj_tmp)
253 {
254  bool spi_ok = false;
255 
256  uint8_t status_data[] = { REG_STATUS };
257  uint16_t status_value = 0;
258 
259  spi_ok = i2c_write_read(status_data, sizeof(status_data),
260  &status_value, sizeof(status_value));
261  if(!spi_ok) {
262  return false;
263  }
264  status_value = SWAP16(status_value);
265 
266  if((status_value & CONV_RDY_BIT) == 0) {
267  return false;
268  }
269 
270  uint8_t local_temp_data[] = { REG_LOCAL_TEMP };
271  uint16_t local_temp_value = 0;
272 
273  spi_ok = i2c_write_read(local_temp_data, sizeof(local_temp_data),
274  &local_temp_value, sizeof(local_temp_value));
275  if(!spi_ok) {
276  return false;
277  }
278 
279  uint8_t obj_temp_data[] = { REG_OBJ_TEMP };
280  uint16_t obj_temp_value = 0;
281 
282  spi_ok = i2c_write_read(obj_temp_data, sizeof(obj_temp_data),
283  &obj_temp_value, sizeof(obj_temp_value));
284  if(!spi_ok) {
285  return false;
286  }
287 
288  *local_tmp = SWAP16(local_temp_value);
289  *obj_tmp = SWAP16(obj_temp_value);
290 
291  return true;
292 }
293 /*---------------------------------------------------------------------------*/
294 /**
295  * \brief Convert raw data to values in degrees Celsius.
296  * \param local_tmp Output variable holding the raw ambient temperature
297  * from sensor.
298  * \param obj_tmp Output variable holding the raw object temperature
299  * from sensor.
300  */
301 static void
302 convert(uint16_t *local_tmp, uint16_t *obj_tmp)
303 {
304  uint32_t local = (uint32_t)*local_tmp;
305  uint32_t obj = (uint32_t)*obj_tmp;
306 
307  local = (local >> 2) * 3125 / 100;
308  obj = (obj >> 2) * 3125 / 100;
309 
310  *local_tmp = (uint16_t)local;
311  *obj_tmp = (uint16_t)obj;
312 }
313 /*---------------------------------------------------------------------------*/
314 /**
315  * \brief Returns a reading from the sensor.
316  * \param type TMP_007_SENSOR_TYPE_OBJECT or TMP_007_SENSOR_TYPE_AMBIENT.
317  * \return Object or Ambient temperature in milli degrees Celsius.
318  */
319 static int
320 value(int type)
321 {
322  uint16_t raw_local_tmp = 0, local_tmp = 0;
323  uint16_t raw_obj_tmp = 0, obj_tmp = 0;
324 
325  if(tmp_007.status != TMP_007_STATUS_READY) {
326  PRINTF("Sensor disabled or starting up (%d)\n", tmp_007.status);
327  return TMP_007_READING_ERROR;
328  }
329 
330  switch(type) {
331  case TMP_007_TYPE_OBJECT: return tmp_007.obj_tmp_latched;
332  case TMP_007_TYPE_AMBIENT: return tmp_007.local_tmp_latched;
333 
334  case TMP_007_TYPE_ALL:
335  if(!read_data(&raw_local_tmp, &raw_obj_tmp)) {
336  return TMP_007_READING_ERROR;
337  }
338 
339  local_tmp = raw_local_tmp;
340  obj_tmp = raw_obj_tmp;
341  convert(&local_tmp, &obj_tmp);
342 
343  PRINTF("TMP: %04X %04X o=%d a=%d\n", raw_local_tmp, raw_obj_tmp,
344  (int)(local_tmp), (int)(obj_tmp));
345 
346  tmp_007.local_tmp_latched = (int)(local_tmp);
347  tmp_007.obj_tmp_latched = (int)(obj_tmp);
348 
349  return 0;
350 
351  default:
352  PRINTF("Invalid type (%d)\n", type);
353  return TMP_007_READING_ERROR;
354  }
355 }
356 /*---------------------------------------------------------------------------*/
357 /**
358  * \brief Configuration function for the TMP-007 sensor.
359  * \param type Activate, enable or disable the sensor. See below.
360  * \param enable Enable or disable sensor.
361  *
362  * When type == SENSORS_HW_INIT we turn on the hardware.
363  * When type == SENSORS_ACTIVE and enable==1 we enable the sensor.
364  * When type == SENSORS_ACTIVE and enable==0 we disable the sensor.
365  */
366 static int
367 configure(int type, int enable)
368 {
369  switch(type) {
370  case SENSORS_HW_INIT:
371  if(!sensor_init()) {
372  return TMP_007_STATUS_DISABLED;
373  }
374 
375  enable_sensor(false);
376 
377  tmp_007.status = TMP_007_STATUS_INITIALIZED;
378  break;
379 
380  case SENSORS_ACTIVE:
381  /* Must be initialised first */
382  if(tmp_007.status == TMP_007_STATUS_DISABLED) {
383  return TMP_007_STATUS_DISABLED;
384  }
385  if(enable) {
386  enable_sensor(true);
387  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
388  tmp_007.status = TMP_007_STATUS_NOT_READY;
389  } else {
390  ctimer_stop(&startup_timer);
391  enable_sensor(false);
392  tmp_007.status = TMP_007_STATUS_INITIALIZED;
393  }
394  break;
395 
396  default:
397  break;
398  }
399 
400  return tmp_007.status;
401 }
402 /*---------------------------------------------------------------------------*/
403 /**
404  * \brief Returns the status of the sensor.
405  * \param type Ignored.
406  * \return Status of the sensor.
407  */
408 static int
409 status(int type)
410 {
411  (void)type;
412 
413  return tmp_007.status;
414 }
415 /*---------------------------------------------------------------------------*/
416 SENSORS_SENSOR(tmp_007_sensor, "TMP-007", value, configure, status);
417 /*---------------------------------------------------------------------------*/
418 #endif /* BOARD_SENSORS_ENABLE */
419 /*---------------------------------------------------------------------------*/
420 /** @} */
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static bool i2c_write_read(void *wbuf, size_t wcount, void *rbuf, size_t rcount)
Setup and peform an I2C transaction.
static bool i2c_write(void *wbuf, size_t wcount)
Peform a write only I2C transaction.
static bool enable_sensor(bool enable)
Turn the sensor on or off.
static int value(int type)
Returns a reading from the sensor.
static bool read_data(uint16_t *local_tmp, uint16_t *obj_tmp)
Read the sensor value registers.
Header file for the callback timer
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
static bool i2c_read(void *rbuf, size_t rcount)
Peform a read only I2C transaction.
#define VAL_CONFIG_OFF
Sensor off state.
static void notify_ready_cb(void *not_used)
Callback when sensor is ready to read data from.
static int configure(int type, int enable)
Configuration function for the TMP-007 sensor.
#define VAL_CONFIG_ON
Sensor on state.
Header file with definitions related to the sensors on the Sensortags.
static bool sensor_init(void)
Initialize the TMP-007 sensor driver.
static int status(int type)
Returns the status of the sensor.
static void convert(uint16_t *local_tmp, uint16_t *obj_tmp)
Convert raw data to values in degrees Celsius.