I am hitting the wall when creating custom library

I created the custom 7 seg display with WS2812B leds where 14 leds make a display 2 leds per each segment. Those displays can be daisychained. To simplyfy the use of such display module I wanted to create the library which gives two methods. To display a given disgit on the specific display in display chain. And also lit a given segment on given display. I created .h and .cpp files. Here they are:

#include "Custom7SegD.h"

// Constructor
Custom7SegD::Custom7SegD(int numDisplays, int ledPin, int brightness)
    : numDisplays(numDisplays), numLeds(numDisplays * 14) {
    leds = new CRGB[numLeds];
    FastLED.addLeds<WS2812B, GRB>(leds, numLeds, ledPin).setCorrection(TypicalLEDStrip);
    FastLED.setBrightness(brightness);
}

// Function to display a digit
void Custom7SegD::displayDigit(int displayNum, int digit, CRGB color, int brightness) {
    // Calculate the starting LED index for the specified display
    int startIdx = (displayNum - 1) * 14;
    // Turn off all LEDs first
    for (int i = 0; i < 14; i++) {
        leds[startIdx + i] = CRGB::Black;
    }
    // Light up the LEDs for the specified digit
    for (int segment = 0; segment < 14; segment++) {
        if (digitStates[digit][segment] == 1) {
            leds[startIdx + segment] = color;
        }
    }
    FastLED.setBrightness(brightness);
    FastLED.show();
}

// Function to light up a specific segment
void Custom7SegD::lightSegment(int displayNum, char segment, CRGB color, int brightness) {
    // Define segment to LED mapping
    int segmentMapping[7][2] = {
        {0, 1}, // Segment A
        {2, 3}, // Segment B
        {4, 5}, // Segment C
        {6, 7}, // Segment D
        {8, 9}, // Segment E
        {10, 11}, // Segment F
        {12, 13}  // Segment G
    };

    // Calculate the starting LED index for the specified display
    int startIdx = (displayNum - 1) * 14;

    // Light up the LEDs for the specified segment
    if (segment >= 'A' && segment <= 'G') {
        int segIdx = segment - 'A';
        for (int i = segmentMapping[segIdx][0]; i <= segmentMapping[segIdx][1]; i++) {
            leds[startIdx + i] = color;
        }
        FastLED.setBrightness(brightness);
        FastLED.show();
    }
}

#ifndef CUSTOM7SEGD_H
#define CUSTOM7SEGD_H

#include <FastLED.h>

class Custom7SegD {
public:
    // Constructor
    Custom7SegD(int numDisplays, int ledPin, int brightness);

    // Function to display a digit on a specific display
    void displayDigit(int displayNum, int digit, CRGB color, int brightness);

    // Function to light a specific segment on a specific display
    void lightSegment(int displayNum, char segment, CRGB color, int brightness);

private:
    int numDisplays;
    int numLeds;
    int initialBrightness;
    CRGB *leds;
    const byte segmentMap[7][2] = {
        {3, 4},   // A
        {5, 6},   // B
        {12, 13}, // C
        {0, 1},   // D
        {7, 8},   // E
        {9, 10},  // F
        {2, 11}   // G
    };
    byte digitStates[10][14] = {
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1}, // 0
        {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1}, // 1
        {1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, // 2
        {1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, // 3
        {0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1}, // 4
        {1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1}, // 5
        {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1}, // 6
        {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1}, // 7
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 8
        {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}  // 9
    };
};

#endif

I installed the library in Arduino IDE. But when I try to run this sample program

#include <Custom7SegD.h>  // Include your custom library

#define LED_PIN 5         // Pin where the WS2812B LEDs are connected
#define NUM_DISPLAYS 1    // Number of 7-segment displays in the chain

// Create an instance of the Custom7SegD class with 1 display, connected to LED_PIN, and initial brightness of 150
Custom7SegD myDisplay(NUM_DISPLAYS, LED_PIN, 150);

void setup() {
  // Nothing needed here since the brightness is set during initialization
}

void loop() {
  // Loop to count from 0 to 9
  for (int digit = 0; digit <= 9; digit++) {
    myDisplay.displayDigit(1, digit, CRGB::Magenta, 150);  // Display digit on the first (and only) display with brightness 150
    delay(1000); // Wait for 1 second before moving to the next digit
  }
}

I am getting this error message


In file included from C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/FastLED.h:58:0,

