Yet another WS2812 driver, uses the BusrtSPI library. Less features than the PixelArray library but I felt like making my own version.

Dependencies:   BurstSPI

Dependents:   WS2812Text cylon

An alternative WS2811/2812 (NeoPixel) driver using the BusrtSPI library.

Credit for the inspiration goes to Jacob Bramley for his pixelArray library that can be found here:

This version was written mainly to help me understand what was going on rather than to overcome any shortcomings in the other library and as such it lacks some features (800kHz only, no callback on each pixel etc...)

Connect the SPI output to the LED data input, other SPI pins are unused.

Note: The voltage thresholds between the LEDs and mbed devices are on paper incompatible. The datasheet for the WS2812 indicated that running at 5V it requires 4V on Din to count it as a high (the threshold is 0.8*the supply voltage). Most mbeds are lucky to output much over 3.1V. In reality things normally work OK but it depends on the mBed and batch to batch variations in the LEDs, I've seen some combinations that start to fail at an LED supply voltage of 4.4V or more. If something odd is going on try dropping the LED power supply voltage, they run fine down to 4V.



File content as of revision 5:6aa3e7de65f9:

#ifndef __wsDrive_h__
#define __wsDrive_h__

#include "BurstSPI.h"

* An alternative WS2811/2812 driver using the BusrtSPI library
* Credit for the inspiration goes to Jacob for his pixelArray library
* This version was written mainly to help me understand what was going on
* While the end result is the same the code is completely from scratch.

/** A structure used to hold a single pixel or a pixel colour
* Each colour can be set to any value between 0 and 255.
* 0 = off, 255 = full brightness.
* Note, lots of LEDs on bright will use a lot of power, make sure your supply can cope.
* @param G The green component
* @param R The red component
* @param B The blue component
typedef struct pixelInfo {
    unsigned char G;
    unsigned char R;
    unsigned char B;
} pixelInfo;

typedef struct pixelInfo16 {
    int16_t G;
    int16_t R;
    int16_t B;
} pixelInfo16;

/** Drives a WS2812 LED chain
* An alternative WS2811/2812 driver using the BusrtSPI library
* Credit for the inspiration goes to Jacob for his pixelArray library
* This version was written mainly to help me understand what was going on and is a little more basic.
* While the end result is muc the same the code is completely from scratch.
*  BurstSPI is used to generate the timing so support is limited to the parts supported by that library.
*  Also note that while all 3 SPI pins are specified only the MOSI pin is actually needed and should connect to the data in on the LEDs
*  Example code to run a single lit led along a chain
*  @code
*  #include "mbed.h"
*  #include "wsDrive.h"
*  // update period in ms
*  #define updatePeriod 100
*  // number of LEDs
*  #define chainLen 8
*  DigitalIn dummy(MOSI,PullDown); // first activate the pulldown on the pin.
*  wsDrive ledDriver(MOSI,MISO,CLK); // create the SPI bus. You can normally list the MISO and CLK as NC but some mbed library versions don't like that
*  // pixel storage buffer
*  pixelInfo pixelData[chainLen];
*  Timer updateRateTimer;
*  void blankBuffer(pixelInfo *Ptr)
*  {
*     memset( (void *)Ptr, 0, chainLen*sizeof(pixelInfo) );
*  }
*  void setPixel(unsigned int index, pixelInfo *colourToUse) {
*    if (index < chainLen) {
*      pixelData[index].R = colourToUse->R;
*      pixelData[index].G = colourToUse->G;
*      pixelData[index].B = colourToUse->B;
*    }
*  }
*  void clearPixel(unsigned int index) {
*    if (index < chainLen) {
*      pixelData[index].R = 0;
*      pixelData[index].G = 0;
*      pixelData[index].B = 0;
*    }
*  }
* int main () {
*   int litLed = 0;
*   pixelInfo colour;
*   colour.R = 0x80;
*   colour.G = 0x00;
*   colour.B = 0x00;
*   // Tell the driver where the data is stored
*   ledDriver.setData(pixelData, chainLen);
*   // Set the buffer to the pattern we want
*   blankBuffer(pixelData);
*   setPixel(litLed, &colour);
*   updateRateTimer.start();
*   while (true) {
*     ledDriver.sendData(); // send the LED data
*     // modify the buffer ready for the next update
*     clearPixel(litLed);
*     litLed++;
*     if (litLed == chainLen)
*       litLed = 0;
*     setPixel(litLed, &colour);
*     // wait until the correct time since the last update...
*     while (updateRateTimer.read_ms() < updatePeriod) {
*     }

*    updateRateTimer.reset();
*    }
* }
* @endcode
* Troubleshooting:
* If the LEDs aren't lighting up correctly then check that your power supply is up to the job (or decrease the brightness you are using)
* Also check the supply voltage, on paper when running off 5V the WS2812 needs 4V on the data in pin to detect a high. Mbed based boards rarely output much over 3.1V.
* This problem is normally indicated by the very first pattern send on power up being displayed but then no further updates being recieved. Dropping the supply voltage
* to about 4.2 - 4.3 V will normally fix this problem without any meaningful impact on the LED output.
class wsDrive : private BurstSPI
    /** create the driver
    wsDrive(PinName mosi, PinName miso, PinName clk);

    /** Set the data pointer

    Before data can be sent the driver must be given a pointer to the pixel data to use.
    Setting this is normally a one time operation unless you want to switch between buffers.

    @param dataStart The start of an array of pixelInfo items. This will be sent to the chain in order.
    @param dataLen   The length of the array.
    void setData(pixelInfo *dataStart, uint16_t dataLen);

    void setData(pixelInfo16 *dataStart, uint16_t dataLen);

    /** Sends the data to the LEDs
    * setData() must be called prior to this.
    void sendData();


    void sendByte(unsigned char value);
    void sendPixel(pixelInfo *pixToSend);
    void sendPixel(pixelInfo16 *pixToSend);

    pixelInfo *pixArray;
    pixelInfo16 *pixArray16;
    uint16_t pixelLen;