Simplifying control of LED 2801 square pixel

Thanks very much! Really appreciate your help on that.

It's currently giving me an error saying...

request for member 'b' in 'BlueLedGroup[p]', which is of non-class type 'byte''

But I'll try to figure that out.

Cheers

t

What's the code look like?

Probably like a chimp has been hacking away ;-). Here's where I've got to so far:

#include <FastSPI_LED.h>

#define NUM_LEDS 80

// Sometimes chipsets wire in a backwards sort of way
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
// struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

#define PIN 4

void setup()
{
FastSPI_LED.setLeds(NUM_LEDS);
FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
FastSPI_LED.setPin(PIN);

FastSPI_LED.init();
FastSPI_LED.start();

leds = (struct CRGB*)FastSPI_LED.getRGBData();

}

void loop() {

byte BlueLEDgroup[] = {2, 20, 47, 60};

// BlueLedGroup ON
//have I declared 'p' correctly?
for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
BlueLEDgroup[p].r = 0;
BlueLEDgroup[p].g = 0;
BlueLEDgroup[p].1b = 255;
}
//following array equals all LEDS that are not specified in BlueLedGroup (0-79 LEDs possible)
byte WhiteLEDgroup[] = {0, 1, 3-19, 21-46, 48-59, 61-79};

//WhiteLedGroup ON whilst BlueLedGroup is ON
for (int p = 0; p < sizeof(WhiteLEDgroup); p++) {
WhiteLEDgroup[p].r = 255;
WhiteLEDgroup[p].g = 255;
WhiteLEDgroup[p].b = 255;
}
}

Please use the code button to insert code in your posts. It looks like a #-sign.

TSD_80:
#define PIN 4

This is not needed for the WS2801 chips.

TSD_80:
FastSPI_LED.setPin(PIN);

Neither is this.

However, you do need a data rate line for the WS2801s. This isn't defined in the test program. Add this line within the setup() portion:

FastSPI_LED.setDataRate(2);

TSD_80:
BlueLEDgroup[p].1b = 255;

What's '1b' ?

TSD_80:
//following array equals all LEDS that are not specified in BlueLedGroup (0-79 LEDs possible)
byte WhiteLEDgroup[] = {0, 1, 3-19, 21-46, 48-59, 61-79};

That won't work for defining the remaining LEDs. You're better off not bothering with this second array. Just set everything to white first (you don't need an array for that), then cycle through the BlueLEDgroup array and turn those blue. When you're done with that, then you can call FastSPI_LED.show() which will turn the LEDs on.

Legend. Thanks once again. All comments will be addressed and are gratefully received. 1b was a typo alone. Great to know I can simplify the loop by having all default to white upfront too.

Sorry to be so demanding here. I've reviewed the code and added more to it - all code seems to verify with the exception of the same issue as before. I still get the error message 'LED_arrays_3.cpp: In function 'void loop()':
LED_arrays_3:48: error: request for member 'r' in 'BlueLEDgroup[p]', which is of non-class type 'byte'
LED_arrays_3:49: error: request for member 'g' in 'BlueLEDgroup[p]', which is of non-class type 'byte'
LED_arrays_3:50: error: request for member 'b' in 'BlueLEDgroup[p]', which is of non-class type 'byte''

for:

byte BlueLEDgroup[] = {2, 20, 47, 60};
// BlueLedGroup ON
for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
  BlueLEDgroup[p].r = 0;
  BlueLEDgroup[p].g = 0;
  BlueLEDgroup[p].b = 255;
}
FastSPI_LED.show();
}

Right. While BlueLEDgroup holds the position of each pixel that you want to change to blue, it doesn't translate to what FastSPI needs. FastSPI keeps an array called 'leds' which is what you manipulate. That array contains all of the pixels in your string. Your BlueLEDgroup only holds those pixels you want changed, so you need to pass that information to the leds array, like so:

#include <FastSPI_LED.h>

#define NUM_LEDS 10

struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

byte BlueLEDgroup[] = {2, 20, 47, 60};
int done = 0;

void setup() {
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);

  FastSPI_LED.setDataRate(2);
  
  FastSPI_LED.init();
  FastSPI_LED.start();

  leds = (struct CRGB*)FastSPI_LED.getRGBData(); 
}

