driver for WS2812B LED, modified for better compatibility with LPC812 and LPC1549

Dependencies:   BurstSPI

Dependents:   RGB-balls cylon

Fork of wsDrive by Andy A

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