Library for TLC5940 16-channel PWM chip

Thanks, mikel. I'll give that a go, soon.

it's essentially what I was thinking, but I didn't have the knowledge to build it :wink:

I have created a breakout board for this circuit for a more simple and quick build of projects and experiments. Take a look at http://www.instructables.com/id/The_Dawm/ where I have put a short instruction how to solder it together with some pictures. I also refer to your library acleone hope that is alright...

The nice thing of the breakout board is that it is easily connectable after each other creating a lot of outputs fast together with the TLC5940 library

If anyone is interested in a breakout board please mail me or soon look at http://blushingboy.org/ where it will be sold as soon as the page is ready...

Good instructable, zervez!

I added a comment regarding the header pin soldering (as coffeebot). I'll keep an eye out for the boards on your site, for sure!

Nice breakout boards, zervez.

nphillips: I didn't see the new reply email until today, sorry! You're right about the 9-hour rollover bug. I'll fix that straight away (lazy coding in the first place always bites you in the back).

As for the problems with 0012, it's because the new millis() function disables interrupts while running. The library uses a few interrupts every time update() is called, so calling millis() right after an update might be the problem. I'll try running a few updates without millis to see if that fixes anything.

nphillips: I didn't see the new reply email until today, sorry!

Not a problem. Life and monetary restrictions have put my project on hold, anyway. It's good to see that you're still interested though!

(lazy coding in the first place always bites you in the back).

I'm all too familiar with that one.

ok, thanks for taking a look at the 012 IDE issue.

Can someone test this with 0012?

TLC5940LED_test_0012.zip

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.

Thanks

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:-
http://focus.ti.com.cn/cn/lit/sw/slvc106/slvc106.pdf

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.

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

         _   _   _   _   _ 
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.