WS2812

Dependents:   pelion-example-common

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WS2812.cpp Source File

WS2812.cpp

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