Go Down

Topic: Arduino Uno Inconsistent and Flickering with TLC5940 (Read 4978 times) previous topic - next topic

abocanegra

Jun 15, 2013, 01:05 pm Last Edit: Jun 15, 2013, 01:09 pm by abocanegra Reason: 1
I have been working on a project that will be using python on 2 Raspberry Pi's to control 4 Arduinos and 120 tlc5940's (30 per arduino).
I bought 4 new Arduino Uno R3 smd boards to run the program. However, I had been testing on a Duemilanove before.

The code works exactly as expected when it is ran on my old Duemilanove. Which is what is making me think my issue is hardware related.

When I switched over to the Uno the lights no longer light up consistently, some don't light up at all, and others flicker.
When there are many lights turning on at once it the Uno doesn't work without multiple updateTLCs called. This is not a problem with the Duemilanove.

Things I have tried:

  • every baud rate between 9600 and 115200. I found that at 38400 the updateTLC's at least turns on first try.

  • playing with dozens of different delay setups in both the python code and the arduino code

  • making a link with sudo ln /dev/ttyACM0 /dev/ttyS0 on the raspberry pi

  • I have the same troubles when I control the daisy chain directly from the UNO (again not repeatable in the Duemilanove)

  • I have tried external power to the Arduinos

  • Rechecking all pcb boards, decoupling, buffers, and signal terminators

  • Have switched out all 4 Uno's and they all perform identically

  • Have tried an even older Diecimila and it works perfectly like the Duemilanove

  • checked the config code for the TLC5940 library to be sure that it has the correct number of TLC's set

  • gone over the code many times



After checking the software and connections in so many different ways I am wondering if there is a hardware conflict being created by the new USB setup of the UNO. I have ordered some old Due's from ebay (not my favorite choice) especially since this will be installed for a long time, and I would be happier if I could work this out so that I can be using the latest tech. That way I could be more confident about updating it in the future.

I have found issues with uploading to the Uno and getting the Raspberry Pi to communicate with the Uno, neither of these have been an issue for me. I can't find anything directly referring to my problem, any advice or direction would be greatly appreciated.

Below is the Arduino Code
Code: [Select]

// 2013-06-15

/*
   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


//#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>


int brightness = 4095; // brightness level for LEDs. 0 - 4095
const int numNames = 16*NUM_TLCS;
int names[numNames];
unsigned long serialdata;
int inbyte;
String indata;

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);
 Tlc.clear();
 while(Tlc.update());
 delay(50);
}

/* 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. */

void loop()

{
 indata = ""; // empty buffer for serial data
 if(Serial.available()>0) { //check to see if data is available
   delay(5);  // wait for data to be completely sent
   readData();  // read in string of data until ; is encountered

   switch(indata[0]) {
     case 'u': // 'u' means update tlc
       while(Tlc.update());
       break;
     case 'c': // 'c' means clear tlc
       Tlc.clear();
       break;
     case 'l': // 'l' means turn on the numbered list of leds which follows. l12,3000,;
       parseNames();
       int led;
       led = names[0];
       int bright;
       bright = names[1];
       
       if (bright > brightness){
         bright = 4095;
       }
       
       if (bright < 0) {
         bright = 0;
       }
       turnOn(led, bright);
       break;
     case 'a': // 'a' means turn all on. command to send is a####; where #### is brightness level
       int beginIdx = 1;
       int idx = indata.indexOf(";");
       String brightString = indata.substring(beginIdx, idx);
       char brightArray[16];
       brightString.toCharArray(brightArray,16);
       bright = atoi(brightArray);
       Tlc.setAll(bright);
       break;
   }
 }

}

void readData() { // read data from serial until ; is encountered
 while(Serial.available()>0) { // while data is available
   char inchar = Serial.read(); // get a character
   delay(5);
   if (inchar == ';') { // ; indicates end of command
     break;
   }
   else{
     indata += inchar; // build string.
   }
 }
}
//

// 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() { // parse serial data from string to int array
 clearNames();
 int name=0;
 int beginIdx = 1;
 int idx = indata.indexOf(",");
 char portBuf[16];
 while (idx != -1) {
   String port = indata.substring(beginIdx, idx);
   port.toCharArray(portBuf, 16);
   names[name++] = atoi(portBuf);
   beginIdx = idx+1;
   idx = indata.indexOf(",",beginIdx);
 }
}

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;
 }
}






James C4S

How are the LEDs being powered? 

Each TLC has its own decoupling capacitors?

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

abocanegra

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.

Nick Gammon

I don't like this:

Code: [Select]

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


Nor this:

Code: [Select]

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:

http://www.gammon.com.au/serial




Code: [Select]

       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.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

abocanegra

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?


James C4S


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.
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

abocanegra

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.

James C4S

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). 
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

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/

abocanegra

#9
Jun 18, 2013, 07:25 am Last Edit: Jun 18, 2013, 07:27 am by abocanegra Reason: 1
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:

Code: [Select]

// 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;
 }
}

Grumpy_Mike


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.

abocanegra


Grumpy_Mike


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.

abocanegra

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.

abocanegra

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

Go Up