After I bought a new TSL2561 digital light sensor from Adafruit, I found that the very cool and small device cannot be accessed directly from linux (rasbian doesn’t have it’s kernel module compiled). Since I didn’t want to cross recompile my whole raspberry pi kernel just to have the tsl2563.ko driver enabled, and since it seems that raspbian does not relase genuine kernel headers to just compile custom kernel modules, I decided to write a user space simple library driver in C.
I found out that Adafruit relases proof of concept libraries written in C++ and python to access its hardware devices, the problem is that the c++ version is ready for arduino but it was not so directly usable for my raspberry pi. It also makes use of an adafruit unified sensor library and other external stuff. Since I am too lazy I decided yesterday to write a new simple library in plain C without external dependencies, just ready for my raspberry pi.
This is the arduino version that inspired me: https://github.com/adafruit/TSL2561-Arduino-Library
This is another cool blog post that inspired me (it now seems dead!!): http://russelldavis.org/2013/03/23/raspberryhunt-part-2/
This is an example:
/* prepare the sensor (the first parameter is the raspberry pi i2c master controller attached to the TSL2561, the second is the i2c selection jumper) The i2c selection address can be one of: TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT or TSL2561_ADDR_HIGH */ TSL2561 light1 = TSL2561_INIT(1, TSL2561_ADDR_FLOAT); /* initialize the sensor */ rc = TSL2561_OPEN(&light1); /* sense the luminosity from the sensor (lux is the luminosity taken in "lux" measure units) the last parameter can be 1 to enable library auto gain, or 0 to disable it */ rc = TSL2561_SENSELIGHT(&light1, &broadband, &ir, &lux, 1); TSL2561_CLOSE(&light1);
Compile:
gcc -Wall -O2 -o TSL2561.o -c TSL2561.c
gcc -Wall -O2 -o TSL2561_test.o -c TSL2561_test.c
gcc -Wall -O2 -o TSL2561_test TSL2561.o TSL2561_test.o
The output is like this:
root@rasponi:~/test/gpio# ./TSL2561_test
Test. RC: 0(Success), broadband: 141, ir: 34, lux: 12
As you can see it’s very easy at this point to get the light measures in C. Just include TSL2561.c and TSL2561.h inside your project and use the public APIs to setup and sense the IC.
I decided to release the code with the liberal apache v2 license, so feel free to include it into your commercial projects if you like.
It’s useful for me, and I hope that it can be useful to you too. Obviously it comes with absolutely no warranty.
p.s.1: I left the hardware stuff out of this article (just attach +vcc, gnd and i2c bus to the sensor
p.s.2: you have to load two kernel modules to get i2c bus working on you Raspberry pi:
modprobe i2c_bcm2708
modprobe i2c_dev
Ciao, Dino.
TSL2561.c
TSL2561.h
TSL2561_test.c
This is an example on how to use all 3 sensors on the same i2c bus:
#include <stdio.h> #include <string.h> #include "TSL2561.h" int main() { int i; int rc; uint16_t broadband, ir; uint32_t lux=0; TSL2561 lights[3]; // we can handle 3 sensors // prepare the sensors // (the first parameter is the raspberry pi i2c master controller attached to the TSL2561, the second is the i2c selection jumper) // The i2c selection address can be one of: TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT or TSL2561_ADDR_HIGH // prepare all sensors /* cannot assign that way lights[0] = TSL2561_INIT(1, TSL2561_ADDR_LOW); lights[1] = TSL2561_INIT(1, TSL2561_ADDR_FLOAT); lights[2] = TSL2561_INIT(1, TSL2561_ADDR_HIGH); */ // initialize at runtime instead // FIRST SENSOR --> TSL2561_ADDR_LOW lights[0].adapter_nr=1; // change this according to your i2c bus lights[0].sensor_addr=TSL2561_ADDR_LOW; // don't change this lights[0].integration_time=TSL2561_INTEGRATIONTIME_402MS; // don't change this lights[0].gain=TSL2561_GAIN_16X; // don't change this lights[0].adapter_fd=-1; // don't change this lights[0].lasterr=0; // don't change this bzero(&lights[0].buf, sizeof(lights[0].buf)); // don't change this // SECOND SENSOR --> TSL2561_ADDR_FLOAT lights[1].adapter_nr=1; // change this according to your i2c bus lights[1].sensor_addr=TSL2561_ADDR_FLOAT; // don't change this lights[1].integration_time=TSL2561_INTEGRATIONTIME_402MS; // don't change this lights[1].gain=TSL2561_GAIN_16X; // don't change this lights[1].adapter_fd=-1; // don't change this lights[1].lasterr=0; // don't change this bzero(&lights[1].buf, sizeof(lights[1].buf)); // don't change this // THIRD SENSOR --> TSL2561_ADDR_HIGH lights[2].adapter_nr=1; // change this according to your i2c bus lights[2].sensor_addr=TSL2561_ADDR_HIGH; // don't change this lights[2].integration_time=TSL2561_INTEGRATIONTIME_402MS; // don't change this lights[2].gain=TSL2561_GAIN_16X; // don't change this lights[2].adapter_fd=-1; // don't change this lights[2].lasterr=0; // don't change this bzero(&lights[2].buf, sizeof(lights[2].buf)); // don't change this // initialize the sensors for(i=0; i<3; i++) { rc = TSL2561_OPEN(&lights[i]); if(rc != 0) { fprintf(stderr, "Error initializing TSL2561 sensor %i (%s). Check your i2c bus (es. i2cdetect)\n", i+1, strerror(lights[i].lasterr)); return 1; } // set the gain to 1X (it can be TSL2561_GAIN_1X or TSL2561_GAIN_16X) // use 16X gain to get more precision in dark ambients, or enable auto gain below rc = TSL2561_SETGAIN(&lights[i], TSL2561_GAIN_1X); // set the integration time // (TSL2561_INTEGRATIONTIME_402MS or TSL2561_INTEGRATIONTIME_101MS or TSL2561_INTEGRATIONTIME_13MS) // TSL2561_INTEGRATIONTIME_402MS is slower but more precise, TSL2561_INTEGRATIONTIME_13MS is very fast but not so precise rc = TSL2561_SETINTEGRATIONTIME(&lights[i], TSL2561_INTEGRATIONTIME_101MS); } // you can now sense each sensor when you like for(i=0; i<3; i++) { // sense the luminosity from the sensors (lux is the luminosity taken in "lux" measure units) // the last parameter can be 1 to enable library auto gain, or 0 to disable it rc = TSL2561_SENSELIGHT(&lights[i], &broadband, &ir, &lux, 1); printf("Test sensor %i. RC: %i(%s), broadband: %i, ir: %i, lux: %i\n", i+1, rc, strerror(lights[i].lasterr), broadband, ir, lux); } // when you have finisched, you can close things for(i=0; i<3; i++) { TSL2561_CLOSE(&lights[i]); } return 0; }
How can I modify this program to work on Windows MPLAB software?
Sorry, I don’t know what MPLAB is, and I also hate windoze.
Hallo,
can we use this header file for TSL45315 light sensor too??
Regards
Hi there.
I’m very sorry, but I don’t know if it will going to work with TSL45315. Sincerely I don’t think so.
hallo,
No problem, let me try it
Hallo,
as you mentioned , it doesnt work!!! i am planning to write a library for TSL45315. could you please give some suggestion about the process?
i am totally new to these thigs?
Thanks a lot !
I would begin reading the python driver from WebIOPi (once downloaded go to: WebIOPi-0.7.1/python/webiopi/devices/sensor/tslXXXX.py)
You can check the classes “TSL45315” and “TSL4531” where the driver is implemented.
It seems to be quite similar to TSL2561, but the capture times are different:
VAL_TIME_400_MS = 0x00
VAL_TIME_200_MS = 0x01
VAL_TIME_100_MS = 0x02
Thanks for tips..
I like to code in c and using wiringpi…
Thanks for the tips.i started already!
My pleasure!
By the way i forgot to mention that it worked by changing capture times…So others can do the same..
It works great also on Arietta G25… of course.
Thanks very much for sharing it.
I used this library in my project, thank you! One question… With the sensor looking out the window and a light on, turning the light off causes the lux to increase. Can you explain this? Thanks again for the great library.
Hi Anon. I don’t know what it could be.
Already tried with TSL2561_INTEGRATIONTIME_402MS (that is more precise) and gain set to TSL2561_GAIN_16X (more precise in dark ambients, autogain disabled) ?
Hi,
I try to use the tsl2561 with TWI(i2C)in avrstudio. But i’m totaly lost and the compiling from your code say ”TXEN” & ”UDRE” undeclared . That’s normal ? Can I use your code in AVR ?
Thanks.
It goes where linux goes. If you have linux then you can compile and use it.
This code uses linux’ i2c facility and cannot be run natively.
Thank you for this.
I would like to use 3 light sensors. I can find each at 29, 39, and 49. I can find them using “sudo i2cdetect -y 1″. I see you defaulted to thee 39 address or “Float”. I am having problems opening a second sensor at the same time. should I open one, intilize, read, close, then Open, Intilialize, read, close the second?
Would it be possable to have 2 or 3 open at the same time?
Yes, it’s possibile to use them in parallel.
Just do the same you already did with the selectors TSL2561_ADDR_LOW, TSL2561_ADDR_FLOAT and TSL2561_ADDR_HIGH.
Now I’m in bed, writing with my google nexus 4, and it’s 04.24 AM. Time to sleep. I’ll show you how to do tomorrow.
Bye.
Please check the last example I’ve just added to the post.
Let me know if it works for you, I don’t have 3 sensors to try it, but it should work.
Bye!! Dino.
Thanks for this code. I used this in my project nettemp.pl https://github.com/sosprz/nettemp. For now beta wersion.
thanks to you I’ve added support for sensor TSL2561 😀
Cool!! Very happy to know it.
Hi,
Thank you so much. Initially when I compiled the program it showed an error message to check with i2c bus.
But when I tried with “sudo i2cdetect -y 1” it could actually detect and also checked with address and everything seemed perfect.
So the problem was not installing “wiringpi library” So by installing and including this library i could check with gpio pins which was enabled and showed status high (with i2c pins)
So now the program is working after installing the library “wiringPi”
Thank you so much 🙂
This is great! Exactly what I was looking for. By the way, it seems to work out of the box on the Beaglebone Black.
Please consider posting this code on github to make it more widely available.
Thanks very much for sharing it.
https://github.com/amolyp/TSL2561_Simple_Library
thanks. I was lazy 🙂