Library for TLC5940 16-channel PWM chip

Samples in the mail, yippee!

Okay...I should have posted this last night, while I had my code in front of me...but I didn't.

I'm trying to get my LEDs to pseudo-randomly fade (intensity, length of fade, and delay until fade). After 2-3 loops, it's as if the timer breaks down. Rather than a series of slow, (sort of) subtle changes, it's a horrendous seizure-inducing strobe effect.

I added some serial output to see the values getting passed, and the values are all a-ok, and the time between loops (checking millis() at the beginning of each) is appropriately spaced. Yet, everything is running at super-speed.

I originally had 6 LEDs running this, but I dropped down to one, just to see what was going on.

my code (as best as I can remember it), without the serial output.

void setup()
{
    Tlc.init();
    Tlc.resetTimers();
}
void loop()
{
    aLast = a; //our previous intensity
    a = random(0, 4095); //grab our new intensity

    fadeDuration = random(500, 1500); //duration of fade between .5 and 1.5 seconds
    fadeDelay = random(5000, 15000); //delay before fading between 5 and 15 seconds

    Tlc.newFade(3, fadeDuration, aLast, a, fadeDelay);
    while(Tlc.updateFades());
}

So, with that, I get about 2-3 "appropriately" timed fades, before it clicks into strobe mode. I should note, too, that the "strobe mode" appears to be following the code correctly, except that it's almost as if the changes are occurring at 1/100th of the time (i.e. 15000ms becomes 150ms). It's a high-intensity red LED, so I can't stand to look at it for very long, even from the side, especially when it's flickering.

Updates: TLC5940LEDv004.zip

For people who want to use the TLC5940 to drive motors, use the old library from the first post for now. The PWM period for the TLC5940LED library is fixed at 488Hz, which might be too fast for driving a DC motor.

Just as a note, the TLC should act as GND for whatever you're using with it (voltage should flow from +5V, through whatever, and into the TLC pin). If you want to use RGB LEDs, make sure the LED is common anode (meaning each color shares the same +5V pin)

nphillips:

(unsigned long)      fadeDelay = millis() + random(5000, 15000);

The last parameter of Tlc.newFade is the start time in millis. v004 has proper commenting in the examples (sorry)!

Also, if you need to run more than 5 fades at once (if you call newFade more than 5 times before while(Tlc.updateFades());), you need to add more parameters to Tlc.init. For say 10 fades at once, use Tlc.init(1 tlc, 10 fades). Tlc.newFade(...) will return false if you have too many fades running at once.

nphillips:

(unsigned long)      fadeDelay = millis() + random(5000, 15000);

The last parameter of Tlc.newFade is the start time in millis. v004 has proper commenting in the examples (sorry)!

Ah hah! I suppose if I paid closer attention to your example, too, it would have been obvious. (testfades002 is what I used to help construct my code)

Also, if you need to run more than 5 fades at once (if you call newFade more than 5 times before while(Tlc.updateFades());), you need to add more parameters to Tlc.init. For say 10 fades at once, use Tlc.init(1 tlc, 10 fades). Tlc.newFade(...) will return false if you have too many fades running at once.

Is there an upper bound to this? Rather, will it break if I try to have it run a boat-load of fades? (I may end up looking at 32+ LEDs for one project....)

Is there an upper bound to this? Rather, will it break if I try to have it run a boat-load of fades? (I may end up looking at 32+ LEDs for one project....)

Each fade takes up 12 bytes of the 1024 byte SRAM. I don't know how much SRAM is used normally, but I'm guessing you could have like 64 fades (768 bytes) at once. Just keep trying higher values until something breaks!

But that's only running at once; if some finish and you want to start more, you could do something like

// create a bunch of fades
Tlc.newFade(...);
Tlc.newFade(...);
Tlc.newFade(...);
...
while (Tlc.updateFades()) {
  if(Tlc.newFade(...)) {
    // added successfully!
  } else {
    // too many fades right now
  }
}

That worked perfectly, acleone!

Once again, thanks for the amazing library, and quick, helpful responses!

Now, I just need to buy more LEDs... :o

For people who want to use the TLC5940 to drive motors, use the old library from the first post for now. The PWM period for the TLC5940LED library is fixed at 488Hz, which might be too fast for driving a DC motor.

As far as those 3V/80mA Sparkfun vibration motors are concerned, they seem to run fine at 500Hz, ramping up and down smoothly, based on prior experience. Alas, I won't be able to confirm with the TLC5940 for at least two weeks (vacation).

Just as a note, the TLC should act as GND for whatever you're using with it (voltage should flow from +5V, through whatever, and into the TLC pin).

Thanks for the pointer. Turns out that's how I had it wired in the old setup (PWM pins on the low side) but now I'll make sure to carry it over to the TLC5940 setup.

Yet another question, acleone :smiley:

Is there a way to get the immediate grayscale value of a particular channel?

In your last response, you had mentioned running additional newFade() functions inside the updateFades() while loop. I'd like to experiment with "interactions" between LEDs during the fading process and being able to grab the current value of an LED would be perfect.

Minor Example:

while(updateFades())
{
    if(getGreyscaleValue(3) > 2048)
    {
        newFade(4, 1000, 1024, 4095);
    }
}

