As you will doubtless recall, a lot of my current hobby projects -- like my Infinity Mirror, my Prognostication Engine, and my BADASS Display -- are based on NeoPixel rings and strips from Adafruit.com
In turn, Adafruit's NeoPixels are based on the WS2812 integrated light source from Worldsemi. This is an incredible little device that is only 5x5 mm square (and about 1 mm thick). Each WS2812 includes a tiny constant-current driver chip, along with three incredibly bright red, green, and blue (RGB) LEDs.
One area of potential confusion is that you sometimes hear people saying WS2811 or WS2812 when referring to these elements. In fact, WS2811 refers to the driver chip, while WS2812 refers to the larger package containing the WS2811 driver chip along with the RGB LEDs.
The great thing about these devices is that they can be daisy chained together, and the entire chain can be controlled using a single digital output pin on your microcontroller. Each WS2812 has four terminals: 5 V (power), 0 V (ground), data in, and data out. When you use your MCU to output a stream of data to the chain, each WS2811 accepts the first 24 bits it sees (eight bits for each RGB color channel) and then buffers and retransmits the remainder of the data stream to the next WS2811 in the chain.
Now, one of the things I really like about the NeoPixels from Adafruit is that they come equipped with an Arduino library and some really easy-to-use examples. You can literally be up and running within a couple of minutes. Let's use some simple pseudo-code examples. First, we instantiate a chain of NeoPixels:
NeoPixel myChain = NeoPixel(60, 6);
In this example, the first parameter (60) is the number of pixels we have in our chain. The second parameter (6) is the digital I/O pin we wish to use to drive the chain. If we wish to set the color values associated with one of the pixels in the chain, we might use a function call like the following:
In this case, the first parameter ('i') is an integer between 0 and 59 that specifies the pixel of interest. The second parameter ('c') is a 24-bit value comprising three eight-bit fields to define the RGB values to be associated with this pixel.
Of course, we could use loops and other control structures to specify the values of multiple pixels. The important thing to note here is that the "setPixelColor()" function doesn't actually modify the physical pixels. When we originally instantiated myChain, we created an array of 60x24-bit elements in the Arduino's memory. When we use the "setPixelColor()" function, all this does is change a value in the memory array. When we are ready to rock and roll, we use the "show()" function as follows:
One other thing I really like is the fact that Adafruit's NeoPixel library allows you to instantiate multiple chains. Suppose I decided to use eight chains, each containing 60 pixels. A pseudo-code version of this might be as follows:
NeoPixel myChain0 = NeoPixel(60, 6);
NeoPixel myChain1 = NeoPixel(60, 7);
NeoPixel myChain2 = NeoPixel(60, 8);
NeoPixel myChain3 = NeoPixel(60, 9);
NeoPixel myChain4 = NeoPixel(60, 10);
NeoPixel myChain5 = NeoPixel(60, 11);
NeoPixel myChain6 = NeoPixel(60, 12);
NeoPixel myChain7 = NeoPixel(60, 13);
Now, I love working with NeoPixels, but there are some downsides. For example, the timing requirements to upload data to a NeoPixel chain are so stringent that Adafruit implemented things using assembly code that runs only on 16MHz Arduino Unos and Megas, both of which are eight-bit machines.
Another small gotcha is that, when you call the "show()" function, it disables the Arduino's interrupts. The CPU is totally dedicated to outputting the data to the chain. Now, suppose we have instantiated multiple chains as shown above. Consider what happens if we do the following:
Though this might be advantageous for organizing, visualizing, and controlling a display, it doesn't confer any speed advantages. Each chain is processed one after the other. Apart from anything else, this might result in some unwanted visual artifacts if we are driving long pixel chains.
To Page 2 >