Go Down

Topic: Binary very large when using FastLED (Read 388 times) previous topic - next topic

Shuzz

Hi all!

I'm currently facing a problem when using the FastLED library to control a few P9823 based LEDs.
Just calling the "addLED" function causes my binary to grow to well over 3k Flash size, with nothing else in the sketch.

When I'm adding a few effects to the sketch, I'm quickly hitting the ceiling of 8k flash on my Tiny85.

Now, I can't easily switch to a larger controller - therefore I'm looking for alternatives to FastLED that will provide me with a smaller compiled binary.

Or, alternatively, I'm looking for a way to reduce the compiled binary size so I can fit as much animation code as possible into the sketch.

AWOL

There seems to be something missing from your post.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

Shuzz

OK, I'm not 100% sure what you mean exactly, but I noticed that I did, in fact, not ask a specific question.
Also, I did not post code since it would be trivial, but here you go anyway:

Code: [Select]

#include <FastLED.h>

#define NUM_LEDS 7
#define DATA_PIN 4

CRGB leds[NUM_LEDS];

void setup() {
//  FastLED.addLeds<WS2811, DATA_PIN>(leds, NUM_LEDS);

}

void loop() {
  // put your main code here, to run repeatedly:

}


This code will compile to 396 bytes using the Spence Kondes ATTinyCore.
Now, if you uncomment the call to FastLED.addLeds(...) in the setup() function, the binary size jumps to 2664 bytes, which means that FastLED weighs in at a little less than 2.3kB.

Does anyone know of a way to reduce that amount?
Some flags for the compiler? Maybe some #define that might help?

Alternatively, can somebody please suggest an alternative library to drive P9823 based LEDs with that may result in smaller binary sizes?


Thanks and best regards,

Shuzz

septillion

#3
Jan 23, 2019, 11:43 am Last Edit: Jan 23, 2019, 11:44 am by septillion
I doubt it. You quite need a bit when using NeoPixels. And the moment you call .addLeds() the compiler sees everything you want to use. Including stuff from the core you only start to use after calling .addLeds(). And a ATtiny is called that with a reason :) FastLed is a pretty damn efficient library.
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Shuzz

#4
Jan 23, 2019, 04:34 pm Last Edit: Jan 23, 2019, 04:46 pm by Shuzz
Yes, that's just my point, @septillion.

Problem is, I don't really use that much of the library - at least I think I don't. All that fancy stuff that is present there (e.g. global brightness control, max power limitation, ...) is not used by me.

The only feature I really use is the rainbow hsv2rgb conversion.

That's why I thought "Hmmm, maybe we can leave some of that out..."
If that's not the case I'll have to try to find another solution.

I checked out Adafruit's NeoPixel lib and reproduced the code snippet above with it (using the appropriate commands to setup a string of a few LEDs and not doing anything else) and the binary size reduced to significantly under 2k - which is a huge win in my books.
I haven't been able to test it with the target hardware, yet, but according to documentation on the net, it should work with my P9823 LEDs. Will try tonight or tomorrow and post feedback here.

Do you happen to know about other libraries that would support ws2811 leds?

septillion

Problem is, I don't really use that much of the library - at least I think I don't.
There's your problem ;) Stuff you don't use isn't included by the linker so apparently you DO use it ;)

Main difference with the Adafruit library, lack of HSV.... Which indeed probably saves quite a bit.... Because other than that the Adafruit library isn't better written.
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Shuzz

Well, the HSV stuff is exactly the reson why I used FastLED, especially their Rainbow-HSV mode really does make prettier color fades than the code you'd find at e.g. Wikipedia.

Nevertheless, the Adafruit Lib still weighs in at several hundres bytes less than FastLED in the example I outlined in my last post.

I'll try and see if I can just rip out the HSV calculations from FastLED (which will probably be difficult) and use them standalone while accessing the LEDs with Adafruit and see where that takes me.

All libs seem to be optimized for speed, i.e. controlling as many LEDs as possible with as little compute overhead as possible, thus needing more space.
My use-case is just the opposite: I only want to control seven LEDs at framerates of at most 60Hz or so, therefore I have plenty of cycles to waste if need be.
So the libs are not bad or at fault - they're just not optimized for the parameters of my particular use case.

I probably won't be able to really dig into this for the next few days, but I'll post an update if/when I have tangible results - even if they're not the results I want... ;-)

septillion

60Hz is already blazing fast for Neopixels... So I doubt you have any cycles to wast...

And using the HSV part is pretty easy, it's a separate class.

Would be interesting to see MCVE's of
- FastLed RGB
- AdaFruit RGB
- FastLed HSV
- Adafruit + FastLed HCS

And the sizes you get :)
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Shuzz

Why is 60Hz blazing fast?

I think I'm missing something here...

I only use seven Neopixels, that's 3*8*7 Bits of data per cycle.
At 60Hz, that would be around 10kBit per second.
Since the neopixels are running at 800kBit/s, there should be plenty of headroom in terms of cycles that I can waste, right? Even assuming that the data needs to be prepared for sending in some way...

What am I missing?

I'll try to come up with MCVEs, but as I said, I'll likely be busy with other things the next few days.

Shuzz

Hello again!

Some deadlines shifted and I found myself with a bit of free time on my hands - so I went ahead and wrote that I believe to be MCVEs.
I tried to keep the code as uniform as possible between the four sketches, but naturally there will be small discrepancies.