I'll admit, I haven't delved too deeply into the code, so there may be something available I could use, without the need of anything additional. (/me goes off to skim the code as best he can)

EDIT:
Line 243 of TLC5940LED.cpp:

Tlc.set(fp->channel, fp->endValue - ((((int32_t)(fp->stopMillis - currentMillis)) * fp->dValue) / fp->duration));

That looks like it has what I'd need. Unfortunately, I don't know enough c++ to figure out whether or not I could pull that information from within the sketch itself, or if I would need to write a function for it.

I'm not 100% sure how to use structs, but it does appear that you're incrementing it, as if it's an array of data. If that's the case, it should be pretty easy to build a simple array of integers containing the current values of all active LEDs. Though, for larger numbers of LEDs, this would get fairly memory-intensive.

EDIT 2:
Would something like this work:

int TLC5940LED::getGreyscaleValue(uint8_t channel)
{
      struct fade *fp = channel;
      return (fp->endValue - ((((int32_t)(fp->stopMillis - currentMillis)) * fp->dValue) / fp->duration));
}

Again, I'm operating at Ignorance Level 10 (of 10). And I know I'm missing error-checking.

Major points for delving into my horrible code! You're kind of close; all the current LED states are stored in the _GSData array. The problem is the array packs all the data together to save space.

I don't have my Arduino at the moment, but try this version. I added Tlc.get(channel(1-16));, eg

int value = Tlc.get(1);

Awesome. I don't have my Ardy around either...but I'll certainly give it a whirl tonight!

And, your code isn't horrible, by any means. I once had to debug an entire patchwork content manager written by a 16 year old from the Ukraine. Now, I'm not making fun of the Ukranian Language...but the kid used nothing more than 2-character variable/function/class names, and had maybe 6 comments for 2000+ lines of code. Maybe it made sense in his native tongue, but it didn't make a lick of sense to me. THAT was deserving of points for delving into horrible code! ;D

Hmm...finally got around to trying out the Tlc.get() function, but it doesn't compile.

the line of code with the error:

j = Tlc.get(ledPins[5]);

the error returned:

o: In function `loop':
undefined reference to `TLC5940LED::get(unsigned char)'

That usually means that your library's .o file is not available in the expected place. See by comparison the EEPROM library, which is in hardware/libraries/EEPROM/EEPROM.o.

Mikal

Try deleting the .o file in library folder (/hardware/libraries/TLC5940LED), then open the Arduino IDE again.

Bingo. Thanks.

Have you run any fades over many hours?

I've been testing a few different wave-like motions, and when I come back to them in the morning, things are either off-sync or "stuck" flickering between two pins. The fade action of each pin seems fine, it's just the timing that breaks.

I thought it might be related to the millis() function, but last night I used a generic "Cylon" sweeper and it ended up stuck flickering between pins 5 and 7.

Here's my crappy code:

#include <TLC5940LED.h>
int i;
void setup()
{        
      Tlc.init();
      Tlc.resetTimers();
}

void loop()
{
  
  for(i=5;i<14;i+=2)
  {
    Tlc.newFade(i, 1500, 0, 4095);
    Tlc.newFade(i-2,1500,4095,0);
    while(Tlc.updateFades());
  }
 for(i=13;i>2;i-=2)
  {
    Tlc.newFade(i, 1500, 0, 4095);
    Tlc.newFade(i+2, 1500, 4095, 0);
    while(Tlc.updateFades());
  }
}

EDIT: I forgot to add that hitting the reset button gets things back to normal.

And the "stuck" part of the cylon script is, as i said, between i=7 and i=5 on the second half.

This didn't happen with the regular arduino PWM controls. I'm wondering if it's something inside updateFades()

Once again, I started poking around in the Library...

if (fp->stopMillis <= currentMillis)

As soon as the arduino's millis counter rolls over, this will get stuck in a 9-hour loop.

I don't have anything off the top of my head right now, but I think a simple for or switch statement to check if the stopMillis is higher than the millis() rollover point.

Has anyone tested or used this library with Arduino IDE 12?

I can no longer use the library once I switched from 11 to 12

-nima

I haven't upgraded yet, myself.

No time to do so, and play around with this lib. acleone, the creator, seems to have "disappeared" for the time being. Apparently, we all get busy around the same time. :wink:

I still need to figure out a fix for the millis() issue I noted above.

If I knew anything about what changes were made in IDE 12, and how to update libraries accordingly, I'd lend a hand. Unfortunately, I have no idea how to do it, nor do I currently have the time to try :confused:

usually there is a limit for millis(), that's why it wraps around and it's not an issue specific to the TLC5940 library (it's arduino limit). But look around the forums for other solutions to the problem ( i think some ppl, once the millis reaches its limit, count down backwards or something)

"As far as those 3V/80mA Sparkfun vibration motors are concerned, they seem to run fine at 500Hz, ramping up and down smoothly, based on prior experience. Alas, I won't be able to confirm with the TLC5940 for at least two weeks (vacation)."

I've used the TLC5940 to drive motors... a tip that usually emerges is to use diodes to protect the chip from any reverse current from the motors. I've used the tlc5940 with motors with diodes and without, and it never harmed the arduino or tlc5940 but it's good to use as a precaution