Initial commit
[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 uint32_t i;
75
76 static bool _tsl2561Initialised = false;
77 static tsl2561IntegrationTime_t _tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_402MS;
78 static tsl2561Gain_t _tsl2561Gain = TSL2561_GAIN_0X;
79
80 /**************************************************************************/
81 /*!
82 @brief Sends a single command byte over I2C
83 */
84 /**************************************************************************/
85 tsl2561Error_t tsl2561WriteCmd (uint8_t cmd)
86 {
87 // Clear write buffers
88 for ( i = 0; i < I2C_BUFSIZE; i++ )
89 {
90 I2CMasterBuffer[i] = 0x00;
91 }
92
93 I2CWriteLength = 2;
94 I2CReadLength = 0;
95 I2CMasterBuffer[0] = TSL2561_ADDRESS; // I2C device address
96 I2CMasterBuffer[1] = cmd; // Command register
97 i2cEngine();
98 return TSL2561_ERROR_OK;
99 }
100
101 /**************************************************************************/
102 /*!
103 @brief Writes an 8 bit values over I2C
104 */
105 /**************************************************************************/
106 tsl2561Error_t tsl2561Write8 (uint8_t reg, uint32_t value)
107 {
108 // Clear write buffers
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 for ( i = 0; i < I2C_BUFSIZE; i++ )
132 {
133 I2CMasterBuffer[i] = 0x00;
134 }
135
136 I2CWriteLength = 2;
137 I2CReadLength = 2;
138 I2CMasterBuffer[0] = TSL2561_ADDRESS; // I2C device address
139 I2CMasterBuffer[1] = reg; // Command register
140 // Append address w/read bit
141 I2CMasterBuffer[2] = TSL2561_ADDRESS | TSL2561_READBIT;
142 i2cEngine();
143
144 // Shift values to create properly formed integer (low byte first)
145 *value = (I2CSlaveBuffer[0] | (I2CSlaveBuffer[1] << 8));
146
147 return TSL2561_ERROR_OK;
148 }
149
150 /**************************************************************************/
151 /*!
152 @brief Enables the device
153 */
154 /**************************************************************************/
155 tsl2561Error_t tsl2561Enable(void)
156 {
157 if (!_tsl2561Initialised) tsl2561Init();
158
159 // Enable the device by setting the control bit to 0x03
160 return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON);
161 }
162
163 /**************************************************************************/
164 /*!
165 @brief Disables the device (putting it in lower power sleep mode)
166 */
167 /**************************************************************************/
168 tsl2561Error_t tsl2561Disable(void)
169 {
170 if (!_tsl2561Initialised) tsl2561Init();
171
172 // Turn the device off to save power
173 return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF);
174 }
175
176 /**************************************************************************/
177 /*!
178 @brief Initialises the I2C block
179 */
180 /**************************************************************************/
181 tsl2561Error_t tsl2561Init(void)
182 {
183 // Initialise I2C
184 if (i2cInit(I2CMASTER) == false)
185 {
186 return TSL2561_ERROR_I2CINIT; /* Fatal error */
187 }
188
189 _tsl2561Initialised = true;
190
191 // Set default integration time and gain
192 tsl2561SetTiming(_tsl2561IntegrationTime, _tsl2561Gain);
193
194 // Note: by default, the device is in power down mode on bootup
195
196 return TSL2561_ERROR_OK;
197 }
198
199 /**************************************************************************/
200 /*!
201 @brief Sets the integration time and gain (controls sensitivity)
202 */
203 /**************************************************************************/
204 tsl2561Error_t tsl2561SetTiming(tsl2561IntegrationTime_t integration, tsl2561Gain_t gain)
205 {
206 if (!_tsl2561Initialised) tsl2561Init();
207
208 tsl2561Error_t error = TSL2561_ERROR_OK;
209
210 // Enable the device by setting the control bit to 0x03
211 error = tsl2561Enable();
212 if (error) return error;
213
214 // Turn the device off to save power
215 error = tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, integration | gain);
216 if (error) return error;
217
218 // Update value placeholders
219 _tsl2561IntegrationTime = integration;
220 _tsl2561Gain = gain;
221
222 // Turn the device off to save power
223 error = tsl2561Disable();
224 if (error) return error;
225
226 return error;
227 }
228
229 /**************************************************************************/
230 /*!
231 @brief Reads the luminosity on both channels from the TSL2561
232 */
233 /**************************************************************************/
234 tsl2561Error_t tsl2561GetLuminosity (uint16_t *broadband, uint16_t *ir)
235 {
236 if (!_tsl2561Initialised) tsl2561Init();
237
238 tsl2561Error_t error = TSL2561_ERROR_OK;
239
240 // Enable the device by setting the control bit to 0x03
241 error = tsl2561Enable();
242 if (error) return error;
243
244 // Wait x ms for ADC to complete
245 switch (_tsl2561IntegrationTime)
246 {
247 case TSL2561_INTEGRATIONTIME_13MS:
248 systickDelay(14);
249 break;
250 case TSL2561_INTEGRATIONTIME_101MS:
251 systickDelay(102);
252 break;
253 default:
254 systickDelay(400);
255 break;
256 }
257
258 // Reads two byte value from channel 0 (visible + infrared)
259 error = tsl2561Read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW, broadband);
260 if (error) return error;
261
262 // Reads two byte value from channel 1 (infrared)
263 error = tsl2561Read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW, ir);
264 if (error) return error;
265
266 // Turn the device off to save power
267 error = tsl2561Disable();
268 if (error) return error;
269
270 return error;
271 }
272
273 /**************************************************************************/
274 /*!
275 @brief Calculates LUX from the supplied ch0 (broadband) and ch1
276 (IR) readings
277 */
278 /**************************************************************************/
279 uint32_t tsl2561CalculateLux(uint16_t ch0, uint16_t ch1)
280 {
281 unsigned long chScale;
282 unsigned long channel1;
283 unsigned long channel0;
284
285 switch (_tsl2561IntegrationTime)
286 {
287 case TSL2561_INTEGRATIONTIME_13MS:
288 chScale = TSL2561_LUX_CHSCALE_TINT0;
289 break;
290 case TSL2561_INTEGRATIONTIME_101MS:
291 chScale = TSL2561_LUX_CHSCALE_TINT1;
292 break;
293 default: // No scaling ... integration time = 402ms
294 chScale = (1 << TSL2561_LUX_CHSCALE);
295 break;
296 }
297
298 // Scale for gain (1x or 16x)
299 if (!_tsl2561Gain) chScale = chScale << 4;
300
301 // scale the channel values
302 channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE;
303 channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE;
304
305 // find the ratio of the channel values (Channel1/Channel0)
306 unsigned long ratio1 = 0;
307 if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;
308
309 // round the ratio value
310 unsigned long ratio = (ratio1 + 1) >> 1;
311
312 unsigned int b, m;
313
314 #ifdef TSL2561_PACKAGE_CS
315 if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C))
316 {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;}
317 else if (ratio <= TSL2561_LUX_K2C)
318 {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;}
319 else if (ratio <= TSL2561_LUX_K3C)
320 {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;}
321 else if (ratio <= TSL2561_LUX_K4C)
322 {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;}
323 else if (ratio <= TSL2561_LUX_K5C)
324 {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;}
325 else if (ratio <= TSL2561_LUX_K6C)
326 {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;}
327 else if (ratio <= TSL2561_LUX_K7C)
328 {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;}
329 else if (ratio > TSL2561_LUX_K8C)
330 {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;}
331 #else
332 if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T))
333 {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;}
334 else if (ratio <= TSL2561_LUX_K2T)
335 {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;}
336 else if (ratio <= TSL2561_LUX_K3T)
337 {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;}
338 else if (ratio <= TSL2561_LUX_K4T)
339 {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;}
340 else if (ratio <= TSL2561_LUX_K5T)
341 {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;}
342 else if (ratio <= TSL2561_LUX_K6T)
343 {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;}
344 else if (ratio <= TSL2561_LUX_K7T)
345 {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;}
346 else if (ratio > TSL2561_LUX_K8T)
347 {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;}
348 #endif
349
350 unsigned long temp;
351 temp = ((channel0 * b) - (channel1 * m));
352
353 // do not allow negative lux value
354 if (temp < 0) temp = 0;
355
356 // round lsb (2^(LUX_SCALE-1))
357 temp += (1 << (TSL2561_LUX_LUXSCALE-1));
358
359 // strip off fractional portion
360 uint32_t lux = temp >> TSL2561_LUX_LUXSCALE;
361
362 // Signal I2C had no errors
363 return lux;
364 }
This page took 0.065461 seconds and 5 git commands to generate.