Main Site Documentation

RLP needed for bit banging RGB LED strip?


#1

Got a sweet 32 light strip of 3 color LEDs from Sparkfun http://www.sparkfun.com/products/10312 . A sample sketch was provided for an arduino, which ran with (literally) a blindingly fast refresh rate (duino pro, 5v, 16mhtz). I ported the code to NETMF, ran it on a Domino, and discovered the refresh rate of the strip slowed down considerably. This is some straight up bit banging, and I’m wondering if it is better done in RLP?


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace RgbStrip
{
    public class Program
    {
        const int LEN = 32;         // 32 LEDs on this strip.
        const bool HIGH = true;     // I like using HIGH/LOW 
        const bool LOW = false;     // for bit bangin' like this.
        
        static long[] strip;        // strip color data array
        static OutputPort sdi;      // digital pin 2
        static OutputPort cki;      // digital pin 3

        public static void Main()
        {
            strip_colors = new long[LEN];
            sdi = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di2, LOW);
            cki = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di3, LOW);

            // spit out some bytes
            loop();

        }

        // Push out increasingly bright primary colors
        private static void loop()
        {
            /////////////////////////////////////////////////
            // Saturation must be byte sized, 0-255.
            // Outside this range,  strange things happen...
            /////////////////////////////////////////////////

            int lHue = 120;     // low sat value
            int hHue = 160;     // high sat value
            while(true)
            {
                for (int i = lHue; i < hHue; i++)
                    addColor(i, 0, 0);
                for (int i = lHue; i < hHue; i++)
                    addColor(0, i, 0);
                for (int i = lHue; i < hHue; i++)
                    addColor(0, 0, i);
                
            }
        }

        // Add one color to the strip
        private static void addColor (int R, int G, int B) 
        { 
            // shift all existing colors 
            for (int x = (LEN - 1); x > 0; x--)
                strip[x] = strip[x - 1];

            ////////////////////////////
            // create a new RGB color
            ////////////////////////////

            long new_color = R;   // red
            new_color <<= 8;      // byte shift
            new_color |= G;       // green
            new_color <<= 8;      // shift again
            new_color |= B;       // blue
            strip[0] = new_color; // add to strip
            postFrame();         // push data
        }


        // Pushes out current strip color array.
        // Each LED requires 24 bits of data.
        // Once the bits have been delivered, 
        // the IC immediately relays these bits to its neighbor.
        // Pulling the clock low for 500us or more causes the 
        // IC to post the data.

        private static void postFrame () 
        {
            for(int i=0;i<LEN;i++) 
            {
                for(byte bit = 23 ; bit != 255 ; bit--) 
                {
                    cki.Write(LOW);             // only change data when clock is low
                    long mask = 1 << bit;
                    if ((strip[i] & mask) > 0) 
                        sdi.Write(HIGH);
                    else
                        sdi.Write(LOW);
                    cki.Write(HIGH);            // data is latched when clock goes high
                }
            }
            cki.Write(LOW);                     // pull clock low to put strip into reset/post mode
            //Thread.Sleep(1);                  // required delay. Note, this was not needed here (slow enough already).
        }
    }
}



#2

I think this code is well optimized. But you can do more analysis by breaking down the code and see where exactly most of the time is being spent. You can use time stamping for that. But your application is perfect example where you can utilize RLP to speed up routines.


#3

You should have sequences programmed in RLP using “kernel mode tasks” then then you can activate a sequence form C#. Not only it will be very fast, it will be non-blocking so the LED will go through the sequence while your program is doing anything else!


#4

It would be interesting to test performance at a function level on both boards, as they are mirrored. Thanks for the feedback. Once I get the blinky-ness perfected on a FEZ, I’ll post a video.

Do you guys ever get a weekend (entirely) off? :wink:


#5

That looks like SPI protocol…

It will be WAY faster if you use the SPI port. I think it was bitbanged on the arduno because it doesn’t have an SPI port?

For your wiring you only need MOSI(data) and SCK(clock). You can ignore the rest, i think…

Then change the PostFrame to use the SPI hardware…

It might be even faster to assemble all the data in a 96 byte array and then post the whole block over SPI in one go…


#6

It is SPI and it works great! Ask Travis (aka TheRobotGeek)

http://www.tinyclr.com/forum/1/2980/


#7

I asked him for a peek at his code in that thread, but no joy…

I am refactoring this to use SPI. My fish tank will soon be getting a lighting upgrade 8)


#8

Ooops. Missed your reply :-[
Make sure to post a video after you are done ;D


#9

SPI really makes this thing rock. The refresh rate is so fast I had to slow it down to prevent seizures :o

Code (with video) posted. http://code.tinyclr.com/project/320/sparkfun-32-rgb-led-strip-wic/


#10

Thanks! Very cool!


#11

The LED fun…never ends :slight_smile: