Displays text on a WS2812 (NeoPixel) matrix display

Dependencies:   mbed miniFont wsDrive

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "wsDrive.h"
00003 #include "miniFont.h"
00004 
00005 #define updatePeriodMS 2000
00006 
00007 
00008 /*
00009 LED config - Assume all LEDs are in one logical chain of len*count leds.
00010 Physical layout is:
00011 
00012 ChainLen = 4, ChainCount = 2, cascadeZigZag undefined
00013 
00014   D1 -> D2 -> D3 -> D4
00015   D5 -> D6 -> D7 -> D8
00016 
00017 ChainLen = 4, ChainCount = 3, cascadeZigZag defined
00018 
00019   D1 -> D2  -> D3  -> D4
00020   D8 <- D7  <- D6  <- D5
00021   D9 -> D10 -> D11 -> D12
00022 
00023 Text will use the top 5 rows. Text displayed on a chainCount of < 5 will be trimmed.
00024 Letters are generally 5 pixels wide, numbers and punctuation are 5 or less.
00025 The default is for a 1 pixel gap between characters so you will need 6 leds per letter displayed.
00026 
00027 System uses two buffers, one for that data to display, one to calculate the next data.
00028 This allows shifts in either direction without overwriting values we haven't used yet.
00029 Rather than do lots of copying each frame we toggle between which one is being displayed
00030 and which calculated.
00031 
00032 */
00033 
00034 // LED config options:
00035 
00036 // uncomment if the direction of connections reverse each row.
00037 const bool cascadeZigZag = false;
00038 const bool topRowL2R = true;
00039 
00040 const uint16_t chainLen = 35;
00041 const uint16_t chainCount = 5;
00042 
00043 // IO setup - currently set for mbuino.
00044 
00045 DigitalIn dummy(P0_21,PullDown);
00046 wsDrive ledDriver(P0_21,P0_22,P1_15);
00047 DigitalIn progMode(P0_3,PullDown);
00048 BusOut LEDs(LED1, LED2, LED3, LED4, LED5, LED6, LED7);
00049 
00050 
00051 // globals
00052 
00053 miniFont pixelText;
00054 
00055 Timer updateRateTimer;
00056 
00057 pixelInfo pixelData1[chainLen * chainCount];
00058 pixelInfo pixelData2[chainLen * chainCount];
00059 pixelInfo *livePixels;
00060 pixelInfo *nextPixels;
00061 
00062 // could be optimised more but most of this is constants so the compiler should
00063 // do that for us. This is confusing enough as it is.
00064 inline bool reverseRow(uint16_t row)
00065 {
00066     if (cascadeZigZag) {
00067         if (topRowL2R) {         // left to right we reverse odd rows
00068             if (row%2) // odd row
00069                 return true;
00070             else
00071                 return false;
00072         } else {                   // right to left reverse even rows.
00073             if (row%2) // odd row
00074                 return false;
00075             else
00076                 return true;
00077         }
00078     } else {
00079         if (topRowL2R)         // left to right reverse none
00080             return false;
00081         else                   // right to left reverse all.
00082             return true;
00083     }
00084 }
00085 
00086 inline uint16_t xy2index(uint16_t x, uint16_t y)
00087 {
00088     if (x >= chainLen)
00089         x = 0;
00090     if (y >= chainCount)
00091         y = 0;
00092 
00093     if (reverseRow(y))
00094         return (y+1)*chainLen - x - 1;
00095     else
00096         return y*chainLen + x;
00097 }
00098 
00099 
00100 void blankBuffer(pixelInfo *Ptr)
00101 {
00102     memset( (void *) Ptr, 00, sizeof(pixelInfo)*chainCount*chainLen );
00103 }
00104 
00105 
00106 void initColour(pixelInfo *colour)
00107 {
00108     for (int i = 0; i<(chainLen * chainCount); i++) {
00109         nextPixels[i].R = colour->R;
00110         nextPixels[i].G = colour->G;
00111         nextPixels[i].B = colour->B;
00112     }
00113 }
00114 
00115 void initGradient(pixelInfo *startColour, pixelInfo *endColour)
00116 {
00117     uint16_t thisPixIndex;
00118     float redDelta = ((float)(endColour->R) - (float)(startColour->R)) / chainLen;
00119     float greenDelta = ((float)(endColour->G) - (float)(startColour->G)) / chainLen;
00120     float blueDelta = ((float)(endColour->B) - (float)(startColour->B)) / chainLen;
00121 
00122     for (int i = 0; i<(chainLen); i++) {
00123         for (uint8_t row = 0; row < chainCount; row++) {
00124 
00125             thisPixIndex = xy2index(i,row);
00126 
00127             nextPixels[thisPixIndex].R = redDelta*i + startColour->R;
00128             nextPixels[thisPixIndex].G = greenDelta*i + startColour->G;
00129             nextPixels[thisPixIndex].B = blueDelta*i + startColour->B;
00130         }
00131     }
00132 }
00133 
00134 uint16_t initText(const char *text, pixelInfo colour, int16_t startPixel = 0, int16_t startRow = 0)
00135 {
00136 
00137     uint8_t charIndex = 0;
00138     uint8_t thisWidth;
00139     uint8_t thisHeight;
00140     uint16_t pixelY;
00141     uint16_t pixelX;
00142     uint16_t thisPixIndex;
00143     const char *charData;
00144 
00145 
00146     if (startRow >= chainCount)
00147         return startPixel;
00148 
00149     while (*(text+charIndex)) {
00150 
00151 
00152         if (startPixel >= chainLen)
00153             return chainLen;
00154 
00155         thisHeight = pixelText.getPixHeight(*(text+charIndex));
00156         thisWidth = pixelText.getPixWidth(*(text+charIndex));
00157 
00158         if (pixelText.getChar(*(text+charIndex),&charData)) {
00159 
00160             if ((startPixel + thisWidth) > chainLen)
00161                 thisWidth = chainLen - startPixel;
00162 
00163             for (uint8_t row = 0; row < thisHeight; row++) {
00164 
00165                 pixelY = row + startRow;
00166                 if (pixelY >= chainCount)
00167                     break;
00168 
00169                 for (int16_t col = 0; col < thisWidth; col++) {
00170                     pixelX = startPixel + col;
00171                     if (pixelX >= chainLen)
00172                         break;
00173 
00174                     thisPixIndex = xy2index(pixelX,pixelY);
00175 
00176                     if (*(charData+row) & (1<<(thisWidth-col-1)) ) {
00177                         nextPixels[thisPixIndex].R = colour.R;
00178                         nextPixels[thisPixIndex].G = colour.G;
00179                         nextPixels[thisPixIndex].B = colour.B;
00180                     }
00181 
00182                 } // end for col
00183             } //end for each row
00184         } // end if we got data for that character
00185         startPixel += thisWidth + 1;
00186         charIndex++;
00187     } // end while characters left
00188     return startPixel;
00189 }
00190 
00191 void initChain ()
00192 {
00193     pixelInfo textColour;
00194     pixelInfo bgColour1;
00195     pixelInfo bgColour2;
00196 
00197     // optionally use initColour to set a background colour
00198     bgColour1.R = 0x00;
00199     bgColour1.G = 0x08;
00200     bgColour1.B = 0x00;
00201     
00202     bgColour2.R = 0x08;
00203     bgColour2.G = 0x00;
00204     bgColour2.B = 0x00;
00205 
00206     initGradient(&bgColour1,&bgColour2);
00207 
00208     // set text colour
00209     textColour.R = 0x40;
00210     textColour.G = 0x00;
00211     textColour.B = 0x00;
00212 
00213     // add text keeping the index for the next character.
00214     uint16_t nextChar = initText("H", textColour);
00215 
00216     // change the colour
00217     textColour.R = 0x10;
00218     textColour.G = 0x10;
00219     textColour.B = 0x30;
00220     // add more text.
00221     nextChar = initText("el", textColour, nextChar);
00222 
00223     // change the colour
00224     textColour.R = 0x30;
00225     textColour.G = 0x30;
00226     textColour.B = 0x00;
00227     // add more text.
00228     nextChar = initText("l", textColour, nextChar);
00229 
00230     // one more colour
00231     textColour.R = 0x00;
00232     textColour.G = 0x40;
00233     textColour.B = 0x00;
00234     // and a final letter.
00235     initText("0", textColour, nextChar);
00236 
00237 }
00238 
00239 
00240 // in theory lets you rotate red green and blue independantly an arbitary number of places in either direction.
00241 // not well tested.
00242 void rotateChain (int redStep, int greenStep, int blueStep)
00243 {
00244     while (redStep < 0)
00245         redStep += chainLen;
00246 
00247     while (greenStep < 0)
00248         greenStep += chainLen;
00249 
00250     while (blueStep < 0)
00251         blueStep += chainLen;
00252 
00253     uint16_t thisPixIndex;
00254     uint16_t redPixIndex;
00255     uint16_t bluePixIndex;
00256     uint16_t greenPixIndex;
00257 
00258     for (uint16_t col = 0; col<chainLen; col++) {
00259         for (uint8_t row = 0; row < chainCount; row++) {
00260 
00261             thisPixIndex = xy2index(col,row);
00262 
00263             redPixIndex   = xy2index((col+redStep)%chainLen,  row);
00264             bluePixIndex  = xy2index((col+blueStep)%chainLen, row);
00265             greenPixIndex = xy2index((col+greenStep)%chainLen,row);
00266 
00267             nextPixels[thisPixIndex].R = livePixels[redPixIndex].R;
00268             nextPixels[thisPixIndex].G = livePixels[greenPixIndex].G;
00269             nextPixels[thisPixIndex].B = livePixels[bluePixIndex].B;
00270         }
00271     }
00272 }
00273 
00274 
00275 void rotateChain (int stepsLeft)
00276 {
00277     while (stepsLeft < 0)
00278         stepsLeft += chainLen;
00279 
00280     uint16_t thisPixIndex;
00281     uint16_t sourcePixIndex;
00282 
00283     for (uint16_t col = 0; col<chainLen; col++) {
00284         for (uint8_t row = 0; row < chainCount; row++) {
00285 
00286             thisPixIndex = xy2index(col,row);
00287 
00288             sourcePixIndex   = xy2index((col+stepsLeft)%chainLen,  row);
00289 
00290             nextPixels[thisPixIndex].R = livePixels[sourcePixIndex].R;
00291             nextPixels[thisPixIndex].G = livePixels[sourcePixIndex].G;
00292             nextPixels[thisPixIndex].B = livePixels[sourcePixIndex].B;
00293         }
00294     }
00295 }
00296 
00297 
00298 void swapBuffer()
00299 {
00300     pixelInfo *tmpPtr = nextPixels;
00301     nextPixels = livePixels;
00302     livePixels = tmpPtr;
00303 }
00304 
00305 
00306 int main ()
00307 {
00308     LEDs = 1;
00309 
00310 // setup buffers
00311     livePixels = pixelData1;
00312     nextPixels = pixelData2;
00313 
00314     blankBuffer(livePixels);
00315     blankBuffer(nextPixels);
00316 
00317     ledDriver.setData(livePixels, chainLen*chainCount);
00318     LEDs = LEDs+1;
00319 
00320 // create the data to display
00321     initChain();
00322     LEDs = LEDs+1;
00323 
00324 // set the active buffer to be displayed.
00325     swapBuffer();
00326     LEDs = LEDs+1;
00327 
00328     updateRateTimer.start();
00329     while (true) {
00330 
00331         // update which buffer to use.
00332         ledDriver.setData(livePixels, chainLen*chainCount);
00333         // send the data
00334         ledDriver.sendData();
00335 
00336         LEDs = LEDs + 1;
00337 
00338         // Copy move everthing to the left
00339         rotateChain(1);
00340 
00341         // change which buffer to use.
00342         swapBuffer();
00343         while (updateRateTimer.read_ms() < updatePeriodMS) {
00344         }
00345         updateRateTimer.reset();
00346     }
00347 }