Arduino Due + Tlc5940

The tlc5940arduino library isn't working due to the differences between arm and avr. So, has someone tried to get the Tlc5940 working with the Arduino due? I want to drive my 8x8 rgb matrix with it.

Edit: I found some documentation and started making my own library. (or at least code) I am going to try it tomorrow.

Hey,
I know this topic hasnt been updated but I was wondering if you made a working tlc5940 library, because I would love to use it.

CakeBoss

CakeBoss:
Hey,
I know this topic hasnt been updated but I was wondering if you made a working tlc5940 library, because I would love to use it.

CakeBoss

I made something, but it didn't work very well. I could post the source here. Maybe someone could work it out.

I would be interested to see the code. I have the Due just for interfacing to make and 8x8x8 rbg cube and plan on using the 5940.

plctim:
I would be interested to see the code. I have the Due just for interfacing to make and 8x8x8 rbg cube and plan on using the 5940.

Okay, I will post it tomorrow.

Here it is:

//TLC5940
#define GSCLK_PIN 2
#define SIN_PIN 3
#define SCLK_PIN 4
#define BLANK_PIN 5
#define DCPRG_PIN 6
#define VPRG_PIN 7
#define XLAT_PIN 8

#define TLC5940_N 2

//74HC595
#define LATCH_PIN 9
#define CLOCK_PIN 10
#define DATA_PIN 11

//Display
int rowId = 0;

uint16_t rowR[8][8] = 
{
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
};

uint16_t rowG[8][8] = 
{
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
};

uint16_t rowB[8][8] = 
{
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
  ,
  {
    4095,4095,4095,4095,4095,4095,4095,4095  }
};

uint8_t dcData[96 * TLC5940_N] = {
  //MSB          LSB
  //TLC 1
  1, 1, 1, 1, 1, 1, // Channel 15
  1, 1, 1, 1, 1, 1, // Channel 14
  1, 1, 1, 1, 1, 1, // Channel 13
  1, 1, 1, 1, 1, 1, // Channel 12
  1, 1, 1, 1, 1, 1, // Channel 11
  1, 1, 1, 1, 1, 1, // Channel 10
  1, 1, 1, 1, 1, 1, // Channel 9
  1, 1, 1, 1, 1, 1, // Channel 8
  1, 1, 1, 1, 1, 1, // Channel 7
  1, 1, 1, 1, 1, 1, // Channel 6
  1, 1, 1, 1, 1, 1, // Channel 5
  1, 1, 1, 1, 1, 1, // Channel 4
  1, 1, 1, 1, 1, 1, // Channel 3
  1, 1, 1, 1, 1, 1, // Channel 2
  1, 1, 1, 1, 1, 1, // Channel 1
  1, 1, 1, 1, 1, 1, // Channel 0
  //TLC 2
  1, 1, 1, 1, 1, 1, // Channel 15
  1, 1, 1, 1, 1, 1, // Channel 14
  1, 1, 1, 1, 1, 1, // Channel 13
  1, 1, 1, 1, 1, 1, // Channel 12
  1, 1, 1, 1, 1, 1, // Channel 11
  1, 1, 1, 1, 1, 1, // Channel 10
  1, 1, 1, 1, 1, 1, // Channel 9
  1, 1, 1, 1, 1, 1, // Channel 8
  1, 1, 1, 1, 1, 1, // Channel 7
  1, 1, 1, 1, 1, 1, // Channel 6
  1, 1, 1, 1, 1, 1, // Channel 5
  1, 1, 1, 1, 1, 1, // Channel 4
  1, 1, 1, 1, 1, 1, // Channel 3
  1, 1, 1, 1, 1, 1, // Channel 2
  1, 1, 1, 1, 1, 1, // Channel 1
  1, 1, 1, 1, 1, 1, // Channel 0
};

uint8_t gsData[192 * TLC5940_N] = {
  //MSB                            LSB
  //TLC 1
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 15
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 14
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 13
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // Channel 12
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, // Channel 11
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // Channel 10
  0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // Channel 9
  0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // Channel 8
  0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // Channel 7
  0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Channel 6
  0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // Channel 5
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 4
  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 3
  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 2
  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 1
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Channel 0
  //TLC 2
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 15
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 14
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 13
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // Channel 12
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, // Channel 11
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // Channel 10
  0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // Channel 9
  0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // Channel 8
  0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // Channel 7
  0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Channel 6
  0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // Channel 5
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 4
  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 3
  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 2
  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Channel 1
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Channel 0
};

