Library for TLC5940 16-channel PWM chip

Yes the playground stuff is well out of date.

Hi very instresting lib and chip! Someone had tried to connect 2 or more TLC5940 in series? i mean Arduino -> |SIN ->SOUT| -> |SIN ...
this could be very useful to drive long chain on LED

sorry i must pay more attention on old post... so yes it is possible, i read that could be problem if we conncect more than 10 TLC is this still true or you are found a work around?

As far as I know, you can definitely daisy-chain more than 10 5940s.

acleone has a few pics up where he's using 3 of them to drive 16 RGB LEDs (48 total!).

FWIW, I seem to recall seeing that the upper limit was 32 chained chips. Don't quote me on that, though. (I skimmed the thread, but didn't immediately see anything about it)

I might be popping this into the wrong thread, but since it's related to the library, I'll start here.

My project has two states - manual & automatic. In order to switch between the two, I have a mini pushbutton. Unfortunately, it's cheap, and bounces like a kid on a trampoline -- usually 3-6 times, depending on how I push it.

The mode is "monitored" by a boolean - 1 or 0, and an interrupt changes the value of it.

Unfortunately, when you trigger the interrupt, it runs it's code, then goes right back to where the program was last running. If it's in the middle of the automatic function, it could take up to 30 seconds before the state change is put into effect (LEDs fade between colors, with a delay(30000) between each fade).

As a "fix" I moved the button from an interrupt to the reset pin, and save the state variable into EEPROM. Then, everytime the arduino is powered off or reset, it switches modes. Personally, I think this method is horribly kludgy, if not "inappropriate."

I suppose I could simply break down the delay segments into 10ms increments, and lump them together in a small loop that watches for a change in the state. But that still doesn't fix the bouncing issue.

My "Perfect Case Scenario" would be that if a user pushes the button, the state is switched, and the main loop() would restart, regardless of where the program currently is.

So, to summarize all of this:

  • How can I debounce an interrupt? (I'm low on physical space, so proper hardware debouncing (using a schmitt trigger) isn't a great option)
  • How can I get the interrupt to literally stop everything and start back at the beginning of the main loop()?

Thanks!

  1. Debounce an interrupt pin by disabling the interrupt as soon as you see it, waiting a debounce interval (typically 10 to 30 ms) and recheck the input to make sure it's the same state. Enable the interrupt again after you've done what you wanted to do.

  2. Break the delay into smaller chunks and exit the loop when necessary.

  1. Aha! I should have thought of that. I merely added a 10ms delay into the interrupt function, but for whatever reason, it locked everything up (even going as low as 1ms, too!)

  2. I figured as much.

Also, is there any sort of "limit" to the interrupts? For whatever reason, I could only push the button 3-4 times before the entire system locked up. It was almost like the Arduino was getting angry someone "ringing the doorbell" all the time. Initially, it seemed like I could hit it 30-40 times without a problem, but then it only allowed me to do it a tiny handful of times. This is between resets and reprogrammings, too.

Could it be that I'm pushing too much information into memory? I have a quite a few ints and integer arrays

16 ints for pin mappings
3 1x7 integer arrays for color maps
4 1x3 integer arrays for color settings
4 longs for millis()

plus a few more for random other things, but those above are global (they're used in quite a few functions; I'm not just lazy). Should I use #define for them instead? The pin maps and color arrays are static.

Edit: the final size of the sketch burned is about 6k, if that helps at all.

I ran across this thread while searching to resolve a problem I'm having using attachInterrupt(). According to the reference page:

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

I thought of using a debounce delay in the interrupt function until I remembered reading this...

Okay...this is crazy...

either I'm doing something horribly wrong, or....I'm doing something horribly wrong.

Here's my interrupt code:

void changeMode(void)
{
  detachInterrupt(0);
  debounce = 1;
  Serial.println(repeater++);
  setMode = !setMode;
}

...and the middle of the delays where my issue was...

while(tlc_updateFades()) {
      if (setMode == 0) { return 0; }
    }
    for(int i=0;i<delayTime/10;i++)
    {
      if (setMode == 0) { return 0; }
      delay(10);
    }

...and then back at the beginning of loop() once it all starts back up again

