SPI Bits and channels

This is on a FEZ Panda II

I am trying to do a simple test controlling this RGB LED strip octobrite [macetech documentation]

I think I understand the SPI sort of


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace Octo1
{    
    public class Program
    {
        public static void Main()
        { 
             SPI.Configuration conf = new SPI.Configuration((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di13,false, 0, 0, false, false, 4000,SPI.SPI_module.SPI1);
             SPI SPI_port = new SPI(conf);
             OutputPort BL = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di10, false );
             OutputPort XL = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di9, false);
         
             byte[] tx_data = new byte[4095];
         
             XL.Write(true);
             SPI_port.Write(tx_data);
             Thread.Sleep(1000);
        }
    }
}

All I want to do is turn on all 8 LEDs with the same color then shut them off I know the

“byte[] tx_data = new byte[4095];”

line is incorrect. The input requires 12 Bits by 24 Channels I am not to sure how to load that? Can it even be done this way?

SPI is probably the best method. You could use an array of 18 words

or just the write method, but I dont know if the write method writes the complete array. I cannot see the clock in your construtor. Try filling the array with 1023 to start.

EDIT: Sorry 1023 should be 62463 or hex 0xF3FF I wasnt thinking 12 bits! The MSB bits 0xF is part of the next 12 bit word. The next 16 bit word will be 0xFF3F… I guess you get the picture for the rest.

OK so now I have this but it still seems wrong some how

but all the LEDs light up and blink that’s something I guess


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace octobright
{
    public class Program
    {
        public static void Main()       
            {
                SPI.Configuration MyConfig =
                     new SPI.Configuration(Cpu.Pin.GPIO_Pin1,
                     false, 0, 0, false, true, 100, SPI.SPI_module.SPI1);
                SPI MySPI = new SPI(MyConfig);
                OutputPort BL = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di10, false);
                OutputPort XL = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di9, false);


                ushort[] ar1 = new ushort[24] {4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,4095,
                    4095,4095,4095,4095,4095,4095};
               // byte[] b1 = new byte[2045];

                while (true)
                {
                    BL.Write(false);                  
                    MySPI.Write(ar1);
                    XL.Write(true);            
                    Thread.Sleep(1000);
                    BL.Write(true);
                    Thread.Sleep(1000);
             

                }          
            }
        }
    }

You only need an array of 18 words, 18 * 16 = 288. I would also try the numbers in my last post, unless you are sure that you can supply enough current to have all leds running at max. You say something is wrong please explain.

OH man I am stupid thanks that got it

swestcott,

I’ve re-written the Arduino software from the document from your first post, to run on Panda II. Would you be intrested in testing it? As far as I can see it works but I dont have an OctoBrite to test. Its bit banging not SPI.

Thank you yes I will test it and post a video as well

@ swestcott, PM me here david_adotfletcheratskydotcom. I cant send for a while as its my bed time.

can anybody see a way of speeding this program up my NETMF skills are not that good.

//Re-written for Panda II taken from http://docs.macetech.com/doku.php/octobrite

using System;
using Microsoft.SPOT;

using OctoBrite;


namespace FEZ_Panda_II_Application_OctoBrite
{ 
    public class Program
    {
        public static void Main()
        {

           Debug.EnableGCMessages(false); 
           // Variables for sample function
           float offset = 0.0f;

           var octoBrite = new TLC5947();

           while (true)
           {
               
               // Scan across whole array with fading, in red, green, and blue
               for (offset = 0.0f; offset < 360; offset += 0.5f)
               {
                   octoBrite.LEDscan(4095, 0, 0, offset);
                   //Thread.Sleep(2);
               }

               for (offset = 0.0f; offset < 360; offset += 0.5f)
               {
                   octoBrite.LEDscan(0, 4095, 0, offset);
                   //Thread.Sleep(2);
               }

               for (offset = 0.0f; offset < 360; offset += 0.5f)
               {
                   octoBrite.LEDscan(0, 0, 4095, offset);
                   //Thread.Sleep(2);
               }

           }   
       }       
    }
}


//Re-written for Panda II taken from http://docs.macetech.com/doku.php/octobrite

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.System;
using GHIElectronics.NETMF.FEZ;

namespace OctoBrite
{
    public class TLC5947
    {

        // Number of OctoBrites / TLC5947 devices
        public byte NumOctoBrites = 1;

        // Jagged Array storing color values
        //  BLUE: LEDChannels[x][0]   Range: {0 to 4095}
        // GREEN: LEDChannels[x][1]   Range: {0 to 4095}
        //   RED: LEDChannels[x][2]   Range: {0 to 4095}
        public ushort[][] LEDChannels = new ushort[8][] { new ushort[3] {0,0,0}, new ushort[3] {0,0,0}, new ushort[3] {0,0,0}, new ushort[3] {0,0,0}, 
                                                          new ushort[3] {0,0,0}, new ushort[3] {0,0,0}, new ushort[3] {0,0,0}, new ushort[3] {0,0,0}};