Code: ("FastLED RGB") [Select]

#include <FastLED.h>

#define DATA_PIN 4
#define NUM_LEDS 7

// Little under 60Hz
#define FRAME_MS 17

CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.show();
}



void loop() {

  static uint32_t ts = 0;
  static int anim_counter = 0;
  uint32_t now = millis();
  if(now > ts){
    ts = now + FRAME_MS;
    CRGB val;
    switch((anim_counter/256)){
      case 0: // RED
        val = CRGB(anim_counter % 255, 0, 0);
      break;
      case 1: // GREEN
        val = CRGB(0, anim_counter % 255, 0);
      break;
      case 2: // BLUE
        val = CRGB(0, 0, anim_counter % 255);
      break;
    }
    if(++anim_counter >= 768)anim_counter = 0;
    for(int i = 0; i < NUM_LEDS; i++){
      leds[i] = val;
    }
    FastLED.show();
  }

}


Code: ("FastLED HSV") [Select]

#include <FastLED.h>

#define DATA_PIN 4
#define NUM_LEDS 7

// Little under 60Hz
#define FRAME_MS 17

CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
  FastLED.show();
}



void loop() {

  static uint32_t ts = 0;
  static int anim_counter = 0;
  uint32_t now = millis();
  if(now > ts){
    ts = now + FRAME_MS;
    CHSV val;
    switch((anim_counter/256)){
      case 0: // RED
        val = CHSV(0, 255, anim_counter % 255);
      break;
      case 1: // GREEN
        val = CHSV(96, 255, anim_counter % 255);
      break;
      case 2: // BLUE
        val = CHSV(160, 255, anim_counter % 255);
      break;
    }
    if(++anim_counter >= 768)anim_counter = 0;
    for(int i = 0; i < NUM_LEDS; i++){
      leds[i] = val;
    }
    FastLED.show();
  }

}


Code: ("Adafruit RGB") [Select]

#include <Adafruit_NeoPixel.h>

#define DATA_PIN 4
#define NUM_LEDS 7

// Little under 60Hz
#define FRAME_MS 17

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  strip.begin();
//  strip.setBrightness(50);
  strip.show();

}

void loop() {
  static uint32_t ts = 0;
  static int anim_counter = 0;
  uint32_t now = millis();
  if(now > ts){
    ts = now + FRAME_MS;
    byte red = 0;
    byte green = 0;
    byte blue = 0;
    switch((anim_counter/256)){
      case 0: // RED
        red = anim_counter % 255;
      break;
      case 1: // GREEN
        green = anim_counter % 255;
      break;
      case 2: // BLUE
        blue = anim_counter % 255;
      break;
    }
    if(++anim_counter >= 768)anim_counter = 0;
    for(int i = 0; i < NUM_LEDS; i++){
      strip.setPixelColor(i, red, green, blue);
    }
    strip.show();
  }
}


Code: ("Adafruit HSV") [Select]

#include <Adafruit_NeoPixel.h>
#include <hsv2rgb.h>

#define DATA_PIN 4
#define NUM_LEDS 7

// Little under 60Hz
#define FRAME_MS 17

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  strip.begin();
//  strip.setBrightness(50);
  strip.show();

}

void loop() {
  static uint32_t ts = 0;
  static int anim_counter = 0;
  uint32_t now = millis();
  if(now > ts){
    ts = now + FRAME_MS;
    CRGB val;
    switch((anim_counter/256)){
      case 0: // RED
        val = CHSV(0, 255, anim_counter % 255);
      break;
      case 1: // GREEN
        val = CHSV(96, 255, anim_counter % 255);
      break;
      case 2: // BLUE
        val = CHSV(160, 255, anim_counter % 255);
      break;
    }
    if(++anim_counter >= 768)anim_counter = 0;
    for(int i = 0; i < NUM_LEDS; i++){
      strip.setPixelColor(i, val.red, val.green, val.blue);
    }
    strip.show();
  }
}



All four sketches were compiled using Arduino IDE 1.8.3 on Win10.
I compiled using Spence Konde's ATTinyCore v1.2.2, Neopixel v1.1.8 and FastLED v3.2.1.

The sketches expects a string of seven (configurable) Neopixels and will display a simple color chase where Red, Green and Blue will fade from black to full brightness consecutively. It runs at around 60Hz, but I didn't check how many cycles are going to waste. Might do that sometime...

Here's the results:

FastLED RGB: 3560 byte flash
FastLED HSV: 3894 byte flash

Adafruit RGB: 2796 byte flash
Adafruit HSV: 3200 byte flash

(Note: Adafruit HSV uses the hsv2rgb lib from FastLED since Adafruit's lib does not support HSV ootb.)

Adafruit comes out 764 bytes ahead of FastLED in RGB mode and 694 bytes in HSV mode.

The difference between RGB and HSV modes is 334 bytes for FastLED and 404 bytes for Adafruit.
This discrepancy is probably due to the fact that the CRGB class is used in both sketches for FastLED, but only introduced into the sketch in HSV mode for Adafruit, thus increasing the binary size by a larger margin for that case.

I think I will try to refactor the hsv2rgb code from FastLED into the Adafruit lib and leave out the CRGB/CHSV classes since they're not really needed in that case.

But I will definitely switch this project over to using Adafruit in order to save the 700 bytes of flash because it really is a lot on a Tiny85...


Cheers,

Shuzz

Go Up