FAB_LED: A WS2812B Library with Palette Support

FAB_LED Is a Fast Arduino Bitbanging library for addressable LEDs, like WS2812B.

Download

The Library can be downloaded here from GitHub, or directly as a zip file.

To install the library, unzip the source files into your Arduino  “libraries” directory, like any other library. Rename the directory FAB_LED. Restart your arduino IDE. You’re ready to test it.

Load an example, plug your WS2812B LEDs onto pin D6 of your board (pin “~6” on Arduino Uno), power it, compile and load the program. The led strip should cycle different patterns. If you don’t use pin D6 then just change the declaration in the program.

  • Jun 19,2016: Refactoring the library to make it more compact and maintainable. Simplifying the a API to draw() and send() from send_pixels().
  • May 2016: support for palettes, pixel remapping, parallel port updates (up to 6 ports on 16mhz avr) beginning support for apa102 and arm.
  • Apr 1, 2016: updated repository. Added APA104, WS2812 support, fixed Mac compile bugs, slowed aggressive timing to handle APA104.
  • Mar 29, 2016: Library should adapt to CPU frequency, added 1K pixels demo. Forgot to update GIT repository!
  • Mar 23, 2016: The beta is available, with one code example.
  • Feb 29, 2016: I’ve finally debugged my WS2812B library to the point where it all works on a 16MHz Arduino UNO. Now why would anyone care for a me too library?

Overview

The FAB_LED library has a few benefits attached to it versus other libraries (AdaFruit NeoPixel or FastLED libraries):

  • The low level bit-banging code is written in gcc C, without any inline assembly. This means it should support any CPU frequency, not just the frequencies that I have hardcoded.
  • The LED class supports multiple pixel formats, which provide great flexibility to choose between pixel manipulation convenience and pixel memory size. A pixel can use from 1 bit of memory to 32 bits, using different schemes:
    • 3 uint8_t per pixel (24 bits)
    • One uint32_t word per pixel (32 bits)
    • 1, 2, 4 or 8 bits per pixel mapped to a color palette of 2, 4, 16 or 256 colors
    • One uint16_t word per pixel (16 bits, 5 bits per pixel), with a choice of 3 levels of brightness
    • Separate pixel clear method and a 256-gray levels method allow you to clear or set a LED strip of any size without using up any memory.
  • The methods can be called back to back to duplicate patterns on infinitely long LED strips, tested on a 16MHz Arduino Uno. Timings for the palette method work but are very tight.
  • Alternatively, you can define multiple arrays to draw frames of an animation, and just change which array is drawn at every clock tick. There is no need to re-draw the frames, unlike other LED libraries.
  • Using the class requires nothing more than knowing which port your LED strip is attached to. A physical port on Arduino is 2 elements, the port letter A to F, and the port pin, from 0 to 7.

At this point FAB_LED is not vaporware anymore. It is fully working.

Example

The following example uses the palette routine, using 2 bits per pixels.

  • It uses a color palette taking only 12 bytes of RAM to hold the 4 color values.
  • It defines a 16-pixel pattern which fits in another 4 bytes of RAM.
  • The 16-pixels pattern is sent 11 times in a tight loop, to light up the whole 170-LED strip.

The animation is done by manipulating the palette colors after the tight sendPixel loop:

  • We rotate one of the four colors (blue-green pulse).
  • We blink on/off the red color.

All this uses a total of 16 bytes for the data arrays, and a one page user code loop to animate. The code page is shown as screen capture.

The bottom loop does the display directly, there is no need for a show() routine since it paints the pixels on the fly as soon as sendPixel() is called.

Here’s a video of this code running:

I am adding slowly 2D support. This is my first rendering. I had to put a cloth to diffuse the LEDs to take the photo. It’s an 8×8 pixel board:

photo418910434535516422

Other links

 

Ooh and posting my video I see someone posted how to pipeline data from a USB port directly… I’ll have to look into that, to maybe stream from USB or a SD card! They can handle thousands of LEDs.

