W5100 Ethernet shield and TLC5940

Hi all. I was looking at controlling some TLC5940's over local network but I have just discovered that it won't work.

I have searched quite extensively on this topic and found a few bits of info, but none seem relevant with the newer versions of the IDE and TLC library.

I 'think' I need to just edit the tlc_config.h file, set to bit bang mode and specify the pin changes, but Im not 100% so could anyone clarify? I'm not sure how to change the pins or the format the definition should be in?

Looking at the Ethernet information, I will need to free up pins 11,12,13 which means moving SIN & SCLK (TLC5940) to other arduino pins.

/*  Copyright (c) 2009 by Alex Leone <acleone ~AT~ gmail.com>

    This file is part of the Arduino TLC5940 Library.

    The Arduino 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.

    The Arduino TLC5940 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 The Arduino TLC5940 Library.  If not, see
    <http://www.gnu.org/licenses/>. */

#ifndef TLC_CONFIG_H
#define TLC_CONFIG_H

#include <stdint.h>

/** \file
    Configuration for the Arduino Tlc5940 library.  After making changes to
    this file, delete Tlc5940.o in this folder so the changes are applied.

    A summary of all the options:
    - Number of TLCs daisy-chained: NUM_TLCS (default 1)
    - Enable/Disable VPRG functionality: VPRG_ENABLED (default 0)
    - Enable/Disable XERR functionality: XERR_ENABLED (default 0)
    - Should the library use bit-banging (any pins) or hardware SPI (faster):
        DATA_TRANSFER_MODE (default TLC_SPI)
    - Which pins to use for bit-banging: SIN_PIN, SIN_PORT, SIN_DDR and
        SCLK_PIN, SCLK_PORT, SCLK_DDR
    - The PWM period: TLC_PWM_PERIOD (be sure to change TLC_GSCLK_PERIOD
        accordingly!)

    How to change the pin mapping:
    - Arduino digital pin 0-7  = PORTD, PD0-7
    - Arduino digital pin 8-13 = PORTB, PB0-5
    - Arduino analog pin  0-5  = PORTC, PC0-5 */

/** Bit-bang using any two i/o pins */
#define TLC_BITBANG        1
/** Use the much faster hardware SPI module */
#define TLC_SPI            2

/* ------------------------ START EDITING HERE ----------------------------- */

/** Number of TLCs daisy-chained.  To daisy-chain, attach the SOUT (TLC pin 17)
    of the first TLC to the SIN (TLC pin 26) of the next.  The rest of the pins
    are attached normally.
    \note Each TLC needs it's own IREF resistor */
#define NUM_TLCS    1

/** Determines how data should be transfered to the TLCs.  Bit-banging can use
    any two i/o pins, but the hardware SPI is faster.
    - Bit-Bang = TLC_BITBANG
    - Hardware SPI = TLC_SPI (default) */
#define DATA_TRANSFER_MODE    TLC_SPI

/* This include is down here because the files it includes needs the data
   transfer mode */
#include "pinouts/chip_includes.h"

/* Set DATA_TRANSFER_MODE to TLC_BITBANG and change the pins below if you need
   to use different pins for sin and sclk.  The defaults are defined in
   pinouts/ATmega_xx8.h for most Arduino's. */

#if DATA_TRANSFER_MODE == TLC_BITBANG
/** SIN (TLC pin 26) */
#define SIN_PIN        DEFAULT_BB_SIN_PIN
#define SIN_PORT       DEFAULT_BB_SIN_PORT
#define SIN_DDR        DEFAULT_BB_SIN_DDR
/** SCLK (TLC pin 25) */
#define SCLK_PIN       DEFAULT_BB_SCLK_PIN
#define SCLK_PORT      DEFAULT_BB_SCLK_PORT
#define SCLK_DDR       DEFAULT_BB_SCLK_DDR
#endif


/** If more than 16 TLCs are daisy-chained, the channel type has to be uint16_t.
    Default is uint8_t, which supports up to 16 TLCs. */
#define TLC_CHANNEL_TYPE    uint8_t

