Is FastLED / WS2812Serial Broken in Teensyduino 1.59?

I don't think WS2812Serial is broken as the sketch in this thread still runs fine (just tried).
But indeed FastLED_Cylon.ino does not run now.
What version FastLED library are you using? Here I'm on version 3.6.0. The version that comes with Teensyduino 1.59 is 3.4.0.
I suspect that WS2812Serial & FastLED do not cooperate anymore.

Paul

edit: FastLED V3.4.0 and WS2812Serial also do not cooperate.
 
Last edited:
Paul,
I've noted the failure with FastLED v3.6.0 and and 3.4.0.

The working Arduino 1.8.15 / Teensyduino 1.54 combination uses FastLED 3.3.0.

I've narrowed the problem down to this call in FastLED.cpp:
C++:
pLed->init();

In fact, it seems any call to a virtual function declared in the CLEDController class and implemented in ws2812serial_controller.h seems fails even though the inheritance chain CWS2812SerialController --> CPixelLEDController --> CLEDController should allow it.

However, adding a call to init() does work here (I added a print inside the init() function in ws2812serial_controller.h to check if it's called). This call to init() works in FastLED.h:
C++:
#ifdef USE_WS2812SERIAL
    template<SWS2812 CHIPSET, int DATA_PIN, EOrder RGB_ORDER>
    static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
    {
        Serial.println("GFV - Constructing Controller");
        static CWS2812SerialController<DATA_PIN,RGB_ORDER> controller;
        controller.init();
        Serial.println("GFV - Calling addLeds");
        return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset);
        Serial.println("GFV - Back from addLeds");
    }
#endif

But it never returns from the call to addLed that follows. Very odd.
 
Last edited:
@Paul,
So, it’s looking to me like it’s not just WS2812Serial that’s broken with Teensyduino 1.59, but all of FastLED. I tried the most basic library example trying both WS2812Serial and standard ‘NEOPIXEL’ types in the initialization. Nothing works. I tried FastLED versions v3.6, v3.5, v3.4, and v3.3.3 … all failed.

In every case, the failure happens on the call to FastLED.addLeds() in the initialization code. It never returns. That’s a templated function in FastLED.h with the template parameters determined by LED Type, Connection Pin, etc. Each of these templated functions in turn calls the same function in FastLED.cpp:

Code:
CLEDController &CFastLED::addLeds(CLEDController *pLed,
                                       struct CRGB *data,
                                       int nLedsOrOffset, int nLedsIfOffset) {
    int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
    int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;


    pLed->init();
    pLed->setLeds(data + nOffset, nLeds);
    FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
    return *pLed;
}

And the failure ALWAYS happens with the on the call:
Code:
pLed->init();
This is a call using a pointer to a Base class (polymorphism), so it requires use of VTABLES, etc.

I'm starting to think the problem lies with the fact that Teensyduino 1.59 uses C++17 and that somehow causes a problem with FastLED. However, I'm not good enough of a Toolchain guy to be able to test this theory.

So far, I've also been unable to reproduce the behavior in simpler polymorphic code with templated functions. It's only happening with FastLED.

Wondering if anyone else has had this problem or any ideas how to solve it.

PS - I've logged the issue on GitHub:
https://github.com/PaulStoffregen/cores/issues/736
 
I'm running this program on a Teensy 4.0, programmed by Arduino 1.8.19 + Teensyduino 1.59.

Code:
#include <FastLED.h>

#define NUM_LEDS 8
#define DATA_PIN 1
CRGB leds[NUM_LEDS];

#define RED    0x160000
#define GREEN  0x001600
#define BLUE   0x000016
#define YELLOW 0x101400
#define PINK   0x120009
#define ORANGE 0x100400
#define WHITE  0x101010

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

void loop() {
  // change all the LEDs in 1.5 seconds
  int microsec = 1500000 / NUM_LEDS;

  colorWipe(RED, microsec);
  colorWipe(GREEN, microsec);
  colorWipe(BLUE, microsec);
  colorWipe(YELLOW, microsec);
  colorWipe(PINK, microsec);
  colorWipe(ORANGE, microsec);
  colorWipe(WHITE, microsec);
}

