(The library is on Github here. Look at program.cs – it has a few example animations that I cooked up. )
I picked up a Netduino and a couple of the Adafruit RGB LED strips – 1 meter of the non-addressable kind, and 1 meter of the addressable kind.
Ironically, the non-addressable one is harder to use, because you need some outboard transistors to source enough current to drive all the LEDs (which are connected in parallel), and you have to write code to set up the PWM to dim the red/green/blue channels separately (so you get the color you want).
The Adafruit site has a bit of code to set up the netduino to drive the LPD8806, which I used as a starting point:
using Microsoft.SPOT.Hardware; ... public static void LightStripSpi() { var spi = new SPI(new SPI.Configuration(Cpu.Pin.GPIO_NONE, false, 0, 0, false, true, 10000, SPI.SPI_module.SPI1)); var colors = new byte[3 * 32]; var zeros = new byte[3 * ((32 + 63) / 64)]; while (true) { // all pixels off for (int i = 0; i < colors.Length; ++i) colors[i] = (byte)(0x80 | 0); // a progressive yellow/red blend for (byte i = 0; i < 32; ++i) { colors[i * 3 + 1] = 0x80 | 32; colors[i * 3 + 0] = (byte)(0x80 | (32 - i)); spi.Write(colors); spi.Write(zeros); Thread.Sleep(1000 / 32); // march at 32 pixels per second } } }
Not really the prettiest code around, but it works and worked as a starting point. Before I get into the details of the library I built, a few details on the LPD8806 strips.
The Support Library
I wrote a library to make it easier to use the strip. It has a Raw mode for those who want speed (though it’s not very fast), and animation support for those who want to do more complex things.
Raw mode
If you are interested in the most speed possible with this library, you should use raw mode. Here’s a sample:
RGBStrip strip = new RGBStrip(32); strip.ClearAllRaw(); // turn off all leds strip.SetLedColorsRaw(0, 35, 0, 0); // first led to dim red strip.WriteToStripRaw(); // update the strip
In a real use, you would create a loop that sets the leds the way you want them and then updates the strip.
If we use this code and do some timings, we’ll find that the following approximate costs:
SetLedColorsRaw() 0.00031 seconds
WriteToStripRaw() 0.00063 seconds
Code that set all 32 leds and then wrote out the values took about 0.0136, which translates to about 73 updates/second. You would obviously need some code to figure out what to set the led values to, and that will slow things down. If you wanted to do 5 meters of strip (160 LEDs), that would take you down to 20 updates/second, which really isn’t that fast. It’s slow not because we’re trying to do a lot, but because the IL that the C# compiler generates is being interpreted on the netduino, and that (plus the other things the managed runtime has to do) add a lot of overhead.
Dimming
After a few hours of working on the library, I got tired of spots before my eyes whenever I was running the animations; those LEDs are bright.
So, I added the DimFactor property to the RGBStrip class. This provides a brightness pre-scalaing for all of the color values; the colors are the same as before, only dimmer (this is only roughly true, but it’s true enough in most cases). The DimFactor setting maps to brightness as follows:
DimFactor | Brightness |
0 | 100% |
1 | 50% |
2 | 25% |
3 | 13% |
4 | 6% |
The DimFactor defaults to 1 (50%)
I also hooked up the on-board pushbutton on the Netduino to cycle through the dim factors. That means you can do most of your testing at an eye-saving brightness, and then toggle it to full brightness when you want to test the final product.
To use DimMode, just call SetLedColorsRawWithDim() instead of SetLedColorsRaw(). I’ve kept both methods because the dimming adds one extra operation and slows things down slightly.
Animation Mode
Raw mode is fast for simple animations, but if you are doing complex ones, you’ll be writing a lot of code yourself. The library provides support for more sophisticated effects, where it will handle doing a smooth fade from one color value to another.
Here’s an example:
RGBStrip strip = new RGBStrip(32); strip.ClearAll(); Animator animator = new Animator(strip); Animation item = new Animation(0, 127, 127, 0, 0, 30); Animation item2 = new Animation(0, 0, 0, 127, 30, 30); animator.AddAnimation(item); animator.AddAnimation(item2); animator.DoAnimation(2);
Each animation is described by an Animation instance, which specifies the following:
- The led to animate (0 through num-1)
- The red, green, and blue values that are the endpoint of the animation.
- The number of cycles to wait before starting the animation.
- The number of cycles that the animation will take.
In this case, we add one animation to take the first pixel to full yellow, and then one that will start when that first one is done to take the pixel to full blue. The call to DoAnimation will run the animations until they are finished (which will take 60 cycles), and it will wait 2 milliseconds after each loop.
This is very convenient to use, but will be considerably slower than raw mode because of all the extra calculations required.
Handling the animation loop yourself
Using the start count to delay animations works well if you don’t mind setting up a whole group of animations at once, but it may be more convenient to just add animations along the way. If so, you can call DoAnimationCycle(), which does one cycle. If you take this approach, you will have to handled deciding when the cycle is complete yourself.
So, what do you think ?