tlc5947 with tlc5940 library - daisy, but..

Hi, I'm trying to daisy chain 2 TLC5947's and use the TLC5940 Library - which from what I understand in the forum should work - but doesn't.. I wonder if there's anything to note specifically? I've changed the tlc.config.h file and it works perfect on 5940's, so I'm slightly riddled. Any tips?
Thanks

5947's are pretty different from the 5940's. Exactly what changes did you make to the library? Certainly need to get rid of the grayscale timer since the 5947 already has it, and also need to account for the 24 channels instead of 16 channels.

Really the 5947 is easy. A library is not really necessary. Here's some code that I use on my 5947 boards: octobrite [macetech documentation]

Hi, I haven't changed the library at all - as that was working well for 3 5940's and for one 5947, and I'm just trying to make the step to the 5947's without having looked into changing the software yet. But thanks a lot, I'll look into the code you linked to.

-edit-

I've puzzled a bit with the code, but find it hard to reduce it to one channel as opposed to 3 channel RGB - I'm using just plain white LED's instead of RGB. Do you by any chance know of an example with just one channel - I mean 24 independent channels?
Thanks,

-edit 2-
Sorry the TLC5940 Library does actually work for daisy chaining TLC5947's, I had a loose wire.. ::slight_smile: But I'm still curious to using the code above to 24 independent channels.

Hi,

So this is what I managed to make of the Octobrite code you referred to, in terms of switching each channel individually:

// Defines for use with Arduino functions
#define clockpin   13 // CL
#define enablepin  10 // BL
#define latchpin    9 // XL
#define datapin    11 // SI

// Defines for direct port access
#define CLKPORT PORTB
#define ENAPORT PORTB
#define LATPORT PORTB
#define DATPORT PORTB
#define CLKPIN  5
#define ENAPIN  2
#define LATPIN  1
#define DATPIN  3

// Number of OctoBrites / TLC5947 devices
#define NumOctoBrites 8
#define NumPixels NumOctoBrites*24
uint16_t LEDChannels[NumPixels] = {0};

// Variables for sample function
float offset = 0;

