Total Control Lighting

Total Control Lighting is a new product from Cool Neon. It's a series of addressable LED lights whose colors you can control to a very high order of precision. Each LED can be set to have red, green, and blue values between 0 (fully off) and 255 (fully on). The LEDs are arranged in series and SPI is used to communicate with each LED. The LEDs function by reading 4 bytes (3 for the RGB values, and one flag byte). On receipt of a subsequent set of 4 bytes the LED switches to the indicated color and moves the previously received bytes down the line to the next LED. There are 4 wires connecting each LED to the next, these wires are arranged as follows:

Color Value
Red +5V
White Data
Green Clock
Blue Ground

Cool Neon sells shields and Seeeduinos (an Arduino compatible board) which make connecting the total control lighting strands, as well as external power, a snap. I recommend the Cool Neon Total Control Lighting Developer Shield (discussed and shown below) because in addition to connecting the lighting strands to the Arduino, it includes some buttons, switches, and potentiometers which can help to easily create a lighting control system.

Using Total Control Lighting with an Arduino

Note: I have now written an Arduino library. If you want to get started quickly, just download the latest version of the library. You can also download previous versions from the download page. The source code is available on bitbucket and github. Follow the instructions and examples provided. Also feel free to try PixelPaint, my open source LED sequence designer for Total Control Lighting.

The Arduino has dedicated hardware SPI pins, which allow for fast communication to the total control lighting pixels. The specific group of pins on the Arduino UNO board are:

Pin Value
pin 13 Serial Clock
pin 12 Master In/Slave Out
pin 11 Master Out/Slave In
pin 10 Slave Select

Note that the mega uses different pins. To find those pins, read the SPI documentation.

For this application, we only need to use pin 13 (the serial clock) and pin 11 (the master out/slave in data line). Connect the Total Control Lighting strand (or T-connector) data line to pin 11 of the Arduino and connect the clock line to pin 13 of the Arduino. There are three modes for powering the Arduino and LED lights. Note: The Total Control Lighting shields handle the connection to the correct pins automatically.

  • If you are running the Arduino on USB power or using an external battery or adapter, but running the Total Control Lighting strand with an additional 5V source then connect only the Ground line of the Total Control Lighting strand or T-connector to a Ground pin of the Arduino. Leave the +5V Total Control Lighting line disconnected from the Arduino.
  • If you plan on powering both the Arduino and the Total Control Lighting from a power source connected to the T-connector. Then connect the Ground line of the T-connector to a Ground pin of the Arduino, and connect the +5V Power line of the T-connector to the 5V pin of the Arduino. You may be tempted to use the Vin pin, but that would run the power through the regulator, which will drop the voltage a bit. Note: If you are going to run the Total Control Lighting strands at higher voltages than +5V, you should connect the power connection on the T-connector to the Vin pin of the Arduino.
  • If you plan on powering the Total Control Lighting pixels directly from the Arduino, then connect the +5V wire of the Total Control Lighting to the 5V pin of the Arduino and the Ground wire of the Total Control Lighting to a Ground on the Arduino.

Now that everything is connected, what do you do? It's time to program a sketch for the Arduino.

The Total Control Lighting library includes several example sketches, which I recommend looking through to get a sense of how it works. Please feel free to use the examples as a starting point for building your own projects.

First, download the open source TCL library. To install this library, unzip it into the "libraries" directory of yourArduino sketchbook folder. If there is not already a folder named "libraries" then create it. When you next start the Arduino IDE you will have a new TCL library and a couple of new examples using the TCL library. I encourage you to take a look at the examples and try them out using your Total Control Lighting strands to make sure everything is working.

Second, be sure to include the SPI library and the TCL in your sketch using the include directive:

#include <SPI.h>
#include <TCL.h>

Next, within the setup() section of the code, be sure to activate the TCL library, which sets up the SPI interface to work with the Total Control Lighting strands.

void setup() {
  TCL.begin();
}

There are a few simple commands you need. First, to initialize the strand, you need to send a TCL.sendEmptyFrame() command. Then send the colors you want in order, starting from the pixel nearest the Arduino connection to the pixel farthest from the Arduino connection using the TCL.sendColor(byte red, byte green, byte blue) command, and then end the sequence by sending another TCL.sendEmptyFrame() command.

Now, using these simple routines we can start sending data to the LEDs. Let's suppose I want to send the colors red, orange, yellow, green, and blue to a strand of 5 Total Control Lighting LEDs attached to my arduino. I could write the routine:

void loop() {
    TCL.sendEmptyFrame();
    TCL.sendColor(0xff,0x00,0x00);
    TCL.sendColor(0xff,0x60,0x00);
    TCL.sendColor(0xff,0xb0,0x00);
    TCL.sendColor(0x00,0x80,0x00);
    TCL.sendColor(0x00,0x00,0xff);
    TCL.sendEmptyFrame();
    delay(1000);
}

Of course this routine resends the colors every second, which is not necessary. The colors will remain for as long as the strand has power supplied to it.

The Developer Shield

Cool Neon is starting to offer a developer shield which includes 4 potentiometers, two momentary buttons, and two two-position switches. The shield is pictured below:

Cool Neon Total Control Lighting Developer
Shield

