5 by 14 Neo array
Dependencies: mbed
Diff: NeoMatrix/NeoMatrix.cpp
- 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(); +} +