Library for the WS2812 LED Driver. Uses bit banging and nops for precise timing. Number of nops executed are configurable at run time.
Diff: WS2812.cpp
- Revision:
- 0:0b79cafcb387
- Child:
- 1:aadbf08c62a2
diff -r 000000000000 -r 0b79cafcb387 WS2812.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WS2812.cpp Thu Feb 12 19:17:10 2015 +0000 @@ -0,0 +1,128 @@ +#include "WS2812.h" + +WS2812::WS2812(PinName d, int size) : __gpo(d) +{ + __size = size; + __transmitBuf = new bool[size * FRAME_SIZE]; + __use_II = 0; // 0=off,1=use global,2=per pixel + __II = 0xFF; // set global intensity to full + __outPin = d; + + // Default values designed for K64f. Assumes GPIO toggle takes ~0.4us + setDelays(0, 5, 5, 0); +} + + +WS2812::~WS2812() +{ + delete[] __transmitBuf; +} + +void WS2812::setDelays(int zeroHigh, int zeroLow, int oneHigh, int oneLow) { + __zeroHigh = zeroHigh; + __zeroLow = zeroLow; + __oneHigh = oneHigh; + __oneLow = oneLow; +} + +void WS2812::__loadBuf(int buf[],int r_offset, int g_offset, int b_offset) { + for (int i = 0; i < __size; i++) { + int color = 0; + + color |= ((buf[(i+g_offset)%__size] & 0x0000FF00)); + color |= ((buf[(i+r_offset)%__size] & 0x00FF0000)); + color |= (buf[(i+b_offset)%__size] & 0x000000FF); + color |= (buf[i] & 0xFF000000); + + // Outut format : GGRRBB + // Inout format : IIRRGGBB + unsigned char agrb[4] = {0x0, 0x0, 0x0, 0x0}; + + unsigned char sf; // scaling factor for II + + // extract colour fields from incoming + // 0 = green, 1 = red, 2 = blue, 3 = brightness + agrb[0] = (color & 0x0000FF00) >> 8; + agrb[1] = (color & 0x00FF0000) >> 16; + agrb[2] = color & 0x000000FF; + agrb[3] = (color & 0xFF000000) >> 24; + + // set and intensity scaling factor (global, per pixel, none) + if (__use_II == 1) { + sf = __II; + } else if (__use_II == 2) { + sf = agrb[3]; + } else { + sf = 0xFF; + } + + // Apply the scaling factor to each othe colour components + for (int clr = 0; clr < 3; clr++) { + agrb[clr] = ((agrb[clr] * sf) >> 8); + + for (int j = 0; j < 8; j++) { + if (((agrb[clr] << j) & 0x80) == 0x80) { + // Bit is set (checks MSB fist) + __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 1; + } else { + // Bit is clear + __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 0; + } + } + } + } +} + +void WS2812::write(int buf[]) { + write_offsets(buf, 0, 0, 0); +} + +void WS2812::write_offsets (int buf[],int r_offset, int g_offset, int b_offset) { + int i, j; + + __loadBuf(buf, r_offset, g_offset, b_offset); + + for (i = 0; i < FRAME_SIZE * __size; i++) { + j = 0; + if (__transmitBuf[i]){ + __gpo = 1; + for (; j < __oneHigh; j++) { + __nop(); + } + __gpo = 0; + for (; j < __oneLow; j++) { + __nop(); + } + } else { + __gpo = 1; + for (; j < __zeroHigh; j++) { + __nop(); + } + __gpo = 0; + for (; j < __zeroLow; j++) { + __nop(); + } + } + } +} + + +void WS2812::useII(int d) +{ + if (d > 0) { + __use_II = d; + } else { + __use_II = 0; + } +} + +void WS2812::setII(unsigned char II) +{ + __II = II; +} + + + + + +