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
;
76 static bool _tsl2561Initialised
= false;
77 static tsl2561IntegrationTime_t _tsl2561IntegrationTime
= TSL2561_INTEGRATIONTIME_402MS
;
78 static tsl2561Gain_t _tsl2561Gain
= TSL2561_GAIN_0X
;
80 /**************************************************************************/
82 @brief Sends a single command byte over I2C
84 /**************************************************************************/
85 tsl2561Error_t
tsl2561WriteCmd (uint8_t cmd
)
87 // Clear write buffers
88 for ( i
= 0; i
< I2C_BUFSIZE
; i
++ )
90 I2CMasterBuffer
[i
] = 0x00;
95 I2CMasterBuffer
[0] = TSL2561_ADDRESS
; // I2C device address
96 I2CMasterBuffer
[1] = cmd
; // Command register
98 return TSL2561_ERROR_OK
;
101 /**************************************************************************/
103 @brief Writes an 8 bit values over I2C
105 /**************************************************************************/
106 tsl2561Error_t
tsl2561Write8 (uint8_t reg
, uint32_t value
)
108 // 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
131 for ( i
= 0; i
< I2C_BUFSIZE
; i
++ )
133 I2CMasterBuffer
[i
] = 0x00;
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
;
144 // Shift values to create properly formed integer (low byte first)
145 *value
= (I2CSlaveBuffer
[0] | (I2CSlaveBuffer
[1] << 8));
147 return TSL2561_ERROR_OK
;
150 /**************************************************************************/
152 @brief Enables the device
154 /**************************************************************************/
155 tsl2561Error_t
tsl2561Enable(void)
157 if (!_tsl2561Initialised
) tsl2561Init();
159 // Enable the device by setting the control bit to 0x03
160 return tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_CONTROL
, TSL2561_CONTROL_POWERON
);
163 /**************************************************************************/
165 @brief Disables the device (putting it in lower power sleep mode)
167 /**************************************************************************/
168 tsl2561Error_t
tsl2561Disable(void)
170 if (!_tsl2561Initialised
) tsl2561Init();
172 // Turn the device off to save power
173 return tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_CONTROL
, TSL2561_CONTROL_POWEROFF
);
176 /**************************************************************************/
178 @brief Initialises the I2C block
180 /**************************************************************************/
181 tsl2561Error_t
tsl2561Init(void)
184 if (i2cInit(I2CMASTER
) == false)
186 return TSL2561_ERROR_I2CINIT
; /* Fatal error */
189 _tsl2561Initialised
= true;
191 // Set default integration time and gain
192 tsl2561SetTiming(_tsl2561IntegrationTime
, _tsl2561Gain
);
194 // Note: by default, the device is in power down mode on bootup
196 return TSL2561_ERROR_OK
;
199 /**************************************************************************/
201 @brief Sets the integration time and gain (controls sensitivity)
203 /**************************************************************************/
204 tsl2561Error_t
tsl2561SetTiming(tsl2561IntegrationTime_t integration
, tsl2561Gain_t gain
)
206 if (!_tsl2561Initialised
) tsl2561Init();
208 tsl2561Error_t error
= TSL2561_ERROR_OK
;
210 // Enable the device by setting the control bit to 0x03
211 error
= tsl2561Enable();
212 if (error
) return error
;
214 // Turn the device off to save power
215 error
= tsl2561Write8(TSL2561_COMMAND_BIT
| TSL2561_REGISTER_TIMING
, integration
| gain
);
216 if (error
) return error
;
218 // Update value placeholders
219 _tsl2561IntegrationTime
= integration
;
222 // Turn the device off to save power
223 error
= tsl2561Disable();
224 if (error
) return error
;
229 /**************************************************************************/
231 @brief Reads the luminosity on both channels from the TSL2561
233 /**************************************************************************/
234 tsl2561Error_t
tsl2561GetLuminosity (uint16_t *broadband
, uint16_t *ir
)
236 if (!_tsl2561Initialised
) tsl2561Init();
238 tsl2561Error_t error
= TSL2561_ERROR_OK
;
240 // Enable the device by setting the control bit to 0x03
241 error
= tsl2561Enable();
242 if (error
) return error
;
244 // Wait x ms for ADC to complete
245 switch (_tsl2561IntegrationTime
)
247 case TSL2561_INTEGRATIONTIME_13MS
:
250 case TSL2561_INTEGRATIONTIME_101MS
:
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
;
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
;
266 // Turn the device off to save power
267 error
= tsl2561Disable();
268 if (error
) return error
;
273 /**************************************************************************/
275 @brief Calculates LUX from the supplied ch0 (broadband) and ch1
278 /**************************************************************************/
279 uint32_t tsl2561CalculateLux(uint16_t ch0
, uint16_t ch1
)
281 unsigned long chScale
;
282 unsigned long channel1
;
283 unsigned long channel0
;
285 switch (_tsl2561IntegrationTime
)
287 case TSL2561_INTEGRATIONTIME_13MS
:
288 chScale
= TSL2561_LUX_CHSCALE_TINT0
;
290 case TSL2561_INTEGRATIONTIME_101MS
:
291 chScale
= TSL2561_LUX_CHSCALE_TINT1
;
293 default: // No scaling ... integration time = 402ms
294 chScale
= (1 << TSL2561_LUX_CHSCALE
);
298 // Scale for gain (1x or 16x)
299 if (!_tsl2561Gain
) chScale
= chScale
<< 4;
301 // scale the channel values
302 channel0
= (ch0
* chScale
) >> TSL2561_LUX_CHSCALE
;
303 channel1
= (ch1
* chScale
) >> TSL2561_LUX_CHSCALE
;
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
;
309 // round the ratio value
310 unsigned long ratio
= (ratio1
+ 1) >> 1;
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
;}
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
;}
351 temp
= ((channel0
* b
) - (channel1
* m
));
353 // do not allow negative lux value
354 if (temp
< 0) temp
= 0;
356 // round lsb (2^(LUX_SCALE-1))
357 temp
+= (1 << (TSL2561_LUX_LUXSCALE
-1));
359 // strip off fractional portion
360 uint32_t lux
= temp
>> TSL2561_LUX_LUXSCALE
;
362 // Signal I2C had no errors