µracoli Manual  Version foo
tsl2550.h
1 /* Copyright (c) 2013 Axel Wachtler
2  All rights reserved.
3 
4  Redistribution and use in source and binary forms, with or without
5  modification, are permitted provided that the following conditions
6  are met:
7 
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * 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  * Neither the name of the authors nor the names of its contributors
14  may be used to endorse or promote products derived from this software
15  without specific prior written permission.
16 
17  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  POSSIBILITY OF SUCH DAMAGE. */
28 
29 #ifndef TSL2550_H
30 #define TSL2550_H
31 
42 /* === includes ============================================================ */
43 #include <avr/pgmspace.h>
44 #include "sensor_defs.h"
45 
46 /* === macros ============================================================== */
48 #define TSL2550_ADDR (0x39)
49 
50 #define TSL2550_PWR_DOWN (0x00)
51 
52 #define TSL2550_RD_CMD (0x03)
53 
54 #define TSL2550_EXT_RANGE (0x1D)
55 
56 #define TSL2550_STD_RANGE (0x18)
57 
58 #define TSL2550_RD_ADC0 (0x43)
59 
60 #define TSL2550_RD_ADC1 (0x83)
61 
62 #define ADC_VALID_MASK (0x80)
63 
64 #define TSL2550_ADC_VALID(a) (a & ADC_VALID_MASK)
65 #define TSL2550_MAX_LUX (1846)
66 
67 /* === types =============================================================== */
68 typedef struct {
70  uint8_t addr;
71 } tsl2550_ctx_t;
72 
73 
74 /* === prototypes ========================================================== */
75 #ifdef __cplusplus
76 extern "C" {
77 #endif
78 static inline uint8_t tsl2550_init(void)
79 {
80  uint8_t rv;
81  rv = i2c_probe(TSL2550_ADDR);
82  return rv;
83 }
84 
85 static inline void tsl2550_set_command(uint8_t cmd)
86 {
87  i2c_master_writeread(TSL2550_ADDR, &cmd, 1, NULL, 0);
88 }
89 
93 static inline uint8_t tsl2550_get(uint8_t adc)
94 {
95  uint8_t rv;
96  uint8_t cmd;
97  cmd = (adc == 0) ? TSL2550_RD_ADC0 : TSL2550_RD_ADC1;
98 
99  i2c_master_writeread(TSL2550_ADDR, &cmd, 1, &rv, 1);
100  return rv;
101 }
102 
103 
105 static inline uint16_t tsl2550_scale(uint8_t adc0, uint8_t adc1)
106 {
107 
108  // Lookup table for channel ratio (i.e. channel1 / channel0)
109  static const unsigned char ratioLut[129] = {
110  100,100,100,100,100,100,100,100,
111  100,100,100,100,100,100,99,99,
112  99,99,99,99,99,99,99,99,
113  99,99,99,98,98,98,98,98,
114  98,98,97,97,97,97,97,96,
115  96,96,96,95,95,95,94,94,
116  93,93,93,92,92,91,91,90,
117  89,89,88,87,87,86,85,84,
118  83,82,81,80,79,78,77,75,
119  74,73,71,69,68,66,64,62,
120  60,58,56,54,52,49,47,44,
121  42,41,40,40,39,39,38,38,
122  37,37,37,36,36,36,35,35,
123  35,35,34,34,34,34,33,33,
124  33,33,32,32,32,32,32,31,
125  31,31,31,31,30,30,30,30,
126  30
127  };
128  // Lookup table to convert channel values to counts
129  static const unsigned short countLut[128] = {
130  0, 1, 2, 3, 4, 5, 6, 7,
131  8, 9, 10, 11, 12, 13, 14, 15,
132  16, 18, 20, 22, 24, 26, 28, 30,
133  32, 34, 36, 38, 40, 42, 44, 46,
134  49, 53, 57, 61, 65, 69, 73, 77,
135  81, 85, 89, 93, 97, 101, 105, 109,
136  115, 123, 131, 139, 147, 155, 163, 171,
137  179, 187, 195, 203, 211, 219, 227, 235,
138  247, 263, 279, 295, 311, 327, 343, 359,
139  375, 391, 407, 423, 439, 455, 471, 487,
140  511, 543, 575, 607, 639, 671, 703, 735,
141  767, 799, 831, 863, 895, 927, 959, 991,
142  1039,1103,1167,1231,1295,1359,1423,1487,
143  1551,1615,1679,1743,1807,1871,1935,1999,
144  2095,2223,2351,2479,2607,2735,2863,2991,
145  3119,3247,3375,3503,3631,3759,3887,4015
146  };
147 
148  /* lookup count from channel value */
149  uint16_t count0 = countLut[adc0 & ~ADC_VALID_MASK];
150  uint16_t count1 = countLut[adc1 & ~ADC_VALID_MASK];
151 
152 
153  /* calculate ratio
154  * Note: the "128" is a scaling factor
155  */
156  uint8_t ratio = 128;
157 
158  /* avoid division by zero and count1 cannot be greater than count0 */
159  if ((count0) && (count1 <= count0))
160  {
161  ratio = (count1 * 128 / count0);
162  }
163  /* calculate lux
164  * Note: the "256" is a scaling factor
165  */
166  unsigned long lux = ((count0 - count1) * ratioLut[ratio]) / 256;
167  /* range check lux */
168  if (lux > TSL2550_MAX_LUX)
169  {
170  lux = TSL2550_MAX_LUX;
171  }
172  return lux;
173 }
174 
175 /* highlevel interface */
176 
177 static inline void tsl2550_trigger(void *pctx, bool one_shot)
178 {
179  tsl2550_set_command(TSL2550_RD_CMD);
180 }
181 
182 static inline uint8_t tsl2550_get_val(void *pctx, uint8_t *pdata)
183 {
184 uint16_t lv_f;
185 uint8_t adc0, adc1;
186 sensor_light_t *p = (sensor_light_t*)pdata;
187 
188  if(p)
189  {
190  adc0 = tsl2550_get(0);
191  /* a time gap between two reads is needed, todo: check datasheet */
192  DELAY_US(10);
193  adc1 = tsl2550_get(1);
194  if ( TSL2550_ADC_VALID(adc0) && TSL2550_ADC_VALID(adc1))
195  {
196  lv_f = tsl2550_scale( adc0 , adc1);
197  }
198  else
199  {
200  lv_f = 0xaaaa;
201  }
202  p->type = SENSOR_DATA_LIGHT;
203  p->sensor = SENSOR_LEDPS;
204  p->light = lv_f;
205  }
206  return sizeof(sensor_light_t);
207 }
208 
209 static inline uint8_t tsl2550_get_raw(void *pctx, uint8_t *pdata)
210 {
211  uint8_t rv;
212  rv = sizeof(sensor_raw_t) - 1 + 2*sizeof(uint8_t);
213  if (pdata != NULL)
214  {
215  ((sensor_raw_t*)pdata)->type = SENSOR_DATA_RAW | 2*sizeof(uint8_t);
216  ((sensor_raw_t*)pdata)->sensor = SENSOR_TSL2550;
217  ((sensor_raw_t*)pdata)->data[0] = tsl2550_get(0);
218  ((sensor_raw_t*)pdata)->data[1] = tsl2550_get(1);
219  }
220  return rv;
221 }
222 static inline uint8_t sensor_create_tsl2550(void *pdata, bool raw)
223 {
224  uint8_t rv = sizeof(tsl2550_ctx_t);
225  tsl2550_ctx_t *pcfg;
226  uint8_t tst;
227 
228  if (pdata != NULL)
229  {
230  /* init generic sensor data */
231  pcfg = (tsl2550_ctx_t *)pdata;
232  pcfg->g.id = SENSOR_TSL2550;
233  pcfg->g.f_trigger = tsl2550_trigger;
234  pcfg->g.f_get_val = raw ? tsl2550_get_raw : tsl2550_get_val;
235  pcfg->g.f_sleep = NULL;
236 
237  /* initialize sensor */
238  tst = i2c_probe(TSL2550_ADDR);
239  pcfg->g.last_error = tst ? SENSOR_ERR_OK : SENSOR_ERR_INIT;
240  }
241  return rv;
242 }
243 
244 #ifdef __cplusplus
245 } /* extern "C" */
246 #endif
247 
248 #endif /* #ifndef TSL2550_H */
#define DELAY_US(x)
Macro for delays with us resolution.
Definition: board.h:89
uint8_t i2c_probe(uint8_t devaddr)
#define TSL2550_ADDR
Definition: tsl2550.h:48
uint8_t i2c_master_writeread(uint8_t devaddr, uint8_t *writebuf, uint8_t bytestowrite, uint8_t *readbuf, uint8_t bytestoread)
static uint16_t tsl2550_scale(uint8_t adc0, uint8_t adc1)
Definition: tsl2550.h:105
#define TSL2550_RD_ADC1
Definition: tsl2550.h:60
#define TSL2550_RD_CMD
Definition: tsl2550.h:52
static uint8_t tsl2550_get(uint8_t adc)
Definition: tsl2550.h:93
#define TSL2550_RD_ADC0
Definition: tsl2550.h:58