void TLC5940_Init()
{
  pinMode(GSCLK_PIN, OUTPUT);
  pinMode(SCLK_PIN, OUTPUT);
  pinMode(DCPRG_PIN, OUTPUT);
  pinMode(VPRG_PIN, OUTPUT);
  pinMode(XLAT_PIN, OUTPUT);
  pinMode(BLANK_PIN, OUTPUT);
  pinMode(SIN_PIN, OUTPUT);

  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);

  digitalWrite(GSCLK_PIN, LOW);
  digitalWrite(SCLK_PIN, LOW);
  digitalWrite(DCPRG_PIN, LOW);
  digitalWrite(VPRG_PIN, HIGH);
  digitalWrite(XLAT_PIN, LOW);
  digitalWrite(BLANK_PIN, HIGH);
}

void TLC5940_ClockInDC()
{
  digitalWrite(DCPRG_PIN, HIGH);
  digitalWrite(VPRG_PIN, HIGH);

  uint8_t Counter = 0;

  while(true)
  {
    if (Counter > TLC5940_N * 96 - 1) {
      digitalWrite(XLAT_PIN, HIGH);
      digitalWrite(XLAT_PIN, LOW);
      break;
    } 
    else {
      digitalWrite(SIN_PIN, dcData[Counter]);
      digitalWrite(SCLK_PIN, HIGH);
      digitalWrite(SCLK_PIN, LOW);
      Counter++;
    }
  }
}

void TLC5940_SetGS_And_GS_PWM() 
{
  uint8_t firstCycleFlag = 0;
  if (digitalRead(VPRG_PIN)) 
  {
    digitalWrite(VPRG_PIN, LOW);
    firstCycleFlag = 1;
  }
  uint16_t GSCLK_Counter = 0;
  uint8_t Data_Counter = 0;
  digitalWrite(BLANK_PIN, LOW);
  while (true)
  {
    if (GSCLK_Counter > 4095) 
    {
      digitalWrite(BLANK_PIN, HIGH);
      digitalWrite(XLAT_PIN, HIGH);
      digitalWrite(XLAT_PIN, LOW);
      if (firstCycleFlag) 
      {
        digitalWrite(SCLK_PIN, HIGH);
        digitalWrite(SCLK_PIN, LOW);
        firstCycleFlag = 0;
      }
      break;
    } 
    else 
    {
      if (!(Data_Counter > TLC5940_N * 192 - 1)) 
      {
        if (gsData[Data_Counter])
          digitalWrite(SIN_PIN, HIGH);
        else
          digitalWrite(SIN_PIN, LOW);
        digitalWrite(SCLK_PIN, HIGH);
        digitalWrite(SCLK_PIN, LOW);
        Data_Counter++;
      }
    }
    digitalWrite(GSCLK_PIN, HIGH);
    digitalWrite(GSCLK_PIN, LOW);
    GSCLK_Counter++;
  }
}

void setLed(int ledId, int driverId, uint16_t value)
{
  for(int i = 0; i < 12; i++)
  {
    gsData[driverId * 12 * 16 + 12 * ledId + i] = value >> (12 - i - 1);
  }
}

/*void TC3_Handler()
{
  TC_GetStatus(TC1, 0);
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << rowId);
  digitalWrite(LATCH_PIN, HIGH);
  for(int i = 0; i < 8; i++)
  {
   setLed(i, 0, rowR[i][rowId]);
   setLed(i, 1, rowG[i][rowId]);
   setLed(i + 8, 1, rowB[i][rowId]);
  }
  rowId++;
  if(rowId == 8) rowId = 0;
  TLC5940_SetGS_And_GS_PWM();
}*/

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
  pmc_set_writeprotect(false);
  pmc_enable_periph_clk((uint32_t)irq);
  TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
  uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
  TC_SetRA(tc, channel, rc/2); //50% high, 50% low
  TC_SetRC(tc, channel, rc);
  TC_Start(tc, channel);
  tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
  tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
  NVIC_EnableIRQ(irq);
}

void setup()
{
  TLC5940_Init();
  TLC5940_ClockInDC();
 // startTimer(TC1, 0, TC3_IRQn, 84000000 / 2);
}