/** Determines how long each PWM period should be, in clocks.
    \f$\displaystyle f_{PWM} = \frac{f_{osc}}{2 * TLC\_PWM\_PERIOD} Hz \f$
    \f$\displaystyle TLC\_PWM\_PERIOD = \frac{f_{osc}}{2 * f_{PWM}} \f$
    This is related to TLC_GSCLK_PERIOD:
    \f$\displaystyle TLC\_PWM\_PERIOD =
       \frac{(TLC\_GSCLK\_PERIOD + 1) * 4096}{2} \f$
    \note The default of 8192 means the PWM frequency is 976.5625Hz */
#define TLC_PWM_PERIOD    8192

/** Determines how long each period GSCLK is.
    This is related to TLC_PWM_PERIOD:
    \f$\displaystyle TLC\_GSCLK\_PERIOD =
       \frac{2 * TLC\_PWM\_PERIOD}{4096} - 1 \f$
    \note Default is 3 */
#define TLC_GSCLK_PERIOD    3

/** Enables/disables VPRG (TLC pin 27) functionality.  If you need to set dot
    correction data, this needs to be enabled.
    - 0 VPRG is not connected.  <em>TLC pin 27 must be grounded!</em> (default)
    - 1 VPRG is connected
    \note VPRG to GND inputs grayscale data, VPRG to Vcc inputs dot-correction
          data */
#define VPRG_ENABLED    0

/** Enables/disables XERR (TLC pin 16) functionality to check for shorted/broken
    LEDs
    - 0 XERR is not connected (default)
    - 1 XERR is connected
    \note XERR is active low */
#define XERR_ENABLED    0

/*  You can change the VPRG and XERR pins freely.  The defaults are defined in
    the chip-specific pinouts:  see pinouts/ATmega_xx8.h for most Arduino's. */

#if     VPRG_ENABLED
/** VPRG (TLC pin 27) */
#define VPRG_PIN        DEFAULT_VPRG_PIN
#define VPRG_PORT       DEFAULT_VPRG_PORT
#define VPRG_DDR        DEFAULT_VPRG_DDR
#endif

#if     XERR_ENABLED
/** XERR (TLC pin 16) */
#define XERR_PIN        DEFAULT_XERR_PIN
#define XERR_PORT       DEFAULT_XERR_PORT
#define XERR_DDR        DEFAULT_XERR_DDR
#define XERR_PINS       DEFAULT_XERR_PINS
#endif

/* ------------------------- STOP EDITING HERE ----------------------------- */

#if DATA_TRANSFER_MODE == TLC_SPI
/** SIN (TLC pin 26) */
#define SIN_PIN        TLC_MOSI_PIN
#define SIN_PORT       TLC_MOSI_PORT
#define SIN_DDR        TLC_MOSI_DDR
/** SCLK (TLC pin 25) */
#define SCLK_PIN       TLC_SCK_PIN
#define SCLK_PORT      TLC_SCK_PORT
#define SCLK_DDR       TLC_SCK_DDR
#endif



#if !(DATA_TRANSFER_MODE == TLC_BITBANG \
 || DATA_TRANSFER_MODE == TLC_SPI)
#error "Invalid DATA_TRANSFER_MODE specified, see DATA_TRANSFER_MODE"
#endif

/* Various Macros */

/** Arranges 2 grayscale values (0 - 4095) in the packed array format (3 bytes).
    This is for array initializers only: the output is three comma seperated
    8-bit values. */
#define GS_DUO(a, b)    ((a) >> 4), ((a) << 4) | ((b) >> 8), (b)


#if VPRG_ENABLED
/** Arranges 4 dot correction values (0 - 63) in the packed array format.
    \see setDCtoProgmemArray */
#define DC_QUARTET(a, b, c, d)   ((a) << 2) | ((b) >> 4), \
                                 ((b) << 4) | ((c) >> 2), \
                                 ((c) << 6) | (d)
#endif

#endif

Which Chip are you using?

change line 61 from

#define DATA_TRANSFER_MODE    TLC_SPI

to