// Set pins to outputs and initial states
void setup() {
  pinMode(datapin, OUTPUT);
  pinMode(latchpin, OUTPUT);
  pinMode(enablepin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  digitalWrite(latchpin, LOW);
  digitalWrite(enablepin, LOW);
}

// Read all bits in the LEDChannels array and send them on the selected pins
void WriteLEDArray() {

  unsigned int tempOne = 0;
  for (int i = 0; i < (NumPixels); i++) {
    tempOne = *(&LEDChannels[0] + i);
    for (int j = 0; j < 12; j++) {
      if ((tempOne >> (11 - j)) & 1) {
        DATPORT |= (1 << DATPIN);
      } 
      else {
        DATPORT &= ~(1 << DATPIN);
      }
      CLKPORT |= (1 << CLKPIN);
      CLKPORT &= ~(1 << CLKPIN); 
    } 

  }
  LATPORT |= (1 << LATPIN);
  LATPORT &= ~(1 << LATPIN);
}


void loop() {

       // all on, one after the other
       for(int index = 0; index < (NumPixels); index++) {
          LEDChannels[index] = 4000;
          WriteLEDArray(); 
        }
        
       delay(500);

      // all off, all at at once
       for(int index = 0; index < (NumPixels); index++) {
          LEDChannels[index] = 4000;
          WriteLEDArray(); 
        }
        
       delay(500);

}

Which does the job, but for some reason I don't understand it inverses the order of each channel, as in the last channel becomes the first? I don't mean it updates the last channel first, the last channel on the end of the daisy chain actually becomes channel 0. Any ideas why?

More importantly though, with this code (and with other Octobrite examples on the forum) I have the problem that if I run 8 TLC5947's (or actually any number over 4) I have a very faint and troubled output in the last TLC's, when all channels are activated.

Do you for the Octobrites have a recommended max amount of that one can connect?

Thank you,

Channel order is up to the programmer. It's a shift register so it all depends which order the bytes are pulled from memory.

I'm not aware of a problem chaining the devices. You'd only need to worry about fanout or signal wire length since there is no buffering for the common signals. For the OctoBrites we've had a customer chain 10 devices on one Arduino with no problems.

Many thanks, I've looked into the signal wire, and indeed, wiring XLAT, Blank and Clock out of the last unit back into to the first made a massive difference when using the TLC5940 library, but with the above script based on Octobrite, it doesn't make a difference - strangely?

I have the TLC's chained by 150mm FFC (flat cable) with 1mm tracks, and will try another type of signal cable.
I was wondering, for a string of 16 TLC5947's, would you think it's better to try and connect them all back to 1 arduino and to solve the signal wire issue, or to use 4 arduino's with each 4 TLC's, and link the arduino's together by I2C?

Well, 600 to 1200mm is quite a distance to be sending unshielded 5V logic signals cycling a few hundred KHz up to a few MHz. Probably best to use the shortest cables possible, or shielded.

We don't really have more details to work with here, like a schematic or photo of your setup, so can't make any commentary on construction techniques, too many pullups, etc.

Maybe adding a short delay to the latch cycle would be useful.

I didn't expect the distance <30 cm to be of issue, but at the same time I'm not sure what I based that expectation on.. I don't have a camera at hand now, but will try and send some images soon - the setup is very basic - 8 plain breakout boards with TLC5947's connected by 150mm FFC cable, no further components apart from one plain LED per board to test. Arduino Mini Pro or Duemilanove.

With shielded cable, do you think 50cm (*16 TLC's) would be somehow achievable? I have no idea what kind of shielding this would require, do you have a direction to look in?

I hardly dare any more questions, but I'm very curious to controlling the TLC's along the library and explanation at http://www.makingthingsmove.org/blog/ which indicates it should be possible to control the TLC's externally over shiftOut. As Firmata seems to be un capable of any kind of speed/volume, it looks very promising.
But that leads me to something I structurally don't understand; everything I can find on Arduino + TLC5947 is pointing towards that every 12 bytes for every 24 channel need to be updated in a { ...>24 { ...>11 } } type for loop, and I cannot find one example or explanation that uses Arduino's own shiftOut function
shiftOut(dataPin, clockPin, msbFirst , data);
which the above library uses.

Is it possible to control the TLC5947 with Arduino's shiftOut function at all?

I'm getting some kind of output but it's in all the wrong places and I don't understand how it would work. I've managed to control 8 TLC's it over serial through Processing, but it's very slow, a mere few fps.
Many thanks

A set of 0.1uF and 10uF decoupling capacitors would be considered a minimum for such a board out on a cable by itself. I believe the TLC5947 also requires a current setting resistor for correct operation.

The shiftOut command is very very slow. It's based on digitalWrite which takes around 70 instructions per pin change. Throughout the forums there are various replacements for it. The software method in my code is probably about as fast as you can get without using hardware SPI.

The other problem with shiftOut is that it sends 8 bits only. In order to send out the 12 bit TLC5947 data you must split two pieces of 12 bit data into three bytes. I believe there are some other shiftOut implementations that allow you to specify a number of bits to shift, from a byte, integer, or long type.

If you use hardware SPI then you still need to figure out how to cut up and reassemble the 12 bit data into a stream of 8 bit data.

Yes I do see the point that your way of coding would be better, and see the difference in speed, its just that I don't quite get the basics of applying it;

Could you explain how you in your way of coding would turn LED (or Channel) 20 to PWM value 4000?
(As in the tlc library one would do: Tlc.set (20,4000) Tlc.update(); )

I think if I understand that, I would understand the structure of applying it.

Thank you very much!

The thing I don't understand (and probably what I'm doing wrong) is that it for me takes a lot longer on the above mentioned Octobrite based code. To somehow make this visible here I follow a timing instructable on both codes I get this result, with massive difference:

With the 'Octobrite=based' code in the post above here:

//Timing the Octobrite-based code
void loop() {
 int initial = 0;
 int final = 0;
 initial = millis();

for (int j = 0; j < 192; j++) {
  LEDChannels[j] = 4000;
  WriteLEDArray();
  delayMicroseconds(10);
}

 final = millis();
 Serial.print("Time for WriteLEDArray(): ");
 Serial.print(final-initial);
 Serial.println("");
 while(1);

output = Time for WriteLEDArray(): 3180

And for TLC Library:

//time TLC code
 int initial = 0;
 int final = 0;
 initial = millis();

for (int j = 0; j < 192; j += 1) { 
  Tlc.set(j, 4000); Tlc.update(); 
  delayMicroseconds(10);
}

 final = millis();
 Serial.print("Time for TLC library(): ");
 Serial.print(final-initial);
 Serial.println("");
 while(1);

output = Time for TLC library(): 8

And next to it being much slower, it also makes the second half of the chain flicker when everything is on.

Are you using SPI mode on the tlc5940 library? That would increase speed significantly, as I use on other shift register devices.

Did you add the delay I suggested during the latch cycle?

I'm not claiming the code I'm using is optimized, in fact looking back at it, casually throwing some pointer math at an AVR is not the best approach.

Not sure what you mean with the SPI in TLC Library, but I have not modified the TLC Library any else than changing the amount of TLC's in NUM_TLCS - it's straight out of the box.

Yes I tried the delay in the latch cycle, (as someone recommended in another post). I'm still looking into the decoupling capacitors btw.

The thing I'm trying to understand is that I'm obviously doing something very wrong, if the method you describe as faster or at least highly likely to be faster, in my case actually is running 3180/8 = 400 times (!) slower.

What I feel I might be doing wrong (as my question two posts above); In order to update one channel, is it in your way necessary to run through the whole 24x12 loop - I mean, update every channel ? How would you go about updating one channel?
Many thanks!

Ps. the TLC Library code that I'm using is:

#include "Tlc5940.h"
void setup()
{
 Serial.begin(57600); 
 Tlc.init(); Tlc.clear(); Tlc.update();
}
void loop() {  
 int initial = 0;
 int final = 0;
 initial = millis();
for (int j = 0; j < 192; j += 1) { 
  Tlc.set(j, 4000); Tlc.update(); 
  delayMicroseconds(10);
}
final = millis();
 Serial.print("Time for TLC library(): ");
 Serial.print(final-initial);
 Serial.println("");
 while(1);
}

--
Ps. As promising as the TLC Library looks here, the reason why I'm still hoping to find a way with your code, is that it seems possible to add that to Firmata and thus control the TLC's externally, where as the TLC Library seems impossible to add to Firmata. If that is not so, I'd be very happy to hear.

While reading further, I had a thought that reducing the 4096 12 bit level could maybe speed up things. Grumpy_Mike wrote in the forum " The hardware (TLC) is capable of 4096 brightness levels but there is no need to use all those. For 3 bits just use the 3 most significant bits in the brightness field." And for me, 255 or even 50 would be enough.

I'm not sure how to accomplish this, but I noticed that changing in your WriteLEDArray() :

void WriteLEDArray() {

  unsigned int tempOne = 0;
  for (int i = 0; i < (NumPixels); i++) {
    tempOne = *(&LEDChannels[0] + i);
    for (int j = 0; j < 12; j++) {
      if ((tempOne >> (11 - j)) & 1) {
        DATPORT |= (1 << DATPIN);
      } 
      else {
        DATPORT &= ~(1 << DATPIN);
      }
      CLKPORT |= (1 << CLKPIN);
      CLKPORT &= ~(1 << CLKPIN); 
    } 
  }
  LATPORT |= (1 << LATPIN);
  LATPORT &= ~(1 << LATPIN);
}

changing the 11 in 'if ((tempOne >> (11 - j)) & 1) ' to lower levels makes it run a lot quicker, in what seems like a reduced amount of grayscale levels.

Does that 11 indeed stand for the amount of bits per channel, or is there another way of doing this?

I know this trial and error is a silly way of going about it, but am just trying to understand..

It's impossible to run the TLC5947 this way, it has its own PWM clock. You have to do the full 12 bit cycle. It might look faster because you aren't shifting out a full 288 bits to fill up the register and you have all kinds of unexpected values aliasing through the 288 bits.