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
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.
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...
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.
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?
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.