Arduino Uno Inconsistent and Flickering with TLC5940

How are the LEDs being powered?

Each TLC has its own decoupling capacitors?

The LED's are being powered by a seperate 5V with a common ground, They are triggered by the TLC5940's through transistors. Each TLC has it's own decoupling caps.

I don't like this:

  if(Serial.available()>0) { //check to see if data is available
    delay(5);  // wait for data to be completely sent=

Nor this:

 while(Serial.available()>0) { // while data is available
    char inchar = Serial.read(); // get a character
    delay(5);

You simply should not need delay "to be completely sure" that data arrives. No, you are just slightly more sure. Rework to do proper serial comms, where you don't use delay, and it definitely works:


       int idx = indata.indexOf(";");
        String brightString = indata.substring(beginIdx, idx);

I advise against String.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software

Even if you are on the latest IDE the String class can cause memory fragmentation.


None of the above specifically explains the difference between the Uno and the Duemilanove, however it would be a good start to fix them up.

Which rev Uno do you have? There have been some changes to the way the LED is wired to pin 13, which possibly may account for what you are seeing.

I am using Revision 3 (R3). Thanks for your advice on the code. I'll clean it up. If the pin 13 LED is causing the problem is there a way to disable it?

abocanegra:
They are triggered by the TLC5940's through transistors.

Through transistors? That's not a tlc5940 is normally used. It is a constant current, not voltage, source.

There are amperage limits to the TLC. To be able to use an external power source it is standard practice to use the TLC to trigger transistors rather than run the lights directly.

Since there isn't an appreciable difference between the boards to cause the problems you are describing, maybe there is a non-obivous application issue causing the "problem".

I think it would be good to post the schematic of what you have wired. Again, these are constant current drivers, not constant voltage. They were intended to drive LEDs directly, not through transistors.

For example, when you turn on a TLC5940's output, it doesn't "output" anything. The output changes its effective resistance to drop a voltage (and control the current).

The tlc can only handle 120ma. Therefore, to run higher current you have to use transistors and a constant power supply.
Here is a link to an example I found through the arduino page for the library. http://sonicrobots.com/2012/04/24/the-pwm-controller-tlc-5940-the-arduino-and-a-high-current-output-circuit/

So I followed the directions to move away from string and use C++ instead. It seems to have helped, though there is still some flickering when the UNO board is driving the system.
I also installed Arduino 1.0.5 and added the malloc.c
Here is the new code:

// 2013-06-17

/*
    Basic Pin setup:
    ------------                                  ---u----                                          Cable Pin Out  
    ARDUINO   13|-> SCLK (pin 25)   W       OUT1 |1     28| OUT channel 0                          NC   |10  9|   Blank
              12|                           OUT2 |2     27|-> GND (VPRG)                           SIN  |8   7|   SCLCK
              11|-> SIN (pin 26)    B       OUT3 |3     26|-> SIN (pin 11)                         GND  |6   5|   GND
              10|-> BLANK (pin 23)  Y       OUT4 |4     25|-> SCLK (pin 13)                        XLAT |4   3|   GSCLK
               9|-> XLAT (pin 24)   O         .  |5     24|-> XLAT (pin 9)                         GND  |2   1|   VCC (12V)                     
               8|                             .  |6     23|-> BLANK (pin 10)
               7|                             .  |7     22|-> GND
               6|                             .  |8     21|-> VCC (+5V)
               5|                             .  |9     20|-> 10K Resistor -> GND
               4|                             .  |10    19|-> +5V (DCPRG)
               3|-> GSCLK (pin 18)  G         .  |11    18|-> GSCLK (pin 3)
               2|                             .  |12    17|-> SOUT
               1|                             .  |13    16|-> XERR
               0|                           OUT14|14    15| OUT channel 15
    ------------                                  --------

    -  Put the longer leg (anode) of the LEDs in the +5V and the shorter leg
         (cathode) in OUT(0-15).
    -  +5V from Arduino -> TLC pin 21 and 19     (VCC and DCPRG)
    -  GND from Arduino -> TLC pin 22 and 27     (GND and VPRG)
    -  digital 3        -> TLC pin 18            (GSCLK)
    -  digital 9        -> TLC pin 24            (XLAT)
    -  digital 10       -> TLC pin 23            (BLANK)
    -  digital 11       -> TLC pin 26            (SIN)
    -  digital 13       -> TLC pin 25            (SCLK)
    -  The 2K resistor between TLC pin 20 and GND will let ~20mA through each
       LED.  To be precise, it's I = 39.06 / R (in ohms).  This doesn't depend
       on the LED driving voltage.
    - (Optional): put a pull-up resistor (~10k) between +5V and BLANK on the first board so that
                  all the LEDs will turn off when the Arduino is reset.

    If you are daisy-chaining more than one TLC, connect the SOUT of the first
    TLC to the SIN of the next.  All the other pins should just be connected
    together:
        BLANK on Arduino -> BLANK of TLC1 -> BLANK of TLC2 -> ...
        XLAT on Arduino  -> XLAT of TLC1  -> XLAT of TLC2  -> ...
    The one exception is that each TLC needs it's own resistor between pin 20
    and GND.

    This library uses the PWM output ability of digital pins 3, 9, 10, and 11.
    Do not use analogWrite(...) on these pins.
*/    
// for my setup:
// latch green
// clock yellow
// gclock yellow/black
// data blue
// blank blue/black


//#define DEBUG_MESSAGES  // Turn on Serial Print

//#include "Tlc5940.h"

//#include <tlc_servos.h>
//#include <tlc_animations.h>
//#include <tlc_progmem_utils.h>
#include <tlc_config.h>
#include <Tlc5940.h>
//#include <tlc_shifts.h>
//#include <tlc_fades.h>


/* NUM_TLCS is defined in "tlc_config.h" in the
   library folder.  After editing tlc_config.h for your setup, delete the
   Tlc5940.o file to save the changes. */
   
int brightness = 4095; // brightness level for LEDs. 0 - 4095
const int numNames = 16*NUM_TLCS;
int names[numNames];
unsigned long serialdata;
int inbyte;
char indata [12];
static unsigned int input_pos = 0;

void setup()
{
  /* Call Tlc.init() to setup the tlc.
     You can optionally pass an initial PWM value (0 - 4095) for all channels.*/
  clearNames();
  Tlc.init(1000);
  delay(1000);
  Serial.begin(9600);
  while (!Serial) {
    // wait for serial port to connect. Needed for Leonardo only
  }
  Tlc.clear();
  while(Tlc.update());
  delay(50);
  #ifdef DEBUG_MESSAGES
    Serial.println("READY");
  #endif
}



void loop()
{
  while(Serial.available()>0) { //check to see if data is available
    char input = Serial.read();
    //Read Data into indata
    switch(input)
      {
        case ';'://end of string
          indata[input_pos] = '\0';
          processData(indata);
          break;
        default:
          if(input_pos < sizeof(indata)){
            indata[input_pos++] = input;
          }
          break;
      } 
  }
}

void processData(char * data){
  #ifdef DEBUG_MESSAGES
    Serial.print("data-");
    Serial.println(data);
  #endif
  switch(data[0]) {
      case 'u': // 'u' means update tlc
        while(Tlc.update());
        #ifdef DEBUG_MESSAGES
          Serial.println("UPDATE");
        #endif
        break;  
      case 'c': // 'c' means clear tlc
        Tlc.clear();
        #ifdef DEBUG_MESSAGES
          Serial.println("CLEARED");
        #endif
        break;
      case 'l': // 'l' means turn on the numbered list of leds which follows. l12,3000;
        parseNames(data);
        int led;
        led = names[0];
        int ledbright;
        ledbright = names[1];
        
        if (ledbright > brightness){
          ledbright = 4095;
        }
        
        if (ledbright < 0) {
          ledbright = 0;
        }
        turnOn(led, ledbright);
        #ifdef DEBUG_MESSAGES
          Serial.print("LED-");
          Serial.print(led);
          Serial.print(": ");
          Serial.println(ledbright);
        #endif
        break;
      case 'a': // 'a' means turn all on. command to send is a####; where #### is brightness level
        Tlc.clear();
        int beginIdx = 1;
        int idx = input_pos - 1;
        int allbright;
        
        char brightString[16];
        memset(&brightString, '\0', sizeof(brightString));
        memcpy(brightString, data + beginIdx, idx);
        allbright = atoi(brightString);
        Tlc.setAll(allbright);
        #ifdef DEBUG_MESSAGES
          Serial.print("All On-");
          Serial.println(allbright);
        #endif
        delay(1);
        break;
    }
    memset(&indata, '\0', sizeof(indata));
    input_pos = 0;
}


// gets light & brightness data from a command of the form
// l15,200;
// that's a lowercase L followed by the led number a comma the brightness a comma and a semicolon

 void parseNames(char * data) { // parse serial data from string to int array
  clearNames();
  int name=0;
  int beginIdx = 1;
  int idx = input_pos - 1;
  char port[16];
  memset(&port,'\0',sizeof(port));
  memcpy(port, data + beginIdx, idx);
  char* chars_array = strtok(port, ",");
  while(chars_array)
    {
       names[name++] = atoi(chars_array);
       chars_array= strtok(NULL, ",");
    }
}


void turnOn(int led, int bright) {
  if (bright > 4095){bright=4095;}
  if (bright < 0){bright=0;}
  Tlc.set(led,bright); // turn on led at port 'led' with brightness 'bright'
  delay(1);
}

void clearNames() {
  for (int name = 0; name < numNames; name++) {
    names[name] = 0;
  }
}

abocanegra:
The tlc can only handle 120ma. Therefore, to run higher current you have to use transistors and a constant power supply.
Here is a link to an example I found through the arduino page for the library. http://sonicrobots.com/2012/04/24/the-pwm-controller-tlc-5940-the-arduino-and-a-high-current-output-circuit/

I am assuming that you used that circuit. It is a poor circuit because the TLC will not source any voltage so it looks like it is only working off leakage current. Each TLC output needs a pull up to 5V.

Each output does have a pull-up resistor.

abocanegra:
Each output does have a pull-up resistor.

This is why we asked you to post your schematic and you did not.
Anything else you are not telling us.
It makes it impossible to help if you don't cooperate.

I am not trying to be difficult. I have the schematic on another computer. As soon as I get a chance I will post it. Sorry if I am not moving fast enough on some requests.

I made a PDF of the schematic, I am attaching it to this post.

tlc5940_mwt_v1.5.pdf (25.8 KB)

**** UPDATE *****
So reworking the arduino code to utilize C++ chars rather than strings seems to have solved the problem with it acting inconsistently. The flicker that remained ended up a simple fix. I shortened the length of the wires connecting the buffers as much as physically possible (approximately an inch). I am still unsure why it only was a problem with the Uno and not the Duemilanove. Regardless, it works perfectly on both now. I am attaching a photo of the 1st panel running on the Raspberry Pi with an Uno (Left) and a Duemilanove (Right). All addresses work perfectly and no flicker.


Thanks for all of your help. After this project is over, I'll scour the forum to see if there is anything I can help out with.

abocanegra:
**** UPDATE *****
So reworking the arduino code to utilize C++ chars rather than strings

Could you please be more clear for all of us what you mean by

A) C++ chars

B) strings

