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