void colorWipe(int color, int wait) {
  for (int i=0; i < NUM_LEDS; i++) {
    leds[i] = color;
    FastLED.show();
    delayMicroseconds(wait);
  }
}

It seems to be working fine. Here's a quick photo.

1711196953730.png


As you can see, my test hardware has 8 LEDs connected to pin 1. I can also quickly switch it to pin 6 or pin 8.

Any chance you could compose a small program but complete program which demonstrates the problem by driving 8 LEDs on pin 1?
 
I also tried running the WS2812Serial library FastLED_Cylon example. It defaults to pin 1 and 64 LEDs, so I ran it exactly as-is.

I see it animating on the 8 LEDs and then they fade. I'm guessing the animation travels to the other 56 LEDs I don't have connected. It's definitely doing *something* on the LEDs. Here's another photo (sorry it's a big dark... my camera adjusts to the brighter LED light and I just snapped a quick photo without messing with the camera settings)

1711197619401.png
 
I'm running this program on a Teensy 4.0, programmed by Arduino 1.8.19 + Teensyduino 1.59.
Hi Paul, thanks for the followup.
Just to be on the safe side, I downloaded a fresh (portable) installation of Arduino 1.8.19 and Teensyduino 1.59. I then ran your exact code from Post #6 except that I added two debug prints around the call to ‘FastLED.addLeds<WS2812, DATA_PIN>(leds, NUM_LEDS);’. See below.

I ran this on a Teensy 3.6. The first debug print appeared but the second one did not, indicating that control never returned from the function call. If I comment out the call to ‘FastLED.addLeds<WS2812, DATA_PIN>(leds, NUM_LEDS);’, both debug prints appeared.

I repeated the test and got the same result with a new Teensy 3.2.

I did not have an actual LED strip connected, but I think the debug print results are pretty conclusive that something is wrong. The tests worked correctly with Arduino 1.8.15 / Teensyduino 1.54.

Thanks again.

C++:
#include <FastLED.h>

#define NUM_LEDS 8
#define DATA_PIN 1
CRGB leds[NUM_LEDS];

#define RED    0x160000
#define GREEN  0x001600
#define BLUE   0x000016
#define YELLOW 0x101400
#define PINK   0x120009
#define ORANGE 0x100400
#define WHITE  0x101010

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("Calling addLEDS");
  FastLED.addLeds<WS2812, DATA_PIN>(leds, NUM_LEDS);
  Serial.println("Returned from addLEDS");
}

void loop() {
  // change all the LEDs in 1.5 seconds
  int microsec = 1500000 / NUM_LEDS;

  colorWipe(RED, microsec);
  colorWipe(GREEN, microsec);
  colorWipe(BLUE, microsec);
  colorWipe(YELLOW, microsec);
  colorWipe(PINK, microsec);
  colorWipe(ORANGE, microsec);
  colorWipe(WHITE, microsec);
}

void colorWipe(int color, int wait) {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = color;
    FastLED.show();
    delayMicroseconds(wait);
  }
}
 
Until now I was running a huge project with WS2811serial and FastLED 3.6.0 on Arduino IDE 1.8.19 and Teensyduino 1.58. Teensy 4.0.

Updated now to Teensyduino 1.59. FastLED version 3.6.0 is used as before. No problems here.

I will check with the example on a Teensy 4.0 and a Teensy 3.2. Maybe the problem occurs only with Teensy 3.2 and Teensy 3.6?

... update:
can confirm:
Running on Teensy 4.0.
Hanging on Teensy 3.2.
 
Last edited:
Additional info: with Teensyduino 1.58.2, the sketch from message #6 runs fine on both Teensy 4.0 and Teensy 3.2.
I tried with 2 versions of FastLED: 3.4.0 and 3.6.0, same results.

Paul
 
Additional info: with Teensyduino 1.58.2, the sketch from message #6 runs fine on both Teensy 4.0 and Teensy 3.2.
I tried with 2 versions of FastLED: 3.4.0 and 3.6.0, same results.

Paul
Thanks Paul. Where do I download previous versions of the Teensyduino installer?
All I can find is v1.59.
 
Using Arduino IDE 2.3.2, I'm using the Boards Manager to switch between Teensyduino versions:

1711206268306.png


Paul

