TSL2591
A high dynamic range ambient light sensor breakout with separate full-spectrum and infrared channels, read over I2C as lux.
- Chip supply2.7 V to 3.6 V (3 V typical)
- Absolute maximum supply3.8 V
- I2C address0x29 (TSL25911FN); Adafruit notes 0x28 is also taken
- Dynamic range600,000,000:1

The TSL2591 is an ams light-to-digital converter with a full-spectrum (visible plus infrared) photodiode and an infrared photodiode, a 600,000,000:1 dynamic range, gains of 1, 25, 428 and 9876× and integration times of 100 to 600 ms (ams TSL2591 datasheet, pp. 1, 6, 13). It answers at I2C address 0x29 and the chip runs from 2.7 V to 3.6 V (pp. 4 to 5). The Adafruit breakout adds a 3.3 V regulator, so VIN takes 3 V to 5 V, and measures from 188 µlux to 88,000 lux (Adafruit guide, pp. 3, 6).
The TSL2591 measures light with two photodiodes: channel 0 sees visible plus infrared, channel 1 sees mostly infrared (ams datasheet, p. 1). Subtracting one from the other approximates what the eye sees, and the library's lux calculation uses both, so readings stay sensible under incandescent or sunlight where infrared is strong.
Its range is what sets it apart: a 600,000,000:1 dynamic range (p. 1), covered by four gain settings (1×, 25×, 428× and 9876×, p. 6) and six integration times from 100 ms to 600 ms (p. 13). At maximum gain it detects starlight-level light; at low gain and short time it handles direct sun. Adafruit quotes 188 µlux to 88,000 lux for its breakout (guide, p. 3).
The chip draws 275 µA active and 2.3 µA asleep (p. 5) and runs from 2.7 V to 3.6 V. Adafruit's breakout puts a 3.3 V regulator on VIN with a 3vo output for up to 100 mA, and is powered at the logic level of the board (guide, p. 6). It occupies 0x29 and, per Adafruit, also answers at 0x28 (guide, p. 11).
TSL2591 pinout
| Pin | Function | Type |
|---|---|---|
| VIN | Vin3 V to 5 V, equal to your board's logic level | power in |
| 3Vo | 3vo3.3 V | power out |
| GND | GND | power in |
| SCL | I2C SCL | input |
| SDA | I2C SDA | bidirectional |
| INT | Interrupt | open collector |
How to wire the TSL2591
Pin by pin, for the board you have.
| TSL2591 | Arduino Uno | Note |
|---|---|---|
| VIN | 5V | |
| GND | GND | |
| SCL | A5 | |
| SDA | A4 |
| TSL2591 | ESP32 DevKit V1 | Note |
|---|---|---|
| VIN | 3V3 | |
| GND | GND | |
| SCL | GPIO22 (D22) | |
| SDA | GPIO21 (D21) |
- Power VIN from 3V3, the ESP32's logic level, as Adafruit advises.
| TSL2591 | Raspberry Pi Pico | Note |
|---|---|---|
| VIN | 3V3(OUT) | |
| GND | GND | |
| SCL | GP5 | |
| SDA | GP4 |
- Power VIN from 3V3(OUT), the Pico's logic level, not VBUS.
TSL2591 code
Every example here compiles for its board.
// TSL2591 on Arduino Uno: wiring and a free simulation at https://www.tinkered.ai/components/tsl2591
// TSL2591 on an Arduino Uno: VIN 5V, SDA A4, SCL A5, address 0x29
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl(2591);
void setup() {
Serial.begin(115200);
Wire.begin();
if (!tsl.begin()) {
Serial.println("TSL2591 not found at 0x29. Check wiring.");
while (true) delay(10);
}
tsl.setGain(TSL2591_GAIN_MED); // 25x: indoor light
tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // 100 to 600 ms in 100 ms steps
Serial.println("TSL2591 ready");
}
void loop() {
uint32_t lum = tsl.getFullLuminosity(); // waits for one integration
uint16_t ir = lum >> 16;
uint16_t full = lum & 0xFFFF;
float lux = tsl.calculateLux(full, ir);
Serial.print("Full: "); Serial.print(full);
Serial.print(" IR: "); Serial.print(ir);
Serial.print(" Visible: "); Serial.print(full - ir);
Serial.print(" Lux: ");
if (lux < 0) Serial.println("overflow, lower the gain or time");
else Serial.println(lux, 3);
delay(500);
}
Compiled for arduino:avr:uno on 2026-10-30// TSL2591 on ESP32 DevKit V1: wiring and a free simulation at https://www.tinkered.ai/components/tsl2591
// TSL2591 on an ESP32 DevKit V1: VIN 3V3, SDA GPIO21, SCL GPIO22, address 0x29
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl(2591);
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL
if (!tsl.begin(&Wire)) {
Serial.println("TSL2591 not found at 0x29. Check wiring.");
while (true) delay(10);
}
tsl.setGain(TSL2591_GAIN_MED); // 25x: indoor light
tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // 100 to 600 ms in 100 ms steps
Serial.println("TSL2591 ready");
}
void loop() {
uint32_t lum = tsl.getFullLuminosity(); // waits for one integration
uint16_t ir = lum >> 16;
uint16_t full = lum & 0xFFFF;
float lux = tsl.calculateLux(full, ir);
Serial.print("Full: "); Serial.print(full);
Serial.print(" IR: "); Serial.print(ir);
Serial.print(" Visible: "); Serial.print(full - ir);
Serial.print(" Lux: ");
if (lux < 0) Serial.println("overflow, lower the gain or time");
else Serial.println(lux, 3);
delay(500);
}
Compiled for esp32:esp32:esp32 on 2026-10-30// TSL2591 on Raspberry Pi Pico: wiring and a free simulation at https://www.tinkered.ai/components/tsl2591
// TSL2591 on a Raspberry Pi Pico (arduino-pico): VIN 3V3(OUT), SDA GP4, SCL GP5, address 0x29
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl(2591);
void setup() {
Serial.begin(115200);
Wire.setSDA(4);
Wire.setSCL(5);
Wire.begin();
if (!tsl.begin(&Wire)) {
Serial.println("TSL2591 not found at 0x29. Check wiring.");
while (true) delay(10);
}
tsl.setGain(TSL2591_GAIN_MED); // 25x: indoor light
tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // 100 to 600 ms in 100 ms steps
Serial.println("TSL2591 ready");
}
void loop() {
uint32_t lum = tsl.getFullLuminosity(); // waits for one integration
uint16_t ir = lum >> 16;
uint16_t full = lum & 0xFFFF;
float lux = tsl.calculateLux(full, ir);
Serial.print("Full: "); Serial.print(full);
Serial.print(" IR: "); Serial.print(ir);
Serial.print(" Visible: "); Serial.print(full - ir);
Serial.print(" Lux: ");
if (lux < 0) Serial.println("overflow, lower the gain or time");
else Serial.println(lux, 3);
delay(500);
}
Compiled for rp2040:rp2040:rpipico on 2026-10-30Before you wire it
- Lower gain or integration time when a channel reads 65535: the ADC is saturated and the library reports an overflow.
- Raise gain (up to 9876×) and time (up to 600 ms) for dim scenes (datasheet, pp. 6, 13).
- Keep 0x28 and 0x29 free of other devices on the bus (Adafruit guide, p. 11).
- Read no faster than the integration time you set; getFullLuminosity() waits for it.
- Never power a bare TSL2591 above 3.6 V; 3.8 V is its absolute maximum (pp. 4 to 5).
- Never put it on the same bus as a VL53L0X, VL53L1X or TCS34725 at their default 0x29 without moving one of them.
- Never cover it with tinted plastic without recalibrating: the lux formula assumes an open window.
- Visible light is roughly channel 0 minus channel 1; the library's calculateLux() uses both with ams's coefficients.
- INT can fire when light leaves a programmed window, so a microcontroller can sleep until dusk or dawn.
- In bright sun start at 1× gain and 100 ms; indoors 25× and 300 ms is a good default; for night sky 9876× and 600 ms.
- The breakout's power LED and regulator dominate its current; the chip itself sleeps at 2.3 µA (datasheet, p. 5).
Specifications
- Chip supply
- 2.7 V to 3.6 V (3 V typical)ams TSL2591 datasheet ams163.5 (Apr 2013), p. 5
- Absolute maximum supply
- 3.8 Vams TSL2591 datasheet ams163.5 (Apr 2013), p. 4
- I2C address
- 0x29 (TSL25911FN); Adafruit notes 0x28 is also takenams TSL2591 datasheet ams163.5 (Apr 2013), p. 4; Adafruit TSL2591 guide (PDF), p. 11
- Dynamic range
- 600,000,000:1ams TSL2591 datasheet ams163.5 (Apr 2013), p. 1
- Gain
- Low 1×, medium 25×, high 428×, maximum 9876×ams TSL2591 datasheet ams163.5 (Apr 2013), p. 6
- Integration time
- 100, 200, 300, 400, 500 or 600 msams TSL2591 datasheet ams163.5 (Apr 2013), p. 13
- Channels
- Channel 0 full spectrum (visible plus IR), channel 1 infraredams TSL2591 datasheet ams163.5 (Apr 2013), p. 1
- Supply current
- 275 µA typical active (325 µA max); 2.3 µA sleepams TSL2591 datasheet ams163.5 (Apr 2013), p. 5
- Breakout
- 3.3 V regulator, VIN 3 V to 5 V, 3vo output up to 100 mA; 188 µlux to 88,000 luxAdafruit TSL2591 guide (PDF), pp. 3, 6
From the TSL2591 datasheet (ams163.5), published by ams OSRAM.
Common mistakes
Lux reads -1 or 0 in daylight
The channels have saturated at 65535 and the library flags an overflow. Drop to TSL2591_GAIN_LOW and a 100 ms integration time.
Address clash with a ToF sensor
The TSL2591 sits at 0x29 like ST's ToF sensors and the TCS34725, and Adafruit says 0x28 is taken too (guide, p. 11). Re-address the ToF sensor at start-up or use a second bus.
Readings change under different bulbs
Incandescent and halogen light carry lots of infrared. Use the lux value, which subtracts infrared, not the raw full-spectrum count.
Slow updates
At 600 ms integration a reading takes 600 ms or more. Shorten the time if you need faster updates and the light is bright enough.
TSL2591 questions
What is the TSL2591's I2C address?
0x29 for the TSL25911FN (ams datasheet, p. 4), and it cannot be changed. Adafruit notes the chip also uses 0x28 (guide, p. 11), so keep both free.
TSL2591 or BH1750?
The BH1750 is simpler and outputs lux directly up to about 65,000 lux. The TSL2591 has a far wider range (600,000,000:1, p. 1), an infrared channel and gains up to 9876×, so it handles both starlight and sunlight.
TSL2591 or VEML7700?
Both are high dynamic range lux sensors. The TSL2591 has a separate infrared channel; the VEML7700 has a filtered photodiode close to the eye's response and a simpler register set.
Can it run on 5 V?
The chip cannot: 2.7 V to 3.6 V (p. 5). The Adafruit breakout's regulator lets VIN take 3 V to 5 V; power it at your board's logic level (guide, p. 6).
What gain and time should I use?
Start at medium gain (25×) and 300 ms indoors. If a channel hits 65535, go down; if counts are tiny, go up to high (428×) or maximum (9876×) gain and longer time (pp. 6, 13).
Build something with the TSL2591
- Build this
Photography light meter
Measure lux and suggest shutter speed for an aperture and ISO.
- Build this
Sky quality meter
Log night-sky darkness at maximum gain.
- Build this
Auto-dimming lamp
Dim a LED strip as the room gets brighter.
This page as plain Markdown, for ChatGPT, Claude or your own agent. /components/tsl2591.md