USB TLC5940 protocol

Hey all,

I've been working on and off for a loong time trying to get Jitter talking to my arduino, specifically to drive the LEDs on my TLC5940 shield.

I've just recently been able to get it working, though at horrendous frame rates. 33fps works for a little, then gives tons of quick blackouts, pulses of unlimited current, quick hangs and then an inevitable freeze. The RX light is still on however. Resetting the serial port in max restarts the process. 2fps is relatively stable, but will still blackout every now and again, then freeze.

I made a project a while ago (solely using arduino) using an accelerometer to drive functions that set the LEDs to new values in a disgustingly inefficient manner, with little difficulty, and it ran for a week non stop. Also all the code examples in the library are working of course.

I cannot for the life of me figure out what the bottleneck is. I know it's not the baud rate, and i've seen other projects using essentially the same SPI protocol as the TLC library on an atmegaXX8 to drive 16 x 16 grids. Anyway, here's my code, adapted from (http://arduino.cc/forum/index.php/topic,69403.0.html)

#include "Tlc5940.h"
#define FRAME_START  255
#define FRAME_END  254

unsigned char buffer[] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int i = 0;

void setup(){

Serial.begin(115200);
Tlc.init();

}


void rxComplete(){

//the shield is using one TLC per color (in series), 16 channels a piece.

  for (int r=0; r < 16; r++){
    Tlc.set(r, buffer[r]);
  }
    
  for (int g=16; g < 32; g++){
    Tlc.set(g, buffer[g]);
  }
  for (int b=32; b < 48; b++){
    Tlc.set(b, buffer[b]);
  }
}


void loop(){
  if(Serial.available() > 0){
    byte rxbyte = Serial.read();
    if(rxbyte == FRAME_START){
        i = 0;
        while(Serial.peek() < FRAME_END){
          while(Serial.available() < 2) delayMicroseconds(1);
          buffer[i++] = Serial.read();
        }
        Serial.flush();
        rxComplete();
        
        
    }
  }

Tlc.update();


}

is it something to do with the serial.flush? i couldn't exactly figure it out, but should I be using the other functions of the library to deal with the XLAT? Or is the amount of utilized SRAM in the arduino bogging everything down?

oh and i'm only using 253 / 4095 steps, and ive been able to get near full brightness (4095) on all channels with cmdmessenger without causing a power draw reset.

I've looked at a lot of different protocols, my favorite being the Adavision LEDstream.pde, but I can't wrap my head around most of it. I feel like it does everything I want it to (underrun protection, checksum matching, avoiding loop) but i realize baby steps are the way to go, I don't know much about all the SPI stuff and using PORTB.

I've also had a look at grumpy_mike's projects with the 5940 but the multiplexing puts it wayy over my head. No time like the present to learn though, I'm sure it'd help a ton with scalability, which is the ultimate goal.

I've been looking for a way to do this for ages (well, a year or so), any help is greatly appreciated!

best,
z

I would only do the Tlc.update(); doing it so often is not going to help stability.
Why the Serial.flush(); you should not need to do this.
Got decoupling on the chips?

I don't have decoupling on the chips, I had a look at that section of your LED tutorials but i've been able to switch all on to off very quickly without causing the chip to freeze. I'm using HTINK RGB Shield I don't know a ton about electromagnetics, correct me if i'm wrong.

I've tried a number of things since then, putting Tlc.update on a millis timer, calling it while !tlc_needsXLAT, and doing a while(Tlc.update)()){

... none of which help. Also removing the flush doesn't do much for it. I'm really at my wits end here. I'm gonna wire up my teensy to it, maybe decouple them like you said, but that will take some time. After that i guess i'm gonna give up on the TLC and start trying to make an LPD8806 based system and hope i can do that, but i'd like to work this out first.

I feel like it's definitely a timing issue, when I refresh the serial port, the transfer works for a variable amount of time before freezing / hanging, non dependent upon which colors come on. Its sort of like a bell curve of instability-stability-instability-freeze that I enter into by the refresh.

bleh.

I don't have decoupling on the chips, I had a look at that section of your LED tutorials but i've been able to switch all on to off very quickly without causing the chip to freeze.

No that is not what a lack of decoupling does to a circuit. It makes it misbehave in an erratic manor exactly the way you are describing.

I'm using HTINK RGB Shield

I had a look at that, it is quite a poor layout. There is no decoupling anywhere on the board and the power tracks are way too thin. If I had it I would get three surface mount 0.1uF ceramic capacitors and solder one between the pins 21 & 22 (power and ground) of each chip. I would also parallel up the ground and power lines with some solid insulated wire. A 10 to 47uF bulk decoupling capacator somewhere on the board wouldn't go amiss either.

When things work for a variable amount of time before going wrong it is seldom the software in something as simple as this.

really appreciate the heads up, good to know i'm not going completely nuts.

on the one I have (the one on that site was the first revision) it looks like there are 0.1uF caps on the ICs

http://www.seeedstudio.com/depot/rgb-led-shield-v14-kit-p-430.html

should i go ahead and put a 47uF cap between power and ground before the chips then?

I would, it can't do any harm.

zeef:
I've tried a number of things since then, putting Tlc.update on a millis timer, calling it while !tlc_needsXLAT, and doing a while(Tlc.update)()){

There is no reason to call it, except after you need to update the TLCs. If no bits have been changed, why update them?

Have you seen less erratic behavior by reducing the serial rate?

 while(Serial.available() < 2) delayMicroseconds(1);

buffer[i++] = Serial.read();

Why delay?

What happens if FRAME_END never comes? Serial doesn't always guarantee data will be correctly received (there's no "resend"). How does your code handle that? What if "i" gets to be larger than the size of buffer?

thanks mike, putting that cap there made everything perfect. appreciate the help! :grin:

actually now its perfect, needed two of those 47 caps