TLC5955 48 Channel LED driver not working with my Arduino Code

Hi,

I am literally pulling out my hair as I cannot seem to find why the TLC5955(datasheet) is not working.

I have an Arduino Mega ADK connected to the TLC5955 using the SPI interface.

The TLC5955 has a ridiculous 769 bit main register that must be written... I find this ridiculous as it is not a multiple of 8bits(byte). It is 96bytes and 1bit.

Non the less, my first assumption is that if I write 97bytes per SPI transaction the 7leading bits will fall out and be irrelevant.

So i create the Control Data Latch information, and write it once.
Then I write the Grayscale Data latch every second with all LEDs to Full.

I've been observing random flashes from the LEDs connected to the TLC5955 and not expected continuous full brightness.

Please can someone look at my code and advise on potential issues. I really appreciate your feedback.

My code:

#include "SPI.h" // necessary library

byte cdlFill[1] = {0x00};  //5bits used
byte cdlDC[48]; //7bits used
byte cdlMC[3];  //3bits used
byte cdlBC[3];  //7bits used
byte cdlFC[1];  //5bits used

byte GSDL[96];
byte CDL[47];
byte CDLbuffer[48];
byte counter = 0;
byte mode_cd = 0xFF; //FF=CD
byte mode_gs = 0x00; //00=GS
byte modecdl = 0x96; //mode must be FF followed by 96 for control data.
SPISettings settingsA(1000000, MSBFIRST, SPI_MODE0); 

//need to create the Control Data sequence in the required format
void combine_cdl() {
  int arrayPosCDL=0;
  int arrayPosFill=0;
  int arrayPosDC=0;
  int arrayPosMC=0;
  int arrayPosBC=0;
  int arrayPosFC=0;
  //append the 0 fill values to CDL
  for (int bitPos=0;bitPos<5;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosFill = (bitPos-0)/5;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlFill[arrayPosFill], 4-((bitPos-0)%5)));
  }
  //append the DC values to CDL
  for (int bitPos=5;bitPos<341;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosDC = (bitPos-5)/7;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlDC[arrayPosDC], 6-((bitPos-5)%7)));
   } 
  //append the MC values to CDL  
  for (int bitPos=341;bitPos<350;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosMC = (bitPos-341)/3;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlMC[arrayPosMC], 2-((bitPos-341)%3)));
   }   
   //append the BC values to CDL
   for (int bitPos=350;bitPos<371;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosBC = (bitPos-350)/7;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlBC[arrayPosBC], 6-((bitPos-350)%7)));
   } 
   //append the FC values to CDL
   for (int bitPos=371;bitPos<376;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosFC = (bitPos-371)/5;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlFC[arrayPosFC], 4-((bitPos-371)%5)));
   }  
}