void loop()
{
digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << rowId);
  digitalWrite(LATCH_PIN, HIGH);
  for(int i = 0; i < 8; i++)
  {
   setLed(i, 1, rowR[i][rowId]);
   //setLed(i, 0, rowG[i][rowId]);
   setLed(i + 8, 0, rowB[i][rowId]);
  }
 // rowId++;
 // if(rowId == 8) rowId = 0;
  TLC5940_SetGS_And_GS_PWM();
}

Maybe someone can fix it.

Hi,
this one works for me with 2 TLC5940s daisy-chained:
https://code.google.com/p/arduino-due-tlc5940/

I didn't use the error input pin (isn't implemented yet) but instead put the VPRG on pin 2, so there are pins 2,3,4,5 used and also TX1 and SDA1.

You have to put these files into the folder where your sketch is located:
due_timer_counters.cpp
due_timer_counters.h
due_tlc5940.cpp
due_tlc5940.h
due_tlc5940_config.h
due_usart.cpp
due_usart.h

My due_tlc5940_config.h looks like this:

/*
================================================================================
File name: due_tlc5940_config.h
   System: Due TLC5940 Library
 Platform: Arduino Due (Amtel SAM3X8E ARM Cortex-M3)
   Author: Madeline Usher
  Created: July 5, 2013
  Purpose: Configuration parameters for the Due TLC5940 Library.
================================================================================
  $LastChangedDate: 2013-07-14 11:51:11 -0500 (Sun, 14 Jul 2013) $
  $LastChangedBy: maddy314@gmail.com $
================================================================================
  Copyright (c) 2013 Madeline Usher <maddy314 ~@~ gmail.com>
 
  The Arduino Due TLC5940 Library is free software: you can redistribute it
  and/or modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation, either version 3 of the License, 
  or (at your option) any later version.

  This library is distributed in the hope that it will be useful, but WITHOUT 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with 
  this library.  If not, see <http://www.gnu.org/licenses/>.
================================================================================
*/


////////////////////////////////////////////////////////////////////////////////
/// To use this library, copy all the files in this folder into your sketch's
/// folder and edit this file.
///
/// The files have to be in your sketch's directory to allow individual 
/// customization via the #defines in the config file, which is unfortunately
/// necessary -- the name of the interrupt handler function must be known at
/// compile-time, which basically means we're dependent upon #defines to 
/// configure the library.
///
/// You should edit the configuration parameters in this file.
///
/// Because some of the TIOA outputs of the microcontroller's timers are not
/// connected to any Due pins, and because the GSCLK and BLANK timers must be
/// channels within the same timer counter, only some combinations are valid.
/// The following are the only valid configurations:
///
/// GSCLK output on Due pin 2 (digital 2):
///   GSCLK_TC = TC0_CH0
///   BLANK_TC = TC0_CH1
///
/// GSCLK output on Due pin 2 (digital 2):
///   GSCLK_TC = TC0_CH0
///   BLANK_TC = TC0_CH2
///
/// GSCLK output on Due pin 61 (analog 7):
///   GSCLK_TC = TC0_CH1
///   BLANK_TC = TC0_CH0  // can't use pin 2 as PWM in this config?
///
/// GSCLK output on Due pin 61 (analog 7):
///   GSCLK_TC = TC0_CH1
///   BLANK_TC = TC0_CH2
///
/// GSCLK output on Due pin 5 (digital 5):
///   GSCLK_TC = TC2_CH0
///   BLANK_TC = TC2_CH1  // can't use pin 3 as PWM in this config?
///
/// GSCLK output on Due pin 5 (digital 5):
///   GSCLK_TC = TC2_CH0
///   BLANK_TC = TC2_CH2  // can't use pin 11 as PWM in this config?
///
/// GSCLK output on Due pin 3 (digital 3):
///   GSCLK_TC = TC2_CH1
///   BLANK_TC = TC2_CH0  // can't use pin 5 as PWM in this config?
///
/// GSCLK output on Due pin 3 (digital 3):
///   GSCLK_TC = TC2_CH1
///   BLANK_TC = TC2_CH2  // can't use pin 11 as PWM in this config?
///
/// GSCLK output on Due pin 11 (digital 11):
///   GSCLK_TC = TC2_CH2
///   BLANK_TC = TC2_CH0  // can't use pin 5 as PWM in this config?
///
/// GSCLK output on Due pin 11 (digital 11):
///   GSCLK_TC = TC2_CH2
///   BLANK_TC = TC2_CH1  // can't use pin 3 as PWM in this config?
///


////////////////////////////////////////////////////////////////////////////////

// # of TLC5940 chips daisy-chained:
#define NUM_TLCS 2