        OutputPort enablepin = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di10, false);//BL
        OutputPort latchpin = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di9, false);//XL
        OutputPort clockpin = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di13, false);//CL
        OutputPort datapin = new OutputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.Di11, false);//SI 

        // Sample function to draw a scanning pattern with fading
        public void LEDscan(int red, int green, int blue, float degreeoffset)
        {

            float brightnessfactor = 0.0f;

            float scanindex = (float)(1 + MathEx.Sin((double)(degreeoffset * 3.14159f / 180))) * ((float)(NumOctoBrites * 8 ) / 2);

            for (int LEDindex = 0; LEDindex < (NumOctoBrites * 8); LEDindex++)
            {

                brightnessfactor = (float)MathEx.Exp((double)(0 - Fabs(scanindex - ((float)LEDindex + 0.5f)) * 1.3f));

                LEDChannels[LEDindex][0] = (ushort)(blue * brightnessfactor);
                LEDChannels[LEDindex][1] = (ushort)(green * brightnessfactor);
                LEDChannels[LEDindex][2] = (ushort)(red * brightnessfactor);
            }

            WriteLEDArray();
        }

        //Bit banging method
        public void WriteLEDArray()
        {
            ushort tempOne = 0;
            
            //This method is used to get around the pointers used in the original Arduino code.
            //The first two loops combine to give us the 24 channels assuming 1(NumOctoBrites * 8 * 3 = 24)
            //The 3rd loop reads the bits and writes them out to the SI pin.
            for (int i = 0; i < (NumOctoBrites * 8); i++)//Led channels 0-7
                {
                    for (int h = 0; h < 3; h++)//Colours 0-2 Red, Green, Blue
                    {
                        tempOne = LEDChannels[i][h];//Colour brightness value 

                        for (int j = 0; j < 12; j++)//12 bits 0-11
                        {
                            int bit = ((tempOne >> (11 - j)) & 1);//Bit = right shift. One bit at a time. For 12 bits * 24 = 288
                            if (bit == 1)
                            {
                                datapin.Write(true);//Its a 1
                            }
                            else
                            {
                                datapin.Write(false);//Its a 0
                            }
                            clockpin.Write(true);//Clock in the bit
                            clockpin.Write(false);
             
                        }

                    }
                }

                latchpin.Write(true);//Latch all 288 bits
                latchpin.Write(false);
        }

        /// <summary>
        /// Returns the absolute value (Renamed Fabs)
        /// </summary>
        /// <param name="x">A number</param>
        /// <returns>absolute value of x</returns>
            public float Fabs(float x)
        {
            if (x >= 0.0F) return x;
            return (-x);
        }

    }
}

Thanks

Try moving all of your function variables outside of the function and make them private static variables for the class. It looks like everything happens fairly sequentially so I think just about all of them can be moved out. This will eliminate all of your GC.

@ ianlee74,

Thanks for the insight. I’ve done that now, but I didnt see the GC running even before I turned it off. I still dont know if its working correctly, i can see non-stop data on the SI pin, but dont have an OctoBrite to test. I was thinking about writting the SPI code for 12 bits. I checked the LPC2387 manual, and its not that compicated to get it running in RLP. I then thought that it wont help a lot, because writting the data out is not the bottleneck at the moment, well i dont think it is, its the loops in main. I know it was originaly written for the Arduino, and the LPC2387 is at least 4 times faster than a 16Mhz Arduino, but I dont know what the tokenised C# and NETMF overhead is, that was why I asked the question if the program could be run faster.

The code appears fairly lean. You say you haven’t tested it yet. Do you know that there is a performance problem? If you really want to squeeze some more out of it you could move some of your math off into RLP. I’d start with the scanindex & brightness factor algorithms. If you need more still, you could move the entire LedScan function. Of course, rule #1 in performance testing is measuring. If we don’t know where you start then we won’t know what helps or hurts.

@ ianlee74,

Well your not wrong about measuring, so i’ve check one iteration of a single loop in main and found that it took ~69mS but the shock to me was WriteLEDArray, it took ~65 of those mS, so now i’ve got my head down writting an RLP proc for a 12bit SPI transfer!

I’m actually not too surprised by that since all of your SPI communications happens in that loop. I’m not sure how much RLP is going to help here but I’m eager to see your results. One thing you might try is to flatten out and eliminate some of the loops. More code but you might see better performance. Good luck!

@ ianlee74,

The program above uses bit banging for the data as SPI on NETMF only has 8 or 16 bit data transfer, and is very fast. The octobrite needs 12 bits of data. Well first results using SPI @ 12 bits from RLP look promising, if its working (dam I need my scope) using the same timing loop its down to ~8mS. I can see data flicking by using a led connected to MOSI, and a brighter led looking at SCLK, so i’m very hopeful! The only thing i’m not sure about is setting up the SCLK freq, I think i’ve set to 1.25MHz. RLP is difficult, and long winded to debug. The last time i used RLP, i sent back the variables i was intrested in via generalArray, but its a lot of work setting it all up.

Sounds like you’re making some progress. I’m just a novice at RLP, so I probably won’t be able to help much there. Good luck!

Up to now I have no experience with SPI, but the principle of SPI ist a simple shift register.
My question/idea now : Did you ever try the 16 bit SPI commands ?
A 12 bit shift register should just shift the first 4 bit to nowhere so you can use the least 12 bit. (If the MSB is shifted first)
If your chip can be used in a daisy chain ( Serial Peripheral Interface - Wikipedia ) it should be possible.

PS
Sorry about my limited english :slight_smile:

@ Lutz1,

You can use 16 bit SPI just by using short/ushorts in NETMF. 12 bit MSB first in RLP is just a little more complicated as you need to left shift 4 bits before you send it.

Wow thanks for all the interest in this question. @ Davef sorry for the delay I will test code today

Quick update using the sample provided a bit of confusion over the line

((float)(NumOctoBrites * Cool / 2);

I changed it to

((float)(NumOctoBrites * 2));

I get a quick scan all LEDs light up different brightness of blue stay on