void writeCDL(){
  SPI.beginTransaction(settingsA);
  digitalWrite(SS, LOW);
  //set mode bit high
  SPI.transfer(mode_cd);
  if( mode_cd < 0x10){ Serial.print("0");} Serial.print(mode_cd,HEX);
  //TLC5955 Datasheet pg17 bits 767 to 760 must be 0x96
  SPI.transfer(modecdl);
  if( modecdl < 0x10){ Serial.print("0");} Serial.print(modecdl,HEX);
  for (int i=0; i < 48; i++){
    SPI.transfer(CDLbuffer[i]);  //write out some 00s to "pad" the register
    if( CDLbuffer[i] < 0x10){ Serial.print("0");} Serial.print(CDLbuffer[i],HEX);
  }  
  for (int i=0; i < 47; i++){
    SPI.transfer(CDL[i]);  //write out the configured CDL data
    if( CDL[i] < 0x10){ Serial.print("0");} Serial.print(CDL[i],HEX);
  }  
  Serial.println();
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

void setup() {
  //I want to enable serial comms for deugging via ide.
  Serial.begin (115200);   // serial: Typical Rates, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, or 115200
  Serial.println ("\nDebugging Session On...\n");
  
  //Initialise all variable to some predefined level.
  for (int i=0; i < 96; i++){
      GSDL[i] = 0xFF;    //All LEDs Full on
   } 
  
  //Set the configuration byes 
  for (int i=0; i < 47; i++){
      CDL[i] = 0x00;
  } 
  for (int i=0; i < 48; i++){
      CDLbuffer[i] = 0x00; //Padding reqired to get the Control Data into the full Data register
  } 
  for (int i=0; i < 48; i++){
      cdlDC[i] = 0x20;    //set DC halfway
  } 
  for (int i=0; i < 3; i++){
      cdlMC[i] = 0x04;    //set MC halfway
  } 
  for (int i=0; i < 3; i++){
      cdlBC[i] = 0x40;    //set BC halfway
  } 
  cdlFC[0] = 0x10;  //auto display repeat
  
  combine_cdl();  
  
  //Initialise MISO,SS,SCK as an output 
  pinMode(MISO, OUTPUT); 
  pinMode(SS, OUTPUT); 
  pinMode(SCK, OUTPUT); 
  
  //Need to generate a clock signal for GSCLK. (Using following 5 lines we should get a 1MHz Clock on pin 11 (OC1A Pin))
  pinMode(11, OUTPUT);               //set OC1A/PB1 as output
  TCCR1A = _BV(COM1A0);              //toggle OC1A on compare match
  OCR1A = 7;                         //top value for counter
  TCCR1B = _BV(WGM12) | _BV(CS10);   //CTC mode, prescaler clock/1
  
  SPI.begin();
  delay(500);
  writeCDL();  //Setup the TLC5955 once.
  delay(500);
}

void loop() {
  
  SPI.beginTransaction(settingsA);
  digitalWrite(SS, LOW);
  SPI.transfer(mode_gs);
  if( mode_gs < 0x10){ Serial.print("0");}Serial.print(mode_gs,HEX); //prints to serial monitor value with leading 0
  for (int i=0; i < 96; i++){
    SPI.transfer(GSDL[i]);
    if( GSDL[i] < 0x10){ Serial.print("0");}Serial.print(GSDL[i],HEX); //prints to serial monitor value with leading 0
  }  
  Serial.println();
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
  delay(1000);
}

Here is the initial snip of my Serial Monintor:

Debugging Session On...

FF960000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204081020408102040810204081020408102040810204081020408102040810204081020408102040810492040810
00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

this is a bit above my skill set, but I was able to find code that successfully used the tlc5955... maybe that will help...

Thanks for the hint Qdeathstar, The code you refer to was written for a "STM32F4 MCU with ARM Cortex-M4 processor 180 MHz operating frequency".

It is also written in some serious C :slight_smile: , I'll need to spend some time and see how he does it. From a quick look, we seem to do doing pretty much the same thing except he uses SPI with DMA.

If anyone else has arduino code for the TLC5955 I would really appreciate some guidance.

Hi,

If anyone google's their way here, I found my issue. I was creating the Control Data in the wrong order, I was doing DC||MC||BC||FC (where || denotes concatenation).

On re-examination, I noticed that it should be the inverse FC||BC||MC||DC.

Once this was done the TLC5955 responded accordingly, however I noticed that it helped alot to flush the register before a write so I added a flush routine.

I would like to put together a C library and have started a GitHub project Arduino-TLC5955

Working Code below:

#include "SPI.h" // necessary library

byte cdlFill[1] = {0x00};  //5bits used
byte cdlDC[48]; //7bits used
byte cdlMC[3];  //3bits used
byte cdlBC[3];  //7bits used
byte cdlFC[1];  //5bits used

byte outBuffer[97];
byte GSDL[96];
byte CDL[47];
byte CDLbuffer[48];
byte counter = 0;
byte mode_cd = 0x01; //FF/01=CD
byte mode_gs = 0x00; //00=GS
byte modecdl = 0x96; //mode must be FF followed by 96 for control data.

byte inByte = 0;
//SPISettings settingsA(1000000, MSBFIRST, SPI_MODE0); 

void latch_tlc() {
  delay(10);
  digitalWrite(SS, HIGH);
  delay(10);
  digitalWrite(SS, LOW);
  delay(10);
}

//need to create the Control Data sequence in the required format
void combine_cdl() {
  int arrayPosCDL=0;
  int arrayPosFill=0;
  int arrayPosDC=0;
  int arrayPosMC=0;
  int arrayPosBC=0;
  int arrayPosFC=0;
  //append the 0 fill values to CDL
  for (int bitPos=0;bitPos<5;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosFill = (bitPos-0)/5;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlFill[arrayPosFill], 4-((bitPos-0)%5)));
  }
  //append the FC values to CDL
  for (int bitPos=5;bitPos<10;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosFC = (bitPos-5)/5;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlFC[arrayPosFC], 4-((bitPos-5)%5)));
  }       
  //append the BC values to CDL
  for (int bitPos=10;bitPos<31;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosBC = (bitPos-10)/7;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlBC[arrayPosBC], 6-((bitPos-10)%7)));
  } 
  //append the MC values to CDL  
  for (int bitPos=31;bitPos<40;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosMC = (bitPos-31)/3;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlMC[arrayPosMC], 2-((bitPos-31)%3)));
  }   
  //append the DC values to CDL
  for (int bitPos=40;bitPos<376;bitPos++) {
    arrayPosCDL = bitPos/8;
    arrayPosDC = (bitPos-40)/7;
    bitWrite(CDL[arrayPosCDL], 7-bitPos%8, bitRead(cdlDC[arrayPosDC], 6-((bitPos-40)%7)));
   } 
}

