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:
JojoS
Date:
Sat Dec 10 14:30:38 2016 +0000
Revision:
6:270a9728ee29
Parent:
3:3c48065d20ff
support for STM32F4

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 3:3c48065d20ff 19 * Each colour can be set to any value between about -32,768 and +32,767 (the 16 bit signed number range)
AndyA 3:3c48065d20ff 20 * 0 or negative values mean that colour is off, 255 or more mean on at full brightness.
AndyA 3:3c48065d20ff 21 * In between means partially on.
AndyA 3:3c48065d20ff 22 * If you are never going to go outside the 0-255 range then use pixelInfo, it uses half the memory.
AndyA 3:3c48065d20ff 23 * however if you are calculating pixel values when superimposing two images and don't want to worry about wrap around then use this version.
AndyA 3:3c48065d20ff 24 *
AndyA 3:3c48065d20ff 25 * Note, lots of LEDs on bright will use a lot of power, make sure your supply can cope.
AndyA 3:3c48065d20ff 26 *
AndyA 3:3c48065d20ff 27 * @param G The green component
AndyA 3:3c48065d20ff 28 * @param R The red component
AndyA 3:3c48065d20ff 29 * @param B The blue component
AndyA 3:3c48065d20ff 30 */
AndyA 3:3c48065d20ff 31 typedef struct pixelInfo16 {
AndyA 3:3c48065d20ff 32 int16_t G;
AndyA 3:3c48065d20ff 33 int16_t R;
AndyA 3:3c48065d20ff 34 int16_t B;
AndyA 3:3c48065d20ff 35 } pixelInfo16;
AndyA 3:3c48065d20ff 36
AndyA 3:3c48065d20ff 37
AndyA 3:3c48065d20ff 38 /** A structure used to hold a single pixel or a pixel colour
AndyA 3:3c48065d20ff 39 *
AndyA 1:741864ea11d4 40 * Each colour can be set to any value between 0 and 255.
AndyA 1:741864ea11d4 41 * 0 = off, 255 = full brightness.
AndyA 1:741864ea11d4 42 *
AndyA 1:741864ea11d4 43 * Note, lots of LEDs on bright will use a lot of power, make sure your supply can cope.
AndyA 1:741864ea11d4 44 *
AndyA 1:741864ea11d4 45 * @param G The green component
AndyA 1:741864ea11d4 46 * @param R The red component
AndyA 1:741864ea11d4 47 * @param B The blue component
AndyA 1:741864ea11d4 48 */
AndyA 0:b3665f91bedc 49 typedef struct pixelInfo {
AndyA 0:b3665f91bedc 50 unsigned char G;
AndyA 0:b3665f91bedc 51 unsigned char R;
AndyA 0:b3665f91bedc 52 unsigned char B;
AndyA 0:b3665f91bedc 53 } pixelInfo;
AndyA 0:b3665f91bedc 54
AndyA 0:b3665f91bedc 55
AndyA 1:741864ea11d4 56 /** Drives a WS2812 LED chain
AndyA 1:741864ea11d4 57 *
AndyA 1:741864ea11d4 58 * An alternative WS2811/2812 driver using the BusrtSPI library
AndyA 1:741864ea11d4 59 *
AndyA 1:741864ea11d4 60 * Credit for the inspiration goes to Jacob for his pixelArray library
AndyA 1:741864ea11d4 61 * http://developer.mbed.org/users/JacobBramley/code/PixelArray/
AndyA 1:741864ea11d4 62 *
AndyA 1:741864ea11d4 63 * This version was written mainly to help me understand what was going on and is a little more basic.
AndyA 1:741864ea11d4 64 * While the end result is muc the same the code is completely from scratch.
AndyA 1:741864ea11d4 65 *
AndyA 1:741864ea11d4 66 * BurstSPI is used to generate the timing so support is limited to the parts supported by that library.
AndyA 1:741864ea11d4 67 *
AndyA 1:741864ea11d4 68 * 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 69 *
AndyA 3:3c48065d20ff 70 * Values for each LED are stored in either an array of pixelInfo or pixelInfo16 structures
AndyA 3:3c48065d20ff 71 * Each LED only supports 0-255 for each colour, the limits of the pixelInfo data type.
AndyA 3:3c48065d20ff 72 *
AndyA 3:3c48065d20ff 73 * The 16 bit version is for when you are adding/subtracting values in order to avoid
AndyA 3:3c48065d20ff 74 * wraparound issues. When displayed the values outside the range are clamped to the limits.
AndyA 3:3c48065d20ff 75 * This allows tricks like having a point with negative brighnesses moving along the line to add a
AndyA 3:3c48065d20ff 76 * dark spot without having to worry about what happens if a number goes negative.
AndyA 3:3c48065d20ff 77 *
AndyA 3:3c48065d20ff 78 *
AndyA 1:741864ea11d4 79 * Example code to run a single lit led along a chain
AndyA 1:741864ea11d4 80 *
AndyA 1:741864ea11d4 81 * @code
AndyA 1:741864ea11d4 82 *
AndyA 1:741864ea11d4 83 * #include "mbed.h"
AndyA 1:741864ea11d4 84 * #include "wsDrive.h"
AndyA 1:741864ea11d4 85 *
AndyA 1:741864ea11d4 86 * // update period in ms
AndyA 1:741864ea11d4 87 * #define updatePeriod 100
AndyA 1:741864ea11d4 88 * // number of LEDs
AndyA 1:741864ea11d4 89 * #define chainLen 8
AndyA 1:741864ea11d4 90 *
AndyA 1:741864ea11d4 91 * DigitalIn dummy(MOSI,PullDown); // first activate the pulldown on the pin.
AndyA 1:741864ea11d4 92 * 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 93 *
AndyA 1:741864ea11d4 94 * // pixel storage buffer
AndyA 1:741864ea11d4 95 * pixelInfo pixelData[chainLen];
AndyA 1:741864ea11d4 96 *
AndyA 1:741864ea11d4 97 * Timer updateRateTimer;
AndyA 1:741864ea11d4 98 *
AndyA 1:741864ea11d4 99 * void blankBuffer(pixelInfo *Ptr)
AndyA 1:741864ea11d4 100 * {
AndyA 1:741864ea11d4 101 * memset( (void *)Ptr, 0, chainLen*sizeof(pixelInfo) );
AndyA 1:741864ea11d4 102 * }
AndyA 1:741864ea11d4 103 *
AndyA 1:741864ea11d4 104 * void setPixel(unsigned int index, pixelInfo *colourToUse) {
AndyA 1:741864ea11d4 105 * if (index < chainLen) {
AndyA 1:741864ea11d4 106 * pixelData[index].R = colourToUse->R;
AndyA 1:741864ea11d4 107 * pixelData[index].G = colourToUse->G;
AndyA 1:741864ea11d4 108 * pixelData[index].B = colourToUse->B;
AndyA 1:741864ea11d4 109 * }
AndyA 1:741864ea11d4 110 * }
AndyA 1:741864ea11d4 111 *
AndyA 1:741864ea11d4 112 * void clearPixel(unsigned int index) {
AndyA 1:741864ea11d4 113 * if (index < chainLen) {
AndyA 1:741864ea11d4 114 * pixelData[index].R = 0;
AndyA 1:741864ea11d4 115 * pixelData[index].G = 0;
AndyA 1:741864ea11d4 116 * pixelData[index].B = 0;
AndyA 1:741864ea11d4 117 * }
AndyA 1:741864ea11d4 118 * }
AndyA 1:741864ea11d4 119 *
AndyA 1:741864ea11d4 120 * int main () {
AndyA 1:741864ea11d4 121 *
AndyA 1:741864ea11d4 122 * int litLed = 0;
AndyA 1:741864ea11d4 123 *
AndyA 1:741864ea11d4 124 * pixelInfo colour;
AndyA 1:741864ea11d4 125 * colour.R = 0x80;
AndyA 1:741864ea11d4 126 * colour.G = 0x00;
AndyA 1:741864ea11d4 127 * colour.B = 0x00;
AndyA 1:741864ea11d4 128 *
AndyA 1:741864ea11d4 129 * // Tell the driver where the data is stored
AndyA 1:741864ea11d4 130 * ledDriver.setData(pixelData, chainLen);
AndyA 1:741864ea11d4 131 *
AndyA 1:741864ea11d4 132 * // Set the buffer to the pattern we want
AndyA 1:741864ea11d4 133 * blankBuffer(pixelData);
AndyA 1:741864ea11d4 134 * setPixel(litLed, &colour);
AndyA 1:741864ea11d4 135 *
AndyA 1:741864ea11d4 136 * updateRateTimer.start();
AndyA 1:741864ea11d4 137 * while (true) {
AndyA 1:741864ea11d4 138 *
AndyA 1:741864ea11d4 139 * ledDriver.sendData(); // send the LED data
AndyA 1:741864ea11d4 140 *
AndyA 1:741864ea11d4 141 * // modify the buffer ready for the next update
AndyA 1:741864ea11d4 142 * clearPixel(litLed);
AndyA 1:741864ea11d4 143 * litLed++;
AndyA 1:741864ea11d4 144 * if (litLed == chainLen)
AndyA 1:741864ea11d4 145 * litLed = 0;
AndyA 1:741864ea11d4 146 * setPixel(litLed, &colour);
AndyA 1:741864ea11d4 147 *
AndyA 1:741864ea11d4 148 * // wait until the correct time since the last update...
AndyA 1:741864ea11d4 149 * while (updateRateTimer.read_ms() < updatePeriod) {
AndyA 1:741864ea11d4 150 * }
AndyA 1:741864ea11d4 151
AndyA 1:741864ea11d4 152 * updateRateTimer.reset();
AndyA 1:741864ea11d4 153 * }
AndyA 1:741864ea11d4 154 * }
AndyA 1:741864ea11d4 155 * @endcode
AndyA 1:741864ea11d4 156 *
AndyA 1:741864ea11d4 157 * Troubleshooting:
AndyA 1:741864ea11d4 158 *
AndyA 1:741864ea11d4 159 * 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 160 *
AndyA 1:741864ea11d4 161 * 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 162 * 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 163 * to about 4.2 - 4.3 V will normally fix this problem without any meaningful impact on the LED output.
AndyA 1:741864ea11d4 164 *
AndyA 1:741864ea11d4 165 */
AndyA 0:b3665f91bedc 166 class wsDrive : private BurstSPI
AndyA 0:b3665f91bedc 167 {
AndyA 0:b3665f91bedc 168 public:
AndyA 1:741864ea11d4 169 /** create the driver
AndyA 1:741864ea11d4 170 */
AndyA 0:b3665f91bedc 171 wsDrive(PinName mosi, PinName miso, PinName clk);
AndyA 1:741864ea11d4 172
AndyA 1:741864ea11d4 173 /** Set the data pointer
AndyA 1:741864ea11d4 174
AndyA 1:741864ea11d4 175 Before data can be sent the driver must be given a pointer to the pixel data to use.
AndyA 1:741864ea11d4 176 Setting this is normally a one time operation unless you want to switch between buffers.
AndyA 3:3c48065d20ff 177 Calling this function will replace any prior buffers including pixelInfo16 ones.
AndyA 1:741864ea11d4 178
AndyA 1:741864ea11d4 179 @param dataStart The start of an array of pixelInfo items. This will be sent to the chain in order.
AndyA 1:741864ea11d4 180 @param dataLen The length of the array.
AndyA 1:741864ea11d4 181 */
AndyA 0:b3665f91bedc 182 void setData(pixelInfo *dataStart, uint16_t dataLen);
AndyA 1:741864ea11d4 183
AndyA 3:3c48065d20ff 184 /** Set the data pointer
AndyA 3:3c48065d20ff 185
AndyA 3:3c48065d20ff 186 Before data can be sent the driver must be given a pointer to the pixel data to use.
AndyA 3:3c48065d20ff 187 Setting this is normally a one time operation unless you want to switch between buffers.
AndyA 3:3c48065d20ff 188 Calling this function will replace any prior buffers including pixelInfo ones.
AndyA 3:3c48065d20ff 189
AndyA 3:3c48065d20ff 190 @param dataStart The start of an array of pixelInfo16 items. This will be sent to the chain in order.
AndyA 3:3c48065d20ff 191 @param dataLen The length of the array.
AndyA 3:3c48065d20ff 192 */
AndyA 3:3c48065d20ff 193 void setData(pixelInfo16 *dataStart, uint16_t dataLen);
AndyA 3:3c48065d20ff 194
AndyA 1:741864ea11d4 195
AndyA 1:741864ea11d4 196 /** Sends the data to the LEDs
AndyA 1:741864ea11d4 197 * setData() must be called prior to this.
AndyA 1:741864ea11d4 198 */
AndyA 0:b3665f91bedc 199 void sendData();
AndyA 1:741864ea11d4 200
AndyA 0:b3665f91bedc 201 private:
AndyA 0:b3665f91bedc 202
AndyA 0:b3665f91bedc 203 void sendByte(unsigned char value);
AndyA 0:b3665f91bedc 204 void sendPixel(pixelInfo *pixToSend);
AndyA 3:3c48065d20ff 205 void sendPixel(pixelInfo16 *pixToSend);
AndyA 1:741864ea11d4 206
AndyA 0:b3665f91bedc 207 pixelInfo *pixArray;
AndyA 3:3c48065d20ff 208 pixelInfo16 *pixArray16;
AndyA 0:b3665f91bedc 209 uint16_t pixelLen;
AndyA 0:b3665f91bedc 210
AndyA 0:b3665f91bedc 211 };
AndyA 0:b3665f91bedc 212
AndyA 0:b3665f91bedc 213 #endif