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