Contiki-NG
opt-3001-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-opt-sensor
32  * @{
33  *
34  * \file
35  * Driver for the Sensortag OPT-3001 light 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 "opt-3001-sensor.h"
47 /*---------------------------------------------------------------------------*/
48 #include <Board.h>
49 
50 #include <ti/drivers/I2C.h>
51 /*---------------------------------------------------------------------------*/
52 #include <stdint.h>
53 #include <stdbool.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 #ifndef Board_OPT3001_ADDR
72 #error "Board file doesn't define I2C address Board_OPT3001_ADDR"
73 #endif
74 /* Slave address */
75 #define OPT_3001_I2C_ADDRESS Board_OPT3001_ADDR
76 /*---------------------------------------------------------------------------*/
77 /* Register addresses */
78 #define REG_RESULT 0x00
79 #define REG_CONFIGURATION 0x01
80 #define REG_LOW_LIMIT 0x02
81 #define REG_HIGH_LIMIT 0x03
82 
83 #define REG_MANUFACTURER_ID 0x7E
84 #define REG_DEVICE_ID 0x7F
85 /*---------------------------------------------------------------------------*/
86 /*
87  * Configuration Register Bits and Masks.
88  * We use uint16_t to read from / write to registers, meaning that the
89  * register's MSB is the variable's LSB.
90  */
91 #define CFG_RN 0x00F0 /**< [15..12] Range Number */
92 #define CFG_CT 0x0008 /**< [11] Conversion Time */
93 #define CFG_M 0x0006 /**< [10..9] Mode of Conversion */
94 #define CFG_OVF 0x0001 /**< [8] Overflow */
95 #define CFG_CRF 0x8000 /**< [7] Conversion Ready Field */
96 #define CFG_FH 0x4000 /**< [6] Flag High */
97 #define CFG_FL 0x2000 /**< [5] Flag Low */
98 #define CFG_L 0x1000 /**< [4] Latch */
99 #define CFG_POL 0x0800 /**< [3] Polarity */
100 #define CFG_ME 0x0400 /**< [2] Mask Exponent */
101 #define CFG_FC 0x0300 /**< [1..0] Fault Count */
102 /*---------------------------------------------------------------------------*/
103 /* Possible Values for CT */
104 #define CFG_CT_100 0x0000
105 #define CFG_CT_800 CFG_CT
106 /*---------------------------------------------------------------------------*/
107 /* Possible Values for M */
108 #define CFG_M_CONTI 0x0004
109 #define CFG_M_SINGLE 0x0002
110 #define CFG_M_SHUTDOWN 0x0000
111 /*---------------------------------------------------------------------------*/
112 /* Reset Value for the register 0xC810. All zeros except: */
113 #define CFG_RN_RESET 0x00C0
114 #define CFG_CT_RESET CFG_CT_800
115 #define CFG_L_RESET 0x1000
116 #define CFG_DEFAULTS (CFG_RN_RESET | CFG_CT_100 | CFG_L_RESET)
117 /*---------------------------------------------------------------------------*/
118 /* Enable / Disable */
119 #define CFG_ENABLE_CONTINUOUS (CFG_M_CONTI | CFG_DEFAULTS)
120 #define CFG_ENABLE_SINGLE_SHOT (CFG_M_SINGLE | CFG_DEFAULTS)
121 #define CFG_DISABLE CFG_DEFAULTS
122 /*---------------------------------------------------------------------------*/
123 /* Register length */
124 #define REGISTER_LENGTH 2
125 /*---------------------------------------------------------------------------*/
126 /* Sensor data size */
127 #define DATA_LENGTH 2
128 /*---------------------------------------------------------------------------*/
129 /* Byte swap of 16-bit register value */
130 #define HI_UINT16(a) (((a) >> 8) & 0xFF)
131 #define LO_UINT16(a) (((a) >> 0) & 0xFF)
132 
133 #define SWAP16(v) ((LO_UINT16(v) << 8) | (HI_UINT16(v) << 0))
134 
135 #define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v))
136 #define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v))
137 /*---------------------------------------------------------------------------*/
138 typedef struct {
139  volatile OPT_3001_STATUS status;
140 } OPT_3001_Object;
141 
142 static OPT_3001_Object opt_3001;
143 /*---------------------------------------------------------------------------*/
144 /* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */
145 #define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3)
146 
147 static struct ctimer startup_timer;
148 /*---------------------------------------------------------------------------*/
149 static I2C_Handle i2c_handle;
150 /*---------------------------------------------------------------------------*/
151 /**
152  * \brief Turn the sensor on/off
153  * \param enable Enable sensor if true; else, disable sensor.
154  */
155 static bool
156 sensor_enable(bool enable)
157 {
158  bool rv;
159  uint16_t data = (enable)
160  ? CFG_ENABLE_SINGLE_SHOT
161  : CFG_DISABLE;
162 
163  i2c_handle = i2c_arch_acquire(Board_I2C0);
164 
165  if(!i2c_handle) {
166  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
167  i2c_arch_release(i2c_handle);
168  return false;
169  }
170 
171  uint8_t cfg_data[] = { REG_CONFIGURATION, LSB16(data) };
172 
173  rv = i2c_arch_write(i2c_handle, OPT_3001_I2C_ADDRESS, cfg_data,
174  sizeof(cfg_data));
175 
176  i2c_arch_release(i2c_handle);
177 
178  return rv;
179 }
180 /*---------------------------------------------------------------------------*/
181 /**
182  * \brief Callback when sensor is ready to read data from.
183  */
184 static void
185 notify_ready_cb(void *unused)
186 {
187  /* Unused args */
188  (void)unused;
189  bool rv;
190 
191  i2c_handle = i2c_arch_acquire(Board_I2C0);
192 
193  if(!i2c_handle) {
194  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
195  return;
196  }
197 
198  /*
199  * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will
200  * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and
201  * if the reading is ready we notify, otherwise we just reschedule ourselves
202  */
203 
204  uint8_t cfg_data[] = { REG_CONFIGURATION };
205  uint16_t cfg_value = 0;
206 
207  rv = i2c_arch_write_read(i2c_handle, OPT_3001_I2C_ADDRESS, cfg_data,
208  sizeof(cfg_data), &cfg_value,
209  sizeof(cfg_value));
210  if(!rv) {
211  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
212  i2c_arch_release(i2c_handle);
213  return;
214  }
215 
216  if(cfg_value & CFG_CRF) {
217  opt_3001.status = OPT_3001_STATUS_DATA_READY;
218  sensors_changed(&opt_3001_sensor);
219  } else {
220  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
221  }
222 
223  i2c_arch_release(i2c_handle);
224 }
225 /*---------------------------------------------------------------------------*/
226 /**
227  * \brief Returns a reading from the sensor.
228  * \param type Ignored.
229  * \return Illuminance in centilux.
230  */
231 static int
232 value(int type)
233 {
234  /* Unused args */
235  (void)type;
236  bool rv;
237 
238  if(opt_3001.status != OPT_3001_STATUS_DATA_READY) {
239  return OPT_3001_READING_ERROR;
240  }
241 
242  i2c_handle = i2c_arch_acquire(Board_I2C0);
243 
244  if(!i2c_handle) {
245  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
246  return OPT_3001_READING_ERROR;
247  }
248 
249  uint8_t cfg_data[] = { REG_CONFIGURATION };
250  uint16_t cfg_value = 0;
251 
252  rv = i2c_arch_write_read(i2c_handle, OPT_3001_I2C_ADDRESS, cfg_data,
253  sizeof(cfg_data), &cfg_value, sizeof(cfg_value));
254  if(!rv) {
255  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
256  i2c_arch_release(i2c_handle);
257  return OPT_3001_READING_ERROR;
258  }
259 
260  uint8_t result_data[] = { REG_RESULT };
261  uint16_t result_value = 0;
262 
263  rv = i2c_arch_write_read(i2c_handle, OPT_3001_I2C_ADDRESS, result_data,
264  sizeof(result_data), &result_value,
265  sizeof(result_value));
266  i2c_arch_release(i2c_handle);
267  if(!rv) {
268  opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
269  return OPT_3001_READING_ERROR;
270  }
271 
272  result_value = SWAP16(result_value);
273 
274  /* formula for computing lux: lux = 0.01 * 2^e * m
275  * scale up by 100 to avoid floating point, then require
276  * users to scale down by same.
277  */
278  uint32_t m = (result_value & 0x0FFF) >> 0;
279  uint32_t e = (result_value & 0xF000) >> 12;
280  uint32_t converted = m * (1 << e);
281 
282  PRINTF("OPT: %04X r=%d (centilux)\n", result_value,
283  (int)(converted));
284 
285  return (int)converted;
286 }
287 /*---------------------------------------------------------------------------*/
288 /**
289  * \brief Configuration function for the OPT3001 sensor.
290  * \param type Activate, enable or disable the sensor. See below.
291  * \param enable Enable or disable sensor.
292  *
293  * When type == SENSORS_HW_INIT we turn on the hardware.
294  * When type == SENSORS_ACTIVE and enable==1 we enable the sensor.
295  * When type == SENSORS_ACTIVE and enable==0 we disable the sensor.
296  */
297 static int
298 configure(int type, int enable)
299 {
300  int rv = 0;
301  switch(type) {
302  case SENSORS_HW_INIT:
303  opt_3001.status = OPT_3001_STATUS_STANDBY;
304  break;
305 
306  case SENSORS_ACTIVE:
307  if(enable) {
308  sensor_enable(true);
309  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
310 
311  opt_3001.status = OPT_3001_STATUS_BOOTING;
312  } else {
313  ctimer_stop(&startup_timer);
314  sensor_enable(false);
315  }
316  break;
317 
318  default:
319  break;
320  }
321 
322  return rv;
323 }
324 /*---------------------------------------------------------------------------*/
325 /**
326  * \brief Returns the status of the sensor.
327  * \param type Ignored.
328  * \return The state of the sensor SENSOR_STATE_xyz.
329  */
330 static int
331 status(int type)
332 {
333  /* Unused args */
334  (void)type;
335 
336  return opt_3001.status;
337 }
338 /*---------------------------------------------------------------------------*/
339 SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status);
340 /*---------------------------------------------------------------------------*/
341 #endif /* BOARD_SENSORS_ENABLE */
342 /*---------------------------------------------------------------------------*/
343 /** @} */
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static int value(int type)
Returns a reading from the sensor.
static void notify_ready_cb(void *unused)
Callback when sensor is ready to read data from.
static int status(int type)
Returns the status of the sensor.
static int configure(int type, int enable)
Configuration function for the OPT3001 sensor.
Implementation of the I2C HAL driver for CC13xx/CC26xx.
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
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
static bool sensor_enable(bool enable)
Turn the sensor on/off.
Header file with definitions related to the sensors on the Sensortags.
#define CFG_CRF
[7] Conversion Ready Field