PS: I ran into an issue when when updating from 1.58.2 to 1.59:
exec: "C:\\Users\\Paul\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-tools\\1.59.0/precompile_helper": file does not exist
Compilation error: exec: "C:\\Users\\Paul\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-tools\\1.59.0/precompile_helper": file does not exist
Need to look into that now...
Update on the precompile_helper": file does not exist issue: had to [1] close the Arduino IDE, [2] delete folder C:\Users\Paul\AppData\Local\Arduino15, [3] restart the Arduino IDE, [4] install Teensyduino 1.59 from the Boards Manager.
 
Last edited:
Update on the precompile_helper": file does not exist issue: had to [1] close the Arduino IDE, [2] delete folder C:\Users\Paul\AppData\Local\Arduino15, [3] restart the Arduino IDE, [4] install Teensyduino 1.59 from the Boards Manager.

Yes, this problem usually happens on Windows if Teensy Loader is still running when uninstalling the older Teensy files or using an older IDE. Windows does not allow the EXE file to be deleted. Arduino IDE does not handle the situation well.

New versions of Teensy software and new IDE run a pre-uninstall script which causes Teensy Loader to close, so the uninstall can succeed.

But even if you have the new IDE, if 1.58.1 was previously installed, versions older than the ones current in the drop-down list won't automatically shut down Teensy Loader before uninstall. So you can still get this problem one last time. But as long as you keep using the new IDE, only the updated copies with the pre-uninstall script can be installed, so this shouldn't be able to happen again. If you uninstall, or change versions (which is really an uninstall followed by an install), if you keep an eye on the Teensy Loader window, you'll be able to notice it automatically disappears in the middle of the install process. That's the new pre-uninstall script at work, so Windows allows the old files to be deleted.
 
Confirm, I'm able to reproduce the problem on Teensy 3.2.

Why it's broken on Teensy 3 but seems to work fine on Teensy 4 is still a mystery...
 
Yes, this problem usually happens on Windows if Teensy Loader is still running when uninstalling the older Teensy files or using an older IDE. Windows does not allow the EXE file to be deleted. Arduino IDE does not handle the situation well.

New versions of Teensy software and new IDE run a pre-uninstall script which causes Teensy Loader to close, so the uninstall can succeed.

But even if you have the new IDE, if 1.58.1 was previously installed, versions older than the ones current in the drop-down list won't automatically shut down Teensy Loader before uninstall. So you can still get this problem one last time. But as long as you keep using the new IDE, only the updated copies with the pre-uninstall script can be installed, so this shouldn't be able to happen again. If you uninstall, or change versions (which is really an uninstall followed by an install), if you keep an eye on the Teensy Loader window, you'll be able to notice it automatically disappears in the middle of the install process. That's the new pre-uninstall script at work, so Windows allows the old files to be deleted.

PaulStoffregen,​

I really didn't understand all the minutiae of what installs, uninstalls, etc. But, I assume none of it is a work around for this problem with Teensy 3.x, Correct?
 
I spent some time try to track this problem down. So far unsuccessful, but here's what I've learned so far.

Everything seems to stop at line 39 in FastLED.cpp, specifically calling pLed->init()

Code:
CLEDController &CFastLED::addLeds(CLEDController *pLed,
                                  struct CRGB *data,
                                  int nLedsOrOffset, int nLedsIfOffset) {
    int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
    int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;

    pLed->init();
    pLed->setLeds(data + nOffset, nLeds);
    FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
    return *pLed;
}

I added a Serial.printf right before that call, like this:

Code:
        Serial.printf("addLeds, pLed = %08X\n", (int)(pLed));
        pLed->init();

I'm pretty sure this is supposed to call the init() function at line 22 in src/platforms/arm/k20/clockless_arm_k20.h. But if I put Serial.print stuff inside that init() function, nothing prints.

To check this really is the place, I added a constructor which prints the instance address.

Code:
public:
        ClocklessController() {
                Serial.printf("ClocklessController ctor, this = %08X\n", (int)this);
        }

        virtual void init() {
                Serial.println("ClocklessController init"); while (1) ;
                FastPin<DATA_PIN>::setOutput();
                mPinMask = FastPin<DATA_PIN>::mask();
                mPort = FastPin<DATA_PIN>::port();
        }

When I run this, indeed the constructor prints the address, and the print just before calling init() shows the pointer is to the same address.

