Merge branch 'master' of git://github.com/microbuilder/LPC1343CodeBase
[hackover2013-badge-firmware.git] / drivers / sensors / tsl2561 / tsl2561.c
1 /**************************************************************************/
2 /*!
3 @file tsl2561.c
4 @author K. Townsend (microBuilder.eu)
5
6 @brief Drivers for the TAOS TSL2561 I2C digital luminosity sensor
7
8 @section DESCRIPTION
9
10 The TSL2561 is a 16-bit digital luminosity sensor the approximates
11 the human eye's response to light. It contains one broadband
12 photodiode that measures visible plus infrared light (channel 0)
13 and one infrared photodiode (channel 1).
14
15 @section EXAMPLE
16
17 @code
18 #include "drivers/sensors/tsl2561/tsl2561.h"
19 ...
20 uint16_t broadband, ir;
21 uint32_t lux;
22
23 // Initialise luminosity sensor
24 tsl2561Init();
25
26 // Optional ... default setting is 400ms with no gain
27 // Set timing to 101ms with no gain
28 tsl2561SetTiming(TSL2561_INTEGRATIONTIME_101MS, TSL2561_GAIN_0X);
29
30 // Check luminosity level and calculate lux
31 tsl2561GetLuminosity(&broadband, &ir);
32 lux = tsl2561CalculateLux(broadband, ir);
33 printf("Broadband: %u, IR: %u, Lux: %d %s", broadband, ir, lux, CFG_PRINTF_NEWLINE);
34
35 @endcode
36
37 @section LICENSE
38
39 Software License Agreement (BSD License)
40
41 Copyright (c) 2010, microBuilder SARL
42 All rights reserved.
43
44 Redistribution and use in source and binary forms, with or without
45 modification, are permitted provided that the following conditions are met:
46 1. Redistributions of source code must retain the above copyright
47 notice, this list of conditions and the following disclaimer.
48 2. Redistributions in binary form must reproduce the above copyright
49 notice, this list of conditions and the following disclaimer in the
50 documentation and/or other materials provided with the distribution.
51 3. Neither the name of the copyright holders nor the
52 names of its contributors may be used to endorse or promote products
53 derived from this software without specific prior written permission.
54
55 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
56 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
57 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
59 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 */
66 /**************************************************************************/
67 #include "tsl2561.h"
68 #include "core/systick/systick.h"
69
70 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
71 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
72 extern volatile uint32_t I2CReadLength, I2CWriteLength;
73
74 static bool _tsl2561Initialised = false;
75 static tsl2561IntegrationTime_t _tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_402MS;
76 static tsl2561Gain_t _tsl2561Gain = TSL2561_GAIN_0X;
77
78 /**************************************************************************/
79 /*!
80 @brief Sends a single command byte over I2C
81 */
82 /**************************************************************************/
83 tsl2561Error_t tsl2561WriteCmd (uint8_t cmd)
84 {
85 // Clear write buffers
86 uint32_t i;
87 for ( i = 0; i < I2C_BUFSIZE; i++ )
88 {
89 I2CMasterBuffer[i] = 0x00;
90 }
91
92 I2CWriteLength = 2;
93 I2CReadLength = 0;
94 I2CMasterBuffer[0] = TSL2561_ADDRESS; // I2C device address
95 I2CMasterBuffer[1] = cmd; // Command register
96 i2cEngine();
97 return TSL2561_ERROR_OK;
98 }
99
100 /**************************************************************************/
101 /*!
102 @brief Writes an 8 bit values over I2C
103 */
104 /**************************************************************************/
105 tsl2561Error_t tsl2561Write8 (uint8_t reg, uint32_t value)
106 {
107 // Clear write buffers
108 uint32_t i;
109 for ( i = 0; i < I2C_BUFSIZE; i++ )
110 {
111 I2CMasterBuffer[i] = 0x00;
112 }
113
114 I2CWriteLength = 3;
115 I2CReadLength = 0;
116 I2CMasterBuffer[0] = TSL2561_ADDRESS; // I2C device address
117 I2CMasterBuffer[1] = reg; // Command register
118 I2CMasterBuffer[2] = (value & 0xFF); // Value to write
119 i2cEngine();
120 return TSL2561_ERROR_OK;
121 }
122
123 /**************************************************************************/
124 /*!
125 @brief Reads a 16 bit values over I2C
126 */
127 /**************************************************************************/
128 tsl2561Error_t tsl2561Read16(uint8_t reg, uint16_t *value)
129 {
130 // Clear write buffers
131 uint32_t i;
132 for ( i = 0; i < I2C_BUFSIZE; i++ )
133 {
134 I2CMasterBuffer[i] = 0x00;
135 }
136
137 I2CWriteLength = 2;
138 I2CReadLength = 2;
139 I2CMasterBuffer[0] = TSL2561_ADDRESS; // I2C device address
140 I2CMasterBuffer[1] = reg; // Command register
141 // Append address w/read bit
142 I2CMasterBuffer[2] = TSL2561_ADDRESS | TSL2561_READBIT;
143 i2cEngine();
144
145 // Shift values to create properly formed integer (low byte first)
146 *value = (I2CSlaveBuffer[0] | (I2CSlaveBuffer[1] << 8));
147
148 return TSL2561_ERROR_OK;
149 }
150
151 /**************************************************************************/
152 /*!
153 @brief Enables the device
154 */
155 /**************************************************************************/
156 tsl2561Error_t tsl2561Enable(void)
157 {
158 if (!_tsl2561Initialised) tsl2561Init();
159
160 // Enable the device by setting the control bit to 0x03
161 return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON);
162 }
163
164 /**************************************************************************/
165 /*!
166 @brief Disables the device (putting it in lower power sleep mode)
167 */
168 /**************************************************************************/
169 tsl2561Error_t tsl2561Disable(void)
170 {
171 if (!_tsl2561Initialised) tsl2561Init();
172
173 // Turn the device off to save power
174 return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF);
175 }
176
177 /**************************************************************************/
178 /*!
179 @brief Initialises the I2C block
180 */
181 /**************************************************************************/
182 tsl2561Error_t tsl2561Init(void)
183 {
184 // Initialise I2C
185 if (i2cInit(I2CMASTER) == false)
186 {
187 return TSL2561_ERROR_I2CINIT; /* Fatal error */
188 }
189
190 _tsl2561Initialised = true;
191
192 // Set default integration time and gain
193 tsl2561SetTiming(_tsl2561IntegrationTime, _tsl2561Gain);
194
195 // Note: by default, the device is in power down mode on bootup
196
197 return TSL2561_ERROR_OK;
198 }
199
200 /**************************************************************************/
201 /*!
202 @brief Sets the integration time and gain (controls sensitivity)
203 */
204 /**************************************************************************/
205 tsl2561Error_t tsl2561SetTiming(tsl2561IntegrationTime_t integration, tsl2561Gain_t gain)
206 {
207 if (!_tsl2561Initialised) tsl2561Init();
208
209 tsl2561Error_t error = TSL2561_ERROR_OK;
210
211 // Enable the device by setting the control bit to 0x03
212 error = tsl2561Enable();
213 if (error) return error;
214
215 // Turn the device off to save power
216 error = tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, integration | gain);
217 if (error) return error;
218
219 // Update value placeholders
220 _tsl2561IntegrationTime = integration;
221 _tsl2561Gain = gain;
222
223 // Turn the device off to save power
224 error = tsl2561Disable();
225 if (error) return error;
226
227 return error;
228 }
229
230 /**************************************************************************/
231 /*!
232 @brief Reads the luminosity on both channels from the TSL2561
233 */
234 /**************************************************************************/
235 tsl2561Error_t tsl2561GetLuminosity (uint16_t *broadband, uint16_t *ir)
236 {
237 if (!_tsl2561Initialised) tsl2561Init();
238
239 tsl2561Error_t error = TSL2561_ERROR_OK;
240
241 // Enable the device by setting the control bit to 0x03
242 error = tsl2561Enable();
243 if (error) return error;
244
245 // Wait x ms for ADC to complete
246 switch (_tsl2561IntegrationTime)
247 {
248 case TSL2561_INTEGRATIONTIME_13MS:
249 systickDelay(14);
250 break;
251 case TSL2561_INTEGRATIONTIME_101MS:
252 systickDelay(102);
253 break;
254 default:
255 systickDelay(400);
256 break;
257 }
258
259 // Reads two byte value from channel 0 (visible + infrared)
260 error = tsl2561Read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW, broadband);
261 if (error) return error;
262
263 // Reads two byte value from channel 1 (infrared)
264 error = tsl2561Read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW, ir);
265 if (error) return error;
266
267 // Turn the device off to save power
268 error = tsl2561Disable();
269 if (error) return error;
270
271 return error;
272 }
273
274 /**************************************************************************/
275 /*!
276 @brief Calculates LUX from the supplied ch0 (broadband) and ch1
277 (IR) readings
278 */
279 /**************************************************************************/
280 uint32_t tsl2561CalculateLux(uint16_t ch0, uint16_t ch1)
281 {
282 unsigned long chScale;
283 unsigned long channel1;
284 unsigned long channel0;
285
286 switch (_tsl2561IntegrationTime)
287 {
288 case TSL2561_INTEGRATIONTIME_13MS:
289 chScale = TSL2561_LUX_CHSCALE_TINT0;
290 break;
291 case TSL2561_INTEGRATIONTIME_101MS:
292 chScale = TSL2561_LUX_CHSCALE_TINT1;
293 break;
294 default: // No scaling ... integration time = 402ms
295 chScale = (1 << TSL2561_LUX_CHSCALE);
296 break;
297 }
298
299 // Scale for gain (1x or 16x)
300 if (!_tsl2561Gain) chScale = chScale << 4;
301
302 // scale the channel values
303 channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE;
304 channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE;
305
306 // find the ratio of the channel values (Channel1/Channel0)
307 unsigned long ratio1 = 0;
308 if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;
309
310 // round the ratio value
311 unsigned long ratio = (ratio1 + 1) >> 1;
312
313 unsigned int b, m;
314
315 #ifdef TSL2561_PACKAGE_CS
316 if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C))
317 {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;}
318 else if (ratio <= TSL2561_LUX_K2C)
319 {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;}
320 else if (ratio <= TSL2561_LUX_K3C)
321 {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;}
322 else if (ratio <= TSL2561_LUX_K4C)
323 {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;}
324 else if (ratio <= TSL2561_LUX_K5C)
325 {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;}
326 else if (ratio <= TSL2561_LUX_K6C)
327 {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;}
328 else if (ratio <= TSL2561_LUX_K7C)
329 {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;}
330 else if (ratio > TSL2561_LUX_K8C)
331 {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;}
332 #else
333 if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T))
334 {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;}
335 else if (ratio <= TSL2561_LUX_K2T)
336 {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;}
337 else if (ratio <= TSL2561_LUX_K3T)
338 {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;}
339 else if (ratio <= TSL2561_LUX_K4T)
340 {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;}
341 else if (ratio <= TSL2561_LUX_K5T)
342 {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;}
343 else if (ratio <= TSL2561_LUX_K6T)
344 {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;}
345 else if (ratio <= TSL2561_LUX_K7T)
346 {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;}
347 else if (ratio > TSL2561_LUX_K8T)
348 {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;}
349 #endif
350
351 unsigned long temp;
352 temp = ((channel0 * b) - (channel1 * m));
353
354 // do not allow negative lux value
355 if (temp < 0) temp = 0;
356
357 // round lsb (2^(LUX_SCALE-1))
358 temp += (1 << (TSL2561_LUX_LUXSCALE-1));
359
360 // strip off fractional portion
361 uint32_t lux = temp >> TSL2561_LUX_LUXSCALE;
362
363 // Signal I2C had no errors
364 return lux;
365 }
This page took 0.083913 seconds and 5 git commands to generate.