热度 22
2014-5-29 18:52
1902 次阅读|
0 个评论
As you will doubtlessly notice, a lot of my current hobby projects --such as my Infinity Mirror 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: myChain.setPixelColor(i, c); 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: myChain.show(); 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: myChain0.show(); myChain1.show(); myChain2.show(); : 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. All of which leads me to some interesting information I discovered while chatting with Paul Stoffregen, one of the founders and owners of PJRC.com . One of PJRC's products is the Teensy 3.1 Arduino-compatible development board, which is an incredible bargain at only $19.80 fully assembled (wow). The Teensy 3.1 is based on a Kinetis MCU chip from Freescale. The Kinetis boasts a 32-bit ARM Cortex-M4 processor core running at 72 MHz. The core in the Teensy features 256 KB of Flash and 64 KB of SRAM. Of particular interest to us here is the fact that the Kinetis also has an eight-bit dynamic memory access (DMA) capability. This leads us to PJRC's OctoWS2811 display library , which works with Adafruit's NeoPixels and all other WS2811/2812-based addressable LEDs. Using the Kinetis DMA capability, the OctoWS2811 can drive eight chains in parallel, which means it can update everything eight times faster. Minimal CPU impact and double buffering allows for complex animations that cannot be achieved using traditional Arduino-compatible platforms and libraries. Consider this video , which features 2,000 LEDs controlled by two Teensy controllers. Did you notice my saying "minimal CPU impact?" This is actually really exciting. When you use the OctoWS2811 library to upload the data to your LED chains, the CPU hands control of this task over to the DMA engine without disabling any of the interrupts or anything like that. This leaves the CPU free to perform other tasks (like the FFT for my BADASS Display ). Below we see videos of a few projects that have used the combination of Teensy boards and the OctoWS2811 library to drive thousands of LEDs to great effect. From top to bottom, these are the Wall of Light , the Penrose Triangle , the Skyline LED Wall Booth , and the CrashSpace Light Show . Well, what can I say? I am very, very impressed. This certainly looks like a strong contender to drive a future incarnation of my BADASS Display. Also, Paul has been telling me about an amazing audio library he's been working on, but we will leave that for a future column. In the meantime, what do you think of the Teensy 3.1 and the OctoWS2811 library?