                 from C:\Users\11\Documents\Arduino\libraries\Custom7SegD\Custom7SegD.h:4,

                 from C:\Users\11\Documents\Arduino\libraries\Custom7SegD\Custom7SegD.cpp:1:

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/fastpin.h: In instantiation of 'class FastPin<66>':

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/platforms/avr/clockless_trinket.h:107:49:   required from 'class ClocklessController<66, 4, 10, 6, (EOrder)10, 0, false, 10>'

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/chipsets.h:509:7:   required from 'class WS2812Controller800Khz<66, (EOrder)10>'

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/FastLED.h:132:52:   required from 'class WS2812B<66, (EOrder)10>'

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/FastLED.h:359:33:   required from 'static CLEDController& CFastLED::addLeds(CRGB*, int, int) [with CHIPSET = WS2812B; unsigned char DATA_PIN = 66]'

C:\Users\11\Documents\Arduino\libraries\Custom7SegD\Custom7SegD.cpp:7:56:   required from here

C:\Users\11\Documents\Arduino\libraries\FastLED-master\src/fastpin.h:261:2: error: static assertion failed: Invalid pin specified

  static_assert(validpin(), "Invalid pin specified");

  ^~~~~~~~~~~~~

exit status 1

Error compiling for board Arduino Uno.



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I am clearly doing something wrong passing the pin to my library which is then in turn passed to fastled library. I have no idea where this pin 66 is coming from.
When I write a sketch using fastled library I am very often passing the pin at initialisation using the variable so it is possible in this case.
Any idea how can I fix it?

The data pin must be defined in the template parameters, not in the addLeds parameters

https://fastled.io/docs/class_w_s2812_controller800_khz.html

FastLED.addLeds<WS2812B, ledPin, GRB>(leds, numLeds).setCorrection(TypicalLEDStrip);

I know. I tried various things . But this is not the fix. If I have FastLED.addLeds<LED_TYPE, ledPin, GRB>(leds, numLeds).setCorrection(TypicalLEDStrip); the problem is the same

Yes, the pin must be a compile-time constant. Maybe add a template parameter to your class :slight_smile:

template<int PIN>
class Custom7SegD {
public:
    // Constructor
    Custom7SegD(int numDisplays, int brightness);
    ...


// Constructor
template<int PIN>
Custom7SegD<PIN>::Custom7SegD(int numDisplays, int brightness)
    : numDisplays(numDisplays), numLeds(numDisplays * 14) {
    leds = new CRGB[numLeds];
    FastLED.addLeds<WS2812B, PIN, GRB>(leds, numLeds).setCorrection(TypicalLEDStrip);
   ...



Custom7SegD<LED_PIN> myDisplay(NUM_DISPLAYS, 150);
...

Also you should not use any FastLED function ( addLeds etc ) in your constructor. Add a begin() method to your class and call it in setup(), when the hardware is ready.

I actually moved FastLed initialisation out of the library Part and then it works.
I really wanted to make all of it behind the seens:( Not sure I understand the template part. For me that looks like hardcoding the pin and I wanted to pass the pin with the variable so you have an option of using different pins to connect the leds without the need of updating the library

#define LED_PIN 5

Custom7SegD<LED_PIN> myDisplay(NUM_DISPLAYS, 150);

The class template allow to choose the pin without modifying the class

Here is an example : t1292054 - Wokwi ESP32, STM32, Arduino Simulator

I think the Neopixel library from Adafruit is better suited for adding features ontop of it. Here you don't deal with a global object.

You cannot use a variable in template initialization. Your pin must be a constant or a macro.

Why is this template line used several times throughout constructor code

It's not. It's used once in the class declaration and once in the constructor declaration. I'm thinking it may not need to be. If the compile-time PIN number is only needed in the constructor, then the template wouldn't be needed before the class declaration. If PIN is used in multiple places within the class, then it should only be needed in the class declaration and not the constructor declaration.

A 7 segment library on top of the Adafruit library already exist,
let me share mine:
https://werner.rothschopf.net/202005_arduino_neopixel_display_en.htm