void writeCDL(){
  //set mode bit high
  outBuffer[0]=SPI.transfer(mode_cd);
  if( mode_cd < 0x10){ Serial.print("0");} Serial.print(mode_cd,HEX);
  //TLC5955 Datasheet pg17 bits 767 to 760 must be 0x96
  outBuffer[1]=SPI.transfer(modecdl);
  if( modecdl < 0x10){ Serial.print("0");} Serial.print(modecdl,HEX);
  for (int i=0; i < 48; i++){
    outBuffer[2+i]=SPI.transfer(CDLbuffer[i]);  //write out some 00s to "pad" the register
    if( CDLbuffer[i] < 0x10){ Serial.print("0");} Serial.print(CDLbuffer[i],HEX);
  }  
  for (int i=0; i < 47; i++){
    outBuffer[50+i]=SPI.transfer(CDL[i]);  //write out the configured CDL data
    if( CDL[i] < 0x10){ Serial.print("0");} Serial.print(CDL[i],HEX);
  }  
  Serial.println();
  //digitalWrite(5, HIGH);
  latch_tlc();
  for (int i=0; i < 97; i++){
     if( outBuffer[i] < 0x10){ Serial.print("0");}Serial.print(outBuffer[i],HEX); //prints to serial monitor value with leading 0
  }  
  Serial.println();
  
}

void flushTLC(){
  for (byte i=0;i<97;i++){
    SPI.transfer(0x00);
  }
}

void setup() {
  //I want to enable serial comms for deugging via ide.
  Serial.begin (115200);   // serial: Typical Rates, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, or 115200
  Serial.println ("\nDebugging Session On...\n");
  
  //Initialise all variable to some predefined level.
  for (int i=0; i < 96; i++){
      GSDL[i] = 0x00;    //All LEDs Full on
   } 
  
  //Set the configuration byes 
  for (int i=0; i < 47; i++){
      CDL[i] = 0x00;
  } 
  
  for (int i=0; i < 48; i++){
      CDLbuffer[i] = 0x00; //Padding reqired to get the Control Data into the full Data register
  } 
  for (int i=0; i < 48; i++){
      cdlDC[i] = 0x40;    //set DC halfway
  } 
  for (int i=0; i < 3; i++){
      cdlMC[i] = 0x04;    //set MC halfway
  } 
  for (int i=0; i < 3; i++){
      cdlBC[i] = 0x40;    //set BC halfway
  } 
  cdlFC[0] = 0x19;  //auto display repeat
  
  
  
  //Initialise MISO,SS,SCK as an output 
  //pinMode(MISO, INPUT); 
  //pinMode(MOSI, OUTPUT);
  //pinMode(SCK, OUTPUT);  
  pinMode(SS, OUTPUT); 
  digitalWrite(SS, LOW);
  //Need to generate a clock signal for GSCLK. (Using following 5 lines we should get a 1MHz Clock on pin 11 (OC1A Pin))
  pinMode(11, OUTPUT);               //set OC1A/PB1 as output
  TCCR1A = _BV(COM1A0);              //toggle OC1A on compare match
  OCR1A = 7;                         //top value for counter
  TCCR1B = _BV(WGM12) | _BV(CS10);   //CTC mode, prescaler clock/1
  
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
  SPI.setBitOrder(MSBFIRST);
  SPI.begin();
  delay(100);
  flushTLC();
  delay(100);
  combine_cdl();  
  writeCDL();  //Setup the TLC5955 once.
}

void loop() {

  flushTLC();
  outBuffer[0]=SPI.transfer(mode_gs);
  if( mode_gs < 0x10){ Serial.print("0");}Serial.print(mode_gs,HEX); //prints to serial monitor value with leading 0
  for (int i=0; i < 96; i++){
    outBuffer[i+1]=SPI.transfer(GSDL[i]);
    if( GSDL[i] < 0x10){ Serial.print("0");}Serial.print(GSDL[i],HEX); //prints to serial monitor value with leading 0
  }  
  Serial.println();
  latch_tlc();
 
  for (int i=0; i < 97; i++){
     if( outBuffer[i] < 0x10){ Serial.print("0");}Serial.print(outBuffer[i],HEX); //prints to serial monitor value with leading 0
  }  
  Serial.println();
  
  if (GSDL[counter]<0x33){GSDL[counter] = GSDL[counter]+1;}
  else{ counter = counter + 1;}
  delay(1);
}

hey

i want to connect a TLC5955 to my arduino nano.
Do you have a schematic of your electrical wiring?

I know this post is from a few months ago, but I've developed a working TLC5955 library as part of a research project, which I've been using to control a 200 RGB LED Array.

Source and download is here:

Please report issues or requests!