A pulse across a led strip without me having to make larger array than the physical led strip (see bottom)

For a project, the goal is to program a large number of WS2811 LED strips. Ultimately, this will require the use of about 10 Arduino Uno's. A pulse needs to be sent along the LED strip. When the pulse is need to start, it is done from a Raspberry Pi with Node-RED, which then sends a UDP message to the Arduino, and then a pulse is started. The communication works perfectly, but the LED strips are not working completely as expected yet. I still encounter the problem that with the code below, I can only control 2 LED strips. The compile is successful and can be uploaded to the Arduino, but only the first 2 defined LED strips work. If I define other LED strips first, then those work.

Now my question is, what is the best library to use for controlling multiple LED strips with an Arduino Uno? I have the impression that <Adafruit_NeoPixel.h> does not meet my expectations, or is there something wrong with my code?

Additionally, I have tried using arrays, but while the compile was successful, the LED strips did not work. If you want i can share this code also but the code below is for me working for 2 ledstrips and not 8. Sorry that the comment in the code is in dutch but i think it is clear what te code does.

#include <Adafruit_NeoPixel.h>

#define PIN2 2        // De pin waarop de LED-strip is aangesloten
#define PIN3 3        // De pin waarop de LED-strip is aangesloten
#define PIN4 4        // De pin waarop de LED-strip is aangesloten
#define PIN5 5        // De pin waarop de LED-strip is aangesloten
#define PIN6 6        // De pin waarop de LED-strip is aangesloten
#define PIN7 7        // De pin waarop de LED-strip is aangesloten
#define PIN8 8        // De pin waarop de LED-strip is aangesloten
#define PIN9 9        // De pin waarop de LED-strip is aangesloten
#define NUM_LEDS 160  // Het totale aantal LEDs in je strip

uint8_t PixelStrip1 = 0;      // Pixel op ledstrip 1
uint8_t PixelStrip2 = 0;  // Pixel op ledstrip 2
uint8_t PixelStrip3 = 0;  // Pixel op ledstrip 3
uint8_t PixelStrip4 = 0;  // Pixel op ledstrip 4
uint8_t PixelStrip5 = 0;  // Pixel op ledstrip 5
uint8_t PixelStrip6 = 0;  // Pixel op ledstrip 6
uint8_t PixelStrip7 = 0;  // Pixel op ledstrip 7
uint8_t PixelStrip8 = 0;  // Pixel op ledstrip 8
uint8_t maxlengte = 160;

