diff --git a/AriesRGB_32x16.cpp b/AriesRGB_32x16.cpp index 46b823c..7310ea0 100644 --- a/AriesRGB_32x16.cpp +++ b/AriesRGB_32x16.cpp @@ -1,57 +1,62 @@ + #include "AriesRGB_32x16.h" +// DIRECT HARDWARE MEMORY MAP (Derived from VEGA gpio.c) +#define VEGA_GPIO_0_BASE 0x10080000UL +#define VEGA_GPIO_1_BASE 0x10180000UL + +volatile unsigned short* fastPort[32]; +unsigned short fastMask[32]; + +inline void fastDigitalWrite(uint8_t pin, bool val) +{ + if (val) *(fastPort[pin]) = fastMask[pin]; + else *(fastPort[pin]) = 0; + + // Crucial RISC-V instruction to force the memory out to the physical pins + __asm__ __volatile__ ("fence"); +} + AriesRGB_32x16::AriesRGB_32x16( uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint8_t clk, uint8_t lat, uint8_t oe, uint8_t a, uint8_t b, uint8_t c, - uint8_t pw, - uint8_t ph) + uint8_t pw, uint8_t ph) { panelsWide = constrain(pw, 1, MAX_PANELS_X); panelsHigh = constrain(ph, 1, MAX_PANELS_Y); - totalWidth = panelsWide * PANEL_WIDTH; totalHeight = panelsHigh * PANEL_HEIGHT; - PIN_R1 = r1; - PIN_G1 = g1; - PIN_B1 = b1; - - PIN_R2 = r2; - PIN_G2 = g2; - PIN_B2 = b2; - - PIN_CLK = clk; - PIN_LAT = lat; - PIN_OE = oe; - - PIN_A = a; - PIN_B = b; - PIN_C = c; + PIN_R1 = r1; PIN_G1 = g1; PIN_B1 = b1; + PIN_R2 = r2; PIN_G2 = g2; PIN_B2 = b2; + PIN_CLK = clk; PIN_LAT = lat; PIN_OE = oe; + PIN_A = a; PIN_B = b; PIN_C = c; scanRow = 0; - clear(); } void AriesRGB_32x16::begin() { - pinMode(PIN_R1, OUTPUT); - pinMode(PIN_G1, OUTPUT); - pinMode(PIN_B1, OUTPUT); - - pinMode(PIN_R2, OUTPUT); - pinMode(PIN_G2, OUTPUT); - pinMode(PIN_B2, OUTPUT); - - pinMode(PIN_CLK, OUTPUT); - pinMode(PIN_LAT, OUTPUT); - pinMode(PIN_OE, OUTPUT); + pinMode(PIN_R1, OUTPUT); pinMode(PIN_G1, OUTPUT); pinMode(PIN_B1, OUTPUT); + pinMode(PIN_R2, OUTPUT); pinMode(PIN_G2, OUTPUT); pinMode(PIN_B2, OUTPUT); + pinMode(PIN_CLK, OUTPUT); pinMode(PIN_LAT, OUTPUT); pinMode(PIN_OE, OUTPUT); + pinMode(PIN_A, OUTPUT); pinMode(PIN_B, OUTPUT); pinMode(PIN_C, OUTPUT); - pinMode(PIN_A, OUTPUT); - pinMode(PIN_B, OUTPUT); - pinMode(PIN_C, OUTPUT); + for(int p = 0; p < 32; p++) + { + if (p <= 15) { + uint32_t bit_pos = (1 << p); + fastPort[p] = (volatile unsigned short*)(VEGA_GPIO_0_BASE + (bit_pos << 2)); + fastMask[p] = bit_pos; + } else { + uint32_t bit_pos = (1 << (p - 16)); + fastPort[p] = (volatile unsigned short*)(VEGA_GPIO_1_BASE + (bit_pos << 2)); + fastMask[p] = bit_pos; + } + } clear(); } @@ -61,12 +66,7 @@ void AriesRGB_32x16::clear() memset(framebuffer, 0, sizeof(framebuffer)); } -void AriesRGB_32x16::drawPixel( - int x, - int y, - bool r, - bool g, - bool b) +void AriesRGB_32x16::drawPixel(int x, int y, bool r, bool g, bool b) { if(x < 0 || x >= totalWidth) return; if(y < 0 || y >= totalHeight) return; @@ -78,67 +78,55 @@ void AriesRGB_32x16::drawPixel( void AriesRGB_32x16::refresh() { - digitalWrite(PIN_OE, HIGH); + fastDigitalWrite(PIN_OE, HIGH); - // Set ABC scan address - digitalWrite(PIN_A, (scanRow >> 0) & 1); - digitalWrite(PIN_B, (scanRow >> 1) & 1); - digitalWrite(PIN_C, (scanRow >> 2) & 1); + fastDigitalWrite(PIN_A, (scanRow >> 0) & 1); + fastDigitalWrite(PIN_B, (scanRow >> 1) & 1); + fastDigitalWrite(PIN_C, (scanRow >> 2) & 1); - // Vertical stacked panels - for(int py = 0; py < panelsHigh; py++) + for(int pCol = panelsWide - 1; pCol >= 0; pCol--) { - int panelBaseY = py * PANEL_HEIGHT; + int panelBaseX = pCol * PANEL_WIDTH; + + for(int pRow = panelsHigh - 1; pRow >= 0; pRow--) + { + int panelBaseY = pRow * PANEL_HEIGHT; - // 1/8 scan rows - int y1 = panelBaseY + scanRow; - int y2 = panelBaseY + scanRow + 8; + int y1 = panelBaseY + scanRow; + int y2 = panelBaseY + scanRow + 8; - // Horizontal panels - for(int px = 0; px < panelsWide; px++) - { - int panelBaseX = px * PANEL_WIDTH; + bool* row1_ptr = &framebuffer[y1][panelBaseX][0]; + bool* row2_ptr = &framebuffer[y2][panelBaseX][0]; for(int col = 0; col < PANEL_WIDTH; col++) { - int x = panelBaseX + col; - - digitalWrite(PIN_R1, framebuffer[y1][x][0]); - digitalWrite(PIN_G1, framebuffer[y1][x][1]); - digitalWrite(PIN_B1, framebuffer[y1][x][2]); + fastDigitalWrite(PIN_R1, *(row1_ptr++)); + fastDigitalWrite(PIN_G1, *(row1_ptr++)); + fastDigitalWrite(PIN_B1, *(row1_ptr++)); - digitalWrite(PIN_R2, framebuffer[y2][x][0]); - digitalWrite(PIN_G2, framebuffer[y2][x][1]); - digitalWrite(PIN_B2, framebuffer[y2][x][2]); + fastDigitalWrite(PIN_R2, *(row2_ptr++)); + fastDigitalWrite(PIN_G2, *(row2_ptr++)); + fastDigitalWrite(PIN_B2, *(row2_ptr++)); - digitalWrite(PIN_CLK, HIGH); - digitalWrite(PIN_CLK, LOW); + fastDigitalWrite(PIN_CLK, HIGH); + fastDigitalWrite(PIN_CLK, LOW); } } } - // Latch - digitalWrite(PIN_LAT, HIGH); - digitalWrite(PIN_LAT, LOW); + fastDigitalWrite(PIN_LAT, HIGH); + fastDigitalWrite(PIN_LAT, LOW); - // Enable output - digitalWrite(PIN_OE, LOW); - delayMicroseconds(50); - digitalWrite(PIN_OE, HIGH); + fastDigitalWrite(PIN_OE, LOW); + + // If the screen is dim, increase this to 500 or 800 + delayMicroseconds(300); + + fastDigitalWrite(PIN_OE, HIGH); - // Next scan row scanRow++; - - if(scanRow >= 8) - scanRow = 0; -} - -uint16_t AriesRGB_32x16::width() -{ - return totalWidth; + if(scanRow >= 8) scanRow = 0; } -uint16_t AriesRGB_32x16::height() -{ - return totalHeight; -} +uint16_t AriesRGB_32x16::width() { return totalWidth; } +uint16_t AriesRGB_32x16::height() { return totalHeight; } diff --git a/AriesRGB_Font5x7_Vert.cpp b/AriesRGB_Font5x7_Vert.cpp index 379d9e9..11f9814 100644 --- a/AriesRGB_Font5x7_Vert.cpp +++ b/AriesRGB_Font5x7_Vert.cpp @@ -1,45 +1,73 @@ -#include - -// Vertical-panel text rendering for AriesRGB_32x16. -// -// PHYSICAL MOUNTING -// ───────────────── -// Rotate the 32×16 panel 90° COUNTER-CLOCKWISE so that: -// • The long (32-pixel) edge becomes the vertical axis → logical HEIGHT = 32 -// • The short (16-pixel) edge becomes the horizontal axis → logical WIDTH = 16 -// • The DATA connector (normally at the bottom) now faces to the RIGHT. -// -// Coordinate transform used internally (logical → physical): -// phys_x = logical_y -// phys_y = (PANEL_HEIGHT - 1) - logical_x = 15 - logical_x -// -// LOGICAL SPACE for a single 32×16 panel mounted vertically: -// x : 0 … 15 (left → right as you look at it) -// y : 0 … 31 (top → bottom) -// -// For multi-panel arrays (panelsWide > 1 etc.) scale accordingly. -// ───────────────────────────────────────────────────────────────────────────── - -#define ARIES_VERT_LOG_WIDTH 16 -#define ARIES_VERT_LOG_HEIGHT 32 - -class AriesRGB_32x16; +#include "AriesRGB_Font5x7_Vert.h" +#include "AriesRGB_32x16.h" +#include "AriesRGB_Font5x7.h" +#include + void AriesDrawPixelVert( AriesRGB_32x16& display, int lx, int ly, - bool r, bool g, bool b -); + bool r, bool g, bool b) +{ + int logWidth = (display.width() / 32) * 16; + int logHeight = (display.height() / 16) * 32; + + while(lx < 0) lx += logWidth; + lx = lx % logWidth; + + if (ly < 0 || ly >= logHeight) return; + + int maxCol = (logWidth / 16) - 1; + int panelCol = maxCol - (lx / 16); + + int panelRow = ly / 32; + + int localX = lx % 16; + int localY = ly % 32; + + int px = (panelCol * 32) + (31 - localY); + int py = (panelRow * 16) + (15 - localX); + + display.drawPixel(px, py, r, g, b); +} + +#define FONT_HEADER_SIZE 6 void AriesDrawCharVert( AriesRGB_32x16& display, - int x, int y, - char c, - bool r, bool g, bool b -); + int x, int y, char c, + bool r, bool g, bool b) +{ + if (c < ARIES_FONT_FIRST || c >= (ARIES_FONT_FIRST + 96)) return; + + uint16_t charIndex = (uint16_t)(c - ARIES_FONT_FIRST); + uint16_t glyphIndex = FONT_HEADER_SIZE + (charIndex * ARIES_FONT_WIDTH); + + for(uint8_t col = 0; col < ARIES_FONT_WIDTH; col++) + { + uint8_t line = pgm_read_byte(&System5x7[glyphIndex + col]); + for(uint8_t row = 0; row < ARIES_FONT_HEIGHT; row++) + { + if(line & (1 << row)) + { + // UN-MIRROR X, KEEP Y UPRIGHT + int drawX = x + col; + int drawY = y + (ARIES_FONT_HEIGHT - 1 - row); + + AriesDrawPixelVert(display, drawX, drawY, r, g, b); + } + } + } +} void AriesDrawStringVert( AriesRGB_32x16& display, - int x, int y, - const char* str, - bool r, bool g, bool b -); + int x, int y, const char* str, + bool r, bool g, bool b) +{ + while(*str) + { + AriesDrawCharVert(display, x, y, *str, r, g, b); + x += (ARIES_FONT_WIDTH + 1); + str++; + } +} diff --git a/AriesRGB_Font5x7_VertScaled.cpp b/AriesRGB_Font5x7_VertScaled.cpp index 40a85d6..790b600 100644 --- a/AriesRGB_Font5x7_VertScaled.cpp +++ b/AriesRGB_Font5x7_VertScaled.cpp @@ -1,60 +1,38 @@ #include "AriesRGB_Font5x7_VertScaled.h" - #include "AriesRGB_Font5x7.h" #include "AriesRGB_Font5x7_Vert.h" - #include #define FONT_HEADER_SIZE 6 - void AriesDrawCharVertScaled( AriesRGB_32x16& display, - int x, - int y, - char c, - bool r, - bool g, - bool b, - int scale -) + int x, int y, char c, + bool r, bool g, bool b, int scale) { - if (c < ARIES_FONT_FIRST || c >= (ARIES_FONT_FIRST + 96)) - return; + if (c < ARIES_FONT_FIRST || c >= (ARIES_FONT_FIRST + 96)) return; - uint16_t charIndex = - c - ARIES_FONT_FIRST; + uint16_t charIndex = c - ARIES_FONT_FIRST; + uint16_t glyphIndex = FONT_HEADER_SIZE + (charIndex * ARIES_FONT_WIDTH); - uint16_t glyphIndex = - FONT_HEADER_SIZE + - (charIndex * ARIES_FONT_WIDTH); - - for(uint8_t col = 0; - col < ARIES_FONT_WIDTH; - col++) + for(uint8_t col = 0; col < ARIES_FONT_WIDTH; col++) { - uint8_t line = - pgm_read_byte( - &System5x7[glyphIndex + col] - ); - - for(uint8_t row = 0; - row < ARIES_FONT_HEIGHT; - row++) + uint8_t line = pgm_read_byte(&System5x7[glyphIndex + col]); + for(uint8_t row = 0; row < ARIES_FONT_HEIGHT; row++) { if(line & (1 << row)) { - for(int sx = 0; sx < scale; sx++) { for(int sy = 0; sy < scale; sy++) { + int normalCol = col; + int invertedRow = (ARIES_FONT_HEIGHT - 1 - row); + AriesDrawPixelVert( display, - - x + (col * scale) + sx, - y + (row * scale) + sy, - + x + (normalCol * scale) + sx, + y + (invertedRow * scale) + sy, r, g, b ); } @@ -64,33 +42,15 @@ void AriesDrawCharVertScaled( } } - void AriesDrawStringVertScaled( AriesRGB_32x16& display, - int x, - int y, - const char* str, - bool r, - bool g, - bool b, - int scale -) + int x, int y, const char* str, + bool r, bool g, bool b, int scale) { while(*str) { - AriesDrawCharVertScaled( - display, - x, - y, - *str, - r, g, b, - scale - ); - - x += - ((ARIES_FONT_WIDTH + 1) - * scale); - + AriesDrawCharVertScaled(display, x, y, *str, r, g, b, scale); + x += ((ARIES_FONT_WIDTH + 1) * scale); str++; } } diff --git a/examples/AriesRGB_32x16/AirportTextScroll_Cylinder/AirportTextScroll_Cylinder.ino b/examples/AriesRGB_32x16/AirportTextScroll_Cylinder/AirportTextScroll_Cylinder.ino new file mode 100644 index 0000000..34b9d43 --- /dev/null +++ b/examples/AriesRGB_32x16/AirportTextScroll_Cylinder/AirportTextScroll_Cylinder.ino @@ -0,0 +1,70 @@ +#include "AriesRGB_32x16.h" +#include "AriesRGB_Font5x7_Vert.h" +#include "AriesRGB_Font5x7_VertScaled.h" + +// Initialize display for 20 wide, 5 high setup +AriesRGB_32x16 display(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 5); + +// Start scrolling from the right edge +int scrollX = 320; +#define REFRESHES_PER_FRAME 20 + +// --- FLIGHT DATA SETUP --- +const int NUM_LINES = 6; + +const char* flights[NUM_LINES] = { + "FLIGHT GATE ", + "AA102 G12 ", + "BA405 G04 ", + "DL992 G18 ", + "AF320 G07 ", + "EK202 G22 " +}; + +// The colors for each row {R, G, B} +const bool colors[NUM_LINES][3] = { + {0, 1, 1}, // Cyan + {0, 1, 0}, // Green + {1, 1, 0}, // Yellow + {1, 0, 0}, // Red + {1, 0, 1}, // Magenta + {0, 1, 0} // Green +}; + +// Y-Coordinates for each row +// Scale 2 char height is 14px. Spaced 26 pixels apart vertically. +const int yCoords[NUM_LINES] = {8, 34, 60, 86, 112, 138}; + +void setup() { + display.begin(); +} + +void loop() { + display.clear(); + + // Draw all 6 lines of text + for(int i = 0; i < NUM_LINES; i++) { + AriesDrawStringVertScaled( + display, + scrollX, + yCoords[i], + flights[i], + colors[i][0], colors[i][1], colors[i][2], + 2 // Scale 2 + ); + } + + // Refresh the hardware + for (int i = 0; i < REFRESHES_PER_FRAME; i++) { + display.refresh(); + } + + // Move text to the left + scrollX--; + + // Reset scroll when the string goes off screen. + // 28 chars * 12 pixels per char = 336 pixels wide. + if (scrollX < -350) { + scrollX = 320; + } +} diff --git a/examples/AriesRGB_32x16/SingleLineScroll_Cylinder/SingleLineScroll_Cylinder.ino b/examples/AriesRGB_32x16/SingleLineScroll_Cylinder/SingleLineScroll_Cylinder.ino new file mode 100644 index 0000000..6dd8d02 --- /dev/null +++ b/examples/AriesRGB_32x16/SingleLineScroll_Cylinder/SingleLineScroll_Cylinder.ino @@ -0,0 +1,30 @@ +#include "AriesRGB_32x16.h" +#include "AriesRGB_Font5x7_Vert.h" +#include "AriesRGB_Font5x7_VertScaled.h" + +AriesRGB_32x16 display(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 5); + +int scrollX = 320; +const int TEXT_Y = 73; // Centered at Scale 2 +#define REFRESHES_PER_FRAME 20 + +void setup() { display.begin(); } + +void loop() { + display.clear(); + const char* flightMsg = "Aries P10 Cylindrical Setup"; + + // Scale 2 + AriesDrawStringVertScaled(display, scrollX, TEXT_Y, flightMsg, 0, 1, 1, 2); + + for (int i = 0; i < REFRESHES_PER_FRAME; i++) { + display.refresh(); + } + + scrollX--; + // 12 pixels wide per char at scale 2 + if (scrollX < -( (int)strlen(flightMsg) * 12 )) { + scrollX = 320; + } +} +