Go Down

Topic: Library for TLC5940 16-channel PWM chip (Read 87745 times) previous topic - next topic


Oct 09, 2008, 11:54 am Last Edit: Oct 09, 2008, 12:05 pm by zervez Reason: 1
I have tested all the examples except the animation one and they all work perfectly with 4 tlc5940 in series and arduino 0012 Alpha. will do some longer tests with the code to see if it starts acting weird since this was just a quick one (uploading checking that it fades correctly and then the next one)

thanks a lot for the updated code.  btw some of the examples could need some modifications (in my view) regarding scaling them up to more than one TLC5940. Some of them are but some are not. Like always multiply the variable NUM_TLCS with 16 everywhere and so on. I could take a quick look at it and send you some updated versions if you like to.

*edit* on a closer look it is only example "testfade02" that needs to be updated to fit multiple TLC5940.


Do you have any measure of how much time is free when a TLC5940 is running?

I want to run three in series and then multiplex these three at a seven scans per frame rate. (guess what I am making) I just wonder if there is any time left to do anything else.

On a related topic, do you know if it is possible to clock the data in at the same time as clocking a grey scale scan? I know the XLAT will terminate a grey scale cycle but can the data sit in the shift registers until the end of the cycle when you could trigger XLAT. The data sheet says I can't do it with the dot correction data but it is strangely silent about the grey scale data.



According to my oscilloscope, Tlc.update() takes ~261 micro-seconds for 1 chip.  One full PWM period is ~244Hz, or ~4095 micro-seconds.  A call to Tlc.set takes 2.812 or 4.187 micro-seconds.

I'm thinking about making a version of the library with the hardware SPI, which should be much faster.

What do you mean by "clock the data in at the same time as clocking a grey scale scan"?  If you're talking about the Status Information Output, that comes out of SOUT every time you clock something in, but the library doesn't read it right now.


What do you mean by "clock the data in at the same time as clocking a grey scale scan"?

I mean clocking in the next set of data with SCLK and SIN at the same time as clocking GSCLK to produce the PWM outputs. Then by the time the grey scale cycle is finished you only need toggle the XLAT and Blank to go again. If GSCLK is being generated by a timer you have time to clock these in by hand.

I'm thinking about making a version of the library with the hardware SPI

Yes that is an idea I have had as well, but I haven't looked into the allocation of internal timers in your library to see if they clashed with the timer used for the SPI.

I am considering designing some sort of hardware assist so that I can more easily use this chip to drive an RGB matrix.

Thanks for the work you have put into this library so far, it has been quite a help.


I've answered my own question and it is yes. There is a very useful application note about programming the chip at:-

It's a large and scary flow chart.


I've found this thread really useful. Many thanks to jims for the initial coding, the great library by acleone and the responses from the other people working with this chip.

Nima and Syvwlch have both mentioned that they've used the TLC5940 to drive small 3V DC motors. I've been attempting this, carefully following all the advice from this forum - separate regulated power supply for the motors and snubber diodes to prevent any return current damaging the chip.

However, when I try and drive just 6 motors,  the motors run at quite different speeds (one not at all) although one would expect that they get the same voltage and current.

Testing with a multimeter indicates that the motors closest to the power supply are drawing more current than those further away.

I've tested the motors individually and they work fine.

I was wondering if anybody had any tips for driving large numbers of DC motors?


Interesting... I've only used pager-type vibration motors, and the intensity felt the same to the touch. Also, in my application I only ever have two on at the same time, never the full sixteen.

What value for the current supply setting resistor did you pick, are you sure your motors don't draw more current than you picked that resistor for, and (sorry for the dumb questions) are you sure the datasheet says the chip can provide that current amount under the voltage you are supplying it with (from memory it's 120mA for 5V, but I'd need to check to be sure)?

I'll play around with mine here, see if I can reproduce this behavior.


Very interesting, I am only driving LEDs but I find that when you set them to very low values (say 0x00f) they vary smoothly in brightness across the chip, with the dimmest being at  output 1 (pin 28) getting brighter as you go through the chip.

That is with the EEPROM or the Dot Correction. However, I have not managed to get the dot correction to work as no matter what values I feed it the brightness spread always comes out the same.


Ah, so I should be able to reproduce this if I set the entire row to a uniform but low value, then... I'll try that when I have some time.


By the way, Mike, what happens if you remove LEDs from one end or the other while this is in effect? Do the LEDs all brighten slightly or does the effect seem to slide over?

I'm wondering if it's sensitive to how much current is being drained... or if it's just something it does at low values.


Oct 24, 2008, 04:50 pm Last Edit: Oct 24, 2008, 04:50 pm by Grumpy_Mike Reason: 1
Sorry I don't know as they are all soldered up.

They are actually 4 RGB LEDs using the first 12 outputs of the chip. I am then multiplexing them but this happens when the multiplexing is off but it's not easy to disconnect things.
So when I see the red LEDs I am actually looking at outputs 1, 4, 7, 10 and they show a smooth change.

Anyway I will be looking at it again this weekend so I will post on Monday if I get anywhere.

P.S. Motors will probably require more decoupling both on the motors and on the chip.


I'm trying to tidy up the library and I keep running into this weird bug with Tlc.update() where the grayscale data is only occasionally latched:

First an explanation of the serial interface
Code: [Select]

        _   _   _   _   _
GSCLK  _| |_| |_| |_| |_| |_ ... (x4095)
BLANK ___________________________________________|   |___
XLAT _____________________________________________| |_____

