5 by 14 Neo array

Dependencies:   mbed

Revision:
0:a32d1a85a830
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NeoMatrix/NeoMatrix.cpp	Mon Jun 12 16:57:43 2017 +0000
@@ -0,0 +1,401 @@
+/**********************************************
+ * NeoMatrix.cpp
+ *
+ * Taylor Powell
+ * March 2015
+ *
+ *  Controls an Adafruit Neopixel NeoMatrix 8x8
+ *  Because of the global nature of the IO register and bitmask variables, only one contiguous chain of NeoMatrix Arrays can be connected
+ *  A large number of NeoMatrix arrays can be chained together by tying Din to Dout of sucessive arrays, but an external power sourece may be required
+ *
+ *  This library supports only the NXP LPC1768
+ */
+
+#include "mbed.h"
+#include "NeoMatrix.h"
+#include "font.h"
+
+
+// FastIO register address and bitmask for the GPIO pin
+// because these are imported in the assembly
+//uint32_t neo_fio_reg;
+//uint32_t neo_bitmask;
+
+// function to write to the strip, implemented in ARM assembly
+//extern "C" void neo_out(NeoColor*, int);
+
+ #define max(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+     
+     #define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+     
+
+//__gpo(pin)
+NeoArr::NeoArr(PinName pin, int N, int zeroHigh, int zeroLow, int oneHigh, int oneLow) : N(N), __gpo(pin)
+{
+    bright = 0.2;
+    Nbytes = N * 70 * 3;    // changed from 64 to 70 - 14 x 5
+    arr = (NeoColor*)malloc(N * 70 * sizeof(NeoColor));
+    if (arr == NULL)
+    {
+        printf("NeoArr: ERROR unable to malloc pixel array data");
+        N = 0;
+    }
+    
+    __size = N * 70; // changed from 64 to 70 - 14 x 5
+    __transmitBuf = new bool[__size * FRAME_SIZE];
+    
+    //gpio_init(&gpio, pin, PIN_OUTPUT);      // initialize GPIO registers
+    //neo_fio_reg = (uint32_t)gpio.reg_dir;   // set registers and bitmask for
+    //neo_bitmask = 1 << ((int)pin & 0x1F);   // the assembly to use
+    
+    // IO pin to use
+    __outPin = pin;
+    // Default values designed for K64f. Assumes GPIO toggle takes ~0.4us
+    setDelays(zeroHigh, zeroLow, oneHigh, oneLow);
+}
+
+void NeoArr::setDelays(int zeroHigh, int zeroLow, int oneHigh, int oneLow) 
+{
+    __zeroHigh = zeroHigh;
+    __zeroLow = zeroLow;
+    __oneHigh = oneHigh;
+    __oneLow = oneLow;
+}
+
+void NeoArr::setBrightness(float bright)
+{
+    this->bright = bright;
+}
+
+
+void NeoArr::setPixel(int idx, int x, int y, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    setPixel(idx, x, y, red, green, blue);
+}
+
+void NeoArr::setPixel(int idx, int x, int y, uint8_t red, uint8_t green, uint8_t blue)
+{
+    //int pixel = idx*64 + x*8 + y;   // specify pixel based on board index, x, and y values
+    //int pixel = idx*70 + x*14 + y;   // specify pixel based on board index, x, and y values
+    int pixel = x + y*14;   // specify pixel based  x and y values
+    // modulate pixel by the total number of pixels
+    arr[pixel % (N*70)].red = (uint8_t)(red * bright);
+    arr[pixel % (N*70)].green = (uint8_t)(green * bright);
+    arr[pixel % (N*70)].blue = (uint8_t)(blue * bright);
+}
+
+void NeoArr::drawLine(int idx, int x1, int y1, int x2, int y2, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawLine(idx, x1, y1, x2,y2, red, green, blue);
+}
+
+void NeoArr::drawLine(int idx, int x1, int y1, int x2, int y2, uint8_t red, uint8_t green, uint8_t blue)
+{
+    float k;
+    int j = rint(sqrt(pow((x1-x2),2.0) + pow((y1-y2),2.0)));    // calculates magnitude of line
+    if(x1 != x2)  // handle infinite case
+        k = atan2( (float)(y2-y1),(float) ( x2-x1));    // calculates angle of line
+    else
+        k = acos(0.0);
+        
+    for(float n=0; n<=j; n++)   // set a number pixels equal to the magnitude of the line along the closest (rounded) line
+        if((x1+ rint(n*cos(k))) >=0 && (x1+rint( n*cos(k))) <=7 &&  (y1+rint(n*sin(k)))>=0 &&  (y1+rint(n*sin(k)))<=7)
+            setPixel(idx, x1+ rint(n*cos(k)), y1+ rint(n*sin(k)), red, green, blue);
+        
+    
+}
+
+void NeoArr::drawRect(int idx, int x1, int y1, int x2, int y2, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawRect(idx, x1, y1, x2,y2, red, green, blue);
+}
+
+void NeoArr::drawRect(int idx, int x1, int y1, int x2, int y2, uint8_t red, uint8_t green, uint8_t blue)
+{
+    // note: drawRect does not use drawLine function because the angles will always be 90 degrees and so for these for loops are faster
+    for(int i=0; i<=(abs(x2-x1)); i++){ // draws horizontal lines
+        if ((max(x1,x2)-i) >= 0 && max(x1, x2) -i <=7){
+            if(max(y1,y2) <= 7)
+                setPixel(idx, max(x1,x2)-i, max(y1,y2), red, green, blue);
+            
+            if(min(y1,y2) >= 0)
+                setPixel(idx, max(x1,x2)-i, min(y1,y2), red, green, blue);
+            }
+        }
+        
+    for(int i=0; i<=(abs(y2-y1)); i++){ // draws verticle lines
+        if ((max(y1,y2)-i) >= 0 && max(y1, y2) -i <=7){
+            if(max(x1,x2) <= 7)
+                setPixel(idx, max(x1,x2), max(y1,y2)-i, red, green, blue);
+            
+            if(min(x1,x2) >= 0)
+                setPixel(idx, min(x1,x2), max(y1,y2)-i, red, green, blue);
+            }
+        }
+}
+
+
+void NeoArr::drawFilledRect(int idx, int x1, int y1, int x2, int y2, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawFilledRect(idx, x1, y1, x2,y2, red, green, blue);
+}
+
+void NeoArr::drawFilledRect(int idx, int x1, int y1, int x2, int y2, uint8_t red, uint8_t green, uint8_t blue)
+{
+    for(int i=0; i<=(abs(x2-x1)); i++){
+        if ((max(x1,x2)-i) >= 0 && max(x1, x2) -i <=7){
+            for(int n=0; n<=(abs(y2-y1)); n++){
+                if((max(y1,y2)-n) >= 0 && max(y1, y2)-n <=7){
+                    setPixel(idx, max(x1,x2)-i, max(y1,y2)-n, red, green, blue);
+                }
+            }
+        }
+    }
+    
+}
+
+void NeoArr::fillScreen(int idx, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    fillScreen(idx, red, green, blue);
+}
+
+// adjusted for 14 x 5 screen
+void NeoArr::fillScreen(int idx,uint8_t red, uint8_t green, uint8_t blue)
+{    
+   for(int i=0; i<14; i++)
+        for(int n=0; n<5; n++)
+            setPixel(idx, i, n, red, green, blue);
+}
+
+
+void NeoArr::drawTriangle(int idx, int x1, int y1, int x2, int y2, int x3, int y3, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawTriangle(idx, x1, y1, x2,y2, x3, y3, red, green, blue);
+}
+
+void NeoArr::drawTriangle(int idx, int x1, int y1, int x2, int y2, int x3, int y3, uint8_t red, uint8_t green, uint8_t blue)
+{
+    
+    drawLine(idx, x1, y1, x2, y2, red, green, blue);
+    drawLine(idx, x2, y2, x3, y3, red, green, blue);
+    drawLine(idx, x3, y3, x1, y1, red, green, blue);
+    
+}
+
+void NeoArr::drawFilledTriangle(int idx, int x1, int y1, int x2, int y2, int x3, int y3, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawFilledTriangle(idx, x1, y1, x2,y2, x3, y3, red, green, blue);
+}
+
+void NeoArr::drawFilledTriangle(int idx, int x1, int y1, int x2, int y2, int x3, int y3, uint8_t red, uint8_t green, uint8_t blue)
+{
+    // note: drawFilledTriangle draws two legs of the triangle and then draws lines from their corner to each point on the opposite leg
+    drawLine(idx, x1, y1, x2, y2, red, green, blue);
+    drawLine(idx, x2, y2, x3, y3, red, green, blue);
+    
+    
+    float k;
+    int j = rint(sqrt(pow((x1-x3),2.0) + pow((y1-y3),2.0)));    // magnitude of opposite leg
+    if(x1 != x3)
+        k = atan2( (float)(y3-y1),(float) ( x3-x1));    // angle of line of opposite leg
+    else
+        k = acos(0.0);
+        
+    for(float n=0; n<=j; n++)
+        if((x1+ rint(n*cos(k))) >=0 && (x1+rint( n*cos(k))) <=7 &&  (y1+rint(n*sin(k)))>=0 &&  (y1+rint(n*sin(k)))<=7)
+            drawLine(idx, x1+ rint(n*cos(k)), y1+ rint(n*sin(k)), x2, y2, red, green, blue);    // draw line from corner to each point on opposite leg
+}
+
+void NeoArr::drawChar(int idx, int x, int y, char c, int color)
+{    
+    int red = (color & 0xFF0000) >> 16;
+    int green = (color & 0x00FF00) >> 8;
+    int blue = (color & 0x0000FF);
+    
+    drawChar(idx, x, y, c, red, green, blue);
+}
+
+void NeoArr::drawChar(int idx, int x, int y, char c, uint8_t red, uint8_t green, uint8_t blue)
+{
+    uint8_t i,j;
+    
+    c = c & 0x7F;  // mask c to avoid errors
+    
+    if (c < ' ') {  // convert c into index of font array
+        c = 0;
+    } else {
+        c -= ' ';
+    }
+
+    // font is BMplain, a 96x6 array stored in font.h, many free available fonts are online and can be swapped into this font
+    const uint8_t* chr = font[c];
+
+    for (j=0; j<6; j++)       // character width is 6
+    {   
+        for (i=0; i<5; i++)   // character height is 5 - changed from 8
+        {
+            if (chr[j] & (1<<(i)))  // if there is a pixel in the vertical line, set pixel on board
+            {
+                //if((x+j) <= 13 && (x+j)>=0 && (y+4-i)>=0 && (y+4-i) <=4)
+                     setPixel(0, x+j, y+i, red,green,blue);
+            }
+        }
+    }
+}
+
+void NeoArr::showImage(int idx, const int *img)
+{
+    int r, g, b;
+    for (int i = 0; i < 8; i++)
+    {
+        for(int n=0; n<8;n++)
+        {
+            r = (img[i] & 0xFF0000) >> 16;
+            g = (img[i] & 0x00FF00) >>8;
+            b = img[i] & 0x0000FF;
+            setPixel(idx,i,n, r, g, b);
+        }
+    }
+}
+
+void NeoArr::showImageRGB(int idx, int bmp, int r, int g, int b)
+{
+    //int r, g, b;
+    bmp &= 0x03;    // bounds check on the index
+    const unsigned char* img = smile_img[bmp];
+    for (int i = 0; i < 8; i++) // each byte in image file
+    {
+        for(int n=0; n<8;n++)   // for each bit
+        {
+            if ( ((img[i] << n) & 0x80) == 0x80 )
+                setPixel(idx,i,n, r, g, b);
+        }
+    }
+}
+
+void NeoArr::clear()
+{
+    for (int i = 0; i < (N*70); i++) // changed from 64 to 70 - 14 x 5
+    {
+        arr[i].red = 0;
+        arr[i].green = 0;
+        arr[i].blue = 0;
+    }
+}
+
+/***************************************************************
+// original NeoArr::write -- 
+void NeoArr::write()
+{
+    __disable_irq();        // disable interrupts
+    neo_out(arr, Nbytes); // output to the strip
+    __enable_irq();         // enable interrupts
+    wait_us(50);            // wait 50us for the reset pulse
+}
+***************************************************************/
+
+void NeoArr::__loadBuf() 
+{
+    for (int i = 0; i < __size; i++) 
+    {
+        unsigned char agrb[3] = {0x0, 0x0, 0x0};
+    
+        // 0 = green, 1 = red, 2 = blue, 3 = brightness        
+        agrb[0] = arr[i % (N*70)].green; // changed from 64 to 70 - 14 x 5
+        agrb[1] = arr[i % (N*70)].red;   // changed from 64 to 70 - 14 x 5
+        agrb[2] = arr[i % (N*70)].blue;  // changed from 64 to 70 - 14 x 5
+        //agrb[3] = (color & 0xFF000000) >> 24;
+
+        // load transmit buffer 
+        for (int clr = 0; clr < 3; clr++)   // for each color
+        {
+            for (int j = 0; j < 8; j++) // for each bit 
+            {
+                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 NeoArr::write_offsets (int buf[],int r_offset, int g_offset, int b_offset) 
+void NeoArr::write()
+{
+    int i, j;
+    
+    // Load the transmit buffer.
+    // transmit buffer is array where each byte represents one bit in the pixel buffer
+    // 24 bytes per pixel * 64 pixels = 1536 bytes of ram
+    __loadBuf();
+
+    // Entering timing critical section, so disabling interrupts
+    __disable_irq();
+    
+    // Begin bit-banging
+    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();
+            }
+        }
+    }
+    
+    // Exiting timing critical section, so enabling interrutps
+    __enable_irq();
+}
+