FastLED project running at half speed (it seems)

Here a simple code I'm using to increment and decrement an active LED position and make it a color corresponding to its position on the strip. Yes, I realize the increment and decrement portions of code are written in two different ways, this was an attempt to see if calling .show() half as often would result in faster output (it doesn't).

#include <FastLED.h>

// How many leds in your strip?
#define NUM_LEDS 144

// For led chips like WS2812, which have a data line, ground, and power, you just
// need to define DATA_PIN.  For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
// Clock pin only needed for SPI based chipsets when not using hardware SPI
#define DATA_PIN 9


// Define the array of leds
CRGB leds[NUM_LEDS];

void setup() { 

    FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
    FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);

    pinMode (8, OUTPUT);
    digitalWrite (8, HIGH);
    pinMode (10, OUTPUT);
    digitalWrite (10, LOW);

    //FastLED.setMaxRefreshRate(0);


}

void loop() { 
  for (int i = 0; i < NUM_LEDS; i++) {
  leds[i] = CHSV(i, 255, 255);
  leds[i-1] = CRGB::Black;
  FastLED.show();
  //FastLED.clear();
}
  for (int i = NUM_LEDS; i > 0; i--) {
  leds[i] = CHSV(i, 255, 255);
  FastLED.show();
  FastLED.clear();
}

}

The pinMode stuff is my hacky way of using three consecutive pins for power and data (don't judge me). Anyway, as you can see, I'm not using any delay in the code, and I'm still getting a super slow display on my strip. I need to display the "down and back" of 144 LEDs on a strip at approximately 2Hz (one end to the other, and back, being one period).

The data I've ready suggest that a 2.5ms delay is inherent in the fastLED library and/or necessary for the WS2812 chipset. Let's say that's true (because I haven't found a 2.5ms delay in the library as of yet), that still works out to a down-and-back (incrementing then decrementing through each position in a 144 LED strip) happening in about .7 seconds, which obviously wouldn't give me 2Hz, but would be above 1Hz, whereas what I'm actually measuring is more like a second-and-a-half.

Can someone point out where this extra delay is coming in, and how I might get it out?

Thanks a ton.

Your sketch in Wokwi: Thanks-a-ton.ino - Wokwi Arduino and ESP32 Simulator

If the simulation runs, check the speed in the upper-right corner. If it is below 100%, then the simulation can not keep up and will be slower.

Which Arduino board do you use ?
Please explain pin 8 and 10. How did you power the ledstrip ?
A ledstrip of 144 leds might require 9A (yes, that is nine amps).

Things to look into:

  1. You don't need to update faster than the human eye can see. Or is it to capture a moment with a high speed camera ?
  2. If you want something faster, then there are ledstrips with separate clock and data.
  3. Wokwi has a Logic Analyzer ! You can analyze the signal to the ledstrip.

It's not a delay, but the time it takes to show() the data on the strip. This time depends on the number of the leds.
The picture below shows the timings of the 2812 protocol. As you can see, the output of the value of one bit takes about 1.25 µs
WS2812B-LED-PWM

The color of each led is encoded with 24 bits (8 bits for each of the three colors). If I didn't miscalculate, it would take

144 * 24 * ( 1.25us ) = 4.3 ms to update a strip of 144 leds.

Pass through all leds down-and-back, thus = 144 * 2 * 4.3 = 1244 ms or 1.2 sec
Very similar to your calculations

Unfortunately, there is no way to reduce this time by driving 144 leds on one wire. It's not a problem of the program or the controller, it's a protocol limitation
As an option, you may split your strip into several parts, connect to different pins and update in parallel. But this is only possible on some controllers, such as Due, Tensy or rp2040. And it's not a simple programming task.

This will cause some problems. When i is zero, the led that gets set to Black will be index -1, which is not part of the array. In many languages like BASIC, this would stop the code with an error message. In C/C++ there is no error message but it will result in memory being overwritten that could and probably does belong to some other variable. This could cause some very strange misbehaviour! Fix it like this:

  if(i>0) leds[i-1] = CRGB::Black;

then check for and fix any similar problems elsewhere in your code (and, yes, there is another).

I don't get it. Why do you think one way would call .show() half as often as the other way? Looks like the same number of calls to me.

By "don't judge me" do you mean "don't warn me if I'm about to burn my arduino"?

You don't say what this "power" is for. The only thing you have mentioned so far that needs power is the led strip. An Arduino Uno pin can source or sink 40mA absolute maximum before the Arduino is permanently damaged. As already mentioned, the strip could need 9,000mA. Even with every led off it will need close to 144mA because each led consumes nearly 1mA even when off.

It is possible with Uno. @Hossifer is using a very simple pattern where only one led is on at a time. So if the strip were separated into 2 halves driven by 2 data pins, each time the pattern is updated, only one of the half-strips needs to be updated (except at the moment where the 'moving' led swaps to the other half-strip).

Are you saying that the number of leds on the strip would affect the time required to update one frame? For example, to clear LED2 and light LED3 would take more time on a strip of 100 LEDs than a strip of 10?

surely!.

FastLED library ALWAYS updated ALL LEDs in the strip. Update goes in sequence, updating 100 LEDs takes 10 times more time than updating 10 leds.
All WS2812 libraries, known to me, works the same way.

it must be that way because that's how the hardware works

Then,

(X number of LEDs * T time required to update one LED) / N number of strings comprising X LEDs

Should equal total update time per cycle through all LEDs.

As in, cutting the strip into fourths and using four different pins should quadruple the maximum frequency, right?

If you can generate four different signals at the same time, then yes. But the library can not do that.

There are libraries that use DMA for some boards, or use a hardware programmable unit. Maybe, some day, there will be a board with a library that can generate four different signals.

Such a library already exists - it's FastLED. But DMA has nothing to do with parallel output.
This can be done by connecting 4 strips to 4 pins related to one controller port. Then, with direct writing to the port, you can update the signal at once on 4 (or more) outputs
But with this method, you need to convert a 4 sequences of color bits into one, where each byte contain bits of 4 parallel strips at once. So DMA is not suitable here. And you need to do this transform at the speed of WS2812 output. Therefore, FastLED supports parallel output only for relatively powerful controllers - Due, Tency, various STM32

I participated in the project where we did a matrix about 8000 addressable leds on Due. We used parallel output to 11 pins at the same time. We managed to get about 30-40 fps.

1 Like

Thank you :+1: I didn't know that there are already two libraries that support it on certain fast boards. There is some explanation in the Wiki, but not much: https://github.com/FastLED/FastLED/wiki/Parallel-Output

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.