Contiki-NG
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
138typedef struct {
139 volatile OPT_3001_STATUS status;
140} OPT_3001_Object;
141
142static 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
147static struct ctimer startup_timer;
148/*---------------------------------------------------------------------------*/
149static I2C_Handle i2c_handle;
150/*---------------------------------------------------------------------------*/
151/**
152 * \brief Turn the sensor on/off
153 * \param enable Enable sensor if true; else, disable sensor.
154 */
155static bool
156sensor_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 */
184static void
185notify_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 };
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 */
231static int
232value(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 };
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 };
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 */
297static int
298configure(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 */
330static int
331status(int type)
332{
333 /* Unused args */
334 (void)type;
335
336 return opt_3001.status;
337}
338/*---------------------------------------------------------------------------*/
339SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status);
340/*---------------------------------------------------------------------------*/
341#endif /* BOARD_SENSORS_ENABLE */
342/*---------------------------------------------------------------------------*/
343/** @} */
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:138
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition ctimer.h:137
static int value(int type)
Returns a reading from the sensor.
static int status(int type)
Returns the status of the sensor.
static int value(int type)
Returns a reading from the sensor.
static bool sensor_enable(bool enable)
Turn the sensor on/off.
static void notify_ready_cb(void *unused)
Callback when sensor is ready to read data from.
#define CFG_CRF
[7] Conversion Ready Field
static int configure(int type, int enable)
Configuration function for the OPT3001 sensor.
Implementation of the I2C HAL driver for CC13xx/CC26xx.
Header file with definitions related to the sensors on the Sensortags.