I'm a bit confused and 2 members have quoted this post to apparently mean opposite things.

My big clue is that you used the term "reworked" as you did.

I am referring to the above advice that the strings in Arduino cause memory issues. Which is what i used in my initial code posting. The reworked code removes all use of Arduino strings in favor of the more reliable (and faster) C++ chars to build the calls from the Serial.read() and trigger the Tlc commands. I posted the reworked code as well.

Hope this helps

abocanegra:
I am referring to the above advice that the strings in Arduino cause memory issues. Which is what i used in my initial code posting. The reworked code removes all use of Arduino strings in favor of the more reliable (and faster) C++ chars to build the calls from the Serial.read() and trigger the Tlc commands. I posted the reworked code as well.

Hope this helps

That's nice except your terms are mixed up which is okay for you since what you do works but is confusing for others.

There is no Arduino strings except as C strings or C++ String objects. Arduino uses C/C++ and that maybe causes confusion among new people.

C strings are kept in char arrays as ASCII text code and always end with a NULL (zero) char.

C++ Strings are declared as capital S String and keep their ASCII text inside.

If/when you get into C++ and learn Classes, String is one of those.

He is clearly referring to the Arduino IDE-supplied String class:

The original post uses String, which I advised against.

Unfortunately the word "string" has quite a few meanings (apart from the stuff you tie up your roast with, and the ones related to theoretical physics).

Character arrays are often referred to as strings, even though the word "string" does not appear. Then there is the Arduino String class, and no doubt lots of other people have their own String classes. Then there is the STL string class (note the lower-case s).

Arduino String Class is an implementation of the standard C++ String Class.