I’ve been trying to figure out things to do with these 16 x 16 RGB LED matrix panels that I’m selling. These things are so bright (over 10,000 candela per square meter) I thought they would make an excellent DMX controlled RGB flood light. I was right, they’re great for that, even if it under-utilizes the ability to access every individual pixel.
I had to pull a few things together for this and I did quite a bit of searching. The first thing I knew I was going to need was a DMX master. After a bit of digging I found a page on Fritzing.org for an Arduino to DMX converter. This allows you to use an Arduino’s FTDI FT232 driver as a DMX master. It doesn’t actually use any code in the Arduino it just connects some external components to the Rx pin on the Arduino. In order to make the FTDI FT232 chip communicate with the DMX control software I use later I also need to install the Open DMX FT232 driver (available under the ‘drivers’ list on the right) which supports the FTDI FT232 chip. I’m not sure which Arduinos use the FT232, but I know my Deumilanove does.
Since the DMX information is being delivered to the Rx pin of the Arduino in the above application, it’s easy enough to set the Arduino up as a DMX slave as have an all in one single unit DMX setup and read the DMX data right off the Rx pin without building a real DMX interface. Data flow is as follows: PC -> USB -> FT232 -> Arduino -> LED Panel. This type of setup will let you play with DMX software and a panel before deciding if you want to build a full blown DMX interface or buy some.
I also needed a DMX library for the Arduino. I used the Conceptinetics DMX library which allows the Arduino to act as a master or slave device on a DMX network. They had a couple of examples and within a few minutes I had things up and running. The code is at the bottom of this post.
I wrote the code for the LED panel as a 5 channel device.
There are 3 channels for Red, Green and Blue, one channel for Strobe and one channel for Intensity. The values coming from the DMX master (my PC) are 0-255. I fed the RGB values into 3 Arduino PWM lines, the panel has 3 Output Enable lines, one each for Red, Green and Blue. PWM into these lines was originally used for global brightness control on the panels when used as a Matrix display, so this works just fine for color mixing. The intensity value is mixed into the RGB level controls which gives 255 steps of brightness mixed with 255 steps of individual color channel control.
The strobe channel as well provides a value of 0-255, I just converted that into a non-blocking type delay as you can see in the code. The value directly represents a ###ms delay for strobe on/strobe off and controls the panel accordingly. As a bonus you can continuously adjust the colors values and intensity seamlessly while the strobe effect is running.
One other duty to take care of was to make sure that all of the pixel drivers had their outputs turned on, since this is a matrix display panel and not just a light board, if we went through all of the above effort without actually turning the pixel outputs on, this would be extremely boring. The LED panel is connected to the Arduino as described in the code below. You can use different pin numbers, but the output enable lines must be tied together in pairs(OE R1 and R2, OE B1 and B2, Oe G1 and G2) and connected to three PWM lines. This is taken care of by a ‘color_wipe(1,1,1)’ which runs a function I wrote to turn all pixels on.
With all that taken care of I need a DMX controller software for my PC. There are a lot of options to choose from and they come in Mac and linux flavors as well so no one gets left out. I went with on called Freestyler 512 which is free and comes with a Sound2Light plugin which is really awesome and a Fixture Creator (in the install directory) for laying out your own fixtures.
I installed the Open DMX driver before installing Freestyler 512, but it probably doesn’t matter either way, you can change the Freestyler setup later. I pointed Freestyler at my FTDI FT232 adapter (Ardunio Duemilanove) for the DMX interface and off we went. It took a few minutes to figure out how to add a fixture to the screen and then start controlling it but before long I was sending out command, changing colors, strobe and everything else.
I created a fixture file for the LED panel as setup in the code below, if you would like to use it, you can download it here:
Unzip the file and copy LED Panel.fxt and LED Panel.gif into the Freestyle ‘Fixtures’ sub-directory, you can now add this panel as a fixture in Freestyler! (Setup -> Add/Remove Fixtures -> Generic -> LED Panel) When you add the fixture make sure you check the box to enable sound control!
If you double click on the panel a bunch of sliders, one for each channel of the device will pop up on the screen and you can experiment with sending commands to the LED panel.
Or you can use the color picker if you want, the color picker updates on the fly so swiping your mouse across the color picker looks pretty sweet!
Here’s a little video I shot using the Sound2Light feature of Freestyler and also setting up a simple sequence it’s not too hard to setup and looks great. It’s pretty much just some music with the panel lighting up my ceiling and showing the interface running.
The Arduino code:
// This is just a simple DMX interface to the 16x16 LED Panel Matrix
// I incorporate the Conceptinetics DMX Library to handle the DMX stuff
// And modified some of my existing code for the LED panel
// I really suggest placing some current limiting resistors between the Arduino
// and the LED panel input lines, something around 160 ohms to 180 ohms should be fine.
// Especially consider this if your VLED and VCC on the LED panel use the same PSU!
// Include the Conceptinetics DMX Library
// How many channels is our DMX slave?
#define SLAVE_CHANNELS 5
DMX_Slave dmx_slave ( SLAVE_CHANNELS );
// Define each channel
#define RED_CHANNEL 3
#define GREEN_CHANNEL 2
#define BLUE_CHANNEL 1
#define STROBE_CHANNEL 4
#define INTENSITY_CHANNEL 5
// Setup the LED Display
// Pin Setup Upper Half
int datar1 = 2; // Data Pin for Red Serial Data
int datag1 = 3; // Data Pin for Green Serial Data
int datab1 = 4; // Data Pin for Blue Serial Data
// Pin Setup Lower Half
int datar2 = 5; // Data Pin for Red Serial Data
int datag2 = 6; // Data Pin for Green Serial Data
int datab2 = 7; // Data Pin for Blue Serial Data
int clock = 8; // Clock pin
int le = 12 ; // Latch Enable Pin
// Output Enable pins use on PWM pins for PWM dimming
int oer = 9; // Red
int oeg = 10; // Green
int oeb = 11; // Blue
// Set Default Brightness
int rbright = 255; // Brightness if using PWM (255 = off, 128 = half, 0 = full)
int bbright = 255; // Brightness if using PWM (255 = off, 128 = half, 0 = full)
int gbright = 255; // Brightness if using PWM (255 = off, 128 = half, 0 = full)
int num_pixels = 256; // Number of pixels (256 = 1 panel)
// Variables to store DMX R, G and B Channel values
int DMXr = 250; // DMX Red Value
int DMXg = 250; // DMX Green Value
int DMXb = 250; // DMX Blue Value
int DMXintensity = 0; // Diming from DMX
int DMXstrobe = 0; // Strobe value from DMX
// Places to store old values
int old_red = 0;
int old_green = 0;
int old_blue = 0;
// Strobe variables
int flag = 0; // flag for strobe
unsigned long timer = 0; // timer for strobe
// Setup the DMX
// Enable DMX slave interface and start recording
// DMX data
// Set start address to 1, this is also the default setting
// You can change this address at any time during the program
// Setup the LED Panel
// Set all the pins we're using as outputs
// Set clock and latch enable(le) low to start with
// In order to fiddle with the pixels colors we actually need to turn
// the pixels on first. This command takes care of that.
// Read in the values from the DMX Master
DMXintensity = dmx_slave.getChannelValue ( INTENSITY_CHANNEL );
DMXstrobe = dmx_slave.getChannelValue ( STROBE_CHANNEL );
DMXr = dmx_slave.getChannelValue ( RED_CHANNEL );
DMXg = dmx_slave.getChannelValue ( GREEN_CHANNEL );
DMXb = dmx_slave.getChannelValue ( BLUE_CHANNEL );
if(DMXstrobe) // If the strobe channel value is greater than 0 we're in strobe mode
else // Otherwise we just do a standard update
// If the current milliseconds run time is equal or greater to the
// previously recorded value, we toggle the strobe
if(millis() - timer >= DMXstrobe)
if(flag == 0) // Strobe flag is 0 so we turn off all the lights.
// Set all panels PWM to 255 (inverse of 0, since the input is inverted on the LED driver chips)
flag = 1;
else // The strobe flag is 1, so we return the lights to their previous setting
update(); // Run the normal update routine to set the lights to the current values
flag = 0;
timer = millis(); // Set the current program run timer as now
// Update takes the values from for RGB and Intensity received from the
// DMX controller and converts those to PWM values for the LED panel.
DMXintensity = map(DMXintensity, 0, 255, 255, 0);
DMXr = map(DMXr, 0, 255, 255, DMXintensity);
DMXg = map(DMXg, 0, 255, 255, DMXintensity);
DMXb = map(DMXb, 0, 255, 255, DMXintensity);
// Wipes the display with the selected color
// example for white. It clocks in all of the pixels
// before latching the data.
void Color_Wipe(int r_value, int g_value, int b_value)
// Clock in all pixels with fixed color
// Pixels are not updated on the panel until data is latched below
for (int count = 0; count < num_pixels; count++)
// We're going to clock in a pixel with each loop, we need to clock the data into
// the Red, Green and Blue Data lines individually
// The clock line is currently low
// Upper Half
digitalWrite(datar1, r_value); // Color_Wipe(1,*,*) we write a 1, if Color_Wipe(0,*,*) we write a 0
digitalWrite(datag1, g_value); // Color_Wipe(*,1,*) we write a 1, if Color_Wipe(*,0,*) we write a 0
digitalWrite(datab1, b_value); // Color_Wipe(*,*,1) we write a 1, if Color_Wipe(*,*,0) we write a 0
// Lower Half
digitalWrite(datar2, r_value); // Color_Wipe(1,*,*) we write a 1, if Color_Wipe(0,*,*) we write a 0
digitalWrite(datag2, g_value); // Color_Wipe(*,1,*) we write a 1, if Color_Wipe(*,0,*) we write a 0
digitalWrite(datab2, b_value); // Color_Wipe(*,*,1) we write a 1, if Color_Wipe(*,*,0) we write a 0
// Now we raise the clock high to clock in the data above
// To finish clocking in the data, the chip datasheets says to bring the data lines low
// then set the clock low, so we'll bring the data lines low.....
// Upper Half
// Lower Half
// Complete the cycle by setting the clock low
// A bit has now been shifted into the 6 RGB channels, we're setting the pixels
// all to the same color, so this for loop will run (num_pixels) times beforef
// dropping down below
// with the (numpixels) clocked into the panel(s) we now need to latch the data
// into the LED driver registers. Simple task.
digitalWrite(le, HIGH); // Latch in 256 pixel data set