16 thoughts on “FAB_LED: A WS2812B Library with Palette Support

    1. Thanks! I will look into why this happens.
      All those methods should be declared in the example file, after loop().
      I suppose this is with the Arduino IDE, else I may need to add forward declarations of methods.

      Like

    2. Hi Bill,

      I made some changes to the code with some fixes. In particular I had forgotten to store the timings in nanoseconds instead of cycles, which made the code work only at 16MHz.

      For your issue all I could think of is to move the setup() and loop() methods to the end of the file, which is equivalent to pre-declaring the functions. Normally with the Arduino IDE, this is not needed.

      I hope to hear from you 🙂

      Thanks.

      Like

    3. I figured out why you get compile errors: the IDE doesn’t like the following declaration on my Mac:
      void
      setup(void)
      {…}
      It wants the return value on the same line:
      void setup(void)
      {…}
      GIT repo updated to fix all that. Hopefully.

      Like

  1. I am interested in integrating your library in my Eclipse ARM GCC environment, i.e. outside of the Arduino environment. I am using a Nordic nRF51422.
    Do you have some experience on how I could get rid of the Arduino dependencies?

    Like

  2. Hi,
    I am interested in using your code in my ARM GCC Eclipse environment. I am using a Nordic nRF51422.
    Do you have some knowledge but how I could get rid of the Arduino dependencies?

    Best regards

    Like

    1. Hi. You would have a hard time since I have not yet implemented a solid ARM bit banging solution. Otherwise, you’d have to pull out the port mappings and it is something I will have to do at some point since I wanna support raspberry pi eventually.

      Like

  3. Hello! Do you have any example of a snake in FAB_LED: turn on from 20 to 80 LED (for example) and then turn off from 20 to 80. Or any similar example. Thank you.

    Like

    1. I don’t.

      you have multiple ways to do it.

      An inner loop that sends one pixel per iteration, and an outer loop that repeats displaying the strip.
      That uses almost no RAM (only one pixel is needed).

      for (int i = 0; i < 80; i++) {
      // clear interupts
      for (int j = 0 ; j < i; j++) {
      send_pixel(…);
      }
      // set interupts
      sleep(100);
      }

      Another option is to allocate an array of 80 pixels and updating the valuesbefore displaying them.

      Look at the "infinite" pixels demo for examples.

      Like

  4. Hi there – first of all, fantastic work on this library; thank you for sharing your hard work with the community.

    I came to your project seeking an alternative to FastLED, which is lacking in RGBW support and is a bit bloated for my requirements – the tiny footprint of FAB_LED is a huge plus!

    In my testing, I’m finding that identical code runs at about half the speed of the same implementation in FastLED. I’m hoping you might be able to point me in the right direction as to how I can improve on this? I’m using SK6812B LEDs in a 144-pixel strip.

    Like

    1. Hi,

      I would need to know a bit more about the code you wrote and the controller you’re using. I’m surprised fastLED would be 2X as fast, but then again there’s good coding done there and maybe you’re able to use a non-bitbang mode with some DMA enabled or something.

      Like

    2. I just thought about this that might be the issue: Each LED type has a native pixel format, like GRBW. If you don’t use it the code runs slower.

      FAB_LED will allow you to use any pixel type, and will convert on the fly the order to match the strip format you declared.
      The library will run full speed without conversion, if the pixel data array you declare is exactly the same type as the LED strip.

      Furthermore with FAB_LED, it is possible to push pixels to up to 6 ports in parallel at 16MHz. So that means the refresh is 6 times faster if you change the wiring!

      Now… even with conversion I’m still not sure where you see the performance difference. You are limited by the LED protocol, unless fastLED for your controller can use non bitbang solution which gives CPU cycles back to your drawing code.

      Like

    1. Yes I am, there’s currently 2 branches because I am modifying the API somewhat to simplify usage when combining multiple calls to update a strip. However it’s moving slow because I always have many things taking priority and I already code all day for work. 🙂
      Thank you so much for taking the time to respond!

      Like

Leave a comment