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: http://developer.mbed.org/users/JacobBramley/code/PixelArray/

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.

Committer:
AndyA
Date:
Thu Nov 06 17:11:43 2014 +0000
Revision:
1:741864ea11d4
Parent:
0:b3665f91bedc
Child:
2:1f20efb81649
Added comments/documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AndyA 0:b3665f91bedc 1 #ifndef __wsDrive_h__
AndyA 0:b3665f91bedc 2 #define __wsDrive_h__
AndyA 0:b3665f91bedc 3
AndyA 0:b3665f91bedc 4 #include "BurstSPI.h"
AndyA 0:b3665f91bedc 5
AndyA 1:741864ea11d4 6 /****************************************************************
AndyA 1:741864ea11d4 7 * An alternative WS2811/2812 driver using the BusrtSPI library
AndyA 1:741864ea11d4 8 * Credit for the inspiration goes to Jacob for his pixelArray library
AndyA 1:741864ea11d4 9 * http://developer.mbed.org/users/JacobBramley/code/PixelArray/
AndyA 1:741864ea11d4 10 *
AndyA 1:741864ea11d4 11 * This version was written mainly to help me understand what was going on
AndyA 1:741864ea11d4 12 * While the end result is the same the code is completely from scratch.
AndyA 1:741864ea11d4 13 *
AndyA 1:741864ea11d4 14 *****************************************************************/
AndyA 0:b3665f91bedc 15
AndyA 1:741864ea11d4 16
AndyA 1:741864ea11d4 17 class SerialBufferedCallbackDummyClass;
AndyA 1:741864ea11d4 18
AndyA 1:741864ea11d4 19
AndyA 1:741864ea11d4 20 /** A structure used to hold a single pixel or a pixel colour
AndyA 1:741864ea11d4 21 *
AndyA 1:741864ea11d4 22 * Each colour can be set to any value between 0 and 255.
AndyA 1:741864ea11d4 23 * 0 = off, 255 = full brightness.
AndyA 1:741864ea11d4 24 *
AndyA 1:741864ea11d4 25 * Note, lots of LEDs on bright will use a lot of power, make sure your supply can cope.
AndyA 1:741864ea11d4 26 *
AndyA 1:741864ea11d4 27 * @param G The green component
AndyA 1:741864ea11d4 28 * @param R The red component
AndyA 1:741864ea11d4 29 * @param B The blue component
AndyA 1:741864ea11d4 30 */
AndyA 0:b3665f91bedc 31 typedef struct pixelInfo {
AndyA 0:b3665f91bedc 32 unsigned char G;
AndyA 0:b3665f91bedc 33 unsigned char R;
AndyA 0:b3665f91bedc 34 unsigned char B;
AndyA 0:b3665f91bedc 35 } pixelInfo;
AndyA 0:b3665f91bedc 36
AndyA 0:b3665f91bedc 37
AndyA 1:741864ea11d4 38 /** Drives a WS2812 LED chain
AndyA 1:741864ea11d4 39 *
AndyA 1:741864ea11d4 40 * An alternative WS2811/2812 driver using the BusrtSPI library
AndyA 1:741864ea11d4 41 *
AndyA 1:741864ea11d4 42 * Credit for the inspiration goes to Jacob for his pixelArray library
AndyA 1:741864ea11d4 43 * http://developer.mbed.org/users/JacobBramley/code/PixelArray/
AndyA 1:741864ea11d4 44 *
AndyA 1:741864ea11d4 45 * This version was written mainly to help me understand what was going on and is a little more basic.
AndyA 1:741864ea11d4 46 * While the end result is muc the same the code is completely from scratch.
AndyA 1:741864ea11d4 47 *
AndyA 1:741864ea11d4 48 * BurstSPI is used to generate the timing so support is limited to the parts supported by that library.
AndyA 1:741864ea11d4 49 *
AndyA 1:741864ea11d4 50 * 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
AndyA 1:741864ea11d4 51 *
AndyA 1:741864ea11d4 52 * Example code to run a single lit led along a chain
AndyA 1:741864ea11d4 53 *
AndyA 1:741864ea11d4 54 * @code
AndyA 1:741864ea11d4 55 *
AndyA 1:741864ea11d4 56 * #include "mbed.h"
AndyA 1:741864ea11d4 57 * #include "wsDrive.h"
AndyA 1:741864ea11d4 58 *
AndyA 1:741864ea11d4 59 * // update period in ms
AndyA 1:741864ea11d4 60 * #define updatePeriod 100
AndyA 1:741864ea11d4 61 * // number of LEDs
AndyA 1:741864ea11d4 62 * #define chainLen 8
AndyA 1:741864ea11d4 63 *
AndyA 1:741864ea11d4 64 * DigitalIn dummy(MOSI,PullDown); // first activate the pulldown on the pin.
AndyA 1:741864ea11d4 65 * 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
AndyA 1:741864ea11d4 66 *
AndyA 1:741864ea11d4 67 * // pixel storage buffer
AndyA 1:741864ea11d4 68 * pixelInfo pixelData[chainLen];
AndyA 1:741864ea11d4 69 *
AndyA 1:741864ea11d4 70 * Timer updateRateTimer;
AndyA 1:741864ea11d4 71 *
AndyA 1:741864ea11d4 72 * void blankBuffer(pixelInfo *Ptr)
AndyA 1:741864ea11d4 73 * {
AndyA 1:741864ea11d4 74 * memset( (void *)Ptr, 0, chainLen*sizeof(pixelInfo) );
AndyA 1:741864ea11d4 75 * }
AndyA 1:741864ea11d4 76 *
AndyA 1:741864ea11d4 77 * void setPixel(unsigned int index, pixelInfo *colourToUse) {
AndyA 1:741864ea11d4 78 * if (index < chainLen) {
AndyA 1:741864ea11d4 79 * pixelData[index].R = colourToUse->R;
AndyA 1:741864ea11d4 80 * pixelData[index].G = colourToUse->G;
AndyA 1:741864ea11d4 81 * pixelData[index].B = colourToUse->B;
AndyA 1:741864ea11d4 82 * }
AndyA 1:741864ea11d4 83 * }
AndyA 1:741864ea11d4 84 *
AndyA 1:741864ea11d4 85 * void clearPixel(unsigned int index) {
AndyA 1:741864ea11d4 86 * if (index < chainLen) {
AndyA 1:741864ea11d4 87 * pixelData[index].R = 0;
AndyA 1:741864ea11d4 88 * pixelData[index].G = 0;
AndyA 1:741864ea11d4 89 * pixelData[index].B = 0;
AndyA 1:741864ea11d4 90 * }
AndyA 1:741864ea11d4 91 * }
AndyA 1:741864ea11d4 92 *
AndyA 1:741864ea11d4 93 * int main () {
AndyA 1:741864ea11d4 94 *
AndyA 1:741864ea11d4 95 * int litLed = 0;
AndyA 1:741864ea11d4 96 *
AndyA 1:741864ea11d4 97 * pixelInfo colour;
AndyA 1:741864ea11d4 98 * colour.R = 0x80;
AndyA 1:741864ea11d4 99 * colour.G = 0x00;
AndyA 1:741864ea11d4 100 * colour.B = 0x00;
AndyA 1:741864ea11d4 101 *
AndyA 1:741864ea11d4 102 * // Tell the driver where the data is stored
AndyA 1:741864ea11d4 103 * ledDriver.setData(pixelData, chainLen);
AndyA 1:741864ea11d4 104 *
AndyA 1:741864ea11d4 105 * // Set the buffer to the pattern we want
AndyA 1:741864ea11d4 106 * blankBuffer(pixelData);
AndyA 1:741864ea11d4 107 * setPixel(litLed, &colour);
AndyA 1:741864ea11d4 108 *
AndyA 1:741864ea11d4 109 * updateRateTimer.start();
AndyA 1:741864ea11d4 110 * while (true) {
AndyA 1:741864ea11d4 111 *
AndyA 1:741864ea11d4 112 * ledDriver.sendData(); // send the LED data
AndyA 1:741864ea11d4 113 *
AndyA 1:741864ea11d4 114 * // modify the buffer ready for the next update
AndyA 1:741864ea11d4 115 * clearPixel(litLed);
AndyA 1:741864ea11d4 116 * litLed++;
AndyA 1:741864ea11d4 117 * if (litLed == chainLen)
AndyA 1:741864ea11d4 118 * litLed = 0;
AndyA 1:741864ea11d4 119 * setPixel(litLed, &colour);
AndyA 1:741864ea11d4 120 *
AndyA 1:741864ea11d4 121 * // wait until the correct time since the last update...
AndyA 1:741864ea11d4 122 * while (updateRateTimer.read_ms() < updatePeriod) {
AndyA 1:741864ea11d4 123 * }
AndyA 1:741864ea11d4 124
AndyA 1:741864ea11d4 125 * updateRateTimer.reset();
AndyA 1:741864ea11d4 126 * }
AndyA 1:741864ea11d4 127 * }
AndyA 1:741864ea11d4 128 * @endcode
AndyA 1:741864ea11d4 129 *
AndyA 1:741864ea11d4 130 * Troubleshooting:
AndyA 1:741864ea11d4 131 *
AndyA 1:741864ea11d4 132 * 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)
AndyA 1:741864ea11d4 133 *
AndyA 1:741864ea11d4 134 * 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.
AndyA 1:741864ea11d4 135 * 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
AndyA 1:741864ea11d4 136 * to about 4.2 - 4.3 V will normally fix this problem without any meaningful impact on the LED output.
AndyA 1:741864ea11d4 137 *
AndyA 1:741864ea11d4 138 */
AndyA 0:b3665f91bedc 139 class wsDrive : private BurstSPI
AndyA 0:b3665f91bedc 140 {
AndyA 0:b3665f91bedc 141 public:
AndyA 1:741864ea11d4 142 /** create the driver
AndyA 1:741864ea11d4 143 */
AndyA 0:b3665f91bedc 144 wsDrive(PinName mosi, PinName miso, PinName clk);
AndyA 1:741864ea11d4 145
AndyA 1:741864ea11d4 146 /** Set the data pointer
AndyA 1:741864ea11d4 147
AndyA 1:741864ea11d4 148 Before data can be sent the driver must be given a pointer to the pixel data to use.
AndyA 1:741864ea11d4 149 Setting this is normally a one time operation unless you want to switch between buffers.
AndyA 1:741864ea11d4 150
AndyA 1:741864ea11d4 151 @param dataStart The start of an array of pixelInfo items. This will be sent to the chain in order.
AndyA 1:741864ea11d4 152 @param dataLen The length of the array.
AndyA 1:741864ea11d4 153 */
AndyA 0:b3665f91bedc 154 void setData(pixelInfo *dataStart, uint16_t dataLen);
AndyA 1:741864ea11d4 155
AndyA 1:741864ea11d4 156
AndyA 1:741864ea11d4 157 /** Sends the data to the LEDs
AndyA 1:741864ea11d4 158 * setData() must be called prior to this.
AndyA 1:741864ea11d4 159 */
AndyA 0:b3665f91bedc 160 void sendData();
AndyA 1:741864ea11d4 161
AndyA 0:b3665f91bedc 162 private:
AndyA 0:b3665f91bedc 163
AndyA 0:b3665f91bedc 164 void sendByte(unsigned char value);
AndyA 0:b3665f91bedc 165 void sendPixel(pixelInfo *pixToSend);
AndyA 1:741864ea11d4 166
AndyA 0:b3665f91bedc 167 pixelInfo *pixArray;
AndyA 0:b3665f91bedc 168 uint16_t pixelLen;
AndyA 0:b3665f91bedc 169
AndyA 0:b3665f91bedc 170 };
AndyA 0:b3665f91bedc 171
AndyA 0:b3665f91bedc 172 #endif