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/*---------------------------------------------------------------------------*/
115static 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
120static PIN_State pin_state;
121static PIN_Handle pin_handle;
122
123static I2C_Handle i2c_handle;
124/*---------------------------------------------------------------------------*/
125typedef 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
132static 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
137static 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 */
143static 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 */
163static void
164notify_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 */
173static bool
174enable_sensor(bool enable)
175{
176 bool rv;
177
178 uint16_t cfg_value = (enable)
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 */
206static bool
207read_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 */
269static void
270convert(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 */
287static int
288value(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 */
335static int
336configure(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 */
377static int
378status(int type)
379{
380 (void)type;
381
382 return tmp_007.status;
383}
384/*---------------------------------------------------------------------------*/
385SENSORS_SENSOR(tmp_007_sensor, "TMP-007", value, configure, status);
386/*---------------------------------------------------------------------------*/
387#endif /* BOARD_SENSORS_ENABLE */
388/*---------------------------------------------------------------------------*/
389/** @} */
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
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
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 read_data(uint16_t *local_tmp, uint16_t *obj_tmp)
Read the sensor value registers.
static int value(int type)
Returns a reading from the sensor.
#define VAL_CONFIG_OFF
Sensor off state.
static void convert(uint16_t *local_tmp, uint16_t *obj_tmp)
Convert raw data to values in degrees Celsius.
static int status(int type)
Returns the status of the sensor.
static bool enable_sensor(bool enable)
Turn the sensor on or off.
static void notify_ready_cb(void *not_used)
Callback when sensor is ready to read data from.
static bool sensor_init(void)
Initialize the TMP-007 sensor driver.
static int configure(int type, int enable)
Configuration function for the TMP-007 sensor.
#define VAL_CONFIG_ON
Sensor on state.
Implementation of the I2C HAL driver for CC13xx/CC26xx.
Header file with definitions related to SmartRF06 EB boards.