void loop() {
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
      leds[BlueLEDgroup[p]].r = 0;
      leds[BlueLEDgroup[p]].g = 0;
      leds[BlueLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
}

Now when you run this, 'p' becomes the counter from 0 to the size of the BlueLEDgroup array. Each time it iterates through it, it returns whatever is at that position in that array. So the first time, it returns the value '2'. When that gets passed to the 'leds' array, you get 'leds[2].r = 0', etc., etc. At the next iteration, p = 1, BlueLEDgroup[1] = 20, which when passed to the 'leds' array you get 'leds[20].r' etc., etc.

Does that make sense?

Yes it does. At least on initial read-through – I'll digest it over a few times so the array handling has sunk it and give it a try. It seems you've essentially packaged up /referenced the original LEDGroup code within the form of array that's understood by FastSPI.

In practical terms then, presumably if I create multiple LEDGroups I add them at the top of the code as you've done:

#include <FastSPI_LED.h>

#define NUM_LEDS 10

struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

byte BlueLEDgroup[] = {2, 20, 47, 60};
byte SecondLEDgroup[] = {x,x,x};
byte ThirdLEDgroup[] = {x, x, x, x, x};
int done = 0;

And then duplicate the Loop code against those as necessary:

void loop() {
//First group
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
      leds[BlueLEDgroup[p]].r = 0;
      leds[BlueLEDgroup[p]].g = 0;
      leds[BlueLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
//SecondGroup
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(SecondLEDgroup); p++) {
      leds[SecondLEDgroup[p]].r = 0;
      leds[SecondLEDgroup[p]].g = 0;
      leds[SecondLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
//ThirdGroup
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(ThirdLEDgroup); p++) {
      leds[ThirdLEDgroup[p]].r = 0;
      leds[ThirdLEDgroup[p]].g = 0;
      leds[ThirdLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
}

Ever grateful. Thanks very much.

Bingo!

Keep in mind, I just added the 'done' part in my test program so it stops. Having built several battery-based LED displays, the less you have to invoke any kind of changes, the better. And one way to do that is to monitor how often you're sending data down the line. And if the lights aren't meant to change for several cycles, then why tell the program to do anything other than to wait outside of the loop. There's certainly no need to call FastSPI_LED() over and over again if nothing's changed.

Since you may have several "sections" of different colors, if they're all going to get set at the same time, you can run all those loops in one shot before jumping out and waiting.

Oh yeah, in your sample code, any loop after the first one will not run because you've set 'done' to 1 in the first one. So the second loop, when it checks whether done = 0 and finds it false, it skips the loop and moves on. This is what I mean with, if you're setting everything in one shot, you can encapsulate the whole series of loops with one break. If that's even necessary. Not knowing how you plan on implementing it, I don't really know what would work here.

Hi there,

Is there a specific reason for why FastSPI_LED.h is recommended for this task rather than SPI.h? There will be 80 LEDs in total.

Thanks

The SPI library is exactly that, a library to control the SPI functions on an Atmel. The FastSPI_LED however is a library written to control a bunch of different types of LED drivers, including the WS2801. So, if you only use the SPI library, you still have to write the various functions needed to control those LED drivers. Whereas with FastSPI_LED, it's already done for you. You just call the necessary functions.

Hi KirAsh4,

Thanks for your feedback. I now have the FastSPI doing what I want it too - hurray! The following step was to add Ethernet functionality so it's now calling a variable PHP file on a web server. As soon as that was added, we're getting 'disco lights' on the LEDs – specifically when it's connecting via the ethernet. Once the code is triggered the lights behave correctly, then go back to disco lights when its finished. This didn't happen when we're using the regular SPI but something on FastSPI sets it off. Is this a common problem that can be worked around? We're using an Arduino Ethernet so I'm wondering if there's a PIN conflict on the default 11 and 13... Could that be? Best

That is because the ethernet add-on that you're using is more than likely also using the SPI bus. And since the LED drivers don't have a select pin, just about anything that goes over the SPI bus will in some way or another mess with the LEDs. That's exactly what you're seeing. You have two options:

a) don't use FastSPI. Use bit-banging instead on two completely different pins, which will leave the SPI open for other devices, or
b) use a gate to control the LEDs, and you can still use FastSPI. It gets a bit trickier, but it can be done.

For my own project last year, I went the bit-bang route. I only had two strings of 20 LEDs each. I used the analog pins (of all things) to control the strings, A0 and A1 for one, and A2 and A3 for the other. Then I had an RF module on the SPI bus.

Note: bit banging IS slower than SPI, so depending on how fast you plan on sending data to the LEDs, bit-banging them may not work for you. For me it was plenty fast still.

I've gotten some great info from this topic, (and others) so I hope its okay that I necroposted. I'm starting down this path myself. Following all the great tips I can control my LEDS individually (mostly) using fastspi, but in seeing the last few posts I know I'm running up against my next obstacle soon :smiley:

KirAsh4:
That is because the ethernet add-on that you're using is more than likely also using the SPI bus.

.......

For my own project last year, I went the bit-bang route. I only had two strings of 20 LEDs each. I used the analog pins (of all things) to control the strings, A0 and A1 for one, and A2 and A3 for the other.
Note: bit banging IS slower than SPI, so depending on how fast you plan on sending data to the LEDs, bit-banging them may not work for you. For me it was plenty fast still.

Could you go into a bit more detail about bitbanging these pixels? Like most people, I'd like to write a function that will do most of the lifting and let me do changeLED(LED[1],'blue'); Since I'll be using the standard Ethernet shield on 13, I'll need a way to go without fastSPI. I'm hoping my project will accept http requests to turn a pixel a certain color, and then another digital out to set of an alarm (when a project needs attention) So I dont think it needs to be fast, the colors wont change rapidly and will stay solid lit.

Should I just look at a basic spi library? Adafruit-WS2801-Library/strandtest.pde at master · adafruit/Adafruit-WS2801-Library · GitHub I'm at work and cant check that out, but it seems close to what I'll need. I don't have the adafruit string, but I assume most 2801 will be similar

You also said

KirAsh4:
Just set everything to white first (you don't need an array for that), then cycle through the BlueLEDgroup array and turn those blue. When you're done with that, then you can call FastSPI_LED.show() which will turn the LEDs on.

Even though I'll be moving off fastspi after your advice, I'm curious what the single command is to set the whole string white :slight_smile:

Thanks!

For those who end up here for info some day, yes, if you want an easy way to control a ws2801 string download the adafruit library, Adafruit-WS2801-Library/strandtest.pde at master · adafruit/Adafruit-WS2801-Library · GitHub run the example and easily pick up on how to control each individual LED. This allows you to still use the standard ethernet shield for control.

Use the following to light up the pixel of your choice

      strip.setPixelColor(21,Color(0, 0, 255));

That Adafruit library is a good start for bit-banging SPI on different pins. There are ways to make both the LED string as well as another shield that requires the same SPI pins to work together, but you would have to add additional circuitry to isolate the string every time you need to access the shield. Bit banging is easier, though a tad slower.

So my project has progressed following the previous help you offered, particularly electronically. There's one sticking point I can't figure out that I'd very much appreciate a suggestion on. I can't work out how to make a function look up the values of the pixel arrays using the variable 'personsname'. The following code is a very stripped back version to highlight the exact problem area...

#include "SPI.h"
#include "Adafruit_WS2801.h"


//DEFINE OUTPUT PINS
int dataPin  = 2; //Yellow wire
int clockPin = 3; //Green wire

//SET NUMBER OF PIXELS
Adafruit_WS2801 strip = Adafruit_WS2801(20, dataPin, clockPin);

//PIXEL ARRAYS
byte Pete[] = { 0, 19, 43, 63};
byte Stephen[] = { 25, 32, 37, 59, 60, 63, 71};
byte Jack[] = { 20, 59, 61, 68};



//SETUP
void setup(){
  strip.begin();
  strip.show();
  Serial.begin(9600);
}

//CHECK & UPDATE LOOP
void loop(){
  
      colorFade(Color(0, 0, 255), "Pete");
    }
    delay(10000); //wait 10 seconds before connecting again
  }




// MAIN FUNCTIONS

//Fade to color
void colorFade(uint32_t c, char* personsname) {
  int i, j;
  for (c=0; c < 256; c++) {
    for (i=0; i < sizeof(personsname); i++) { //Can't get this to work. I can't figure out how to make the function look up the values of the pixel array using the variable 'personsname'. It works if a name is entered directly instead of "personsname", e.g. "Jack" will light up the correct LEDs.
      strip.setPixelColor(personsname[i], c); //Same here.
    }  
    strip.show();   // write all the pixels out
    delay(50);
    Serial.print("Fade In: ");Serial.print(personsname);Serial.println("");
  }
}

Any tips gratefully received. Thanks

The most recent major revision of the FastSPI library will let you use arbitrary pins - and does very high performance bit-banging (faster than just about any other library i've seen out there) when you aren't using the SPI ports. The next version preview release is documented here - http://waitingforbigo.com - and i'm hoping to put up another rev of the library shortly with some more chipsets and refining (I'm shaking out some of the new API pieces by feedback from people using it).

In addition the new library will let you use multiple strips on different pins (and even mix and match the types of strips) and no longer compiles in code for strips that you aren't using, saving you much more program flash memory as well.