The shield includes a +5V DC power input cable with a 2.1mm jack, compatible with the wall-wart power supplies Cool Neon sells (which will power the Arduino as well as the lights). There is also a female total control lighting output, which can connect directly to the total control lighting pixel strands. What makes the shield special is it also comes with four potentiometers, two momentary buttons, and two switches which can be configured as inputs to the Arduino.

If you hold the developer shield so that the two-position switches are at the top and the potentiometers are at the bottom (upside-down in terms of the photo above), then going clockwise from upper-left the potentiometers connect to analog input pins 0, 1, 2, and 3. The momentary switches, moving from bottom to top connect to digital pins 4 and 5, and the two-position switches from bottom to top connect to digital pins 6 and 7. When closed, the switches connect the pin to ground, so you should configure them to use the internal pull-up resistors. The total control library configures the inputs correctly if you issue the command:

TCL.setupDeveloperShield();

There are also defined aliases for each input device:

  • TCL_POT1: Potentiometer 1
  • TCL_POT2: Potentiometer 2
  • TCL_POT3: Potentiometer 3
  • TCL_POT4: Potentiometer 4
  • TCL_MOMENTARY1: Button 1
  • TCL_MOMENTARY2: Button 2
  • TCL_SWITCH1: Two-position Switch 1
  • TCL_SWITCH2: Two-position Switch 2

So, for example to read the state of button 1 I would issue the command:

state = digitalRead(TCL_MOMENTARY1);

It would return state==HIGH if the button was open (not being pressed) and state==LOW if the button was closed (being pressed).

A More Realistic Example

Let's try something a little more realistic. Imagine it's the holidays and you are nostalgic for the blinking christmas lights your mom used to buy. You remember that they drove you crazy when you were little, but now that you've been away from home for years you want them again. However, you notice that they are more expensive than you recall. You decide to program a little blinking light magic on your Total Control Lighting strands. You decide you will stick to some basic colors: red, orange, yellow, green, and blue and that you will have the lights blink for random on and off times of 700-1300 milliseconds and in random colors. You pick a strand of 50 LEDs and start cracking.

Your code starts with some basic definitions:

#include <SPI.h>
#include <TCL.h>
const int LEDS = 50; // 50 LED Total Control Lighting Strand
const int COLORS = 6; // 5 colors and black.
const int BLACK = 0; // Define the colors for your code
const int RED = 1;
const int ORANGE = 2;
const int YELLOW = 3;
const int GREEN = 4;
const int BLUE = 5;
byte color_values[COLORS][3]; // This will store the RGB values of various colors
long change_time[LEDS]; // This array will store at what time the LEDs should change
int current_color[LEDS]; // This array stores an integer for each LED with its current color

Next we need to initiate the SPI interface, store the RGB byte values for each color, and set up our initial colors and durations until the lights blink off.

void setup() {
  int i;
  unsigned long time;

  TCL.begin();

  // Set up RGB values for each color we have defined above
  color_values[BLACK][0] = 0x00;
  color_values[BLACK][1] = 0x00;
  color_values[BLACK][2] = 0x00;

  color_values[RED][0]=0xff;
  color_values[RED][1]=0x00;
  color_values[RED][2]=0x00;

  color_values[ORANGE][0]=0xff;
  color_values[ORANGE][1]=0x60;
  color_values[ORANGE][2]=0x00;

  color_values[YELLOW][0]=0xff;
  color_values[YELLOW][1]=0xb0;
  color_values[YELLOW][2]=0x00;

  color_values[GREEN][0]=0x00;
  color_values[GREEN][1]=0x80;
  color_values[GREEN][2]=0x00;

  color_values[BLUE][0]=0x00;
  color_values[BLUE][1]=0x00;
  color_values[BLUE][2]=0xff;
  time = millis(); // Find the current time
  for(i=0;i<LEDS;i++) {
    change_time[i] = time+random(700,1300); // Set up the time each LED should blink on in 700-1300 ms
    current_color[i]=BLACK; // Set each LED to black
  }
  update_strand(); // Update the colors along the strand of LEDs
}

Notice, I used a subroutine to update the colors on the LEDs, since I will need to do this every loop. The subroutine is defined here:

void update_strand() {
  int i;
  int color;

  TCL.sendEmptyFrame();
  for(i=0;i<LEDS;i++) {
    color = current_color[i];
    TCL.sendColor(color_values[color][0],color_values[color][1],color_values[color][2]);
  }
  TCL.sendEmptyFrame();
}

Each loop involves checking the current time and seeing if it is time for the LEDs to change color and then selecting a color for the LED. If it is already on, then we change the LED to black. If it is off, we randomly select a color for the LED to change to. That is done in this loop:

void loop() {
  int i;
  unsigned long time;

  time=millis();

  for(i=0;i<LEDS;i++) {
    if(change_time[i]<time) {
      change_time[i]=time+random(700,1300);
      if(current_color[i]==BLACK) {
        current_color[i]=random(1,COLORS);
      }
      else {
        current_color[i]=BLACK;
      }
    }
  }
  update_strand();
}

And there you have it... you can enjoy the blinking lights that drove you crazy as a child. Christmas is saved with Total Control Lighting.

About Christopher De Vries
I am an astronomer turned programmer who specializes in fixing things when they are broken.