Pages: [1] 2   Go Down
Author Topic: Arduino Uno Inconsistent and Flickering with TLC5940  (Read 4573 times)
0 Members and 1 Guest are viewing this topic.
Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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




« Last Edit: June 15, 2013, 06:09:43 am by abocanegra » Logged

Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

How are the LEDs being powered? 

Each TLC has its own decoupling capacitors?

Logged

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19080
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't like this:

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

Nor this:

Code:
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:
       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.
Logged


Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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). 
Logged

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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;
  }
}
« Last Edit: June 18, 2013, 12:27:48 am by abocanegra » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 634
Posts: 34559
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Each output does have a pull-up resistor.
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 634
Posts: 34559
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Los Angeles
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

* tlc5940_mwt_v1.5.pdf (25.81 KB - downloaded 58 times.)
Logged

Pages: [1] 2   Go Up
Jump to: