Library for the WS2812 LED Driver. Uses bit banging and nops for precise timing. Number of nops executed are configurable at run time.

Dependents:   WS2812_Example WS2812_Example_fade Lamp_03 Lamp_04 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WS2812.cpp Source File

WS2812.cpp

00001 #include "WS2812.h"
00002 
00003 WS2812::WS2812(PinName pin, int size, int zeroHigh, int zeroLow, int oneHigh, int oneLow) : __gpo(pin)
00004 {
00005     __size = size;
00006     __transmitBuf = new bool[size * FRAME_SIZE];
00007     __use_II = OFF;
00008     __II = 0xFF; // set global intensity to full
00009     __outPin = pin;
00010     
00011     // Default values designed for K64f. Assumes GPIO toggle takes ~0.4us
00012     setDelays(zeroHigh, zeroLow, oneHigh, oneLow);
00013 }
00014 
00015 
00016 WS2812::~WS2812 ()
00017 {
00018     delete[] __transmitBuf;
00019 }
00020 
00021 void WS2812::setDelays(int zeroHigh, int zeroLow, int oneHigh, int oneLow) {
00022     __zeroHigh = zeroHigh;
00023     __zeroLow = zeroLow;
00024     __oneHigh = oneHigh;
00025     __oneLow = oneLow;
00026 }
00027 
00028 void WS2812::__loadBuf(int buf[],int r_offset, int g_offset, int b_offset) {
00029     for (int i = 0; i < __size; i++) {
00030         int color = 0;
00031                
00032         color |= ((buf[(i+g_offset)%__size] & 0x0000FF00));
00033         color |= ((buf[(i+r_offset)%__size] & 0x00FF0000));
00034         color |=  (buf[(i+b_offset)%__size] & 0x000000FF);
00035         color |= (buf[i] & 0xFF000000);
00036         
00037         // Outut format : GGRRBB
00038         // Inout format : IIRRGGBB
00039         unsigned char agrb[4] = {0x0, 0x0, 0x0, 0x0};
00040     
00041         unsigned char sf; // scaling factor for  II
00042     
00043         // extract colour fields from incoming
00044         // 0 = green, 1 = red, 2 = blue, 3 = brightness        
00045         agrb[0] = (color & 0x0000FF00) >> 8;
00046         agrb[1] = (color & 0x00FF0000) >> 16;
00047         agrb[2] = color  & 0x000000FF;
00048         agrb[3] = (color & 0xFF000000) >> 24;
00049     
00050         // set the intensity scaling factor (global, per pixel, none)
00051         if (__use_II == GLOBAL) {
00052             sf = __II;
00053         } else if (__use_II == PER_PIXEL) {
00054             sf = agrb[3];
00055         } else {
00056             sf = 0xFF;
00057         }
00058         
00059         // Apply the scaling factor to each othe colour components
00060         for (int clr = 0; clr < 3; clr++) {
00061             agrb[clr] = ((agrb[clr] * sf) >> 8);
00062             
00063             for (int j = 0; j < 8; j++) {
00064                 if (((agrb[clr] << j) & 0x80) == 0x80) {
00065                     // Bit is set (checks MSB fist)
00066                     __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 1;
00067                 } else {
00068                     // Bit is clear
00069                     __transmitBuf[(i * FRAME_SIZE) + (clr * 8) + j] = 0;
00070                 }
00071             }
00072         }
00073     }
00074 }
00075 
00076 void WS2812::write(int buf[]) {
00077     write_offsets(buf, 0, 0, 0);
00078 }
00079 
00080 void WS2812::write_offsets (int buf[],int r_offset, int g_offset, int b_offset) {
00081     int i, j;
00082     
00083     // Load the transmit buffer
00084     __loadBuf(buf, r_offset, g_offset, b_offset);
00085 
00086     // Entering timing critical section, so disabling interrupts
00087     __disable_irq();
00088     
00089     // Begin bit-banging
00090     for (i = 0; i < FRAME_SIZE * __size; i++) {
00091         j = 0;
00092         if (__transmitBuf[i]){
00093             __gpo = 1;
00094             for (; j < __oneHigh; j++) {
00095                 __nop();
00096             }
00097             __gpo = 0;
00098             for (; j < __oneLow; j++) {
00099                 __nop();
00100             }
00101         } else {
00102             __gpo = 1;
00103             for (; j < __zeroHigh; j++) {
00104                 __nop();
00105             }
00106             __gpo = 0;
00107             for (; j < __zeroLow; j++) {
00108                 __nop();
00109             }
00110         }
00111     }
00112     
00113     // Exiting timing critical section, so enabling interrutps
00114     __enable_irq();
00115 }
00116 
00117 
00118 void WS2812::useII(BrightnessControl bc)
00119 {
00120     if (bc > OFF) {
00121         __use_II = bc;
00122     } else {
00123         __use_II = OFF;
00124     }
00125 }
00126 
00127 void WS2812::setII(unsigned char II)
00128 {
00129     __II = II;
00130 }
00131 
00132 
00133 
00134 
00135 
00136