1 /**************************************************************************/
4 @author K. Townsend (microBuilder.eu)
6 @brief Drivers for the TAOS TSL2561 I2C digital luminosity sensor
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).
18 #include "drivers/sensors/tsl2561/tsl2561.h"
20 uint16_t broadband, ir;
23 // Initialise luminosity sensor
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);
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);
39 Software License Agreement (BSD License)
41 Copyright (c) 2010, microBuilder SARL
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.
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.
66 /**************************************************************************/
68 #include "core/systick/systick.h"
70 extern volatile uint8_t I2CMasterBuffer
[I2C_BUFSIZE
];
71 extern volatile uint8_t I2CSlaveBuffer
[I2C_BUFSIZE
];
72 extern volatile uint32_t I2CReadLength
, I2CWriteLength
;
74 static bool _tsl2561Initialised
= false;
75 static tsl2561IntegrationTime_t _tsl2561IntegrationTime
= TSL2561_INTEGRATIONTIME_402MS
;
76 static tsl2561Gain_t _tsl2561Gain
= TSL2561_GAIN_0X
;
78 /**************************************************************************/
80 @brief Sends a single command byte over I2C
82 /**************************************************************************/
83 tsl2561Error_t
tsl2561WriteCmd (uint8_t cmd
)
85 // Clear write buffers
87 for ( i
= 0; i
< I2C_BUFSIZE
; i
++ )
89 I2CMasterBuffer
[i
] = 0x00;
94 I2CMasterBuffer
[0] = TSL2561_ADDRESS
; // I2C device address
95 I2CMasterBuffer
[1] = cmd
; // Command register
97 return TSL2561_ERROR_OK
;
100 /**************************************************************************/
102 @brief Writes an 8 bit values over I2C
104 /**************************************************************************/
105 tsl2561Error_t
tsl2561Write8 (uint8_t reg
, uint32_t value
)
107 // Clear write buffers
109 for ( i
= 0; i
< I2C_BUFSIZE
; i
++ )
111 I2CMasterBuffer
[i
] = 0x00;
116 I2CMasterBuffer
[0] = TSL2561_ADDRESS
; // I2C device address
117 I2CMasterBuffer
[1] = reg
; // Command register
118 I2CMasterBuffer
[2] = (value
& 0xFF); // Value to write
120 return TSL2561_ERROR_OK
;
123 /**************************************************************************/
125 @brief Reads a 16 bit values over I2C
127 /**************************************************************************/
128 tsl2561Error_t
tsl2561Read16(uint8_t reg
, uint16_t *value
)
130 // Clear write buffers
132 for ( i
= 0; i
< I2C_BUFSIZE
; i
++ )
134 I2CMasterBuffer
[i
] = 0x00;
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
;
145 // Shift values to create properly formed integer (low byte first)
146 *value
= (I2CSlaveBuffer
[0] | (I2CSlaveBuffer
[1] << 8));
148 return TSL2561_ERROR_OK
;
151 /**************************************************************************/
153 @brief Enables the device
155 /**************************************************************************/
156 tsl2561Error_t
tsl2561Enable(void)
158 if (!_tsl2561Initialised
) tsl2561Init();
160 // Enable the device by setting the control bit to 0x03
161 return tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_CONTROL
, TSL2561_CONTROL_POWERON
);
164 /**************************************************************************/
166 @brief Disables the device (putting it in lower power sleep mode)
168 /**************************************************************************/
169 tsl2561Error_t
tsl2561Disable(void)
171 if (!_tsl2561Initialised
) tsl2561Init();
173 // Turn the device off to save power
174 return tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_CONTROL
, TSL2561_CONTROL_POWEROFF
);
177 /**************************************************************************/
179 @brief Initialises the I2C block
181 /**************************************************************************/
182 tsl2561Error_t
tsl2561Init(void)
185 if (i2cInit(I2CMASTER
) == false)
187 return TSL2561_ERROR_I2CINIT
; /* Fatal error */
190 _tsl2561Initialised
= true;
192 // Set default integration time and gain
193 tsl2561SetTiming(_tsl2561IntegrationTime
, _tsl2561Gain
);
195 // Note: by default, the device is in power down mode on bootup
197 return TSL2561_ERROR_OK
;
200 /**************************************************************************/
202 @brief Sets the integration time and gain (controls sensitivity)
204 /**************************************************************************/
205 tsl2561Error_t
tsl2561SetTiming(tsl2561IntegrationTime_t integration
, tsl2561Gain_t gain
)
207 if (!_tsl2561Initialised
) tsl2561Init();
209 tsl2561Error_t error
= TSL2561_ERROR_OK
;
211 // Enable the device by setting the control bit to 0x03
212 error
= tsl2561Enable();
213 if (error
) return error
;
215 // Turn the device off to save power
216 error
= tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_TIMING
, integration
| gain
);
217 if (error
) return error
;
219 // Update value placeholders
220 _tsl2561IntegrationTime
= integration
;
223 // Turn the device off to save power
224 error
= tsl2561Disable();
225 if (error
) return error
;
230 /**************************************************************************/
232 @brief Reads the luminosity on both channels from the TSL2561
234 /**************************************************************************/
235 tsl2561Error_t
tsl2561GetLuminosity (uint16_t *broadband
, uint16_t *ir
)
237 if (!_tsl2561Initialised
) tsl2561Init();
239 tsl2561Error_t error
= TSL2561_ERROR_OK
;
241 // Enable the device by setting the control bit to 0x03
242 error
= tsl2561Enable();
243 if (error
) return error
;
245 // Wait x ms for ADC to complete
246 switch (_tsl2561IntegrationTime
)
248 case TSL2561_INTEGRATIONTIME_13MS
:
251 case TSL2561_INTEGRATIONTIME_101MS
:
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
;
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
;
267 // Turn the device off to save power
268 error
= tsl2561Disable();
269 if (error
) return error
;
274 /**************************************************************************/
276 @brief Calculates LUX from the supplied ch0 (broadband) and ch1
279 /**************************************************************************/
280 uint32_t tsl2561CalculateLux(uint16_t ch0
, uint16_t ch1
)
282 unsigned long chScale
;
283 unsigned long channel1
;
284 unsigned long channel0
;
286 switch (_tsl2561IntegrationTime
)
288 case TSL2561_INTEGRATIONTIME_13MS
:
289 chScale
= TSL2561_LUX_CHSCALE_TINT0
;
291 case TSL2561_INTEGRATIONTIME_101MS
:
292 chScale
= TSL2561_LUX_CHSCALE_TINT1
;
294 default: // No scaling ... integration time = 402ms
295 chScale
= (1 << TSL2561_LUX_CHSCALE
);
299 // Scale for gain (1x or 16x)
300 if (!_tsl2561Gain
) chScale
= chScale
<< 4;
302 // scale the channel values
303 channel0
= (ch0
* chScale
) >> TSL2561_LUX_CHSCALE
;
304 channel1
= (ch1
* chScale
) >> TSL2561_LUX_CHSCALE
;
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
;
310 // round the ratio value
311 unsigned long ratio
= (ratio1
+ 1) >> 1;
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
;}
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
;}
352 temp
= ((channel0
* b
) - (channel1
* m
));
354 // do not allow negative lux value
355 if (temp
< 0) temp
= 0;
357 // round lsb (2^(LUX_SCALE-1))
358 temp
+= (1 << (TSL2561_LUX_LUXSCALE
-1));
360 // strip off fractional portion
361 uint32_t lux
= temp
>> TSL2561_LUX_LUXSCALE
;
363 // Signal I2C had no errors