Code:
ClocklessController ctor, this = 1FFF8EB0
addLeds, pLed = 1FFF8EB0

So basically, I'm stuck. I just don't understand why init() isn't being called. There's a *lot* of C++ template stuff going on here, but the same stuff is done on the Teensy 4 version with works. So far, I just can't understand why init() doesn't run and where we're going so wrong.

Maybe someone with better C++ knowledge might be able to see what's wrong?
 
Everything seems to stop at line 39 in FastLED.cpp, specifically calling pLed->init()
Paul, I came to the exact same conclusion --- Post #4 in this Thread

It's a call to a virtual function that's (overridden in a derived class) using a pointer to a base class. I've tried several times to recreate this behavior outside of FastLED using polymorphic function calls like this, templates, etc. But, those tests have worked perfectly every time ... unusually, that's bad news in this case :(

Would it be possible to try this with Teensyduino 1.59 but an older version of C++? Perhaps C++11 then C++14?

Other than that, I too am out of ideas.
 
Given init() is a virtual function, maybe try printing its address to see where it's pointing (just before calling it) - may require a bit of gcc-specific hackery since taking the address of a virtual function isn't really defined behaviour... something like this iirc:
Code:
void (CLEDController::*init_ptr)() = &CLEDController::init; // get vtable offset for init function
Serial.printf("Init address: %p\n", (void*)(pLed->*init_ptr)); // look up function in vtable using offset
 
Given init() is a virtual function, maybe try printing its address to see where it's pointing (just before calling it)
I did try that. The it was pointing to the function as implemented in the derived class ... just like I would have expected.
 
I tried diving into the assembly listing. Here's the generated code.

Code:
        pLed->init();
     e8e:       6823            ldr     r3, [r4, #0]
     e90:       4620            mov     r0, r4
     e92:       689b            ldr     r3, [r3, #8]
     e94:       4798            blx     r3

From earlier, r4 is the "pLed" pointer. The first instruction dereferences the pointer, so r3 has the address of the CLEDController class we'll be calling. The second instruction I believe it initializing the "this" pointer. Why the compiler didn't just read it into r0 in the first place is beyond me. Anyway, my understanding of the 3rd instruction is looking up the "init" function in the class vtable. Then of course the 4th instruction calls the function.

I tried adding some code to dereference pLed and then read whatever is in memory 8 bytes later.

Code:
CLEDController &CFastLED::addLeds(CLEDController *pLed,
                                          struct CRGB *data,
                                          int nLedsOrOffset, int nLedsIfOffset) {
        int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
        int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;

        uint32_t Led = *(uint32_t *)pLed;
        uint32_t init = *(uint32_t *)(Led + 8);
        Serial.printf("addLeds, pLed = %08X, Led = %08X, init = %08X\n", (int)(pLed), Led, init);
        pLed->init();
        pLed->setLeds(data + nOffset, nLeds);
        FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
        return *pLed;
}

It ends up printing this!!!

Code:
addLeds, pLed = 1FFF8EB0, Led = 00000000, init = 0000122D

So my best guess is we may have some subtle linker or startup problem where the vtable isn't initialized?

Looking at a memory dump, indeed address 00000008 is an unused entry in the ARM exception vector table, and in the assembly listing address 0000122C is the start of the unused_isr function. So we end up inside an infinite loop that does nothing, but not actually as interrupt state. Still the result is the same, nothing else runs.

My best guess is we're supposed to have vtable or some other initialized data at 1FFF8EB0, but instead it's just zero. Why, I don't know.
 
I did try that. The it was pointing to the function as implemented in the derived class ... just like I would have expected.
Correction, I only checked the address of the CLEDController class object, not the address of the function to be called. Paul just did that. It indeed appears to be a VTABLE problem. It's just quite vexing that I can't make it happen outside of the FastLED environment.
 
My best guess is we're supposed to have vtable or some other initialized data at 1FFF8EB0, but instead it's just zero. Why, I don't know.
What if you put that same code (to dump the vtable address and init function pointer) in the ClocklessController constructor? Since we've seen that constructor is being executed, and it's where the relevant vtable should be getting assigned to the object (you should be able to see that in the assembly code for that function).
 
Last edited:
Back
Top