/// GSCLK output on Due pin 3 
// Timer counter channel which will be used to generate the GSCLK signal.  Must 
// be one of the TC*_CH* values.
#define GSCLK_TC TC2_CH1


// Timer counter channel which will be used to generate the BLANK signal.  
// Because the output of the GSCLK will be used as the source clock for this 
// timer, both the GSCLK_TC and BLANK_TC must be differing channels on the same 
// timer counter (e.g. TC2_CH1 and TC2_CH2).  Must be one of the TC*_CH* values.
#define BLANK_TC TC2_CH2


// USART that should be used for the synchronous serial communications to/from 
// the TLC5940.  Must be one of the TLC5940_USART* values.  
// Note that this library uses a USART instead of an SPI unit even though the 
// TLC5940 communications are very much like SPI.  I did this because I'm using 
// this library for a board I designed that fits the Arduino Due like a shield 
// and I didn't have room in the center to make use of the Due's SPI header.
#define TLC_USART TLC5940_USART0


// The following pin outputs the BLANK signal.
#define BLANK_PIN 4


// This pin output the XLAT signal (to latch in new data).
#define XLAT_PIN  5


// This pin will drive the VPRG pin.  It's low when sending grayscale data and 
// high when sending dot-correction data.
#define VPRG_PIN  2


// Input pin for the XERR signal from the TLC5940.  I might not end up 
// implementing code to make use of this.
//#define XERR_PIN  2


// The following array specifies the initial dot-correction data for the 
// TLC5940 output channels.  0 disables all output on that channel, 63 means
// that maximum output is allowed.  There should be as many entries as there
// are TLC5940 output channels (i.e. NUM_TLCS * 16).  The first entry is 
// channel 0.

#define INITIAL_DCDATA {63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63, \
                        63, 63, 63, 63}


////////////////////////////////////////////////////////////////////////////////
/// End of Code

And don't forget to comment line 194 in due_tlc5940.cpp:

  //pinMode(XERR_PIN, INPUT);

Have a look at my wiring, too.

This is my example code:

/// Pin Assignments:
/// - SPI CLK  = SDA1, A.17, peripheral B -> TLC5940 SCLK (pin 25)
/// - SPI MOSI = TX1 (pin 18), A.11. peripheral A -> TLC5940 SIN (pin 26)
/// - (normally SPI MISO = RX1 (pin 17), A.10, peripheral A -> TLC5940 SOUT (pin 17) [opt] - not used in this example)
/// - pin 2 -> TLC5940 VPRG (pin 27)
/// - pin 5 -> TLC5940 XLAT (pin 24)
/// - pin 4 -> TLC5940 BLANK (pin 23)
/// - pin 3 -> TLC5940 GSCLK (pin 18)
/// - (normally pin 2 -> TLC5940 XERR (pin 16)  [optional] - not used/connected in this example)

////////////////////////////////////////////////////////////////////////////////

#include "Arduino.h"
#include "D:\xxxx\TLC5940DUE\example\due_tlc5940.h"


////////////////////////////////////////////////////////////////////////////////
/// The setup() method runs once, when the sketch starts

void setup ()
{
  initTLC5940();
  return;}


////////////////////////////////////////////////////////////////////////////////
/// The loop() method runs over and over again, as long as the Arduino has power

void loop()
{
  // In this example there are 3 LEDs connected to outputs 1, 2 and 17 (second output of the second TLC5940)
  
  // linear fade in
  for (int i = 0; i <= 4095; i++) {
    setGSData(1,   i);
    setGSData(2,   4096-i);
    setGSData(17,  i);
    sendGSData();
    delayMicroseconds(500);
  }
  
  // linear fade out
  for (int i = 4095; i >= 0; i--) {
    setGSData(1,   i);
    setGSData(2,   4096-i);
    setGSData(17,  i);
    sendGSData();
    delayMicroseconds(500);
  }
  
  // exponential fade in
   for (int i = 0; i <=12; i++) {
    setGSData(1,   pow(2,i)-1);
    setGSData(2,   pow(2,i)-1);
    setGSData(17,  pow(2,i)-1);
    sendGSData();
    delay(200);
  }  
  // exponential fade out
  for (int i = 11; i >= 0; i--) {
    setGSData(1,   pow(2,i)-1);
    setGSData(2,   pow(2,i)-1);
    setGSData(17,  pow(2,i)-1);
    sendGSData();
    delay(200);
  }
  

}