#define DATA_TRANSFER_MODE    TLC_BITBANG

Then look at lines 73-79

Change them from

/** SIN (TLC pin 26) */
#define SIN_PIN        DEFAULT_BB_SIN_PIN
#define SIN_PORT       DEFAULT_BB_SIN_PORT
#define SIN_DDR        DEFAULT_BB_SIN_DDR
/** SCLK (TLC pin 25) */
#define SCLK_PIN       DEFAULT_BB_SCLK_PIN
#define SCLK_PORT      DEFAULT_BB_SCLK_PORT
#define SCLK_DDR       DEFAULT_BB_SCLK_DDR

to

/** SIN (TLC pin 26) */
#define SIN_PIN        PD5
#define SIN_PORT       PORTD
#define SIN_DDR        DDRD
/** SCLK (TLC pin 25) */
#define SCLK_PIN       PD6
#define SCLK_PORT      PORTD
#define SCLK_DDR       DDRD

That will use pins 4 and 5 on the arduino I am assuming you are using an UNO (ATMega168)

I am using an UNO with a 328.

Many thanks for the explanation! It makes sense looking at the way you have defined the pins :slight_smile:

Thanks again, I'm looking forward to trying this out later. Can you think of any other reasons why the Ethernet shield and TLC would not work together?

Karma added 8)

Brilliant, the TLC runs fine from the new pins, thanks for the help mrjonny.

Time to try it with the Ethernet shield next :slight_smile:

The reason why they don't work on the same pins is because SPI is an actual interface protocol. The reason the library uses those pins is because it can switch them faster as they are designed for the SPI interface. The TLC is not actually an SPI device. If it was communicating over SPI you would be able to use all the same pins with the exception of pin 10 which is the select pin which has to be unique to each device. This means that 1 device uses 4 pins, 2 devices use 5 pins, 3 use 6 pins. Look up SPI on wiki if you want to learn more. :slight_smile:

Thanks for explaining that Jonny.

Sadly it won't work as PIN10 is required by the shield and the TLC. I tried to change pin 10 to pin 7 in the pinout section of the TLC library but it won't work. I wonder if the shield CS pin could be changed? I did some searching and came up with this http://arduino.cc/forum/index.php/topic,133481.15.html looks like it cant be moved as it is something to do with the timer?

I can't really understand what would need to be done in software to move the TLC blank pin :frowning:

Anyone got any other suggestions for freeing up pin10 from either device?

Can you give me a link to the entire library please?
The file you have uploaded has no mention of the blanking pin. I have never used these things before so I am unsure as to what it does.

Sure Mr Jonny Google Code Archive - Long-term storage for Google Code Project Hosting.

I'm not 100% sure what it does, I think it might clear the array at the end of the 4096 loop? Like I said I tried to re-assign it in the pinout section of the library but it didn't work and I read somewhere about it using a timer on pin12 so can't be moved?

Thanks for the help :slight_smile:

According to the library.

SS will be set to output as to not interfere with SPI master operation.
    If you have changed the pin-outs and the library doesn't seem to work
    or works intermittently, make sure this pin is set correctly.  This pin
    will not be used by the library other than setting its direction to
    output. */

Therefore you should just be able to connect both to pin 10 and everything should still work

Otherwise #define TLC_SS_PIN      PB2 to #define TLC_SS_PIN      PB1 (pin 9)

Other option change the SS pin on the ethernet shield. Will require a bit of modification to the shield. http://arduino.cc/forum/index.php/topic,118265.0.html

Thanks for the info mrjonny, I will be home tonight so I will try it again and see if I can get it working.

Thanks again!

I'm not having any luck tonight :frowning:

I started off by stripping down a sketch to control the TLC and a second one to serve a simple webpage with on/off buttons for a digital output. Both of these work fine on their own with all the hardware connected together (Arduino pin 10 being shared by the TLC & Ethernet shield).

TLC code:

#include "Tlc5940.h"

void setup()
{
  Tlc.init(0);
}

void loop()
{
  Tlc.set(1, 4095);  
  Tlc.set(2, 2000); 
  Tlc.set(3, 1000); 
  Tlc.update();
  delay(100);
}

