Building a mini RGB LED video wall using a Netduino and an Adafruit LPD8806 LED strip
What's not to like about RGB LEDs? With their bright, mesmerizing glow, often capable of displaying millions of colors, they're a great to way to catch the attention of the viewer. Now, what if you had a 5 meter long RGB LED strip, loaded with 160 RGB LEDs to play with? Oh, the possibilities... It so happens that Adafruit, in their infinite wisdom, carries a very nice RGB LED strip, powered by a LPD8806 driver and encased in a waterproof sleeve.

What about turning it into a mini video wall for instance? Think 'Times Square', just smaller :)
Building a 16x10 video display from an RGB LED strip
Having a 160 LEDs, the strip can easily be converted into a 16x10 display: every 16 pixels, the strip overlaps 2 segments and binds them together with solder. It's easy enough to separate the 10 segments with a soldering iron and some patience. Limor covers the casing removal procedure and desoldering method in details here http://www.ladyada.net/products/digitalrgbledstrip/index.html#how_to_separate_longer_strips_advanced so, we'll not re-iterate it.
The method used to create the display was hot-glueing each 16 pixel segment to a hollow plastic board purchased from a local craft store like this:
Each segment was then reconnected to the next one using solid core wire, making sure that the SPI bus lines were properly matched.

The serpentine configuration of the display presents a challenge from a 'memory layout' management point of view but this aspect will be discussed in details later. For the time being, let's just say that managing the strip as a display is a ...hmmm... twisted proposition.
The controller for the RGB LED strip is built around a Netduino mini, coupled with a XBee transceiver so that graphics, text and commands to be sent to the display remotely for fun applications such as Twitter integration, displaying computer performance counters, sensor data, ads, etc.
The LED display and the Netduino Mini, mounted on the back of the display, are both powered using a recycled PC power supply. In terms of power usage the display, while running the demo shown in the YouTube video, consumes between ~10 to ~28 Watts, which is not bad at all. If you don't have a PC power supply handy, which in this instance can deliver ~250 Watts, you will need to find a power suply that can deliver at least 10 Amps @ 5 volts to handle a display at full brightness.
Based on the specifications of the RGB LED strip, we have:
- 20 mA / LED
- 60 mA / RGB LED (3 LEDs * 20 mA)
- 60 mA * 160 RGB LEDs = 9600 mA total for the display with all RGB LEDs at full brightness, which amounts to 9.6 Amps
To determine the required Wattage, apply this formula: W = V x A, which gives us 5v * 9.6 Amps = 48 Watts
As always, it's wise to consider a 20% to 30% buffer above the maximum power requirements to ensure that the system remains as stable as possible.
Finally, because the LEDs are so bright, it was necessary to diffuse the light: using 1" stand-offs, a foam-core board with its center cut out in the shape of a rectangle was placed above the LED segments. A thick plastic sheet was then hotglued to the back of the foam core board before mounting the asembly on the stand-offs. In the end, the setup formed a large, sturdy frame, perfect for testing the Netduino driver code.
The Netduino Driver
The Netduino driver, AdaFruitLPD8806.cs, is part of the Netduino Helpers library located here (http://netduinohelpers.codeplex.com) with the demo sample showcasing the driver being located under \Samples\AdaFruitLPD8806Test. The LED strip is addressable over SPI and in this build, the display is capable of accepting SPI data clocked @ 16 MHz reliably. Above that speed, bits tended to get randomly lost along the way, which is not to say that higher speeds cannot be achieved with proper care. Because multiple strips can be chained together, it is necessary to take propagation delays along the strips into consideration, which is not something that the driver does currently since this scenario could not be tested. To maximize efficiency of SPI communication with the display, the driver manages an internal pixel buffer and only refreshes the display a full frame at a time. Each pixel takes 3 bytes, one byte per red, green and blue component of a color. Note that the strip expects a color to be defined as a GRB tuple instead of a RGB tuple. Each RGB color component can range from 0 to 127, allowing for 2048383 possible colors per RGB LED. The reason for this is that the LPD8806 LED controller uses bit 8 (MSB) as a parity bit for SPI communication with the LPD8806 controllers on the strip and therefore, cannot be used to express color information.
Supported driver functions
The driver is designed to abstract the fact that every other line of the display must be addressed in reverse due to the 'serpentine' configuration of the display segments (see the Copy functions if you really need to know how it works). While more complex from a software point of view, this configuration ensures the shortest possible connections between display segments, minimizing potential SPI issues due to EMI, RF interferences, inductance and resistance as wire-length increases.
- AdaFruitLPD8806(int width, int height, Cpu.Pin chipSelect, SPI.SPI_module spiModule = SPI.SPI_module.SPI1, uint speedKHz = 10000): defines the dimensions of the LED strip expressed in terms of width and height. In the case of a single strip with 160 RGB LEDs, this means 16 columns x 10 lines. If multiple strips are chained together, the overall dimension of the display needs to be provided accordingly.
- void Reset(): Sets the background color to black across the strip
- void SetColor(byte red, byte green, byte blue): Sets the color of the entire strip
- void Refresh(int delayMS = 0): Sends the internal pixel buffer to the strip and optionally waits for a specifies amount of time in milliseconds before returning
- UInt32 RgbToColor(byte red, byte green, byte blue): Generates a 32 bit value from RGB values. RGB values must be between 0 and 127 (2,048,383 colors 'only')
- void SetPixel(int pixelIndex, byte red, byte green, byte blue): Sets a pixel at given index with an RGB value.
- void SetPixel(int pixelIndex, UInt32 color): Sets a pixel at given index with a color value. The color parameter needs to come from RgbToColor()
- void SetPixel(int x, int y, UInt32 color): Set a pixel at a given coordinate with a color value. The color parameter needs to come from RgbToColor()
- void SetBackgroundColor(byte red, byte green, byte blue): Sets the default background color. Internally used by Reset, SetColor, Scroll and Shift.
- void Shift(ScrollDirection direction, ScrollingType scrollingType): Shift the entire strip as a single line, either left or right, circularly or not, one pixel at a time
- void Scroll(ScrollDirection direction, ScrollingType scrollingType, int pixelCount): Scroll the entire frame by x pixels either left or right, circularly or not, one pixel at a time
- void Gradient(int startRed, int startGreen, int startBlue, int endRed, int endGreen, int endBlue, int pixelIndexStart, int pixelIndexEnd): Generates a gradient between two colors and between two pixels indices
- void FadeIn(byte[] bitmap, int sourceBufferOffset = 0, byte Speed = 1): Fade a bitmap into view using the bitmap currently loaded in the LED strip buffer as the point of reference
- void Copy(byte[] bitmap, int sourceBufferOffset = 0): Copies a source bitmap to the LED strip buffer. Source and destinations must be the same size.
- void Copy(byte[] bitmap, int x, int y, int width, int height, int bitmapWidth, int bitmapHeight): Copies a source bitmap at the given x,y coordinates into the LED strip buffer. Does not yet handle the case where the source bitmap is smaller than the target frame size.
- void DrawRectangle(int x, int y, int width, int height, UInt32 color): Draws a rectangle of a given color at the given coordinates
- byte[] BuildMarquee(string text, CharSet charSet, byte redBackground, byte greenBackground, byte blueBackground, byte redText, byte greenText, byte blueText): Takes a string of text, a character set, background and text colors and returns a bitmap intended to be scrolled across the display. Casing (upper) matters with the default CharSet used in the demo. The longer the text string, the more memory will be used to create the bitmap. The code expects 8x8 character sets.
- void Dispose(): Releases all resources used by the driver
About the Copy() functions: they expect bitmaps to be encoded in GRB format, with the 8th MSB bit set to 1, as natively understood by the strip to minimize runtime computations. To this end, 24 bit bitmaps in .BMP format can be easily batch-converted using the 'VideoBmpStrip' tool located under the \Tools folder in the netduino helpers repository.
Conclusion
Turning an Adafruit LPD8806 RGB LED strip into an actual display was a fun software challenge due to the whacky memory layout of the strips. Fortunately, the LPD8806 Netduino driver makes it really easy for a maker to build a display as a weekend project now. The applications for such an RGB display are quite varied, ranging from Twitter feed viewers, stock tickers, graphic ad streamers and can even handle simple video animation playback. It's a compelling, cost effective alternative to the typical commercial LED text-scrolling or static signs that are so pervasive these days. So, go ahead and mesmerize your audience with your own mini-video wall: no matter what your message says, it will get the viewer's attention.
Pingbacks
Hackaday: http://hackaday.com/2011/11/18/video-display-from-rgb-strips-makes-it-seem-so-easy/
15 Comments
Carl said
Very nice display and write up.
I am currently building something very similar, using my own board instead of LED strip. I've been having fun writing a frame buffer and code to update the led panels via SPI which are arranged the same way as yours ( like a snake ).
Mark said
Slick -- and clever! I love the idea of turning the strip's linear LEDs into an array like that. What would you say the total parts cost was for this gem?
Oliver Sumpton said
Dude! This is fantastic!!
By any chance have you tried sending raw pixel data over Serial xBee to your Netduino mini from something like a Processing sketch??
If this is even possible, what kinda framerate do you think you could get?
p.s. huge props :D
Patrick Schles said
Very cool. I've done something similar with the HL1606-based strips, and added some interactivity. Feel free to check out my code on github.
http://www.plainlystated.com/2011/10/snake-attack/
fabien said
@Carl: Cool! Share the results when you're done :)
@Mark: a 5 meter LED strip from Adafruit like the one I used will run you $175. A Netduino mini is about $30. A 1mW XBee module series 1 is about $20. The recycled power supply was free in this build but you can buy one online for $20 or less. The rest of the materials that I used for the frame added up to another $10 for a grand total of $235, which is not bad at all for a sign this size.
@Oliver: Not yet but this is something that I will soon implement. I'll share my results here when I do. It's totally possible to achieve, and with proper caching, the frame rate will be identical or close to what you saw in the video. Thanks for the props :)
@Patrick: Nice snake game :) Thanks for sharing!
Andreas W said
Extremely cool - so am I right in thinking that the code you did for the netduino can in no way be ported to a plain ol' arduino UNO? Because of the .net gubbins?
Fabien, please do keep us posted on the raw pixel work!
This is more or less what we're hoping to achieve; serial data representing each frame sent directly to an ar/net-duino, fed onwards to the LEDs.
fabien said
@Andreas: Thanks :) There's no reason why you could not port this code to an Arduino. You will only need to adapt it to take into account the reduced RAM available on the Arduino.
ethan7557 said
Pretty cool, Ive been thinking of doing something similar for a while. BTW, can you buy the LPD8806 RGB flex strips from http://www.bestlightingbuy.com/waterproof-lpd8806-flexible-rgb-led-lighting-strip.html , as they are 119 bucks, cheaper than at Adafruit.
andrewh said
I'm installing some Arduino controlled LPD8806 led strips (http://www.ledlightinghut.com/lpd8806-digital-led-strip.html ) around my hot tub area for some fun effect lighting and need to have Indigo control them. All is fine on the Arduino end
just need to send it simple integers to trigger the effects.
Sylvain Beaudoin said
Are there led strips available that have a closer pitch than these? How many LEDs can this control? I was thinking of making a panel to replace the tail light panel on my car. I was hoping to be able to include turn signal, brake functionality as well as displaying a plate (tag) image and animation/video. Is this way beyond what this controller can handle?
fabien said
Hi Sylvain. No idea about the closer pitch. You'll need to research that ;-) The number of LEDs you can control is a function of the amount of power you feed the strip (i.e. multiple points where power gets fed). As far as the limits: you will need to experiment with your specific design but I have seen very large art displays built with these.
Cheers,
-Fabien.
Tom porter said
I thought I'd better chime in on this as I recently read the post by "cranium" and took the chance myself based on that post. I ordered 15 meters of the same 5V RGB LED strip that you can find on Adafruit.com and got them for something like $13 per meter. I was a little concerned about the process since I'd never ordered from China before or used Western Union but it all went smoothly. Just tested them a minute ago and they work perfectly. This is not an add. Just wanted to say thanks and give others a little confidence in buying from the same place. Yay! Thanks.
Here's where they have them listed: http://gree-leds.com/productshow.asp?ArticleID=TS7X2X7VTP
fabien said
Hi Tom,
Thanks for sharing a reliable source for these LED strips. It's nice to have options ;)
Cheers,
-Fabien.
Julien said
Hello!
Nice setup there!
I would be interested into doing the same thing; i started searching this afternoon (i'm new to all arduino/netuino stuff).
Is there anywhere where the code used for that exemple can be downloaded?
Does the strips have to be rows or columns to work?
Any limitation on number of leds to drive?
Thanks!
fabien said
Salut Julien,
Please read the section of the article "The Netduino Driver" which provides a link to the code repository.
You can arrange the strip in any physical layout you like but you'll need to change the way the driver manages your specific layout accordingly.
The limit on the number of LEDs largely depends on the amount of stable power you can provide and how you provide it along the strip. Also, there are limits to the SPI frequency at which you can address the strip, which affects frame rate and therefore affects the overall number of LEDs you can have in the display if you show animations.
You'll need to experiment ;-)
Cheers,
-Fabien.