Python library for the TLC59108 and TLC59116 constant-current LED sink driver
Project description
tlc591xx-python
Python library for the TLC59108 (8-channel) and TLC59116 (16-channel) constant-current LED sink drivers over I²C.
Features
- Unified
TLC591xxbase class with chip-specificTLC59108andTLC59116subclasses - Per-channel brightness control (
0= off,1–254= PWM,255= full on) - Bulk update of all channels in a single I²C block write (
set_all_brightness) - Hardware group-blink — chip oscillator drives the blink autonomously, zero CPU overhead (
set_group_blink) - Hardware group-dim — single register write scales a whole group's brightness (
set_group_dim) - Output current reference control (
set_iref) - Sleep / wake power management (
sleep,wake) - Raw register access (
read_register,write_register) for advanced use - Context-manager support — bus is automatically closed on exit
- Error-flag register reading (
read_errors) for open-load / over-temperature diagnostics - Works with any
smbus2-compatible bus object or a plain integer bus number
Installation
pip install tlc591xx
Requires Python ≥ 3.12 and smbus2.
On a Raspberry Pi, make sure I²C is enabled:
sudo raspi-config # Interface Options → I2C → Enable
Quick Start
TLC59108 (8 channels, default address 0x40)
from tlc591xx import TLC59108
with TLC59108(bus=1) as drv:
drv.set_brightness(0, 255) # channel 0 fully on
drv.set_brightness(1, 128) # channel 1 at ~50 % PWM
drv.set_all_brightness([255] * 8) # all channels on
drv.set_all_off() # all channels off
TLC59116 (16 channels, default address 0x60)
from tlc591xx import TLC59116
with TLC59116(bus=1) as drv:
drv.set_all_brightness(list(range(0, 256, 16))) # brightness gradient
Sharing an existing SMBus instance
from smbus2 import SMBus
from tlc591xx import TLC59108
with SMBus(1) as bus:
drv = TLC59108(bus, address=0x41) # external bus: not closed by driver
drv.set_brightness(3, 200)
Usage
Hardware group-blink
The chip contains an internal oscillator that can blink any subset of outputs
autonomously. Once set_group_blink() is called, no further I²C traffic or
CPU involvement is needed to sustain the blink — the chip runs it by itself.
from tlc591xx import TLC59108
with TLC59108(bus=1) as drv:
# Set individual PWM values first (1–254 range writes the PWM register).
# These determine the on-phase brightness once blink mode is active.
drv.set_brightness(0, 200)
drv.set_brightness(1, 100)
# Blink channels 0 and 1 at 2 Hz, 50 % duty cycle.
# After this call the chip handles everything — the CPU can sleep.
drv.set_group_blink(period=0.5, duty=0.5, channels=[0, 1])
import time; time.sleep(30) # chip blinks on its own for 30 s
The period is quantised to the hardware's 24 Hz base clock
(GRPFREQ = round(period × 24 − 1)), so the actual period is
(GRPFREQ + 1) / 24 seconds. The range is ≈ 42 ms – 10.67 s.
Note on PWM values:
set_brightness(ch, 255)sets the output to fully on (LEDOUT = ON) without writing the PWM register. Use values 1–254 before callingset_group_blinkso the PWM register holds a meaningful on-phase brightness.
Hardware group-dim
Group-dim mode lets you scale the brightness of a whole group of LEDs with a
single register write, without touching each channel's individual PWM value.
It works as a hardware multiplier: the final output current is
(PWMn / 256) × (GRPPWM / 255) × Imax.
from tlc591xx import TLC59108
with TLC59108(bus=1) as drv:
# Programme a fixed relative pattern across all 8 channels.
drv.set_all_brightness([30, 60, 90, 120, 150, 180, 210, 240])
# Now dim the whole group to 25 % with one call — the relative
# pattern between channels stays exactly as programmed above.
drv.set_group_dim(0.25)
# Fade the group from full to off in a loop.
import time
for step in range(100, -1, -1):
drv.set_group_dim(step / 100)
time.sleep(0.02)
Channels not passed to channels= (or all channels when channels=None)
are switched to LEDOUT_BLINK state, which in group-dim mode means their
output is multiplied by level. Channels left at LEDOUT_DIM or LEDOUT_ON
are unaffected.
Sleep and wake
The chip's oscillator can be disabled to save power. All outputs go off immediately. Re-enabling restores the previous configuration; allow at least 500 µs for the oscillator to stabilise before driving outputs.
import time
from tlc591xx import TLC59108
with TLC59108(bus=1) as drv:
drv.set_all_brightness([128] * 8) # LEDs on
drv.sleep() # oscillator off, outputs off
time.sleep(5)
drv.wake() # oscillator back on
time.sleep(0.001) # ≥ 500 µs settling time
drv.set_all_brightness([128] * 8) # restore
Current reference (IREF)
The IREF register sets the full-scale output current for all channels. Reducing it globally limits the maximum current regardless of PWM settings — useful when you want to cap brightness at the hardware level rather than through software PWM values.
from tlc591xx import TLC59108, REG59108_IREF
with TLC59108(bus=1) as drv:
drv.set_all_brightness([255] * 8)
# Bit 7 (HC) = half-current mode; bits 6:0 (CC) = 7-bit current-control word.
# Full-scale (chip default after reset): CC = 0b1111111 = 0x7F
drv.set_iref(0x7F) # maximum current
# Set HC=1 to halve the full-scale current with one bit.
drv.set_iref(0xFF) # HC=1, CC=0x7F → half of the above
# Lower CC for a finer reduction — see the datasheet for the Iout formula
# (depends on your external Rext resistor value).
drv.set_iref(0x3F) # HC=0, CC=0x3F → roughly half of maximum
Output-change timing (OCH)
By default outputs latch when the I²C master sends a STOP condition
(OCH = 0). Switching to ACK mode (OCH = 1) makes each output register
take effect as soon as it is acknowledged, which can reduce visible tearing
when updating many channels in rapid succession.
with TLC59108(bus=1) as drv:
drv.set_output_change_on_ack(True) # outputs update on ACK
drv.set_all_brightness([200] * 8)
drv.set_output_change_on_ack(False) # back to STOP (default)
Raw register access
read_register and write_register give direct access to any chip register
by address — useful for features not yet covered by a dedicated method, such
as configuring I²C sub-addresses so multiple chips can be addressed
simultaneously with a single broadcast write.
from tlc591xx import TLC59108
# TLC59108 sub-address registers: SUBADR1=0x0E, SUBADR2=0x0F, SUBADR3=0x10
with TLC59108(bus=1) as drv:
# Configure a shared broadcast address on two chips
drv.write_register(0x0E, 0x92) # SUBADR1 = 0x49 (left-shifted in register)
# Inspect the current value of any register for diagnostics
mode2 = drv.read_register(0x01)
print(f"MODE2 = 0x{mode2:02x}")
API Reference
TLC59108(bus, address=0x40)
TLC59116(bus, address=0x60)
| Parameter | Type | Description |
|---|---|---|
bus |
int or SMBus |
I²C bus number (/dev/i2c-<n>) or an open SMBus instance |
address |
int |
7-bit I²C address — must match the A0–A3 pin strapping on the board |
Methods
Brightness
| Method | Description |
|---|---|
set_brightness(channel, value) |
Set one channel: 0 = off, 1–254 = PWM duty, 255 = full on |
set_all_brightness(values) |
Set all channels from a list (length = num_leds) in one I²C block write |
set_all_off() |
Force all outputs off |
Hardware group generator
| Method | Description |
|---|---|
set_group_blink(period, duty=0.5, channels=None) |
Hardware blink via the chip oscillator. period in seconds (≈ 0.042–10.67 s); duty = on-time fraction 0.0–1.0; channels = indices to blink (None = all) |
set_group_dim(level, channels=None) |
Master-brightness multiplier. level 0.0–1.0 scales all opted-in channels via a single GRPPWM write; channels = indices to include (None = all) |
Current reference
| Method | Description |
|---|---|
set_iref(value) |
Write the IREF register (raw 8-bit). Bit 7 = HC (half-current); bits 6:0 = CC current-control word — see datasheet for the Iout formula |
Power management
| Method | Description |
|---|---|
sleep() |
Oscillator off — low-power sleep, outputs off |
wake() |
Oscillator on — resume normal operation (allow ≥ 500 µs before driving outputs) |
Output-change timing
| Method | Description |
|---|---|
set_output_change_on_ack(enable) |
True = outputs latch on each I²C ACK; False = on STOP (default) |
Register access and diagnostics
| Method | Description |
|---|---|
read_errors() |
Return (eflag1, eflag2) error-flag bytes; TLC59108 always returns eflag2 = 0 |
read_register(reg) |
Read any 8-bit register by address |
write_register(reg, value) |
Write any 8-bit register by address (escape hatch for advanced use) |
close() |
Release the bus if it was opened by the driver |
Properties
| Property | Description |
|---|---|
address |
The I²C address the driver was configured with |
num_leds |
Number of output channels (8 for TLC59108, 16 for TLC59116) |
I²C Address Selection
Both chips use four address pins (A0–A3) to set the 7-bit I²C address. The base addresses are:
| Chip | Base address | Range |
|---|---|---|
| TLC59108 | 0x40 |
0x40–0x4F |
| TLC59116 | 0x60 |
0x60–0x6F |
Pass the matching address as the address parameter. Example with non-default strapping:
drv = TLC59108(bus=1, address=0x43) # A0=1, A1=1, A2=0, A3=0
Examples
Software blink (CPU-driven)
# From the repo root (no install required):
PYTHONPATH=src python3 examples/tlc59108_blink.py
PYTHONPATH=src python3 examples/tlc59108_blink.py --bus 1 --delay 0.2
Hardware group-blink (chip oscillator, zero CPU overhead)
PYTHONPATH=src python3 examples/tlc59108_hw_blink.py
PYTHONPATH=src python3 examples/tlc59108_hw_blink.py --period 0.5 --duty 0.25
PYTHONPATH=src python3 examples/tlc59108_hw_blink.py --channels 0,2,4 --period 2.0
Hardware group-dim (master brightness knob)
PYTHONPATH=src python3 examples/tlc59108_hw_dim.py
PYTHONPATH=src python3 examples/tlc59108_hw_dim.py --delay 0.02
Multi-channel fade / wave
PYTHONPATH=src python3 examples/tlc59108_fade.py -v
PYTHONPATH=src python3 examples/tlc59108_fade.py -c 0,1,5,6 --delay 0.05
Development
git clone https://github.com/trackIT-Systems/tlc591xx-python.git
cd tlc591xx-python
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
Run unit tests (no hardware required)
pytest -m "not hardware"
Run hardware tests
Connect a TLC591xx chip on I²C and set the environment variables:
TLC591XX_I2C_BUS=1 TLC591XX_MODEL=TLC59108 pytest -m hardware -v
| Variable | Default | Description |
|---|---|---|
TLC591XX_I2C_BUS |
— | I²C bus number (required for hardware tests) |
TLC591XX_ADDRESS |
chip default | Override the I²C address |
TLC591XX_MODEL |
TLC59108 |
TLC59108 or TLC59116 |
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tlc591xx-0.2.0.tar.gz.
File metadata
- Download URL: tlc591xx-0.2.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d454c0243ae7204bdab004755249a8dbf36c5ddb86d68d4eb82713ee8eba761b
|
|
| MD5 |
476869e0fe976ee1bd05f5a07521536c
|
|
| BLAKE2b-256 |
ffe19e40b440e4c5a62feb3bf0a4540138aeb5de2ed197ffed90a7344e214984
|
Provenance
The following attestation bundles were made for tlc591xx-0.2.0.tar.gz:
Publisher:
publish.yml on trackIT-Systems/tlc591xx-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tlc591xx-0.2.0.tar.gz -
Subject digest:
d454c0243ae7204bdab004755249a8dbf36c5ddb86d68d4eb82713ee8eba761b - Sigstore transparency entry: 1462158338
- Sigstore integration time:
-
Permalink:
trackIT-Systems/tlc591xx-python@f31713e5b3410f080baac8b21a15d3bc114bd3ed -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/trackIT-Systems
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f31713e5b3410f080baac8b21a15d3bc114bd3ed -
Trigger Event:
push
-
Statement type:
File details
Details for the file tlc591xx-0.2.0-py3-none-any.whl.
File metadata
- Download URL: tlc591xx-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f269b341a5a83eb1011885d738a23501ca46d83001a6704395b98f991fa8714
|
|
| MD5 |
65a86bad8f5d5a1de4642c1072baf734
|
|
| BLAKE2b-256 |
8665ef7fe4275429e60a82fa928b2ee6247cd365efb9c181216279e5fd744b8c
|
Provenance
The following attestation bundles were made for tlc591xx-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on trackIT-Systems/tlc591xx-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tlc591xx-0.2.0-py3-none-any.whl -
Subject digest:
7f269b341a5a83eb1011885d738a23501ca46d83001a6704395b98f991fa8714 - Sigstore transparency entry: 1462158347
- Sigstore integration time:
-
Permalink:
trackIT-Systems/tlc591xx-python@f31713e5b3410f080baac8b21a15d3bc114bd3ed -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/trackIT-Systems
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f31713e5b3410f080baac8b21a15d3bc114bd3ed -
Trigger Event:
push
-
Statement type: