Library for the WS2812 LED Driver. Uses bit banging and nops for precise timing. Number of nops executed are configurable at run time.
WS2812.cpp@0:0b79cafcb387, 2015-02-12 (annotated)
- Committer:
- bridadan
- Date:
- Thu Feb 12 19:17:10 2015 +0000
- Revision:
- 0:0b79cafcb387
- Child:
- 1:aadbf08c62a2
Driver for the WS2812 LED driver. Uses bit banging and relies on nops for timing. Number of nops can be varied to potentially accommodate different platforms. Currently tested on the K64F.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bridadan | 0:0b79cafcb387 | 1 | #include "WS2812.h" |
bridadan | 0:0b79cafcb387 | 2 | |
bridadan | 0:0b79cafcb387 | 3 | WS2812::WS2812(PinName d, int size) : __gpo(d) |
bridadan | 0:0b79cafcb387 | 4 | { |
bridadan | 0:0b79cafcb387 | 5 | __size = size; |
bridadan | 0:0b79cafcb387 | 6 | __transmitBuf = new bool[size * FRAME_SIZE]; |
bridadan | 0:0b79cafcb387 | 7 | __use_II = 0; // 0=off,1=use global,2=per pixel |
bridadan | 0:0b79cafcb387 | 8 | __II = 0xFF; // set global intensity to full |
bridadan | 0:0b79cafcb387 | 9 | __outPin = d; |
bridadan | 0:0b79cafcb387 | 10 | |
bridadan | 0:0b79cafcb387 | 11 | // Default values designed for K64f. Assumes GPIO toggle takes ~0.4us |
bridadan | 0:0b79cafcb387 | 12 | setDelays(0, 5, 5, 0); |
bridadan | 0:0b79cafcb387 | 13 | } |
bridadan | 0:0b79cafcb387 | 14 | |
bridadan | 0:0b79cafcb387 | 15 | |
bridadan | 0:0b79cafcb387 | 16 | WS2812::~WS2812() |
bridadan | 0:0b79cafcb387 | 17 | { |
bridadan | 0:0b79cafcb387 | 18 | delete[] __transmitBuf; |
bridadan | 0:0b79cafcb387 | 19 | } |
bridadan | 0:0b79cafcb387 | 20 | |
bridadan | 0:0b79cafcb387 | 21 | void WS2812::setDelays(int zeroHigh, int zeroLow, int oneHigh, int oneLow) { |
bridadan | 0:0b79cafcb387 | 22 | __zeroHigh = zeroHigh; |
bridadan | 0:0b79cafcb387 | 23 | __zeroLow = zeroLow; |
bridadan | 0:0b79cafcb387 | 24 | __oneHigh = oneHigh; |
bridadan | 0:0b79cafcb387 | 25 | __oneLow = oneLow; |
bridadan | 0:0b79cafcb387 | 26 | } |
bridadan | 0:0b79cafcb387 | 27 | |
bridadan | 0:0b79cafcb387 | 28 | void WS2812::__loadBuf(int buf[],int r_offset, int g_offset, int b_offset) { |
bridadan | 0:0b79cafcb387 | 29 | for (int i = 0; i < __size; i++) { |
bridadan | 0:0b79cafcb387 | 30 | int color = 0; |
bridadan | 0:0b79cafcb387 | 31 | |
bridadan | 0:0b79cafcb387 | 32 | color |= ((buf[(i+g_offset)%__size] & 0x0000FF00)); |
bridadan | 0:0b79cafcb387 | 33 | color |= ((buf[(i+r_offset)%__size] & 0x00FF0000)); |
bridadan | 0:0b79cafcb387 | 34 | color |= (buf[(i+b_offset)%__size] & 0x000000FF); |
bridadan | 0:0b79cafcb387 | 35 | color |= (buf[i] & 0xFF000000); |
bridadan | 0:0b79cafcb387 | 36 | |
bridadan | 0:0b79cafcb387 | 37 | // Outut format : GGRRBB |
bridadan | 0:0b79cafcb387 | 38 | // Inout format : IIRRGGBB |
bridadan | 0:0b79cafcb387 | 39 | unsigned char agrb[4] = {0x0, 0x0, 0x0, 0x0}; |
bridadan | 0:0b79cafcb387 | 40 | |
bridadan | 0:0b79cafcb387 | 41 | unsigned char sf; // scaling factor for II |
bridadan | 0:0b79cafcb387 | 42 | |
bridadan | 0:0b79cafcb387 | 43 | // extract colour fields from incoming |
bridadan | 0:0b79cafcb387 | 44 | // 0 = green, 1 = red, 2 = blue, 3 = brightness |
bridadan | 0:0b79cafcb387 | 45 | agrb[0] = (color & 0x0000FF00) >> 8; |
bridadan | 0:0b79cafcb387 | 46 | agrb[1] = (color & 0x00FF0000) >> 16; |
bridadan | 0:0b79cafcb387 | 47 | agrb[2] = color & 0x000000FF; |
bridadan | 0:0b79cafcb387 | 48 | agrb[3] = (color & 0xFF000000) >> 24; |
bridadan | 0:0b79cafcb387 | 49 | |
bridadan | 0:0b79cafcb387 | 50 | // set and intensity scaling factor (global, per pixel, none) |
bridadan | 0:0b79cafcb387 | 51 | if (__use_II == 1) { |
bridadan | 0:0b79cafcb387 | 52 | sf = __II; |
bridadan | 0:0b79cafcb387 | 53 | } else if (__use_II == 2) { |
bridadan | 0:0b79cafcb387 | 54 | sf = agrb[3]; |
bridadan | 0:0b79cafcb387 | 55 | } else { |
bridadan | 0:0b79cafcb387 | 56 | sf = 0xFF; |
bridadan | 0:0b79cafcb387 | 57 | } |
bridadan | 0:0b79cafcb387 | 58 | |
bridadan | 0:0b79cafcb387 | 59 | // Apply the scaling factor to each othe colour components |
bridadan | 0:0b79cafcb387 | 60 | for (int clr = 0; clr < 3; clr++) { |
bridadan | 0:0b79cafcb387 | 61 | agrb[clr] = ((agrb[clr] * sf) >> 8); |
bridadan | 0:0b79cafcb387 | 62 | |
bridadan | 0:0b79cafcb387 | 63 | for (int j = 0; j < 8; j++) { |
bridadan | 0:0b79cafcb387 | 64 | if (((agrb[clr] << j) & 0x80) == 0x80) { |
bridadan | 0:0b79cafcb387 | 65 | // Bit is set (checks MSB fist) |
bridadan | 0:0b79cafcb387 | 66 | __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 1; |
bridadan | 0:0b79cafcb387 | 67 | } else { |
bridadan | 0:0b79cafcb387 | 68 | // Bit is clear |
bridadan | 0:0b79cafcb387 | 69 | __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 0; |
bridadan | 0:0b79cafcb387 | 70 | } |
bridadan | 0:0b79cafcb387 | 71 | } |
bridadan | 0:0b79cafcb387 | 72 | } |
bridadan | 0:0b79cafcb387 | 73 | } |
bridadan | 0:0b79cafcb387 | 74 | } |
bridadan | 0:0b79cafcb387 | 75 | |
bridadan | 0:0b79cafcb387 | 76 | void WS2812::write(int buf[]) { |
bridadan | 0:0b79cafcb387 | 77 | write_offsets(buf, 0, 0, 0); |
bridadan | 0:0b79cafcb387 | 78 | } |
bridadan | 0:0b79cafcb387 | 79 | |
bridadan | 0:0b79cafcb387 | 80 | void WS2812::write_offsets (int buf[],int r_offset, int g_offset, int b_offset) { |
bridadan | 0:0b79cafcb387 | 81 | int i, j; |
bridadan | 0:0b79cafcb387 | 82 | |
bridadan | 0:0b79cafcb387 | 83 | __loadBuf(buf, r_offset, g_offset, b_offset); |
bridadan | 0:0b79cafcb387 | 84 | |
bridadan | 0:0b79cafcb387 | 85 | for (i = 0; i < FRAME_SIZE * __size; i++) { |
bridadan | 0:0b79cafcb387 | 86 | j = 0; |
bridadan | 0:0b79cafcb387 | 87 | if (__transmitBuf[i]){ |
bridadan | 0:0b79cafcb387 | 88 | __gpo = 1; |
bridadan | 0:0b79cafcb387 | 89 | for (; j < __oneHigh; j++) { |
bridadan | 0:0b79cafcb387 | 90 | __nop(); |
bridadan | 0:0b79cafcb387 | 91 | } |
bridadan | 0:0b79cafcb387 | 92 | __gpo = 0; |
bridadan | 0:0b79cafcb387 | 93 | for (; j < __oneLow; j++) { |
bridadan | 0:0b79cafcb387 | 94 | __nop(); |
bridadan | 0:0b79cafcb387 | 95 | } |
bridadan | 0:0b79cafcb387 | 96 | } else { |
bridadan | 0:0b79cafcb387 | 97 | __gpo = 1; |
bridadan | 0:0b79cafcb387 | 98 | for (; j < __zeroHigh; j++) { |
bridadan | 0:0b79cafcb387 | 99 | __nop(); |
bridadan | 0:0b79cafcb387 | 100 | } |
bridadan | 0:0b79cafcb387 | 101 | __gpo = 0; |
bridadan | 0:0b79cafcb387 | 102 | for (; j < __zeroLow; j++) { |
bridadan | 0:0b79cafcb387 | 103 | __nop(); |
bridadan | 0:0b79cafcb387 | 104 | } |
bridadan | 0:0b79cafcb387 | 105 | } |
bridadan | 0:0b79cafcb387 | 106 | } |
bridadan | 0:0b79cafcb387 | 107 | } |
bridadan | 0:0b79cafcb387 | 108 | |
bridadan | 0:0b79cafcb387 | 109 | |
bridadan | 0:0b79cafcb387 | 110 | void WS2812::useII(int d) |
bridadan | 0:0b79cafcb387 | 111 | { |
bridadan | 0:0b79cafcb387 | 112 | if (d > 0) { |
bridadan | 0:0b79cafcb387 | 113 | __use_II = d; |
bridadan | 0:0b79cafcb387 | 114 | } else { |
bridadan | 0:0b79cafcb387 | 115 | __use_II = 0; |
bridadan | 0:0b79cafcb387 | 116 | } |
bridadan | 0:0b79cafcb387 | 117 | } |
bridadan | 0:0b79cafcb387 | 118 | |
bridadan | 0:0b79cafcb387 | 119 | void WS2812::setII(unsigned char II) |
bridadan | 0:0b79cafcb387 | 120 | { |
bridadan | 0:0b79cafcb387 | 121 | __II = II; |
bridadan | 0:0b79cafcb387 | 122 | } |
bridadan | 0:0b79cafcb387 | 123 | |
bridadan | 0:0b79cafcb387 | 124 | |
bridadan | 0:0b79cafcb387 | 125 | |
bridadan | 0:0b79cafcb387 | 126 | |
bridadan | 0:0b79cafcb387 | 127 | |
bridadan | 0:0b79cafcb387 | 128 |