SIN / SCLK (shifting data in for
          next cycle after BLANK)

Here's how the code currently works:
1.  GSCLK is run off TIMER2 in fast PWM mode
2.  BLANK and XLAT are run off TIMER1 in fast PWM mode
   a.  BLANK pulse width is OCR1B = 1
   b.  XLAT pulse width is OCR1A = 0   This works perfectly, XLAT is inside the BLANK pulse (0 is the shortest pulse width)
   c.  XLAT is not usually pulsing; the compare output bits, COM1A1 and COM1A0, are set to normal port operation (0, 0)
3.  When Tlc.update() is called:
   a.  check _needXLAT to see if we are still waiting on a previous Tlc.update() to latch, return 1 if we are
   b.  shift in the data
   c.  set _needXLAT = 1
   d.  enable the XLAT compare output to give us a pulse at the end of the current grayscale cycle: COM1A1 = 1, COM1A0 = 0 (non-inverting mode)
   e.  enable the output compare A match interrupt, OCIE1A = 1
What should happen at this point but doesn't:
4.  XLAT (OC1A) is pulsed at the end of the current grayscale cycle like the diagram above
5.  the OC1A output compare match interrupt is generated and executed a few clocks after XLAT should have pulsed
6.  the code in the interrupt turns off the XLAT pulsing (COM1A1 and COM1A0 = 0) and the interrupt is disabled (OCIE1A = 0), and _needXLAT is cleared to 0.

I know the interrupt is getting called successfully because the _needXLAT is getting cleared, but apparently XLAT isn't actually pulsing.  I worked around this by waiting two interrupts before I clear _needXLAT and COM1A1 / COM1A0, but Arduino 0012 seems to have broken this.  I can wait 10 interrupts and the same problem still occurs.  I've also tried increasing the pulse width for BLANK and XLAT to no avail.  Ugh!!!!!

Regardless, I would like to use TIMER1 to generate the XLAT pulses so that they're always within the BLANK pulse (as opposed to toggling the pin manually in an interrupt generated by blank: this would put the pulse a few clocks after the blank pulse).  Does anyone with experience with the timers know what I'm doing wrong?

The relevant code is in resetTimers(), update() and the ISR.  ( the latest version is TLC5940LEDv005_.zip)


"Nima and Syvwlch have both mentioned that they've used the TLC5940 to drive small 3V DC motors."

- I used 1.5 V pager motors @ 70 mA..... Plus, I never had more than 4 on at a time, although I had 16 connected......

I dont know if this  makes much difference, but I was using a different TLC5940 library at the time too.


Sorry, took a while to liberate some time for this, but here's my little test sketch trying to reproduce the situation where you have an uneven current value from pin 0 to pin 15 when the set value is low:

(The idea is that a 10k pot allows you to control the value being set for all sixteen LEDs.)

Code: [Select]
* Mathieu Glachant - Low value fader test sketch
* Based on library by Alex Leone - acleone ~AT~ u.washington.edu
* 2008-09-02 - v001
* Pin setup:
* ------------                                             ---u----
* ARDUINO   13|                                      LED2 |1     28| LED channel 1   (short leg (cathode), with the longer leg (anode) hooked up to +5V)
*           12|                                      LED3 |2     27|-> GND
*           11|                                      LED4 |3     26|-> SIN (pin 4)
*           10|-> BLANK (pin 23)                     LED5 |4     25|-> SCLK (pin 6)
*            9|-> XLAT (pin 24)                        .  |5     24|-> XLAT (pin 9)
*            8|                                        .  |6     23|-> BLANK (pin 10)
*            7|                                        .  |7     22|-> GND
*            6|-> SCLK (pin 25)                        .  |8     21|-> VCC (+5V)
*            5|                                        .  |9     20|-> 2K Resistor -> GND
*            4|-> SIN (pin 26)                         .  |10    19|-> +5V
*            3|-> GSCLK (pin 18)                       .  |11    18|-> GSCLK (pin 3)
*            2|                                        .  |12    17|
*            1|                                        .  |13    16|
*            0|                                      LED15|14    15| LED channel 16
* ------------                                             --------
* Put the longer leg of the LEDs in the +5V and the shorter leg in LED(1-16).
* The 2K resistor between pin 20 and GND will let ~20mA through each LED.  The actual formula is
*   Iref value = 39.05 / (desired current in A)           eg       1953Ohms = 39.06 / 0.020A
* This sketch implements a fader based on the analog voltage at analog pin potPin (see constants below).

#include <TLC5940LED.h>
#include <Wire.h>

#define NUM_TLCS      1
#define HMC6352Address  0x21
#define potPin          0  // Analog pot to set the overall brightness

void setup()

int readPot(float scale)
 return (int)(scale*analogRead(potPin)/1024);  // Read the analog voltage from the pot

void headingLED(int heading)
 Tlc.clear(); // sets all the channels to zero, but doesn't update
 for (uint8_t channel = 1; channel <= NUM_TLCS * 16; channel++)
   Tlc.set(channel, heading);  //  Tlc.set(channel, value (0-4095))   this requires a Tlc.update() to set the values.

void loop()

The short of it is, I can't reproduce it. Any value of the analog voltage from the control pot for which the LEDs are visibly lit, I see no difference from one end to the other of the ramp. All the LEDs are lit equally to my naked eye.

What am I doing differently from what you did to get your results?

Go Up