Using Teensy 4.0 or 4.1 With FastLED

Updated 20 April, 2024

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 microcontroller at a very reasonable price, and FastLED is still one of the best libraries for driving WS2812 type addressable LEDs from microcontrollers.

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. (Make sure you have version 3.5). The only two files you’re going to need are OctoWS2811.h and OctoWS2811_imxrt.cpp so just add those to your project.

You can use OctoWS2811 directly to write to the LEDs. Here’s an example using 8 pins, numbered 33-40 (this code goes in your main.cpp or .ino file):

  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 forwards the bits to OctoWS2811. This is the simplest possible FastLED controller; it looks like this (put this in a file called teensy4controller.h and #include that from your main file).

#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();
    }
};

To use this new controller:

#include "teensy4controller.h"

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);
}

Tip: This works for Teensy 4.0, too.

Sample code to get started (for VSCode + PlatformIO)

Another tip: You can use any and all pins in any order. Just change numPins and pinList.

Update (Nov 2024) – there is a library called ObjectFLED which gets you all of the same benefits as this technique, but also lets you configure each pin individually, so if you have different lengths and types of LEDs it can handle that.

Enjoy!