4

I'm new to these addressable LED things – I just received a 149-LED WS2812B strip today, and I'm experimenting with various approaches. Adafruit's own tutorial says the FastLED library is faster than their Adafruit_NeoPixel library, so I wanted to test their performance.

I'm running this code on a Nano clone:

// Adafruit
#include <Adafruit_NeoPixel.h>
// FastLED
#include <FastLED.h>
// Common
#define NUM_LEDS 149
#define DATA_PIN 6

// Adafruit initialization
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);
const uint32_t adaBlack = strip.Color(0, 0, 0);
const uint32_t adaWhite = strip.Color(255, 255, 255);

// FastLED initialization
CRGB leds[NUM_LEDS];

void setup() {
  // Common
  delay(2000);

  // Adafruit setup
  strip.begin();

  // FastLED setup
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);

  // Common
  Serial.begin(57600);
}

void loop() {
  unsigned int adafruitMillis = adafruitLoop();
  unsigned int fastLedMillis = fastLedLoop();
  // Yes, this is ugly -- but it works every time
  Serial.print(adafruitMillis);
  Serial.print(",");
  Serial.println(fastLedMillis);
}

unsigned int adafruitLoop()
{
  long unsigned startMillis = millis();
  for (int whiteLed = 0; whiteLed < NUM_LEDS; whiteLed++) {
    strip.setPixelColor(whiteLed, adaWhite);
    strip.show();
    strip.setPixelColor(whiteLed, adaBlack);
  }
  return (unsigned int) millis() - startMillis;
}

unsigned int fastLedLoop()
{
  long unsigned startMillis = millis();
  for(int whiteLed = 0; whiteLed < NUM_LEDS; whiteLed++) {
    leds[whiteLed] = CRGB::White;
    FastLED.show();
    leds[whiteLed] = CRGB::Black;
  }
  return (unsigned int) millis() - startMillis;
}

The results are totally disastrous for FastLED (shown in red): FastLED is red, Adafruit's library in blue

Am I doing something wrong, or is FastLED winning on features, rather than on speed?

For the record, I did check whether the performance hit comes from setting the pixel values or from sending the data – FastLED is faster at setting the pixel values than Adafruit's library, but that doesn't matter because setting two pixel values takes 3 ms or less for the entire strip, regardless of the library. Sending the data to the strip takes most of the time, and that's where FastLED lags behind big time (900 ms compared to Adafruit's 200 ms).

1
  • 1
    Might I suggest a more realistic test-case. Like setting all pixels to white, then call show, then set all pixels black, and call show. Maybe repeat this like 100 times to get a bigger time-diffence value.
    – Gerben
    Commented Jan 9, 2018 at 16:43

2 Answers 2

12

You can't rely on the timing reported by millis when comparing FastLED and Adafruit's neopixel library. Writing out Neopixel data involves disabling interrupts, which is what the clock uses to advance. FastLED accounts for this and attempts to update the system clock time after writing out led data to account for the amount of time that interrupts were disabled, but the adafruit NeoPixel library doesn't. You need to use something else to compare timing.

(WS2812 data has a pretty strict data rate - 800khz, or about 30µs per rgb led)

(I should know, I wrote FastLED :)

3
  • (Also - when it comes to WS2812 data on AVR, the Fast in FastLED is also for the writing data - the tuned assembly output takes exactly 30µs per pixel (1.25µs per bit, or 20 clock cycles on a 16Mhz avr), and in that 30µs, not only is it writing out data, but it's also doing the scaling/dithering/color correction for the led data to write out)
    – rDg
    Commented Jan 16, 2018 at 1:42
  • Also - the rate throttler referred to above is to cap updating WS2812 leds at a rate no higher than 400Hz - WS2812 leds freak out if you update them more than 400 times/second.
    – rDg
    Commented Jan 16, 2018 at 1:44
  • Fair enough, that makes sense. I had noticed that in practice the speed difference was barely noticeable – certainly nothing like the 4x difference the millis() data seems to suggest. I was just too lazy to actually rig up a separate clock to measure real user time. Thank you for taking the time to clarify this. Having said that, I did manage to squeeze a bit more speed out of it by removing the throttler altogether – and the LEDs didn't get borked. Commented Jan 17, 2018 at 7:40
1

As I understand it, the Fast in FastLED isn't for sending the data, but for manipulating the array/data that holds the colors. The FastLED library contains many functions optimized for dealing with 8-bit unsigned integers for holding color values, including color addition, 8-bit scaling, partially-defined color palettes (for example, you define 8 waypoints in the palette, but can grab a color from the full 8-bit range and it interpolates on the fly using the fast 8-bit math.

Not just math, but also conversion to/from RGB and HSV realms, etc.

It supports pushing multiple strips at the same time (parallel) by writing to the whole PORT instead of just one pin of the 8-pin port, so if you split your strip into multiples, you can really make speed gains in writing to the LEDs.

3
  • Fair enough, I had ended up with the same impression – but the difference in performance for this basic test is so large I wanted to make sure I wasn't using it wrong. Thanks for taking the time to whet my appetite, though! 😊 Commented Jan 9, 2018 at 5:32
  • 1
    Your evaluation code is fine, but probably doesn't represent a real-world use case. I've commonly seen animation code structured to have a fixed rate for the FastLED.show() command, and you have to complete all your animation steps between each frame update. That is where the fast 8-bit color and math routines are useful. Commented Jan 9, 2018 at 13:20
  • That's a legitimate observation, but it depends on whether the library is throttling data bursts, or if what we're seeing is plain overhead. If it's throttling data it's all good, because all of my real-world scenario calculations will eat into the time it's currently idling. But if this is overhead then all of this is going to add up to the calculations, resulting in limited performance. I actually did track down a refresh rate throttler in the library, and hope to experiment a bit tonight. In case you're curious: github.com/FastLED/FastLED/blob/master/FastLED.cpp#L41 Commented Jan 9, 2018 at 13:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.