Ethernet code:

// http://code.google.com/p/arduino/issues/detail?id=605
 
#include <SPI.h>
#include <Ethernet.h>
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 0, 177 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(80); //server port
 
String readString;
 
//////////////////////
 
void setup(){
 
  pinMode(7, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();

}
 
void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
 
        //read char by char HTTP request
        if (readString.length() < 100) {
 
          //store characters to string
          readString += c;
          //Serial.print(c);
        }
 
        //if HTTP request has ended
        if (c == '\n') {
 
          ///////////////
 
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println();
 
          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
          client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
          client.println("<link rel='stylesheet' type='text/css' href='http://homeautocss.net84.net/a.css' />");
          client.println("<TITLE>Home Automation</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");
          client.println("<H1>Home Automation</H1>");
          client.println("<hr />");
          client.println("
");
         
          client.println("<a href=\"/?lighton\"\">Turn On Light</a>");
          client.println("<a href=\"/?lightoff\"\">Turn Off Light</a>
");        
 
          client.println("</BODY>");
          client.println("</HTML>");
 
          delay(1);
          //stopping client
          client.stop();
 
          ///////////////////// control arduino pin
          if(readString.indexOf("?lighton") >0)//checks for on
          {
            digitalWrite(7, HIGH);    // set pin 4 high
          }
          else{
          if(readString.indexOf("?lightoff") >0)//checks for off
          {
            digitalWrite(7, LOW);    // set pin 4 low
          }
          }
          //clearing string for next read
          readString="";
 
        }
      }
    }
  }
}

I since they were working, I combined them together and tested. The TLC output & arduino pin 7 turn on fine from the webpage, but when I tell it to turn off the arduino hangs and I get a 404 error on the web browser?

Combined code:

// http://code.google.com/p/arduino/issues/detail?id=605

#include <SPI.h>
#include <Ethernet.h>

#include "Tlc5940.h"

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 
  192, 168, 0, 177 }; // ip in lan
byte gateway[] = { 
  192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 
  255, 255, 255, 0 }; //subnet mask
EthernetServer server(80); //server port

String readString;

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

void setup(){

  Tlc.init(0);

  pinMode(7, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }

        //if HTTP request has ended
        if (c == '\n') {

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

          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
          client.println("<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />");
          client.println("<link rel='stylesheet' type='text/css' href='http://homeautocss.net84.net/a.css' />");
          client.println("<TITLE>Home Automation</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");
          client.println("<H1>Home Automation</H1>");
          client.println("<hr />");
          client.println("
");

          client.println("<a href=\"/?lighton\"\">Turn On Light</a>");
          client.println("<a href=\"/?lightoff\"\">Turn Off Light</a>
");        

          client.println("</BODY>");
          client.println("</HTML>");

          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf("?lighton") >0)//checks for on
          {
            digitalWrite(7, HIGH);
            Tlc.set(1, 4095);
            Tlc.update();
            delay(50);
          }
          else if(readString.indexOf("?lightoff") >0)//checks for off
          {
            digitalWrite(7, LOW);
            Tlc.set(1, 0);
            Tlc.update();
            delay(50);
          }



          //clearing string for next read
          readString="";

        }
      }
    }
  }
}

I thought this must be a conflict on arduino PIN10 between the shield and TLC so I tried to change the pin mapping in the xx8 pinout file of the TLC lib to PB0 (pin 9 is in use by the TLC already) but I get no output from the TLC, but if I connect the blank pin back to pin 10 then it sill works?

Anyone have an idea how to move the TLC BLANK pin? Ideally I would like to move it to pin 8. I have tried changing the definitions in the relevant pinout file in the TLC library but it just does not want to work on any pin other than 10?

That link I gave you was to change the chip select pin of the ethernet module. The other option is try running the ethernet begin command after turning off the tlc

Gave up with trying to change the blank pin, tried changing the cs pin on the ethernet shield and it works well now :slight_smile:

many thanks mrjonny! karma added :slight_smile:

Glad you got it working.