Using Teensy 4.1 With FastLED

Got a Teensy 4.1? Want to use it with FastLED? You’ve come to the right place. The Teensy 4.1 is an incredibly powerful microprocessor at a very reasonable price, and FastLED is still one of the best libraries for driving WS2812 type addressable LEDs from Arduino type projects.

Paul Stoffregen, creator of Teensy, has a library called OctoWS2811 that provides fairly basic operations to send RGB data out to addressable LEDs. Unlike FastLED, it doesn’t have all the fancy color manipulation, palettes, fast math operations, etc… just basic “set the pixel color” type operations. But OctoWS2811 is blazingly fast and works perfectly on the Teensy 4.1. One of the reasons it is so fast is because it can drive strips using any and all GPIO pins in parallel and without using a lot of CPU time. (More about my experience here).

So what you really want to do is combine OctoWS2811 with FastLED and you will be cooking with fire. Here’s how to do that.

Step one – get the latest version of OctoWS2811 from GitHub. (Last I checked, the version that comes with from the Arduino library manager is not the latest version).

You can use this code directly; here is an example of that:

  const int numPins = 8;
  byte pinList[numPins] = {33, 34, 35, 36, 37, 38, 39, 40};
  const int ledsPerStrip = 300;
  CRGB rgbarray[numPins * ledsPerStrip];

  // These buffers need to be large enough for all the pixels.
  // The total number of pixels is "ledsPerStrip * numPins".
  // Each pixel needs 3 bytes, so multiply by 3.  An "int" is
  // 4 bytes, so divide by 4.  The array is created using "int"
  // so the compiler will align it to 32 bit memory.
  DMAMEM int displayMemory[ledsPerStrip * numPins * 3 / 4];
  int drawingMemory[ledsPerStrip * numPins * 3 / 4];
  OctoWS2811 octo(ledsPerStrip, displayMemory, drawingMemory, WS2811_RGB | WS2811_800kHz, numPins, pinList);

Now to hook this up with FastLED, you create a custom FastLED “controller” which just sends the bits to OctoWS2811 as follows:

#include <OctoWS2811.h>
#include <FastLED.h>
#include <Arduino.h>

template <EOrder RGB_ORDER = RGB,
          uint8_t CHIP = WS2811_800kHz>
class CTeensy4Controller : public CPixelLEDController<RGB_ORDER, 8, 0xFF>
{
    OctoWS2811 *pocto;

public:
    CTeensy4Controller(OctoWS2811 *_pocto)
        : pocto(_pocto){};

    virtual void init() {}
    virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> &pixels)
    {

        uint32_t i = 0;
        while (pixels.has(1))
        {
            uint8_t r = pixels.loadAndScale0();
            uint8_t g = pixels.loadAndScale1();
            uint8_t b = pixels.loadAndScale2();
            pocto->setPixel(i++, r, g, b);
            pixels.stepDithering();
            pixels.advanceData();
        }

        pocto->show();
    }
};

There is a minor bug in this code where I ignore the RGB_ORDER parameter in setting r, g, and b. You can fix this if your strip uses GRB order or other.

To use this new controller:

  CTeensy4Controller<RGB, WS2811_800kHz> *pcontroller;

  void setup()
  {
    octo.begin();
    pcontroller = new CTeensy4Controller<RGB, WS2811_800kHz>(&octo);

    FastLED.setBrightness(255);
    FastLED.addLeds(pcontroller, rgbarray, numPins * ledsPerStrip);
  }

Enjoy!