if(debounce == 0)
  {
      //do nothing
  }
  else
  {
    delay(50);
    attachInterrupt(0, changeMode, FALLING);
    debounce = 0;
  }

So, what it should be doing is

  • triggering the interrupt
  • turning off the interrupt
  • changing setMode to 0 and making debouncer = 1
  • returning to the current function
  • catch setMode being switched back to 0
  • return to the beginning of loop()
  • reactivate the interrupt after 50ms

But somehow, I still see 2-3 bounces, and it still locks up after a couple of button presses.

EDIT:
Never mind...I found a couple of good examples of how folks were debouncing their interrupts, and I'll give them a whirl tonight.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1223543716/
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1216607685/1#1

I followed the links and above and implemented the check for time between interrupts in my interrupt function. It works for me. However, I believe the documentation for attachInterrupt() http://www.arduino.cc/en/Reference/AttachInterrupt is either incorrect or possibly just needs to be worded more clearly as it states

...the value returned by millis() will not increment.

I jumped to the conclusion don't use millis() within the interrupt service routine but one could take it to mean that although millis() can be checked within the ISR subsequent invocations of millis() within the ISR will return the same value. I'll have to test to see if this is the case.

Cheers!

I think that's exactly the case -- millis() will always return the same value. As a result, delay() doesn't work, because the timer has stopped.

You can turn on interrupts, etc (so millis and serial will work) in an interrupt vector with

sei();

I updated the playground page to point to the Google Code project, thanks for the heads-up.

You can turn on interrupts, etc (so millis and serial will work) in an interrupt vector withsei();

Is that run inside the interrupt? I'm trying to search around for more info on how it's used, but the most I can find is sei() enables interrupts (already there by default) and cli() disables them.

They apparently work at a deeper level than the attach/detachInterrupt() functions.

yes, that will work inside the interrupt. See avr-libc: <avr/interrupt.h>: Interrupts

so, something like...

void myInterruptFunction(void)
{
    sei();
    delay(debounceDelay);
    //make state changes
}

...would work? I'm still not 100% sure how exactly it's supposed to work.

Or, should I just keep it simple:

void myInterruptFunction(void)
{
    if(lastInterrupt + 10 > millis())
    {
        //make state changes
        lastInterrupt = millis();
    }
    else
    {
        //do nothing
    }
}

Any time you want to use millis(), delay(), or Serial.xxx() inside an interrupt, you have call sei(); first.

This should work, but it might freeze the arduino if the interrupt is called repeatedly because it would keep getting called in the middle of the delay and would never return from the function. You could lock it like so:

volatile char isRunning;
void myInterruptFunction(void)
{
  if (!isRunning) {
    isRunning = 1;
    sei();
    delay(debounceDelay);
    //make state changes
    isRunning = 0;
  }
}

As an aside:

HTINK is probably using your library for a workshop :smiley:
http://blog.makezine.com/archive/2009/02/electronics_workshops_at_nycs_htink.html?CMP=OTC-0D6B48984890

#1 -- That interrupt/sli() code worked perfectly. Thanks, AC!

#2 -- If anyone else was interested, this library works PERFECTLY with the Mega168's internal clock, and running on 3.3V.

...at least it does in my scenario :smiley:

The library now supports servos - check out the Servo example (thank you Steve Pomeroy).

http://code.google.com/p/tlc5940arduino/

and updated documentation is at
http://students.washington.edu/acleone/codes/tlc5940arduino/html_r8/

so im trying to control 112 rgb leds with this library.

what i do is strobe which pin of a common cathode led gets 5 volts with transistors and then adjust the pwm on the tlc accordingly so i end up with

turn off all transistors
Send data to tlc for red
turnn on red transistor
turn off all transistors
Send data to tlc for green
turnn on green transistor
turn off all transistors
Send data to tlc for blue
turnn on blue transistor
then repeat

the problem im running into is the update time to the tlc since i need to change from r to g to b about once every 2 ms that means i get some flickering due to the update time of the tlc.
my question is is this because of the update time and so how long does it take to update 7 tlc's?
if that is the limiting factor is there any way to speed up the upload?

or could i possibly modify the library to not latch the data in the tlc input buffer untill i told it to?