LED strip taking longer than expected to complete a cycle

Ok so a little background:

I am using an ESP32 board to control a strip of WS2812 LEDs (20m in total). My strips are 5m each. The strips have 30LEDs per m. In total, I have 600 LEDs to control.
I am using the FastLED library for this project.

My project is simple: I want to illuminate each LED at a certain interval until it reaches the end of the strip, and then illuminate each LED in reverse.
I have a predetermined time of 20 seconds to go up and down the strip (10 seconds for each pass). I have been timing this and it has been completing this cycle in 22 secs (+/-40ms accounting for human error).
As per my formulas in the code, each LED should light up every 16.66ms (and since millis() is a long it'll evaulate to 16ms - which means it should run faster).

Now, I have tested my code with a 10m strip (300 LEDs in total) with a time of 6 seconds (3 seconds per pass) which means that each LED should light up every 10ms and it is consistently at 6 seconds (again, +/-40ms for human error).** So I know that the board can handle quick evaluations of millis().

My question:

Why does it take significantly longer to complete a cycle (two passes) when I have 600 LEDs when I know that the LED rate is 16ms is slower than 10ms? I would have thought it would struggle more to keep up with the 10ms?
Is it my quantity of LEDs that's the issue here? I don't see how this could hold my code back unless I am completely missing something.

Any input is appreciated :slight_smile:

Code below:

#include <FastLED.h>
#define DATA_PIN 22//Pin that will send the signal
#define NUM_LEDS 600// = strip length * leds per m

CRGB leds[NUM_LEDS];

int runLength = 20;//the length of led strip (4x5m strips)
int travelLength = 40;//want to travel the strip twice - up and down
int minutes = 0;
int seconds = 20;
int hundrethSeconds = 0;
int minsToMillis = minutes * 60 * 1000;
int secsToMillis = seconds * 1000;
int hunToMillis = hundrethSeconds * 10;
int addedTime = minsToMillis + secsToMillis + hunToMillis;
int numRuns = travelLength/runLength;//40/20 = 2
int timePerRun = addedTime/numRuns;//10 secs per run

int stripLength = runLength;
int ledsPerM = 30;
int totalLeds = stripLength * ledsPerM;//I know I can use NUM_LEDS
//I just chose a different variable for more clarity


unsigned long startMillis;
unsigned long currentMillis;
unsigned long ledRate = timePerRun/totalLeds;//how often to 
//turn each subsequent LED, in the strip, on

int runCounter = 0;
int i = 0;//array index at start of strip
int j = NUM_LEDS - 1;//array index at end of strip


void setup() {

  Serial.begin(115200);//using ESP32
  startMillis = millis();
  FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();//clearing the strip in case it was
  //running code before the reset/upload


}

void loop() {

  currentMillis = millis();
  if(currentMillis - startMillis >= ledRate && i < totalLeds && runCounter < numRuns)
  {
    leds[i] = CRGB(255,0,0);//set color to red
    FastLED.setBrightness(80);
    FastLED.show();
    i++;

    if(i == totalLeds)
    {
      FastLED.clear();
      FastLED.show();//once it reaches the end of the strip
      //clear the strip of colours
     runCounter++;
    }
    startMillis = currentMillis;
  }

  if(i == totalLeds)//if we have reached the end of the strip
  //we will start lighting up from the end of the strip
  {
    currentMillis = millis();
    if(currentMillis - startMillis >= ledRate & j >= 0 && runCounter < numRuns){
      leds[j] = CRGB(0,255,125);//set color to light blue
      FastLED.setBrightness(80);
      FastLED.show();
      j--;

      if(j == 0)//if we have reached the start of the strip
      //clear the strip again
      {
        FastLED.clear();
        FastLED.show();
       runCounter++;
      }
      startMillis = currentMillis;
      if(i == totalLeds && j == 0)//reset values
      //to default values
      {
        i = 0;
        j = totalLeds-1;
      }
    }
  }
}

Basically each of these is a function not a simple instruction. Each one takes time. For an experiment try running each of the functions and timing them. You can do this by saving Millis, running the function then save the current Millis first then. subtract the saved mills from the current mills. The saving will help keep the measurement out of the actual time. You could loop several times if you like. I do not know the library but I think it allows enough time for the function to work. Let us know how it works.

I did what you suggested. Added an array where I could store the values of currentMillis - startMillis during every pass.

This was the output with 600 LEDs, 20m strip, 40m total, and a total time of 20secs (16ms per LED):

14:13:25.023 -> 19
14:13:25.069 -> 18
14:13:25.116 -> 18
14:13:25.164 -> 19
14:13:25.195 -> 18
14:13:25.274 -> 18
14:13:25.321 -> 19
14:13:25.368 -> 18
14:13:25.415 -> 18
14:13:25.446 -> 18
14:13:25.538 -> 19
14:13:25.585 -> 18
14:13:25.631 -> 18
14:13:25.677 -> 19
14:13:25.723 -> 18

And this was the output with 300 LEDs, 10m strip, 20m total, and a total time of 6 secs (10ms per LED):

14:16:20.002 -> 10
14:16:20.082 -> 10
14:16:20.128 -> 10
14:16:20.174 -> 10
14:16:20.222 -> 10
14:16:20.269 -> 10
14:16:20.348 -> 10
14:16:20.395 -> 10
14:16:20.442 -> 10
14:16:20.488 -> 10
14:16:20.535 -> 10
14:16:20.582 -> 10
14:16:20.629 -> 10
14:16:20.676 -> 10
14:16:20.723 -> 10

And this is what I cannot understand: for both cases, the function is doing the same number of operations so should take the same amount of time to complete. The only thing that is changing is the number of LEDs and the time it takes to complete a full pass (20s vs 6s). If it can handle the speed of 10ms, surely it would be able to handle 16ms no issues. But that's not the case...

Each LED takes time. I am not familiar with FastLED, I simply do the coding myself. See if this link helps.

Each LED is 24 bits of data. That goes out with every show().

The data rate is 800000 bits per second.

24*600/800000 = 0.018 seconds, 18 milliseconds it takes. Every call to show().

a7

PS:
Sorry, I removed the code I posted because I found an error and I'm reviewing it.

This routine takes ~= 24 ms, therefore much longer than the 16 ms you predicted.

See with this code printing the time to advance each LED.

Total time for each pass of 600 LEDs = 24 * 600 = 14,400 ms.

#include <FastLED.h>
#define DATA_PIN 22//Pin that will send the signal
#define NUM_LEDS 600// = strip length * leds per m

CRGB leds[NUM_LEDS];

int runLength = 20;//the length of led strip (4x5m strips)
int travelLength = 40;//want to travel the strip twice - up and down
int minutes = 0;
int seconds = 20;
int hundrethSeconds = 0;
int minsToMillis = minutes * 60 * 1000;
int secsToMillis = seconds * 1000;
int hunToMillis = hundrethSeconds * 10;
int addedTime = minsToMillis + secsToMillis + hunToMillis;
int numRuns = travelLength/runLength;//40/20 = 2
int timePerRun = addedTime/numRuns;//10 secs per run

int stripLength = runLength;
int ledsPerM = 30;
int totalLeds = stripLength * ledsPerM;//I know I can use NUM_LEDS
//I just chose a different variable for more clarity


unsigned long startMillis;
unsigned long currentMillis;
unsigned long ledRate = timePerRun/totalLeds;//how often to 
//turn each subsequent LED, in the strip, on

int runCounter = 0;
int i = 0;//array index at start of strip
int j = NUM_LEDS - 1;//array index at end of strip


void setup() {

  Serial.begin(115200);//using ESP32
  startMillis = millis();
  FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();//clearing the strip in case it was
  //running code before the reset/upload
}
unsigned myTime;
void loop() {
  currentMillis = millis();
  if(currentMillis - startMillis >= ledRate && i < totalLeds && runCounter < numRuns)
  {
    myTime = millis();
    leds[i] = CRGB(255,0,0);//set color to red
    FastLED.setBrightness(80);
    FastLED.show();
    i++;
    Serial.println(millis() - myTime);
    if(i == totalLeds)
    {
      FastLED.clear();
      FastLED.show();//once it reaches the end of the strip
      //clear the strip of colours
     runCounter++;
    }
    startMillis = currentMillis;
  }

  if(i == totalLeds)//if we have reached the end of the strip
  //we will start lighting up from the end of the strip
  {
    currentMillis = millis();
    if(currentMillis - startMillis >= ledRate & j >= 0 && runCounter < numRuns){
      leds[j] = CRGB(0,255,125);//set color to light blue
      FastLED.setBrightness(80);
      FastLED.show();
      j--;

      if(j == 0)//if we have reached the start of the strip
      //clear the strip again
      {
        FastLED.clear();
        FastLED.show();
       runCounter++;
      }
      startMillis = currentMillis;
      if(i == totalLeds && j == 0)//reset values
      //to default values
      {
        i = 0;
        j = totalLeds-1;
      }
    }
  }
}

That's what I was completely missing!
That makes a lot of sense and why it is quicker with 300 LEDs.

I may have to think a little harder as to how to approach this. I don't think illuminating only 4 or 5 LEDs at a time is gonna make a difference since with every show() it updates the entire strip and that, again, will depend on the number of LEDs.

Much appreciated!

Heya, is this the code that you modified?
I see you added:

unsigned myTime;
myTime = millis();

Serial.println(millis() - myTime);

I don't know if this is doing anything for speed? Unless you are still working on it as per your other post where you said you had removed the code cus you found an error?

:slight_smile:

Sorry if I expressed it poorly, the error was in the code I modified and not an error in your code.

No, this is not affecting the speed, as I am measuring the speed from point marked with AAAAAAAA......... until BBBBBB...............
This routine spend 24 mS.