From 5bf538e348600c42ef7fc74c88ccccf7f0f93fe6 Mon Sep 17 00:00:00 2001 From: mrfaptastic <12006953+mrfaptastic@users.noreply.github.com> Date: Sun, 10 Oct 2021 19:06:11 +0100 Subject: 1/8 Scan Panel Example --- .../OneEighthScanMatrixPanel.h | 211 ++++++++++ .../One_Eighth_1_8_ScanPanel.ino | 117 ++++++ examples/One_Eighth_1_8_ScanPanel/README.md | 9 + .../OneQuarterScanMatrixPanel.h | 451 +++++++++++++++++++++ .../One_Quarter_1_4_ScanPanel.ino | 226 +++++++++++ examples/One_Quarter_1_4_ScanPanel/README.md | 78 ++++ .../P6_32x16_1_4_ScanPanel.ino | 226 ----------- .../QuarterScanMatrixPanel.h | 451 --------------------- examples/P6_32x16_1_4_ScanPanel/README.md | 78 ---- 9 files changed, 1092 insertions(+), 755 deletions(-) create mode 100644 examples/One_Eighth_1_8_ScanPanel/OneEighthScanMatrixPanel.h create mode 100644 examples/One_Eighth_1_8_ScanPanel/One_Eighth_1_8_ScanPanel.ino create mode 100644 examples/One_Eighth_1_8_ScanPanel/README.md create mode 100644 examples/One_Quarter_1_4_ScanPanel/OneQuarterScanMatrixPanel.h create mode 100644 examples/One_Quarter_1_4_ScanPanel/One_Quarter_1_4_ScanPanel.ino create mode 100644 examples/One_Quarter_1_4_ScanPanel/README.md delete mode 100644 examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino delete mode 100644 examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h delete mode 100644 examples/P6_32x16_1_4_ScanPanel/README.md (limited to 'examples') diff --git a/examples/One_Eighth_1_8_ScanPanel/OneEighthScanMatrixPanel.h b/examples/One_Eighth_1_8_ScanPanel/OneEighthScanMatrixPanel.h new file mode 100644 index 0000000..5fc8bd7 --- /dev/null +++ b/examples/One_Eighth_1_8_ScanPanel/OneEighthScanMatrixPanel.h @@ -0,0 +1,211 @@ +#ifndef _ESP32_ONE_EIGTH_MATRIX_PANEL_I2S_DMA +#define _ESP32_ONE_EIGTH_MATRIX_PANEL_I2S_DMA + +#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" + +struct VirtualCoords { + int16_t x; + int16_t y; +}; + + +#ifdef USE_GFX_ROOT +class OneEighthMatrixPanel : public GFX +#elif !defined NO_GFX +class OneEighthMatrixPanel : public Adafruit_GFX +#else +class OneEighthMatrixPanel +#endif +{ + + public: + int16_t virtualResX; + int16_t virtualResY; + + int16_t vmodule_rows; + int16_t vmodule_cols; + + int16_t panelResX; + int16_t panelResY; + + MatrixPanel_I2S_DMA *display; + + OneEighthMatrixPanel(MatrixPanel_I2S_DMA &disp, int _vmodule_rows, int _vmodule_cols, int _panelResX, int _panelResY, bool serpentine_chain = true, bool top_down_chain = false) +#ifdef USE_GFX_ROOT + : GFX(_vmodule_cols*_panelResX, _vmodule_rows*_panelResY) +#elif !defined NO_GFX + : Adafruit_GFX(_vmodule_cols*_panelResX, _vmodule_rows*_panelResY) +#endif + { + this->display = &disp; + + panelResX = _panelResX; + panelResY = _panelResY; + + vmodule_rows = _vmodule_rows; + vmodule_cols = _vmodule_cols; + + virtualResX = vmodule_cols*_panelResX; + virtualResY = vmodule_rows*_panelResY; + + /* Virtual Display width() and height() will return a real-world value. For example: + * Virtual Display width: 128 + * Virtual Display height: 64 + * + * So, not values that at 0 to X-1 + */ + _s_chain_party = serpentine_chain; // serpentine, or 'S' chain? + _chain_top_down= top_down_chain; + + coords.x = coords.y = -1; // By default use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer + + } + + VirtualCoords getCoords(int16_t x, int16_t y); + + // equivalent methods of the matrix library so it can be just swapped out. + virtual void drawPixel(int16_t x, int16_t y, uint16_t color); + virtual void fillScreen(uint16_t color); // overwrite adafruit implementation + void clearScreen() { + display->clearScreen(); + } + void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b); + void drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows); + + uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { + return display->color444(r, g, b); + } + uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { + return display->color565(r, g, b); + } + uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { + return display->color333(r, g, b); + } + + void flipDMABuffer() { display->flipDMABuffer(); } + + // Rotate display + inline void setRotate(bool rotate); + + private: + VirtualCoords coords; + bool _s_chain_party = true; // Are we chained? Ain't no party like a... + bool _chain_top_down = false; // is the ESP at the top or bottom of the matrix of devices? + bool _rotate = false; + +}; // end Class header + +/** + * Calculate virtual->real co-ordinate mapping to underlying single chain of panels connected to ESP32. + * Then do further calculations for 1/8 scan panel. + * Updates the private class member variable 'coords', so no need to use the return value. + * Not thread safe, but not a concern for ESP32 sketch anyway... I think. + */ +inline VirtualCoords OneEighthMatrixPanel::getCoords(int16_t x, int16_t y) { + + coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer + + // Check if virtual work co-ordinates are outside the virtual display resolution space. This does NOT check + // against the physical real-world DMA matrix resolution / setup configured, that is used to actually output + // the electrical pulse to the panel. + + if (x < 0 || x >= width() || y < 0 || y >= height() ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range! + //Serial.printf("OneEighthMatrixPanel::getCoords(): Invalid virtual display coordinate. x,y: %d, %d\r\n", x, y); + return coords; + } + + // We want to rotate? + if (_rotate){ + uint16_t temp_x=x; + x=y; + y=virtualResY-1-temp_x; + } + + uint8_t row = (y / panelResY) + 1; //a non indexed 0 row number + uint8_t col = (x / panelResX) + 1; //a non indexed 0 row number + if( ( _s_chain_party && !_chain_top_down && (row % 2 == 0) ) // serpentine vertically stacked chain starting from bottom row (i.e. ESP closest to ground), upwards + || + ( _s_chain_party && _chain_top_down && (row % 2 != 0) ) // serpentine vertically stacked chain starting from the sky downwards + ) + { + // First portion gets you to the correct offset for the row you need + // Second portion inverts the x on the row + coords.x = ((y / panelResY) * (virtualResX)) + (virtualResX - x) - 1; + + // inverts the y the row + coords.y = panelResY - 1 - (y % panelResY); + } + else + { + // Normal chain pixel co-ordinate + coords.x = x + ((y / panelResY) * (virtualResX)) ; + coords.y = y % panelResY; + } + + /* ******* + * START: 1/8 Scan Panel Pixel Re-Mapping + * + * We have calculated the x, y co-ordinates as if we have a chain of standard panels this library is designed + * for, this being 1/8 or 1/16 scan panels. We have to do some further hacking to convert co-ords to the + * double length and 1/2 physical dma output length that is required for these panels to work electronically. + */ + + // 1/8 Scan Panel - Is the final x-coord on the 1st or 3rd, 1/4ths (8 pixel 'blocks') of the panel (i.e. Row 0-7 or 17-24) ? + // Double the length of the x-coord if required + if ( (coords.y /8) % 2 == 0) { // returns true/1 for the 1st and 3rd 8-pixel 1/4th of a 32px high panel + coords.x += (panelResX*col); + } + coords.y /= 2; // half the row-coord, to match the PHYSICAL DMA configuration. + + /* + * END: 1/8 Scan Panel Pixel Re-Mapping + * ******* + */ + + // Reverse co-ordinates if panel chain from ESP starts from the TOP RIGHT + // TODO: Remove use of underyling _cfg configuration values! + if (_chain_top_down) + { + const HUB75_I2S_CFG _cfg = this->display->getCfg(); + coords.x = (_cfg.mx_width * _cfg.chain_length - 1) - coords.x; + coords.y = (_cfg.mx_height-1) - coords.y; + + } + + return coords; + +} + +inline void OneEighthMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) +{ + //VirtualCoords coords = getCoords(x, y); + getCoords(x, y); + this->display->drawPixel(coords.x, coords.y, color); +} + +inline void OneEighthMatrixPanel::fillScreen(uint16_t color) // adafruit virtual void override +{ + // No need to map this. + this->display->fillScreen(color); +} + +inline void OneEighthMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) +{ + //VirtualCoords coords = getCoords(x, y); + getCoords(x, y); + this->display->drawPixelRGB888( coords.x, coords.y, r, g, b); +} + +inline void OneEighthMatrixPanel::setRotate(bool rotate) { + _rotate=rotate; + + // We don't support rotation by degrees. + if (rotate) { setRotation(1); } else { setRotation(0); } +} + +// need to recreate this one, as it wouldnt work to just map where it starts. +inline void OneEighthMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t icon_cols, int16_t icon_rows) { + +} + +#endif \ No newline at end of file diff --git a/examples/One_Eighth_1_8_ScanPanel/One_Eighth_1_8_ScanPanel.ino b/examples/One_Eighth_1_8_ScanPanel/One_Eighth_1_8_ScanPanel.ino new file mode 100644 index 0000000..9115388 --- /dev/null +++ b/examples/One_Eighth_1_8_ScanPanel/One_Eighth_1_8_ScanPanel.ino @@ -0,0 +1,117 @@ +/************************************************************************* + * Description: + * + * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only + * supports output to 1/16 or 1/32 scan panels - which means outputting + * two lines at the same time, 16 or 32 rows apart. This cannot be changed + * at the DMA layer as it would require a messy and complex rebuild of the + * library's DMA internals. + * + * However, it is possible to connect 1/8 scan panels to this same library and + * 'trick' the output to work correctly on these panels by way of adjusting the + * pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA + * library (in this example, it is the 'dmaOutput' class). + * + * Supports chaining of multiple 1/8 panels... + * + **************************************************************************/ + + // Panel configuration + #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. + #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module. + + #define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS + #define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW + #define PANEL_CHAIN NUM_ROWS*NUM_COLS // total number of panels chained one to another + + // Change this to your needs, for details on VirtualPanel pls read the PDF! + #define SERPENT true + #define TOPDOWN false + + // GPIO Configuration + #define R1_PIN 2 + #define G1_PIN 15 + #define B1_PIN 4 + #define R2_PIN 16 + #define G2_PIN 27 + #define B2_PIN 17 + + #define A_PIN 5 + #define B_PIN 18 + #define C_PIN 19 + #define D_PIN -1 // Connected to GND on panel (21 if exist) + #define E_PIN -1 // Connected to GND on panel + + #define LAT_PIN 26 + #define OE_PIN 25 + #define CLK_PIN 22 + + #include "OneEighthScanMatrixPanel.h" // Virtual Display to re-map co-ordinates such that they draw correctly on a32x16 1/4 Scan panel + + // placeholder for the matrix object + MatrixPanel_I2S_DMA *dma_display = nullptr; + + // placeholder for the virtual display object + OneEighthMatrixPanel *virtualDisp = nullptr; + + /****************************************************************************** + * Setup! + ******************************************************************************/ + void setup() { + + delay(2000); + Serial.begin(115200); + Serial.println(""); Serial.println(""); Serial.println(""); + Serial.println("*****************************************************"); + Serial.println("* 1/8 Scan Panel Demonstration *"); + Serial.println("*****************************************************"); + + + /****************************************************************************** + * Create physical DMA panel class AND virtual (chained) display class. + ******************************************************************************/ + + /* + The configuration for MatrixPanel_I2S_DMA object is held in HUB75_I2S_CFG structure, + All options has it's predefined default values. So we can create a new structure and redefine only the options we need + + Please refer to the '2_PatternPlasma.ino' example for detailed example of how to use the MatrixPanel_I2S_DMA configuration + */ + + HUB75_I2S_CFG mxconfig( + PANEL_RES_X*2, // DO NOT CHANGE THIS + PANEL_RES_Y/2, // DO NOT CHANGE THIS + PANEL_CHAIN // DO NOT CHANGE THIS + ); + + //mxconfig.driver = HUB75_I2S_CFG::FM6126A; // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object + + // OK, now we can create our matrix object + dma_display = new MatrixPanel_I2S_DMA(mxconfig); + + // let's adjust default brightness to about 75% + dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100% + + // Allocate memory and start DMA display + if( not dma_display->begin() ) + Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); + + // create VirtualDisplay object based on our newly created dma_display object + virtualDisp = new OneEighthMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, SERPENT, TOPDOWN); + + virtualDisp->setTextColor(virtualDisp->color565(0, 0, 255)); + virtualDisp->setCursor(0, virtualDisp->height()/2); + + // Red text inside red rect (2 pix in from edge) + virtualDisp->print(" 1234"); + virtualDisp->drawRect(1,1, virtualDisp->width()-2, virtualDisp->height()-2, virtualDisp->color565(255,0,0)); + + // White line from top left to bottom right + virtualDisp->drawLine(0,0, virtualDisp->width()-1, virtualDisp->height()-1, virtualDisp->color565(255,255,255)); + } + + + void loop() { + + + } // end loop \ No newline at end of file diff --git a/examples/One_Eighth_1_8_ScanPanel/README.md b/examples/One_Eighth_1_8_ScanPanel/README.md new file mode 100644 index 0000000..5920f65 --- /dev/null +++ b/examples/One_Eighth_1_8_ScanPanel/README.md @@ -0,0 +1,9 @@ +# Using this library with 32x16 1/4 Scan Panels + +## Problem +ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 1/8 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default. + +## Solution +It is possible to connect 1/8 scan panels to this library and 'trick' the output to work correctly on these panels by way of adjusting the pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class). + +Creation of a 'OneEighthScanMatrixPanel.h' class which sends an adjusted drawPixel() x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library's drawPixel routine, to trick the output to look pixel perfect. diff --git a/examples/One_Quarter_1_4_ScanPanel/OneQuarterScanMatrixPanel.h b/examples/One_Quarter_1_4_ScanPanel/OneQuarterScanMatrixPanel.h new file mode 100644 index 0000000..2a0f0e7 --- /dev/null +++ b/examples/One_Quarter_1_4_ScanPanel/OneQuarterScanMatrixPanel.h @@ -0,0 +1,451 @@ + +/* + Patch class for 32x16 RGB Matrix panels + + reimplement all functions which use x,y coordinates + +*/ + +#ifndef ESP_HUB75_32x16MatrixPanel +#define ESP_HUB75_32x16MatrixPanel + +#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" +#include +#include "glcdfont.c" + +struct VirtualCoords { + int16_t x; + int16_t y; +}; + +#define VP_WIDTH 32 +#define VP_HEIGHT 16 +#define DEFAULT_FONT_W 5 +#define DEFAULT_FONT_H 7 +#define PIXEL_SPACE 1 // space between chars in a string + + +/* --- PRINTF_BYTE_TO_BINARY macro's --- */ +#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c" +#define PRINTF_BYTE_TO_BINARY_INT8(i) \ + (((i) & 0x80ll) ? '1' : '0'), \ + (((i) & 0x40ll) ? '1' : '0'), \ + (((i) & 0x20ll) ? '1' : '0'), \ + (((i) & 0x10ll) ? '1' : '0'), \ + (((i) & 0x08ll) ? '1' : '0'), \ + (((i) & 0x04ll) ? '1' : '0'), \ + (((i) & 0x02ll) ? '1' : '0'), \ + (((i) & 0x01ll) ? '1' : '0') + +#define PRINTF_BINARY_PATTERN_INT16 \ + PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8 +#define PRINTF_BYTE_TO_BINARY_INT16(i) \ + PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i) + + +/* --- end macros --- */ + + +class QuarterScanMatrixPanel : public Adafruit_GFX +{ + + public: + + MatrixPanel_I2S_DMA *display; + + QuarterScanMatrixPanel(MatrixPanel_I2S_DMA &disp) : Adafruit_GFX(64, 32) + { + this->display = &disp; + size_x = size_y = 1 ; + wrap = false; + cursor_x = cursor_y = 0; + dir = 1; + loop = true; + + } + + VirtualCoords getCoords(int16_t x, int16_t y); + int16_t getVirtualX(int16_t x) { + VirtualCoords coords = getCoords(x, 0); + return coords.x; + } + int16_t getVirtualY(int16_t y) { + VirtualCoords coords = getCoords(0,y); + return coords.y; + } +// int16_t getVirtualY(int16_t y) {return getCoords(0,y).y;} + /** extende function to draw lines/rects/... **/ + virtual uint8_t width() {return VP_WIDTH;}; + virtual uint8_t height() {return VP_HEIGHT;}; + + virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color); + virtual void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color); + virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); + virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); + virtual void scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed); + virtual void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg); + virtual size_t write(unsigned char c); // write a character on current cursor postion + virtual size_t write(const char *str); // write a character array (string) on curreont cursor postion + + virtual void setTextWrap(bool w); + virtual void setCursor (int16_t x, int16_t y); + void setTextFGColor(uint16_t color) {textFGColor = color;}; + void setTextBGColor(uint16_t color) {textBGColor = color;}; + void setTextSize(uint8_t x, uint8_t y) {size_x = x; size_y = y;}; // magnification, default = 1 + + void setScrollDir(uint8_t d = 1) { dir = (d != 1) ? 0 : 1;}; // set scroll dir default = 1 + void setScroolLoop (bool b = true) { loop = b;} ; // scroll text in a loop, default true + void scrollText(const char *str, uint16_t speed, uint16_t pixels); + /**------------------------------------------**/ + + // equivalent methods of the matrix library so it can be just swapped out. + virtual void drawPixel(int16_t x, int16_t y, uint16_t color); + virtual void fillScreen(uint16_t color); // overwrite adafruit implementation + void clearScreen() { fillScreen(0); } + //void drawPixelRGB565(int16_t x, int16_t y, uint16_t color); + void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b); + //void drawPixelRGB24(int16_t x, int16_t y, RGB24 color); + void drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows); + + uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { + return display->color444(r, g, b); + } + uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { + return display->color565(r, g, b); + } + uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { + return display->color333(r, g, b); + } + + void flipDMABuffer() { display->flipDMABuffer(); } + void showDMABuffer() { display->showDMABuffer(); } + + void drawDisplayTest(); + + protected: + int16_t cursor_x, cursor_y; // Cursor position + uint8_t size_x, size_y; // Font size Multiplikator default = 1 => 5x7 Font (5widht,7Height) + uint16_t textFGColor, textBGColor; + bool wrap ; // < If set, 'wrap' text at right edge of display + uint8_t dir ; // used for scrolling text direction + bool loop ; // used for scrolling text in a loop + + private: + VirtualCoords coords; + +}; // end Class header + + +/*************************************************************************************** + + @brief scroll text from right to left or vice versa on current cursor position + please note, this function is not interruptable. + + @param *c pointer to \0 terminated string + @param pixels number of pixels to scroll, if 0, than scroll complete text + @param speed velocity of scrolling in ms +***************************************************************************************/ +void QuarterScanMatrixPanel::scrollText(const char *str,uint16_t speed, uint16_t pixels = 0) { + // first we put all columns of every char inside str into a big array of lines + // than we move through this arry and draw line per line and move this line + // one position to dir + const uint8_t xSize = 6; + uint16_t len = strlen(str); + uint8_t array[len * xSize]; // size of array number of chars * width of char + //uint16_t lenArray = sizeof(array)/sizeof(array[0]); + uint16_t aPtr = 0; + // + // generate array + char c = *str; + // Serial.printf("size *str (%d), size array: (%d) \n", len, lenArray); + + while (c) { + // Serial.printf("** %c ** \n", c); + // read font line per line. A line is a column inside a char + for (int8_t i = 0; i < 5; i++) { + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + array[aPtr++] = line; + // Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + } + str++; + c = *str; + array[aPtr++] = 0x00; // line with 0 (space between chars) + + } + array[aPtr++] = 0x00; // line with 0 (space between chars) +/* + Serial.printf("---------------------------- \n"); + for (aPtr=0; aPtr < (len*xSize); aPtr++) { + Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", aPtr, PRINTF_BYTE_TO_BINARY_INT8(array[aPtr]) ); + } +*/ + + int16_t x,y,lastX, p; + lastX = (dir) ? VP_WIDTH : 0; + x = cursor_x; + y = cursor_y; + Serial.printf("X: %d, Y: %d \n", x,y); + p=0; + pixels = (pixels) ? pixels : len * xSize; + + while (p <= pixels) { + // remove last pixel positions + fillRect(x,y,5,7,textBGColor); + // set new pixel position + x = (dir) ? lastX - p : lastX + p - pixels; + // iterator through our array + for (uint8_t i=0; i < (len*xSize); i++) { + uint8_t line = array[i]; + //Serial.printf("%d:%d : " PRINTF_BINARY_PATTERN_INT8 "\n", x, i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + // read line and shift from right to left + // start with bit 0 (top of char) to 7(bottom) + for (uint8_t j=0; j < 8; j++, line>>=1) { + if (line & 1) { + // got 1, if x + i outside panel ignore pixel + if (x + i >= 0 && x + i < VP_WIDTH) { + drawPixel(x + i, y + j, textFGColor); + } + } + else { + // got 0 + if (x + i >= 0 && x + i < VP_WIDTH) { + drawPixel(x + i, y + j, textBGColor); + } + } // if + } // for j + } // for i + p++; + delay(speed); + + } // while +} + +inline size_t QuarterScanMatrixPanel::write(const char *str) { + uint8_t x, y; + x=cursor_x; + y=cursor_y; + char c = *str; + while (c) { + //Serial.printf("%c ", c); + write(c); + str++; + c = *str; + x = x + ((DEFAULT_FONT_W + PIXEL_SPACE) * size_x); + setCursor(x,y); + } + Serial.printf("\n"); + return 1; +} + +inline size_t QuarterScanMatrixPanel::write(unsigned char c) { + Serial.printf("\twrite(%d, %d, %c)\n", cursor_x, cursor_y, c); + drawChar(cursor_x, cursor_y, c, textFGColor, textBGColor, size_x, size_y); + return 1; +} + +void QuarterScanMatrixPanel::setTextWrap(bool w) {this->display->setTextWrap(w);} +void QuarterScanMatrixPanel::setCursor(int16_t x, int16_t y) { + cursor_x = x; + cursor_y = y; +} + + +/* - new for 16x32 panels - */ +inline void QuarterScanMatrixPanel::drawLine(int16_t x, int16_t y, int16_t x1, int16_t y1, uint16_t color) +{ + int16_t a,b; + for (a=x; a <= x1; a++) { + for (b=y; b <= y1; b++) { + drawPixel(a,b,color); + } + } +} + +inline void QuarterScanMatrixPanel::drawHLine(int16_t x, int16_t y, int16_t w, uint16_t color) +{ + drawLine(x,y,x+w,y, color); +} + +inline void QuarterScanMatrixPanel::drawVLine(int16_t x, int16_t y, int16_t h, uint16_t color) +{ + drawLine(x,y,x,y+h, color); +} + +inline void QuarterScanMatrixPanel::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) +{ + for (int16_t i = x; i < x + w; i++) { + drawVLine(i, y, h, color); + } +} + +void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) +{ + drawChar(x,y,c,color, bg, size, size); +} + +inline void QuarterScanMatrixPanel::scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed){ + + if ((x >= VP_WIDTH) || + (y >= VP_HEIGHT) || + ((x + 6 * size_x-1) < 0) || + ((y + 8 * size_y-1) <0)) + return; + setTextWrap(true); + // text wrap is only for the right end of the panel, to scroll soft out of the left of panel + // algorithm should wrap the character from left to right + + + // loop s = scroll-loop, scrolls char 5 pixels into dir + uint8_t lastX = x; + for (int8_t s = 0; s < 6; s++) { + // loop i : width of a character + Serial.printf("X:%d ", x); + + // clear current position + fillRect(x,y,5,7,0); + x = lastX - s; + for (int8_t i = 0; i < 5; i++) { + // first line is the firste vertical part of a character and 8bits long + // last bit is everytime 0 + // we read 5 lines with 8 bit (5x7 char + 8bit with zeros) + // Example : char A (90deg cw) + // 01111100 + // 00010010 + // 00010001 + // 00010010 + // 01111100 + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + // shift from right to left bit per bit + // loop j = height of a character + // loop through a colunm of currenc character + Serial.printf("i:%d ", i); + // ignore all pixels outside panel + if (x+i >= VP_WIDTH) continue; + + for (int8_t j=0; j < 8; j++, line >>= 1) { + if (line & 1) { + Serial.printf + (" ON %d", x+i); + // we read 1 + if (x >= 0) { + drawPixel(x+i, y+j, color); + } + else if (x+i >= 0) { + drawPixel(x+i, y+j, color); + } + } + else if (bg != color) { + // we read 0 + Serial.printf(" OFF %d", x+i); + + if (x >= 0) { + drawPixel(x+i, y+j, bg); + } + else if (x+i >= 0) { + drawPixel(x+i, y+j, bg); + } + } + } + } + Serial.printf("\n"); + delay(speed); + } +} + + +inline void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) +{ + //Serial.printf("unmapped : drawChar(%d, %d, %c) \n",x, y, c); + + // note: remapping to 16x32 coordinats is done inside drawPixel() or fillRect + + if ((x >= VP_WIDTH) || + (y >= VP_HEIGHT) || + ((x + 6 * size_x-1) < 0) || + ((y + 8 * size_y-1) <0)) + return; + //Serial.printf("Font-Array : %d \n", sizeof(font)); + for (int8_t i = 0; i < 5; i++) { + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + //Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); + for (int8_t j = 0; j < 8; j++, line >>= 1) { + if (line & 1) { + if (size_x == 1 && size_y == 1) + //Serial.printf(""); + drawPixel(x + i, y + j, color); + else + // remark: it's important to call function with orgininal coordinates for x/y + fillRect(x + i * size_x, y + j * size_y, size_x, size_y, + color); + } else if (bg != color) { + if (size_x == 1 && size_y == 1) + drawPixel(x + i, y + j, bg); + else + // remark: it's important to call function with orgininal coordinates for x/y + fillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); + } + } + } + +} + +inline void QuarterScanMatrixPanel::drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg) { + +} + +inline VirtualCoords QuarterScanMatrixPanel::getCoords(int16_t x, int16_t y) +{ + const int y_remap[] = { 0,1,8,9,4,5,12,13,16,17,24,25,22,23,30,31 }; + if (y > VP_HEIGHT) + y = VP_HEIGHT; + if (x > VP_WIDTH) + x = VP_WIDTH; + coords.x = x + VP_WIDTH; + coords.y = y_remap[y]; + return coords; +} + + +/* -------------------------*/ + +inline void QuarterScanMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixel(coords.x, coords.y, color); +} + +inline void QuarterScanMatrixPanel::fillScreen(uint16_t color) // adafruit virtual void override +{ + // No need to map this. + this->display->fillScreen(color); +} +/* +inline void QuarterScanMatrixPanel::drawPixelRGB565(int16_t x, int16_t y, uint16_t color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB565( coords.x, coords.y, color); +} +*/ + + +inline void QuarterScanMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB888( coords.x, coords.y, r, g, b); +} +/* +inline void QuarterScanMatrixPanel::drawPixelRGB24(int16_t x, int16_t y, RGB24 color) +{ + VirtualCoords coords = getCoords(x, y); + this->display->drawPixelRGB24(coords.x, coords.y, color); +} +*/ + + +// need to recreate this one, as it wouldnt work to just map where it starts. +inline void QuarterScanMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows) { } + +#endif \ No newline at end of file diff --git a/examples/One_Quarter_1_4_ScanPanel/One_Quarter_1_4_ScanPanel.ino b/examples/One_Quarter_1_4_ScanPanel/One_Quarter_1_4_ScanPanel.ino new file mode 100644 index 0000000..a3aa5a4 --- /dev/null +++ b/examples/One_Quarter_1_4_ScanPanel/One_Quarter_1_4_ScanPanel.ino @@ -0,0 +1,226 @@ +/************************************************************************* + * Contributor: https://github.com/mrRobot62 + * + * Description: + * + * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only + * supports output to 1/16 or 1/32 scan panels (two scan parallel scan lines) + * this is fixed and cannot be changed. + * + * However, it is possible to connect 1/4 scan panels to this same library and + * 'trick' the output to work correctly on these panels by way of adjusting the + * pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA + * library (in this example, it is the 'dmaOutput' class). + * + * This is done by way of the 'QuarterScanMatrixPanel.h' class that sends + * adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA + * library's drawPixel routine. + * + * Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' + * + **************************************************************************/ + + // PLEASE NOTE THIS EXAMPLE NO LONGER WORKS AS OF AUGUST 2021 + // IT NEEDS TO BE UPDATED TO THE NEW WAY OF USING THE LIBRARY + +// uncomment to use custom pins, then provide below +#define USE_CUSTOM_PINS + +/* Pin 1,3,5,7,9,11,13,15 */ +#define R1_PIN 25 +#define B1_PIN 27 +#define R2_PIN 14 +#define B2_PIN 13 +#define A_PIN 23 +#define C_PIN 5 +#define CLK_PIN 16 +#define OE_PIN 15 + +/* Pin 2,6,10,12,14 */ +#define G1_PIN 26 +#define G2_PIN 12 +#define B_PIN 19 +#define D_PIN 17 +#define LAT_PIN 4 +#define E_PIN -1 // required for 1/32 scan panels + +#include "OneQuarterScanMatrixPanel.h" // Virtual Display to re-map co-ordinates such that they draw correctly on a32x16 1/4 Scan panel +#include + +/* + * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. + * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. + * By default the library assumes a single 64x32 pixel panel is connected. + * + * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library + * for different resolutions / panel chain lengths within the sketch 'setup()'. + * + */ +MatrixPanel_I2S_DMA dmaOutput; + +// Create virtual 1/2 to 1/4 scan pixel co-ordinate mapping class. +QuarterScanMatrixPanel display(dmaOutput); + +#include + +int time_counter = 0; +int cycles = 0; + +CRGBPalette16 currentPalette; +CRGB currentColor; + + +CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { + return ColorFromPalette(currentPalette, index, brightness, blendType); +} + +typedef struct Matrix { + uint8_t x; + uint8_t y; +} Matrix; + +Matrix matrix; + + +void testSimpleChars(uint16_t timeout) { + + /** drawChar() **/ + Serial.println("draw chars with drawChar()"); + display.fillScreen(display.color444(0,0,0)); + + uint16_t myFGColor = display.color565(180,0,0); + uint16_t myBGColor = display.color565(0,50,0); + display.fillScreen(display.color444(0,0,0)); + display.drawChar(0,0,'X',myFGColor, myFGColor,1); + display.drawChar(16,1,'Y',myFGColor, myBGColor,1); + display.drawChar(3,9,'Z',myFGColor, myFGColor,1); + display.drawChar(16,9,'4',display.color565(0,220,0), myBGColor,1); + delay(timeout); + +} + +void testSimpleCharString(uint16_t timeout) { + uint8_t x,y,w,h; + w = 6; h=8; + x = 0; y=0; + display.fillScreen(display.color444(0,0,0)); + display.setTextFGColor(display.color565(0,60,180)); + display.setCursor(x,y); display.write('L'); + display.setCursor(x+w,y); display.write('u'); + display.setCursor(x+(2*w),y); display.write('n'); + display.setCursor(x+(3*w),y); display.write('a'); + display.setTextFGColor(display.color565(180,60,140)); + display.setCursor(x+(4*w),y); display.write('X'); + + delay(timeout); + +} + +void testTextString(uint16_t timeout) { + display.fillScreen(display.color444(0,0,0)); + display.setTextFGColor(display.color565(0,60,255)); + + display.setCursor(0,5); + display.write("HURRA"); + delay(timeout); +} + +void testWrapChar(const char c, uint16_t speed, uint16_t timeout) { + display.setTextWrap(true); + for (uint8_t i = 32; i > 0; i--) { + display.fillScreen(display.color444(0,0,0)); + display.setCursor(i, 5); + display.write(c); + delay(speed); + } + delay(timeout); +} + +void testScrollingChar(const char c, uint16_t speed, uint16_t timeout) { + Serial.println("Scrolling Char"); + uint16_t myFGColor = display.color565(180,0,0); + uint16_t myBGColor = display.color565(60,120,0); + display.fillScreen(display.color444(0,0,0)); + display.setTextWrap(true); + // from right to left with wrap + display.scrollChar(31,5,c, myFGColor, myFGColor, 1, speed); + // left out with wrap + delay(500); + display.scrollChar(0,5,c, myBGColor, myBGColor, 1, speed); + + delay(timeout); +} + +void testScrollingText(const char *str, uint16_t speed, uint16_t timeout) { + Serial.println("Scrolling Text as loop"); + // pre config + uint16_t red = display.color565(255,0,100); + uint16_t blue100 = display.color565(0,0,100); + uint16_t black = display.color565(0,0,0); + uint16_t green = display.color565(0,255,0); + uint16_t green150 = display.color565(0,150,0); + + display.fillScreen(display.color565(0,0,0)); + display.setCursor(31,5); + display.setScrollDir(1); + + /** black background **/ + display.setTextFGColor(green150); + display.scrollText("** Welcome **", speed); + display.fillScreen(black); + delay(timeout / 2) ; + + /** scrolling with colored background */ + display.fillRect(0,4,VP_WIDTH,8,blue100); + // scrolling, using default pixels size = length of string (not used parameter pixels) + display.setTextFGColor(red); + display.setTextBGColor(blue100); + display.scrollText(str, speed); + delay(timeout / 2) ; + + // same as above but now from left to right + display.setScrollDir(0); + display.setTextFGColor(blue100); + display.setTextBGColor(red); + display.fillRect(0,4,VP_WIDTH,8,red); + display.scrollText(str, speed, 0); + + delay(timeout); + display.fillScreen(black); + display.setTextFGColor(red); + + +} + +void setup() { + + Serial.begin(115200); + delay(500); + Serial.println("*****************************************************"); + Serial.println(" dmaOutput 32x16 !"); + Serial.println("*****************************************************"); + +#ifdef USE_CUSTOM_PINS + dmaOutput.begin(R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN ); // setup the LED matrix +#else + display.begin(true); // init buffers +#endif + + // fill the screen with 'black' + display.fillScreen(display.color444(0, 0, 0)); + + // Set current FastLED palette + currentPalette = RainbowColors_p; + // display.fillScreen(display.color565(0, 0, 0)); +} + +void loop() { + display.fillScreen(display.color444(0, 0, 0)); + //testSimpleChars(1500); + //testSimpleCharString (1500); + testTextString(2000); + // length = 16 bytes without \0 + //testWrapChar('A', 250, 1500); + //testScrollingChar('X', 250, 2000); + testScrollingText("Scrolling 16x32", 100, 2000); +} // end loop \ No newline at end of file diff --git a/examples/One_Quarter_1_4_ScanPanel/README.md b/examples/One_Quarter_1_4_ScanPanel/README.md new file mode 100644 index 0000000..6af1fa6 --- /dev/null +++ b/examples/One_Quarter_1_4_ScanPanel/README.md @@ -0,0 +1,78 @@ +# Using this library with 32x16 1/4 Scan Panels + +## Problem +ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 1/4 scan panels such [as this](https://de.aliexpress.com/item/33017477904.html?spm=a2g0o.detail.1000023.16.1fedd556Yw52Zi&algo_pvid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40&algo_expid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40-52&btsid=9a8bf2b5-334b-45ea-a849-063d7461362e&ws_ab_test=searchweb0_0,searchweb201602_10,searchweb201603_60%5BAliExpress%2016x32%5D). + +## Solution +It is possible to connect 1/4 scan panels to this library and 'trick' the output to work correctly on these panels by way of adjusting the pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class). + +Creation of a 'QuarterScanMatrixPanel.h' class which sends an adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library's drawPixel routine, to trick the output to look pixel perfect. Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' + +## Limitations + +* Only one font (glcd - standard font) is implemented. This font can't be resized. + +## New functions (and adapted function) in this QuarterScanMatrixPanel class +### drawLine +`void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)` + +Parameters should be self explained. x0/y0 upper left corner, x1/y1 lower right corner + +### drawHLine +`void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color)` + +Draw a fast horizontal line with length `w`. Starting at `x0/y0` + +### drawVLine +`void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color)` + +Draw a fast vertical line with length `h` Starting at `x0/y0` + +### fillRect +`void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)` + +Draw a rectangle starting at `x/y` with width `w` and height `h`in `color` + +### drawChar (5x7) Standard font +`drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)` + +Draw a char at position x/y in `color` with a background color `bg` +`size` is ignored. + +### writeChar (5x7) +`size_t write(unsigned char c)` + +Write a char at current cursor position with current foreground and background color. + +### writeString (5x7) +`size_t write(const char *c)` + +Write a string at current cursor position with current foreground and background color. +You have to use `setCursor(x,y)` and `setTextFGColor() / setTextBGColor()` + +### drawString (5x7) +`void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg)` + +Draw String at postion x/y wit foreground `color` and background `bg` +Example: `display.drawString(0,5,"**Welcome**",display.color565(0,60,255));` + +### void setScrollDir(uint8_t d = 1) +Set scrolling direction 0=left to right, 1= right to left (default) + +### scrollText +`void scrollText(const char *str, uint16_t speed, uint16_t pixels)` + +Scroll text `str` into `setScrollDir`. Speed indicates how fast in ms per pixel, pixels are the number pixes which should be scrolled, if not set or 0, than pixels is calculates by size of `*str` + +### drawPixel(int16_t x, int16_t y, uint16_t color) +Draw a pixel at x/y in `color`. This function is the atomic function for all above drawing functions + +### clearScreen() (all pixels off (black)) +Same as `fillScreen(0)` + + +## Example videos: +https://user-images.githubusercontent.com/949032/104838449-4aae5600-58bb-11eb-802f-a358b49a9315.mp4 + +https://user-images.githubusercontent.com/949032/104366906-5647f880-551a-11eb-9792-a6f8276629e6.mp4 + diff --git a/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino b/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino deleted file mode 100644 index 7e28f5f..0000000 --- a/examples/P6_32x16_1_4_ScanPanel/P6_32x16_1_4_ScanPanel.ino +++ /dev/null @@ -1,226 +0,0 @@ -/************************************************************************* - * Contributor: https://github.com/mrRobot62 - * - * Description: - * - * The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only - * supports output to 1/16 or 1/32 scan panels (two scan parallel scan lines) - * this is fixed and cannot be changed. - * - * However, it is possible to connect 1/4 scan panels to this same library and - * 'trick' the output to work correctly on these panels by way of adjusting the - * pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA - * library (in this example, it is the 'dmaOutput' class). - * - * This is done by way of the 'QuarterScanMatrixPanel.h' class that sends - * adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA - * library's drawPixel routine. - * - * Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' - * - **************************************************************************/ - - // PLEASE NOTE THIS EXAMPLE NO LONGER WORKS AS OF AUGUST 2021 - // IT NEEDS TO BE UPDATED TO THE NEW WAY OF USING THE LIBRARY - -// uncomment to use custom pins, then provide below -#define USE_CUSTOM_PINS - -/* Pin 1,3,5,7,9,11,13,15 */ -#define R1_PIN 25 -#define B1_PIN 27 -#define R2_PIN 14 -#define B2_PIN 13 -#define A_PIN 23 -#define C_PIN 5 -#define CLK_PIN 16 -#define OE_PIN 15 - -/* Pin 2,6,10,12,14 */ -#define G1_PIN 26 -#define G2_PIN 12 -#define B_PIN 19 -#define D_PIN 17 -#define LAT_PIN 4 -#define E_PIN -1 // required for 1/32 scan panels - -#include "QuarterScanMatrixPanel.h" // Virtual Display to re-map co-ordinates such that they draw correctly on a32x16 1/4 Scan panel -#include - -/* - * Below is an is the 'legacy' way of initialising the MatrixPanel_I2S_DMA class. - * i.e. MATRIX_WIDTH and MATRIX_HEIGHT are modified by compile-time directives. - * By default the library assumes a single 64x32 pixel panel is connected. - * - * Refer to the example '2_PatternPlasma' on the new / correct way to setup this library - * for different resolutions / panel chain lengths within the sketch 'setup()'. - * - */ -MatrixPanel_I2S_DMA dmaOutput; - -// Create virtual 1/2 to 1/4 scan pixel co-ordinate mapping class. -QuarterScanMatrixPanel display(dmaOutput); - -#include - -int time_counter = 0; -int cycles = 0; - -CRGBPalette16 currentPalette; -CRGB currentColor; - - -CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { - return ColorFromPalette(currentPalette, index, brightness, blendType); -} - -typedef struct Matrix { - uint8_t x; - uint8_t y; -} Matrix; - -Matrix matrix; - - -void testSimpleChars(uint16_t timeout) { - - /** drawChar() **/ - Serial.println("draw chars with drawChar()"); - display.fillScreen(display.color444(0,0,0)); - - uint16_t myFGColor = display.color565(180,0,0); - uint16_t myBGColor = display.color565(0,50,0); - display.fillScreen(display.color444(0,0,0)); - display.drawChar(0,0,'X',myFGColor, myFGColor,1); - display.drawChar(16,1,'Y',myFGColor, myBGColor,1); - display.drawChar(3,9,'Z',myFGColor, myFGColor,1); - display.drawChar(16,9,'4',display.color565(0,220,0), myBGColor,1); - delay(timeout); - -} - -void testSimpleCharString(uint16_t timeout) { - uint8_t x,y,w,h; - w = 6; h=8; - x = 0; y=0; - display.fillScreen(display.color444(0,0,0)); - display.setTextFGColor(display.color565(0,60,180)); - display.setCursor(x,y); display.write('L'); - display.setCursor(x+w,y); display.write('u'); - display.setCursor(x+(2*w),y); display.write('n'); - display.setCursor(x+(3*w),y); display.write('a'); - display.setTextFGColor(display.color565(180,60,140)); - display.setCursor(x+(4*w),y); display.write('X'); - - delay(timeout); - -} - -void testTextString(uint16_t timeout) { - display.fillScreen(display.color444(0,0,0)); - display.setTextFGColor(display.color565(0,60,255)); - - display.setCursor(0,5); - display.write("HURRA"); - delay(timeout); -} - -void testWrapChar(const char c, uint16_t speed, uint16_t timeout) { - display.setTextWrap(true); - for (uint8_t i = 32; i > 0; i--) { - display.fillScreen(display.color444(0,0,0)); - display.setCursor(i, 5); - display.write(c); - delay(speed); - } - delay(timeout); -} - -void testScrollingChar(const char c, uint16_t speed, uint16_t timeout) { - Serial.println("Scrolling Char"); - uint16_t myFGColor = display.color565(180,0,0); - uint16_t myBGColor = display.color565(60,120,0); - display.fillScreen(display.color444(0,0,0)); - display.setTextWrap(true); - // from right to left with wrap - display.scrollChar(31,5,c, myFGColor, myFGColor, 1, speed); - // left out with wrap - delay(500); - display.scrollChar(0,5,c, myBGColor, myBGColor, 1, speed); - - delay(timeout); -} - -void testScrollingText(const char *str, uint16_t speed, uint16_t timeout) { - Serial.println("Scrolling Text as loop"); - // pre config - uint16_t red = display.color565(255,0,100); - uint16_t blue100 = display.color565(0,0,100); - uint16_t black = display.color565(0,0,0); - uint16_t green = display.color565(0,255,0); - uint16_t green150 = display.color565(0,150,0); - - display.fillScreen(display.color565(0,0,0)); - display.setCursor(31,5); - display.setScrollDir(1); - - /** black background **/ - display.setTextFGColor(green150); - display.scrollText("** Welcome **", speed); - display.fillScreen(black); - delay(timeout / 2) ; - - /** scrolling with colored background */ - display.fillRect(0,4,VP_WIDTH,8,blue100); - // scrolling, using default pixels size = length of string (not used parameter pixels) - display.setTextFGColor(red); - display.setTextBGColor(blue100); - display.scrollText(str, speed); - delay(timeout / 2) ; - - // same as above but now from left to right - display.setScrollDir(0); - display.setTextFGColor(blue100); - display.setTextBGColor(red); - display.fillRect(0,4,VP_WIDTH,8,red); - display.scrollText(str, speed, 0); - - delay(timeout); - display.fillScreen(black); - display.setTextFGColor(red); - - -} - -void setup() { - - Serial.begin(115200); - delay(500); - Serial.println("*****************************************************"); - Serial.println(" dmaOutput 32x16 !"); - Serial.println("*****************************************************"); - -#ifdef USE_CUSTOM_PINS - dmaOutput.begin(R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN ); // setup the LED matrix -#else - display.begin(true); // init buffers -#endif - - // fill the screen with 'black' - display.fillScreen(display.color444(0, 0, 0)); - - // Set current FastLED palette - currentPalette = RainbowColors_p; - // display.fillScreen(display.color565(0, 0, 0)); -} - -void loop() { - display.fillScreen(display.color444(0, 0, 0)); - //testSimpleChars(1500); - //testSimpleCharString (1500); - testTextString(2000); - // length = 16 bytes without \0 - //testWrapChar('A', 250, 1500); - //testScrollingChar('X', 250, 2000); - testScrollingText("Scrolling 16x32", 100, 2000); -} // end loop \ No newline at end of file diff --git a/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h b/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h deleted file mode 100644 index 2a0f0e7..0000000 --- a/examples/P6_32x16_1_4_ScanPanel/QuarterScanMatrixPanel.h +++ /dev/null @@ -1,451 +0,0 @@ - -/* - Patch class for 32x16 RGB Matrix panels - - reimplement all functions which use x,y coordinates - -*/ - -#ifndef ESP_HUB75_32x16MatrixPanel -#define ESP_HUB75_32x16MatrixPanel - -#include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" -#include -#include "glcdfont.c" - -struct VirtualCoords { - int16_t x; - int16_t y; -}; - -#define VP_WIDTH 32 -#define VP_HEIGHT 16 -#define DEFAULT_FONT_W 5 -#define DEFAULT_FONT_H 7 -#define PIXEL_SPACE 1 // space between chars in a string - - -/* --- PRINTF_BYTE_TO_BINARY macro's --- */ -#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c" -#define PRINTF_BYTE_TO_BINARY_INT8(i) \ - (((i) & 0x80ll) ? '1' : '0'), \ - (((i) & 0x40ll) ? '1' : '0'), \ - (((i) & 0x20ll) ? '1' : '0'), \ - (((i) & 0x10ll) ? '1' : '0'), \ - (((i) & 0x08ll) ? '1' : '0'), \ - (((i) & 0x04ll) ? '1' : '0'), \ - (((i) & 0x02ll) ? '1' : '0'), \ - (((i) & 0x01ll) ? '1' : '0') - -#define PRINTF_BINARY_PATTERN_INT16 \ - PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_PATTERN_INT8 -#define PRINTF_BYTE_TO_BINARY_INT16(i) \ - PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i) - - -/* --- end macros --- */ - - -class QuarterScanMatrixPanel : public Adafruit_GFX -{ - - public: - - MatrixPanel_I2S_DMA *display; - - QuarterScanMatrixPanel(MatrixPanel_I2S_DMA &disp) : Adafruit_GFX(64, 32) - { - this->display = &disp; - size_x = size_y = 1 ; - wrap = false; - cursor_x = cursor_y = 0; - dir = 1; - loop = true; - - } - - VirtualCoords getCoords(int16_t x, int16_t y); - int16_t getVirtualX(int16_t x) { - VirtualCoords coords = getCoords(x, 0); - return coords.x; - } - int16_t getVirtualY(int16_t y) { - VirtualCoords coords = getCoords(0,y); - return coords.y; - } -// int16_t getVirtualY(int16_t y) {return getCoords(0,y).y;} - /** extende function to draw lines/rects/... **/ - virtual uint8_t width() {return VP_WIDTH;}; - virtual uint8_t height() {return VP_HEIGHT;}; - - virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); - virtual void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color); - virtual void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color); - virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - - virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); - virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); - virtual void scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed); - virtual void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg); - virtual size_t write(unsigned char c); // write a character on current cursor postion - virtual size_t write(const char *str); // write a character array (string) on curreont cursor postion - - virtual void setTextWrap(bool w); - virtual void setCursor (int16_t x, int16_t y); - void setTextFGColor(uint16_t color) {textFGColor = color;}; - void setTextBGColor(uint16_t color) {textBGColor = color;}; - void setTextSize(uint8_t x, uint8_t y) {size_x = x; size_y = y;}; // magnification, default = 1 - - void setScrollDir(uint8_t d = 1) { dir = (d != 1) ? 0 : 1;}; // set scroll dir default = 1 - void setScroolLoop (bool b = true) { loop = b;} ; // scroll text in a loop, default true - void scrollText(const char *str, uint16_t speed, uint16_t pixels); - /**------------------------------------------**/ - - // equivalent methods of the matrix library so it can be just swapped out. - virtual void drawPixel(int16_t x, int16_t y, uint16_t color); - virtual void fillScreen(uint16_t color); // overwrite adafruit implementation - void clearScreen() { fillScreen(0); } - //void drawPixelRGB565(int16_t x, int16_t y, uint16_t color); - void drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b); - //void drawPixelRGB24(int16_t x, int16_t y, RGB24 color); - void drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows); - - uint16_t color444(uint8_t r, uint8_t g, uint8_t b) { - return display->color444(r, g, b); - } - uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { - return display->color565(r, g, b); - } - uint16_t color333(uint8_t r, uint8_t g, uint8_t b) { - return display->color333(r, g, b); - } - - void flipDMABuffer() { display->flipDMABuffer(); } - void showDMABuffer() { display->showDMABuffer(); } - - void drawDisplayTest(); - - protected: - int16_t cursor_x, cursor_y; // Cursor position - uint8_t size_x, size_y; // Font size Multiplikator default = 1 => 5x7 Font (5widht,7Height) - uint16_t textFGColor, textBGColor; - bool wrap ; // < If set, 'wrap' text at right edge of display - uint8_t dir ; // used for scrolling text direction - bool loop ; // used for scrolling text in a loop - - private: - VirtualCoords coords; - -}; // end Class header - - -/*************************************************************************************** - - @brief scroll text from right to left or vice versa on current cursor position - please note, this function is not interruptable. - - @param *c pointer to \0 terminated string - @param pixels number of pixels to scroll, if 0, than scroll complete text - @param speed velocity of scrolling in ms -***************************************************************************************/ -void QuarterScanMatrixPanel::scrollText(const char *str,uint16_t speed, uint16_t pixels = 0) { - // first we put all columns of every char inside str into a big array of lines - // than we move through this arry and draw line per line and move this line - // one position to dir - const uint8_t xSize = 6; - uint16_t len = strlen(str); - uint8_t array[len * xSize]; // size of array number of chars * width of char - //uint16_t lenArray = sizeof(array)/sizeof(array[0]); - uint16_t aPtr = 0; - // - // generate array - char c = *str; - // Serial.printf("size *str (%d), size array: (%d) \n", len, lenArray); - - while (c) { - // Serial.printf("** %c ** \n", c); - // read font line per line. A line is a column inside a char - for (int8_t i = 0; i < 5; i++) { - uint8_t line = pgm_read_byte(&font[c * 5 + i]); - array[aPtr++] = line; - // Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); - } - str++; - c = *str; - array[aPtr++] = 0x00; // line with 0 (space between chars) - - } - array[aPtr++] = 0x00; // line with 0 (space between chars) -/* - Serial.printf("---------------------------- \n"); - for (aPtr=0; aPtr < (len*xSize); aPtr++) { - Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", aPtr, PRINTF_BYTE_TO_BINARY_INT8(array[aPtr]) ); - } -*/ - - int16_t x,y,lastX, p; - lastX = (dir) ? VP_WIDTH : 0; - x = cursor_x; - y = cursor_y; - Serial.printf("X: %d, Y: %d \n", x,y); - p=0; - pixels = (pixels) ? pixels : len * xSize; - - while (p <= pixels) { - // remove last pixel positions - fillRect(x,y,5,7,textBGColor); - // set new pixel position - x = (dir) ? lastX - p : lastX + p - pixels; - // iterator through our array - for (uint8_t i=0; i < (len*xSize); i++) { - uint8_t line = array[i]; - //Serial.printf("%d:%d : " PRINTF_BINARY_PATTERN_INT8 "\n", x, i, PRINTF_BYTE_TO_BINARY_INT8(line) ); - // read line and shift from right to left - // start with bit 0 (top of char) to 7(bottom) - for (uint8_t j=0; j < 8; j++, line>>=1) { - if (line & 1) { - // got 1, if x + i outside panel ignore pixel - if (x + i >= 0 && x + i < VP_WIDTH) { - drawPixel(x + i, y + j, textFGColor); - } - } - else { - // got 0 - if (x + i >= 0 && x + i < VP_WIDTH) { - drawPixel(x + i, y + j, textBGColor); - } - } // if - } // for j - } // for i - p++; - delay(speed); - - } // while -} - -inline size_t QuarterScanMatrixPanel::write(const char *str) { - uint8_t x, y; - x=cursor_x; - y=cursor_y; - char c = *str; - while (c) { - //Serial.printf("%c ", c); - write(c); - str++; - c = *str; - x = x + ((DEFAULT_FONT_W + PIXEL_SPACE) * size_x); - setCursor(x,y); - } - Serial.printf("\n"); - return 1; -} - -inline size_t QuarterScanMatrixPanel::write(unsigned char c) { - Serial.printf("\twrite(%d, %d, %c)\n", cursor_x, cursor_y, c); - drawChar(cursor_x, cursor_y, c, textFGColor, textBGColor, size_x, size_y); - return 1; -} - -void QuarterScanMatrixPanel::setTextWrap(bool w) {this->display->setTextWrap(w);} -void QuarterScanMatrixPanel::setCursor(int16_t x, int16_t y) { - cursor_x = x; - cursor_y = y; -} - - -/* - new for 16x32 panels - */ -inline void QuarterScanMatrixPanel::drawLine(int16_t x, int16_t y, int16_t x1, int16_t y1, uint16_t color) -{ - int16_t a,b; - for (a=x; a <= x1; a++) { - for (b=y; b <= y1; b++) { - drawPixel(a,b,color); - } - } -} - -inline void QuarterScanMatrixPanel::drawHLine(int16_t x, int16_t y, int16_t w, uint16_t color) -{ - drawLine(x,y,x+w,y, color); -} - -inline void QuarterScanMatrixPanel::drawVLine(int16_t x, int16_t y, int16_t h, uint16_t color) -{ - drawLine(x,y,x,y+h, color); -} - -inline void QuarterScanMatrixPanel::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) -{ - for (int16_t i = x; i < x + w; i++) { - drawVLine(i, y, h, color); - } -} - -void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) -{ - drawChar(x,y,c,color, bg, size, size); -} - -inline void QuarterScanMatrixPanel::scrollChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint16_t dir, uint16_t speed){ - - if ((x >= VP_WIDTH) || - (y >= VP_HEIGHT) || - ((x + 6 * size_x-1) < 0) || - ((y + 8 * size_y-1) <0)) - return; - setTextWrap(true); - // text wrap is only for the right end of the panel, to scroll soft out of the left of panel - // algorithm should wrap the character from left to right - - - // loop s = scroll-loop, scrolls char 5 pixels into dir - uint8_t lastX = x; - for (int8_t s = 0; s < 6; s++) { - // loop i : width of a character - Serial.printf("X:%d ", x); - - // clear current position - fillRect(x,y,5,7,0); - x = lastX - s; - for (int8_t i = 0; i < 5; i++) { - // first line is the firste vertical part of a character and 8bits long - // last bit is everytime 0 - // we read 5 lines with 8 bit (5x7 char + 8bit with zeros) - // Example : char A (90deg cw) - // 01111100 - // 00010010 - // 00010001 - // 00010010 - // 01111100 - uint8_t line = pgm_read_byte(&font[c * 5 + i]); - // shift from right to left bit per bit - // loop j = height of a character - // loop through a colunm of currenc character - Serial.printf("i:%d ", i); - // ignore all pixels outside panel - if (x+i >= VP_WIDTH) continue; - - for (int8_t j=0; j < 8; j++, line >>= 1) { - if (line & 1) { - Serial.printf - (" ON %d", x+i); - // we read 1 - if (x >= 0) { - drawPixel(x+i, y+j, color); - } - else if (x+i >= 0) { - drawPixel(x+i, y+j, color); - } - } - else if (bg != color) { - // we read 0 - Serial.printf(" OFF %d", x+i); - - if (x >= 0) { - drawPixel(x+i, y+j, bg); - } - else if (x+i >= 0) { - drawPixel(x+i, y+j, bg); - } - } - } - } - Serial.printf("\n"); - delay(speed); - } -} - - -inline void QuarterScanMatrixPanel::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) -{ - //Serial.printf("unmapped : drawChar(%d, %d, %c) \n",x, y, c); - - // note: remapping to 16x32 coordinats is done inside drawPixel() or fillRect - - if ((x >= VP_WIDTH) || - (y >= VP_HEIGHT) || - ((x + 6 * size_x-1) < 0) || - ((y + 8 * size_y-1) <0)) - return; - //Serial.printf("Font-Array : %d \n", sizeof(font)); - for (int8_t i = 0; i < 5; i++) { - uint8_t line = pgm_read_byte(&font[c * 5 + i]); - //Serial.printf("%d - Line " PRINTF_BINARY_PATTERN_INT8 "\n", i, PRINTF_BYTE_TO_BINARY_INT8(line) ); - for (int8_t j = 0; j < 8; j++, line >>= 1) { - if (line & 1) { - if (size_x == 1 && size_y == 1) - //Serial.printf(""); - drawPixel(x + i, y + j, color); - else - // remark: it's important to call function with orgininal coordinates for x/y - fillRect(x + i * size_x, y + j * size_y, size_x, size_y, - color); - } else if (bg != color) { - if (size_x == 1 && size_y == 1) - drawPixel(x + i, y + j, bg); - else - // remark: it's important to call function with orgininal coordinates for x/y - fillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); - } - } - } - -} - -inline void QuarterScanMatrixPanel::drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg) { - -} - -inline VirtualCoords QuarterScanMatrixPanel::getCoords(int16_t x, int16_t y) -{ - const int y_remap[] = { 0,1,8,9,4,5,12,13,16,17,24,25,22,23,30,31 }; - if (y > VP_HEIGHT) - y = VP_HEIGHT; - if (x > VP_WIDTH) - x = VP_WIDTH; - coords.x = x + VP_WIDTH; - coords.y = y_remap[y]; - return coords; -} - - -/* -------------------------*/ - -inline void QuarterScanMatrixPanel::drawPixel(int16_t x, int16_t y, uint16_t color) -{ - VirtualCoords coords = getCoords(x, y); - this->display->drawPixel(coords.x, coords.y, color); -} - -inline void QuarterScanMatrixPanel::fillScreen(uint16_t color) // adafruit virtual void override -{ - // No need to map this. - this->display->fillScreen(color); -} -/* -inline void QuarterScanMatrixPanel::drawPixelRGB565(int16_t x, int16_t y, uint16_t color) -{ - VirtualCoords coords = getCoords(x, y); - this->display->drawPixelRGB565( coords.x, coords.y, color); -} -*/ - - -inline void QuarterScanMatrixPanel::drawPixelRGB888(int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) -{ - VirtualCoords coords = getCoords(x, y); - this->display->drawPixelRGB888( coords.x, coords.y, r, g, b); -} -/* -inline void QuarterScanMatrixPanel::drawPixelRGB24(int16_t x, int16_t y, RGB24 color) -{ - VirtualCoords coords = getCoords(x, y); - this->display->drawPixelRGB24(coords.x, coords.y, color); -} -*/ - - -// need to recreate this one, as it wouldnt work to just map where it starts. -inline void QuarterScanMatrixPanel::drawIcon (int *ico, int16_t x, int16_t y, int16_t module_cols, int16_t module_rows) { } - -#endif \ No newline at end of file diff --git a/examples/P6_32x16_1_4_ScanPanel/README.md b/examples/P6_32x16_1_4_ScanPanel/README.md deleted file mode 100644 index 6af1fa6..0000000 --- a/examples/P6_32x16_1_4_ScanPanel/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# Using this library with 32x16 1/4 Scan Panels - -## Problem -ESP32-HUB75-MatrixPanel-I2S-DMA library will not display output correctly with 1/4 scan panels such [as this](https://de.aliexpress.com/item/33017477904.html?spm=a2g0o.detail.1000023.16.1fedd556Yw52Zi&algo_pvid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40&algo_expid=4329f1c0-04d2-43d9-bdfd-7d4ee95e6b40-52&btsid=9a8bf2b5-334b-45ea-a849-063d7461362e&ws_ab_test=searchweb0_0,searchweb201602_10,searchweb201603_60%5BAliExpress%2016x32%5D). - -## Solution -It is possible to connect 1/4 scan panels to this library and 'trick' the output to work correctly on these panels by way of adjusting the pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA library (in this example, it is the 'dmaOutput' class). - -Creation of a 'QuarterScanMatrixPanel.h' class which sends an adjusted x,y co-ordinates to the underlying ESP32-HUB75-MatrixPanel-I2S-DMA library's drawPixel routine, to trick the output to look pixel perfect. Refer to the 'getCoords' function within 'QuarterScanMatrixPanel.h' - -## Limitations - -* Only one font (glcd - standard font) is implemented. This font can't be resized. - -## New functions (and adapted function) in this QuarterScanMatrixPanel class -### drawLine -`void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)` - -Parameters should be self explained. x0/y0 upper left corner, x1/y1 lower right corner - -### drawHLine -`void drawHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color)` - -Draw a fast horizontal line with length `w`. Starting at `x0/y0` - -### drawVLine -`void drawVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color)` - -Draw a fast vertical line with length `h` Starting at `x0/y0` - -### fillRect -`void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)` - -Draw a rectangle starting at `x/y` with width `w` and height `h`in `color` - -### drawChar (5x7) Standard font -`drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)` - -Draw a char at position x/y in `color` with a background color `bg` -`size` is ignored. - -### writeChar (5x7) -`size_t write(unsigned char c)` - -Write a char at current cursor position with current foreground and background color. - -### writeString (5x7) -`size_t write(const char *c)` - -Write a string at current cursor position with current foreground and background color. -You have to use `setCursor(x,y)` and `setTextFGColor() / setTextBGColor()` - -### drawString (5x7) -`void drawString(int16_t x, int16_t y, unsigned char* c, uint16_t color, uint16_t bg)` - -Draw String at postion x/y wit foreground `color` and background `bg` -Example: `display.drawString(0,5,"**Welcome**",display.color565(0,60,255));` - -### void setScrollDir(uint8_t d = 1) -Set scrolling direction 0=left to right, 1= right to left (default) - -### scrollText -`void scrollText(const char *str, uint16_t speed, uint16_t pixels)` - -Scroll text `str` into `setScrollDir`. Speed indicates how fast in ms per pixel, pixels are the number pixes which should be scrolled, if not set or 0, than pixels is calculates by size of `*str` - -### drawPixel(int16_t x, int16_t y, uint16_t color) -Draw a pixel at x/y in `color`. This function is the atomic function for all above drawing functions - -### clearScreen() (all pixels off (black)) -Same as `fillScreen(0)` - - -## Example videos: -https://user-images.githubusercontent.com/949032/104838449-4aae5600-58bb-11eb-802f-a358b49a9315.mp4 - -https://user-images.githubusercontent.com/949032/104366906-5647f880-551a-11eb-9792-a6f8276629e6.mp4 - -- cgit v1.3.1