FastLED - addLeds with Non-Constant Pin Number

I have a project with several strings of NeoPixels, using the FastLED library. The pin numbers need to be configurable at run-time (set with a configuration file). But, apparently the addLeds templates do not allow this?

This line:

FastLED.addLeds<NEOPIXEL, pin>(Neo, numLEDs;

throws this error:

E:\Users\RayL\Documents\Arduino\Build\sketch\src\LEDLighting\LEDLighting.cpp:191:31: error: the value of 'pin' is not usable in a constant expression

     FastLED.addLeds<NEOPIXEL, pin>(Neo, numLEDs;

                                               ^

Surely there is SOME way to populate the LED array with a run-time-defined pin??? I’m not averse to modifying the library, if necessary, but I can’t even figure out which of the nine billion bloody templates in FastLED this line is invoking…

Regards,
Ray L.

I ran into that same problem yesterday while trying to use an array of pin numbers to declare multiple strips. My assumption was that the compiler needs a constant for the pin number in order to generate the appropriate assembly language, but did not take the time to verify that. I did notice that each pin used adds a significant amount of code, even when using the same leds array.

The pin number is a template all the way down to the FastPin class.
They then use template specialization for every single pin on every single architecture they support.
https://github.com/FastLED/FastLED/blob/8b31b643e42d8a53a3df9abc96bf45f00adf52df/platforms/avr/fastpin_avr.h#L52
This means that all pin registers and bit masks are resolved at compile time, which is much faster than using digitalWrite etc.
I assume that the authors had a good reason to do it like this, digitalWrite probably is too slow.

So in short, there is no way to make them run-time configurable, unless you completely redesign the library from scratch.

Pieter

Well, that sucks!

My primary reason for using FastLED is to be able to use HSV instead of RGB for the color representation. If it is truly not practical to have run-time assignment of pins, then I'll instead go back to the NeoPixel library, and just add my own HSV-to-RGB conversion to it.

Regards,
Ray L.

david_2018:
My assumption was that the compiler needs a constant for the pin number in order to generate the appropriate assembly language, but did not take the time to verify that.

Possibly. Maybe also to select proper code for bit-banging verses hardware support depending on the pin and board selection.

I just thought of something, there might be a way.

Use a dummy pin number (e.g. 255) and then specialize FastPin<255>, using the normal digitalWrite function.

I don’t have time to check it right now, but I think this should work. Whether it’s fast enough or not remains to be seen …

Here’s something I don’t understand… There are a limited number of pins I need to support, and I’m not tight on RAM, so perhaps I could just define multiple LED arrays, covering all the needed options, and just choose the appropriate one at run-time. I’ll give that a go…

Regards,
Ray L.

RayLivingston:
Here’s something I don’t understand… There are a limited number of pins I need to support, and I’m not tight on RAM, so perhaps I could just define multiple LED arrays, covering all the needed options, and just choose the appropriate one at run-time. I’ll give that a go…

Regards,
Ray L.

I like this better:

  switch (pin) {
    case 3:
      FastLED.addLeds<NEOPIXEL, 3>(Neo, numLEDs);
      break;

    case 4:
      FastLED.addLeds<NEOPIXEL, 4>(Neo, numLEDs);
      break;

    case 5:
      FastLED.addLeds<NEOPIXEL, 5>(Neo, numLEDs);
      break;

    default:
      Serial.println("Unsupported Pin");
      break;
  }

gfvalvo:
I like this better:

+1

That's definitely the best (and easiest) solution if you only have to support a handful of pins.

If you need more pins or if you don't have enough memory for all those templates, you could use the template specialization approach I mentioned earlier, but I wouldn't recommend it unless there's really no other way.

The memory footprint appears to be near zero. You can define multiple strings of LEDs, on multiple pins, but they all must map to a single array:

https://github.com/FastLED/FastLED/blob/master/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino

This seems to work fine, but the memory usage I see makes no sense. Here is the code:

void setup(void)
{
    Serial.begin(115200);
    Serial.printf("Starting...\n\n");


    delay(2000);

    Serial.printf("freeMem0=%d\n", freeMemory());

    CRGB LEDs[30];

    Serial.printf("freeMem1=%d\n", freeMemory());
    FastLED.addLeds<NEOPIXEL, 4>(LEDs, 0, 10);
    FastLED.addLeds<NEOPIXEL, 3>(LEDs, 10, 10);
    FastLED.addLeds<NEOPIXEL, 2>(LEDs, 20, 10);
    Serial.printf("freeMem2=%d\n", freeMemory());


    for (int i=20; i<30; i++)
    {
        LEDs[i] = CRGB(100, 0, 0);
    }
    FastLED.show();   
    delay(2000);

    for (int i=23; i<30; i++)
    {
        LEDs[i] = CRGB(0, 100, 0);
    }
    FastLED.show();   
    delay(2000);

    for (int i=27; i<30; i++)
    {
        LEDs[i] = CRGB(0, 0, 100);
    }
    FastLED.show();   

    Serial.printf("freeMem3=%d\n", freeMemory());
    delay(2000);

    while(1);
}

But here’s the output:

Starting...

freeMem0=1312
freeMem1=1306
freeMem2=1316
freeMem3=1316

Memory use goes DOWN?? Huh?

Regards,
Ray L.

Given sufficient memory, defining for every pin you might use, reusing the same buffer array, is probably the easiest approach. You then use the command
FastLED[i].showLeds(Brightness) instead of FastLED.show(), where i specifies which define statement you are referring to, and Brightness is the strip brightness.

gfvalvo:
I like this better:

  switch (pin) {

case 3:
     FastLED.addLeds<NEOPIXEL, 3>(Neo, numLEDs);
     break;

case 4:
     FastLED.addLeds<NEOPIXEL, 4>(Neo, numLEDs);
     break;

case 5:
     FastLED.addLeds<NEOPIXEL, 5>(Neo, numLEDs);
     break;

default:
     Serial.println(“Unsupported Pin”);
     break;
 }

Looks like that would work, it appears FastLED is generating the code needed for all the pins, every additional FastLED.addLeds line appears to be using 1246 bytes of program memory on an UNO.

RayLivingston:
The memory footprint appears to be near zero.

[...]

This seems to work fine, but the memory usage I see makes no sense. Here is the code:

The FastLED library doesn't actually allocate any dynamic memory, so you won't see any significant change from the freeMemory() calls.
If you look at the addLeds source, you'll see that they all return a reference to a controller object that exists in static memory.

If you look at the program storage space and the dynamic memory usage reported by the Arduino Builder, you should see a significant increase in memory usage when adding another addLeds call.