int L1 = 2;          // afstand naar led
int L2 = 4;          // afstand naar led
int Leind = 8;       // afstand vanaf waar de leds uitgaan
int delaytime = 20;  // tijd in milliseconden tussen led overstap

Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(NUM_LEDS, PIN2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(NUM_LEDS, PIN3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip3 = Adafruit_NeoPixel(NUM_LEDS, PIN4, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip4 = Adafruit_NeoPixel(NUM_LEDS, PIN5, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip5 = Adafruit_NeoPixel(NUM_LEDS, PIN6, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip6 = Adafruit_NeoPixel(NUM_LEDS, PIN7, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip7 = Adafruit_NeoPixel(NUM_LEDS, PIN8, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip8 = Adafruit_NeoPixel(NUM_LEDS, PIN9, NEO_GRB + NEO_KHZ800);

uint32_t Color1 = strip1.Color(220, 80, 100);   // kleur led 1
uint32_t Color2 = strip1.Color(225, 90, 110);   // kleur led 2
uint32_t Color3 = strip1.Color(255, 255, 255);  // kleur led 9

/* ------------- ETHERNET --------------------- */
#include <Ethernet.h>
#include <EthernetUdp.h>
int i = 0;
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xEF, 0xED
};
IPAddress ip(192, 168, 0, 11);

unsigned int localPort = 8887;  // local port to listen on

// buffers for receiving and sending data
char packetBuffer[1];  // buffer to hold incoming packet,

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() {
  // start the Ethernet
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  //Serial.begin(9600);
  // start UDP
  Udp.begin(localPort);
  strip1.begin();
  strip1.show();  // Initialiseer alle pixels naar 'uit'
  strip2.begin();
  strip2.show();  // Initialiseer alle pixels naar 'uit'
  strip3.begin();
  strip3.show();  // Initialiseer alle pixels naar 'uit'
  strip4.begin();
  strip4.show();  // Initialiseer alle pixels naar 'uit'
  strip5.begin();
  strip5.show();  // Initialiseer alle pixels naar 'uit'
  strip6.begin();
  strip6.show();  // Initialiseer alle pixels naar 'uit'
  strip7.begin();
  strip7.show();  // Initialiseer alle pixels naar 'uit'
  strip8.begin();
  strip8.show();  // Initialiseer alle pixels naar 'uit'
}

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Udp.read(packetBuffer, 1);
    //Serial.println("packetBuffer: " + String(packetBuffer));
    int strip = atoi(packetBuffer);
    //Serial.println("Strip: " + String(strip));
    switch (strip) {
      case 1: PixelStrip1 = 1; break;
      case 2: PixelStrip2 = 1; break;
      case 3: PixelStrip3 = 1; break;
      case 4: PixelStrip4 = 1; break;
      case 5: PixelStrip5 = 1; break;
      case 6: PixelStrip6 = 1; break;
      case 7: PixelStrip7 = 1; break;
      case 8: PixelStrip8 = 1; break;
    }
  }
  if (PixelStrip1 > 0) {
    PulsStrip1();
  }
  if (PixelStrip2 > 0) {
    PulsStrip2();
  }
  if (PixelStrip3 > 0) {
    PulsStrip3();
  }
  if (PixelStrip4 > 0) {
    PulsStrip4();
  }
  if (PixelStrip5 > 0) {
    PulsStrip5();
  }
  if (PixelStrip6 > 0) {
    PulsStrip6();
  }
  if (PixelStrip7 > 0) {
    PulsStrip7();
  }
  if (PixelStrip8 > 0) {
    PulsStrip8();
  }
  delay(delaytime);  // Wacht voor de volgende stap
}

void PulsStrip1() {
  //Serial.println("PixelStrip1: " + String(PixelStrip1));
  strip1.setPixelColor(PixelStrip1, Color1);       // Zet de huidige pixel aan (wit)
  strip1.setPixelColor(PixelStrip1 - L1, Color2);  // Zet de huidige pixel aan (wit)
  strip1.setPixelColor(PixelStrip1 - L2, Color3);  // Zet de huidige pixel aan (wit)
  strip1.setPixelColor(PixelStrip1 - Leind, 0);    // Zet de pixel 6 stappen terug uit
  strip1.show();
  if (PixelStrip1 < NUM_LEDS) {
    PixelStrip1++;
    Serial.println("PixelStrip1: " + String(PixelStrip1));
  } else {
    PixelStrip1 = 0;
    Serial.println("PixelStrip1: " + String(PixelStrip1));
  }
}

void PulsStrip2() {
  strip2.setPixelColor(PixelStrip2, Color1);
  strip2.setPixelColor(PixelStrip2 - L1, Color2);
  strip2.setPixelColor(PixelStrip2 - L2, Color3);
  strip2.setPixelColor(PixelStrip2 - Leind, 0);
  strip2.show();
  if (PixelStrip2 < NUM_LEDS) {
    PixelStrip2++;
    //Serial.println("PixelStrip2: " + String(PixelStrip2));
  } else {
    PixelStrip2 = 0;
    //Serial.println("PixelStrip2: " + String(PixelStrip2));
  }
}

void PulsStrip3() {
  strip3.setPixelColor(PixelStrip3, Color1);
  strip3.setPixelColor(PixelStrip3 - L1, Color2);
  strip3.setPixelColor(PixelStrip3 - L2, Color3);
  strip3.setPixelColor(PixelStrip3 - Leind, 0);
  strip3.show();
  if (PixelStrip3 < NUM_LEDS) {
    PixelStrip3++;
    //Serial.println("PixelStrip3: " + String(PixelStrip3));
  } else {
    PixelStrip3 = 0;
    //Serial.println("PixelStrip3: " + String(PixelStrip3));
  }
}

void PulsStrip4() {
  strip4.setPixelColor(PixelStrip4, Color1);
  strip4.setPixelColor(PixelStrip4 - L1, Color2);
  strip4.setPixelColor(PixelStrip4 - L2, Color3);
  strip4.setPixelColor(PixelStrip4 - Leind, 0);
  strip4.show();
  if (PixelStrip4 < NUM_LEDS) {
    PixelStrip4++;
    //Serial.println("PixelStrip4: " + String(PixelStrip4));
  } else {
    PixelStrip4 = 0;
    //Serial.println("PixelStrip4: " + String(PixelStrip4));
  }
}

void PulsStrip5() {
  strip5.setPixelColor(PixelStrip5, Color1);
  strip5.setPixelColor(PixelStrip5 - L1, Color2);
  strip5.setPixelColor(PixelStrip5 - L2, Color3);
  strip5.setPixelColor(PixelStrip5 - Leind, 0);
  strip5.show();
  if (PixelStrip5 < NUM_LEDS) {
    PixelStrip5++;
    //Serial.println("PixelStrip5: " + String(PixelStrip5));
  } else {
    PixelStrip5 = 0;
    //Serial.println("PixelStrip5: " + String(PixelStrip5));
  }
}

void PulsStrip6() {
  strip6.setPixelColor(PixelStrip6, Color1);
  strip6.setPixelColor(PixelStrip6 - L1, Color2);
  strip6.setPixelColor(PixelStrip6 - L2, Color3);
  strip6.setPixelColor(PixelStrip6 - Leind, 0);
  strip6.show();
  if (PixelStrip6 < NUM_LEDS) {
    PixelStrip6++;
    //Serial.println("PixelStrip6: " + String(PixelStrip6));
  } else {
    PixelStrip6 = 0;
    //Serial.println("PixelStrip6: " + String(PixelStrip6));
  }
}

void PulsStrip7() {
  strip7.setPixelColor(PixelStrip7, Color1);
  strip7.setPixelColor(PixelStrip7 - L1, Color2);
  strip7.setPixelColor(PixelStrip7 - L2, Color3);
  strip7.setPixelColor(PixelStrip7 - Leind, 0);
  strip7.show();
  if (PixelStrip7 < NUM_LEDS) {
    PixelStrip7++;
    //Serial.println("PixelStrip7: " + String(PixelStrip7));
  } else {
    PixelStrip7 = 0;
    //Serial.println("PixelStrip7: " + String(PixelStrip7));
  }
}

void PulsStrip8() {
  strip8.setPixelColor(PixelStrip8, Color1);
  strip8.setPixelColor(PixelStrip8 - L1, Color2);
  strip8.setPixelColor(PixelStrip8 - L2, Color3);
  strip8.setPixelColor(PixelStrip8 - Leind, 0);
  strip8.show();
  if (PixelStrip8 < NUM_LEDS) {
    PixelStrip8++;
    //Serial.println("PixelStrip8: " + String(PixelStrip8));
  } else {
    PixelStrip8 = 0;
    //Serial.println("PixelStrip8: " + String(PixelStrip8));
  }
}

160 * 8 = 1280 could be a lot of LEDs for an Uno. Do you have enough memory?

I always thought that during the compile of the Arduino, the used variables are calculated. If i use to much memory the compile will not be succesfull when i selected the arduino uno board. When I do this, the following appears:

Sketch uses 13362 bytes (41%) of program storage space. Maximum is 32256 bytes.
Global variables use 599 bytes (29%) of dynamic memory, leaving 1449 bytes for local variables. Maximum is 2048 bytes.

I'm more familiar with FastLED, but to store just three bytes of color state information for 1280 LEDs you'd need 3840 bytes of RAM. Which wouldn't fit into the 599 bytes of allocated global variables, so I think the strip?.begin() statements would be trying to allocate space in the remaining 1449 bytes and failing.

But I'm only guessing.

In fact they are calculated, this is what library do:

void Adafruit_NeoPixel::updateLength(uint16_t n) {
  free(pixels); // Free existing data (if any)

  // Allocate new data -- note: ALL PIXELS ARE CLEARED
  numBytes = n * ((wOffset == rOffset) ? 3 : 4);
  if ((pixels = (uint8_t *)malloc(numBytes))) {
    memset(pixels, 0, numBytes);
    numLEDs = n;
  } else {
    numLEDs = numBytes = 0;
  }
}

If you check the returned value of:

uint16_t numPixels(void) const { return numLEDs; }

you'll see that yours Pixelstrip3 to 8 return 0, 'cause memory was not allocated.
If you need to use such much leds you have to use a module with more memory, e.g. a raspberri pico.

Ciao, Ale.

1 Like

Thank you for the answer, and I understand that it's just a guess, but this way I can move forward. Tomorrow I can test again and will try a different library, namely the one you mentioned: FastLED. There were 8 times 5 meters of LED strip connected to the Arduino, but if I calculate it correctly, that’s 300 LEDs with 100 chips because it is WS2811 per output. From what I hear from you, it’s possible to control 6 outputs with 100 chips each using the Arduino Uno and FastLED? Because then I would be using 1800 bytes for the LED strips and still have some left for my own program.

Thank you for your answer, now it’s clear to me. I thought maybe i did something wrong or using the wrong library. At the moment, I have one Raspberry Pi running Node-RED, but if memory becomes a problem, I will use the Multiple Raspberry Pi to control the LEDs. I have looked into the Adafruit_CircuitPython_NeoPixel for Raspberry Pi, and I also think it’s a better solution.

FastLED uses 4 bytes per LED. So for 600 LEDS, it would need 2400 bytes, more than the entire Uno RAM.

Depending on what exactly you mean by "a pulse", you could conceivably get by with special purpose code; my interpretation is that only a "few" of the LEDs in each strip would be lit at any one time, so that at least in theory you would only need data storage for the illuminated LEDs (the other would just be zeros.)

AFAIK, all of the libraries are going to have the same problem where they want to have 3 or 4 bytes of memory per LED.

OTOH, "get an Arudino-like board with more memory" is probably significantly easier that "write special WS2812 'pulse' code."

Perhaps allocate one NeoPixel strip object but change the output pin number (strip.setPin(p)) as needed to select each hardware strip. Note this drives the strips in sequence, not in parallel so expect slow frame rate.

1 Like

As far as I know, it's nearly always in sequence. There are a few boards (Due, some Teensies) that can do it in parallel.

Are the WS2811 grouped in three-physical-pixels per address?

Don't know. I was going off of:

and then:

...and figuring 4 bytes per RGB for FastLED.

Where do you get the 4 bytes per RGB? FastLED should only need 3 bytes, unless the LED is an RGBW.

@thimohe - Does this sketch light three pixels or nine?

#include <Adafruit_NeoPixel.h>
#define PIN       2
#define NUMPIXELS 3
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  pixels.begin();
  pixels.clear();
  pixels.setPixelColor(0, pixels.Color(255, 000, 000)); // RED
  pixels.setPixelColor(1, pixels.Color(000, 255, 000)); // GRN
  pixels.setPixelColor(2, pixels.Color(000, 000, 255)); // BLU
  pixels.show();
}
void loop() {}

You are right. I was wrongly thinking of 0xFFFFFF colors in uint32_t variables.

You should have continued to use the strips in arrays - it will reduce your program to less than a half.

The compiler can only show Program memory and SRAM occupied by globals/static variables. If memory is allocated dynamically or functions need local variables - it is not represented in the numbers you see at the end of compiling process.

Your main problem is you will run out of SRAM with 8 x 160 LEDs on the UNO.
Either reduce the LEDs or get an µC with more SRAM.

1 Like

Sorry for my late response, but I was busy with work, which left me no time for this project. I will clarify the confusion regarding the number of LEDs. I will be using WS2811 with 60 LEDs per meter and pieces that are 5 meters long. That means 300 LEDs, but only 100 ICs need to be controlled, so the 160 LEDs in my code was incorrect. It should actually be 100, sorry for that mistake.

Are there alternative hardware options with more RAM in a low price range on AliExpress?
I am currently thinking of using Arduino Megas because they have 8KB of RAM. But an arduino uno is only like 5 euro's on ali express.

Anyway, I will try to rewrite my code to use FastLED so that I can utilize as many pixels as possible. If anyone can provide an explanation about using an array with FastLED, I would appreciate it. Becease with the NeoPixel code it doesn't worked for me. The code below is not tested becease i will do that tomorrow.

#include <FastLED.h>

#define PIN2 2        // The pin where the LED strip is connected
#define PIN3 3        // The pin where the LED strip is connected
#define PIN4 4        // The pin where the LED strip is connected
#define PIN5 5        // The pin where the LED strip is connected
#define PIN6 6        // The pin where the LED strip is connected
#define PIN7 7        // The pin where the LED strip is connected
#define PIN8 8        // The pin where the LED strip is connected
#define PIN9 9        // The pin where the LED strip is connected
#define NUM_LEDS 100  // The total number of LEDs in your strip

uint8_t PixelStrip1 = 0;  // Pixel on LED strip 1
uint8_t PixelStrip2 = 0;  // Pixel on LED strip 2
uint8_t PixelStrip3 = 0;  // Pixel on LED strip 3
uint8_t PixelStrip4 = 0;  // Pixel on LED strip 4
uint8_t PixelStrip5 = 0;  // Pixel on LED strip 5

uint8_t distance = 2;
int delaytime = 20;  // time in milliseconds between LED transitions

CRGB strip1[NUM_LEDS];
CRGB strip2[NUM_LEDS];
CRGB strip3[NUM_LEDS];
CRGB strip4[NUM_LEDS];
CRGB strip5[NUM_LEDS];

CRGB Color1 = CRGB(220, 80, 100);   // Color 1
CRGB Color2 = CRGB(225, 90, 110);   // Color 2
CRGB Color3 = CRGB(255, 255, 255);  // Color 3

/* ------------- ETHERNET --------------------- */
#include <Ethernet.h>
#include <EthernetUdp.h>
int i = 0;
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xEF, 0xED
};
IPAddress ip(192, 168, 0, 11);

unsigned int localPort = 8887;  // local port to listen on

// buffers for receiving and sending data
char packetBuffer[1];  // buffer to hold incoming packet,

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup() {
  // start the Ethernet
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  //Serial.begin(9600);
  // start UDP
  Udp.begin(localPort);
  
  FastLED.addLeds<NEOPIXEL, PIN2>(strip1, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN3>(strip2, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN4>(strip3, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, PIN5>(strip4, NUM_LEDS);
  FastLED.show();
}

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Udp.read(packetBuffer, 1);
    //Serial.println("packetBuffer: " + String(packetBuffer));
    int strip = atoi(packetBuffer);
    //Serial.println("Strip: " + String(strip));
    switch (strip) {
      case 1: PixelStrip1 = 1; break;
      case 2: PixelStrip2 = 1; break;
      case 3: PixelStrip3 = 1; break;
      case 4: PixelStrip4 = 1; break;
      case 5: PixelStrip5 = 1; break;
    }
  }
  if (PixelStrip1 > 0) {
    PulsStrip1();
  }
  if (PixelStrip2 > 0) {
    PulsStrip2();
  }
  if (PixelStrip3 > 0) {
    PulsStrip3();
  }
  if (PixelStrip4 > 0) {
    PulsStrip4();
  }
  if (PixelStrip5 > 0) {
    PulsStrip5();
  }
  delay(delaytime);  // Wacht voor de volgende stap
}

void PulsStrip1() {
  //Serial.println("PixelStrip1: " + String(PixelStrip1));
  strip1[PixelStrip1] = Color1;          // Zet de huidige pixel aan (kleur1)
  strip1[PixelStrip1 - (distance * 1)] = Color2;     // Zet de huidige pixel aan (kleur2)
  strip1[PixelStrip1 - (distance * 2)] = Color3;     // Zet de huidige pixel aan (kleur3)
  strip1[PixelStrip1 - (distance * 3)] = CRGB::Black;  // Zet de pixel 6 stappen terug uit
  FastLED.show();
  if (PixelStrip1 < NUM_LEDS) {
    PixelStrip1++;
    Serial.println("PixelStrip1: " + String(PixelStrip1));
  } else {
    PixelStrip1 = 0;
    Serial.println("PixelStrip1: " + String(PixelStrip1));
  }
}

void PulsStrip2() {
  strip2[PixelStrip2] = Color1;
  strip2[PixelStrip2 - (distance * 1)] = Color2;
  strip2[PixelStrip2 - (distance * 2)] = Color3;
  strip2[PixelStrip2 - (distance * 3)] = CRGB::Black;
  FastLED.show();
  
  if (PixelStrip2 < NUM_LEDS) {
    PixelStrip2++;
    //Serial.println("PixelStrip2: " + String(PixelStrip2));
  } else {
    PixelStrip2 = 0;
    //Serial.println("PixelStrip2: " + String(PixelStrip2));
  }
}

void PulsStrip3() {
  strip3[PixelStrip3] = Color1;
  strip3[PixelStrip3 - (distance * 1)] = Color2;
  strip3[PixelStrip3 - (distance * 2)] = Color3;
  strip3[PixelStrip3 - (distance * 3)] = CRGB::Black;
  FastLED.show();
  
  if (PixelStrip3 < NUM_LEDS) {
    PixelStrip3++;
    //Serial.println("PixelStrip3: " + String(PixelStrip3));
  } else {
    PixelStrip3 = 0;
    //Serial.println("PixelStrip3: " + String(PixelStrip3));
  }
}

void PulsStrip4() {
  strip4[PixelStrip4] = Color1;
  strip4[PixelStrip4 - (distance * 1)] = Color2;
  strip4[PixelStrip4 - (distance * 2)] = Color3;
  strip4[PixelStrip4 - (distance * 3)] = CRGB::Black;
  FastLED.show();
  
  if (PixelStrip4 < NUM_LEDS) {
    PixelStrip4++;
    //Serial.println("PixelStrip4: " + String(PixelStrip4));
  } else {
    PixelStrip4 = 0;
    //Serial.println("PixelStrip4: " + String(PixelStrip4));
  }
}

void PulsStrip5() {
  strip5[PixelStrip5] = Color1;
  strip5[PixelStrip5 - (distance * 1)] = Color2;
  strip5[PixelStrip5 - (distance * 2)] = Color3;
  strip5[PixelStrip5 - (distance * 3)] = CRGB::Black;
  FastLED.show();
  
  if (PixelStrip5 < NUM_LEDS) {
    PixelStrip5++;
    //Serial.println("PixelStrip5: " + String(PixelStrip5));
  } else {
    PixelStrip5 = 0;
    //Serial.println("PixelStrip5: " + String(PixelStrip5));
  }
}

I see your are also using ethernet.
I would go for an ESP32 Board. Most of the development boards will do.
Just my first find: https://s.click.aliexpress.com/e/_DDyD5FH

Ethernet needs more efforts, but is also available: https://s.click.aliexpress.com/e/_DFxwbYf (will need an separate USB/TTL programmer, some more information can be found here: WT32-ETH01 - ESP32 Board with Ethernet Socket).

When the ESP is new for you - start with an USB wifi board.

I have seen an ESP32, but unfortunately it works on 3.3V GPIO pins and I need 5V to control the WS2811 LED strip. Or am I wrong?