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:
Wed Nov 23 09:41:48 2016 +0000
Revision:
5:6aa3e7de65f9
Parent:
4:8997e12da7c7
Update to fix issues with 16bit brightness support.

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