FastSPI_LED2, The Introducing

The FastSPI_LED library has been growing a little long in the tooth.  It is monolithic, fairly tied to the arduino platform, has a number of design decisions that reflect its scattershot growth and direction, and more.  In spite of that, it has been downloaded over five thousand times (damn, what are you all doing with it?  I’d love to see the projects!).  However, as bug reports, feature requests (eg playing nicely with other SPI devices), new led chipsets, new host chipsets (teensy 3.0, chipkit, msp430, etc..) come in it has become increasingly clear was a cleaning house.  So I stepped back and thought about the evolution of the code and the library over the past two years and where I wanted it to go, what what features were important going forward.  Then I sat down and sketched out a rough structure for the library going forward, one that focused on easy extensibility, easy portability, and of course, high performance squeezed out of small platforms.

After that, and a few weekends/weeks of grabbing blocks of time here and there to work out code and ideas, I now have code!  Code that appears to work on arduino, teensy 2.0 and teensy 3.0!  Code that appears to be speedy!  Code that makes things glow!  Since I have code that means that you too, shall shortly have code.  First, some details about FastSPI_LED2 as people will be able to use it out of the gate:

  • Initial (tested) platform support: Arduino (uno/nano), Teensy 2.0, and Teensy 3.0 (yes, ARM!)
  • Initial (tested) chipset support: ws2801, lpd8806, ucs1903, tm1809/1804, tm1803, ws2811
  • Silent switching between hardware SPI (6.6+ Mbps) usage and high performance software SPI (2.7Mbps on 16Mhz arduino!) based on selected pins
  • Software based SPI increases ability to play nicely with other SPI libraries/data
  • Ability to run multiple sets of led strips in parallel on different pins
  • Small when compiled, depending on chipsets/options, as little as a few hundred bytes (compared with over 12kb in the old library)
  • Support for using ARGB data structures (up to you to do your own A based blending, however!).  Not yet supported on all chipsets.

In addition, there’s some other pieces of the library and code that I want to call out, and will go into more detail about in subsequent posts:

  • High performance pin access library exposed for use (write only, for now)
  • High performance SPI library available for direct use (write only, for now)
  • Rapid ability to add support for new LED chipsets going forward
  • (Hopefully) Rapid ability to port the codebase to new platforms

Of course, now I imagine there are two questions being asked.  The first being where one can obtain the code, the second being how to use the code.  This being a preview release, the interface to the library is still a little bit on the raw side, and there will need to be some minor changes to your setup and show code to start using the new library.   So, grab the code from the googlecode site, and settle in for some notes on porting code over to the new library.  (This information, as it gets fleshed out, will find its way into in-library documentation files).

Porting Code

The old code involved calling a number of functions to set up the various parameters for the LED library, and then you would get a pointer to the block of memory that the library used for writing from.  This brings us to the first major set of changes to the library.  This version of the library focuses on the LED controllers, and -not- on managing your LED data itself.  So, the first major change is that responsibility for setting up the array of RGB data structures moves from the FastSPI_LED library to you, and when it comes time to call show on the controller, you give the show method a pointer to where your rgb data is.  The second major change is you have to declare your LED controller object – one object per set of leds you want to control.  So, for example, here’s some sample code for making all of your leds blink red:

// Simple rgb data structure
#include "FastSPI_LED2.h"
#define NUM_LEDS 32
struct CRGB { byte r; byte g; byte b; };
struct CRGB ledData[NUM_LEDS];

// Setup/define the Led controller with data pin 11, clock pin 13, and latch pin 10 
// this will trigger use of the hardware SPI support on the arduino uno
LPD8806Controller<11, 13, 10> LedController;

setup() { 
  // zero out all the leds
  memset(ledData, 0, sizeof(struct CRGB) * NUM_LEDS); 

  // initialize the controller
  LedController.init();
}

loop() { 
  // set all the LEDs to red
  for(int i = 0; i < NUM_LEDS; i++) { ledData[i].r = 255; }
  LedController.showRGB((byte*)ledData, NUM_LEDS);
  delay(100);
  // zero out all the leds
  memset(ledData, 0, sizeof(struct CRGB) * NUM_LEDS);
  LedController.showRGB((byte*)ledData, NUM_LEDS);
  delay(100);
}

Pretty straight forward, no?  Apologies for the need to cast to a byte* – it is something that should get fixed up fairly quickly.  Also I need to add controller definitions and options for various predefined pin setups (e.g. make it easier to specify hardware SPI ports for a platform that has them).  All of the LED Controller objects are instances of a base class called CLEDController, so if you want to pass your controller objects around between functions, you can just pass a reference/pointer to an object of type CLEDController, and the Right Things[tm] will happen. For now, take a peek in the FastSPI_LED2.h header file for the supported chipset classes, or look at the code sample in examples for a variety of (commented out) instantiations for various chipsets.

What’s next?

As mentioned multiple times, this is a preview release of the library.  I’m about to take off on some traveling and wanted to get this out there for people to start looking at.  There may be bugs.  Not all the platform combinations are complete, and there are more platforms I want to fully support.  The good news is that any arduino based environment not explicitly mentioned above should work out of the box, albeit a little slower, thanks to various rounds of graceful fallback in the Pin and FastSPI portions of the library.  However, as with any preview type release, I already have a handful of known issues and specific things that I want to fix before a full release or immediately after the initial release, including:

  • Software SPI optimizations assume no other pin writes will occur while output led data.  There is a fallback, slightly slower, but definitely safer, when there are other writes occurring.  I simply need a way to expose this to the user
  • Cleaner high level interface to the controllers, including the ability to manage multiple controllers
  • Documentation and sample/example code
  • Wider arduino platform support
  • Add ability to specify select pins to the non-SPI based chipsets (my test harness will make use of this to use a mux to switch between chipsets under test)
  • Add the ability to specify a -set- of pins to be triggered as a select for a controller (again, for use with abovementioned mux)
  • More performance tuning/code cleanup
  • Getting rid of the need to explicitly cast to byte* when calling show
  • Support for specifying the RGB ordering of bytes on a controller by controller basis
  • Support for ‘background output’ of LED data (teensy 3.0 has a DMA subsystem!)
  • Support for arduino-less AVR environments
  • Support for a few more led chipsets!
  • Some support library surprises

It’s been a fun 2 and a half years making and growing this library.  I’m really happy to finally be dragging this library kicking and screaming into 2013, and I’m looking forward to the next few years of this library and the things you all do with it!

Credits/inspirations/motivators

Also, a shout out to blog posts that contributed to various directions my brain went into and/or information used in refining the code in this library: