From f19dda567722ff6fc2995d7d9baad8e0e19dda7c Mon Sep 17 00:00:00 2001 From: nekuneko Date: Mon, 6 Jul 2020 21:05:08 +0200 Subject: [PATCH 1/3] Added support for ST7735S vscrolling & 160x80 BGR display This kind of display, tipically selled on the internet with ST7735S driver, looks like to be BGR, use different bounds coordinates, and the color scheme is inverted by default. Hardware vscroll is available on ST7735S driver, see datasheet for more information. These changes are thanks to the code viewed on https://simple-circuit.com/st7735-tft-vertical-scrolling-ccs-c/ tutorial. --- Adafruit_ST7735.cpp | 72 ++++++++++++++++++++++++++++++++++++++++----- Adafruit_ST7735.h | 9 ++++++ 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/Adafruit_ST7735.cpp b/Adafruit_ST7735.cpp index bfab90a..8b9fb2f 100644 --- a/Adafruit_ST7735.cpp +++ b/Adafruit_ST7735.cpp @@ -181,6 +181,16 @@ static const uint8_t PROGMEM 0x00, 0x00, // XSTART = 0 0x00, 0x9F }, // XEND = 159 + Rcmd2green160x80bgr[] = { // 7735S init, part 2 (mini 160x80 bgr) + 3, // 3 commands in list: + ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 0x00, 0x4F, // XEND = 79 + ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 0x00, 0x9F, // XEND = 159 + ST77XX_INVON, 0 }, // 3: Invert display, no args + Rcmd3[] = { // 7735R init, part 3 (red or green tab) 4, // 4 commands in list: ST7735_GMCTRP1, 16 , // 1: Gamma Adjustments (pos. polarity), 16 args + delay: @@ -234,6 +244,12 @@ void Adafruit_ST7735::initR(uint8_t options) { displayInit(Rcmd2green160x80); _colstart = 24; _rowstart = 0; + } else if (options == INITR_MINI160x80BGR) { + _height = ST7735_TFTHEIGHT_160; + _width = ST7735_TFTWIDTH_80; + displayInit(Rcmd2green160x80bgr); + _colstart = 26; + _rowstart = 1; } else { // colstart, rowstart left at default '0' values displayInit(Rcmd2red); @@ -242,10 +258,16 @@ void Adafruit_ST7735::initR(uint8_t options) { // Black tab, change MADCTL color filter if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) { - uint8_t data = 0xC0; - sendCommand(ST77XX_MADCTL, &data, 1); + madctl = 0xC0; + sendCommand(ST77XX_MADCTL, &madctl, 1); } + if (options == INITR_MINI160x80BGR) + { + invertOnCommand = ST77XX_INVOFF; + invertOffCommand = ST77XX_INVON; + } + if (options == INITR_HALLOWING) { // Hallowing is simply a 1.44" green tab upside-down: tabcolor = INITR_144GREENTAB; @@ -265,7 +287,6 @@ void Adafruit_ST7735::initR(uint8_t options) { */ /**************************************************************************/ void Adafruit_ST7735::setRotation(uint8_t m) { - uint8_t madctl = 0; rotation = m & 3; // can't be higher than 3 @@ -286,7 +307,7 @@ void Adafruit_ST7735::setRotation(uint8_t m) { if (tabcolor == INITR_144GREENTAB) { _height = ST7735_TFTHEIGHT_128; _width = ST7735_TFTWIDTH_128; - } else if (tabcolor == INITR_MINI160x80) { + } else if (tabcolor == INITR_MINI160x80 || tabcolor == INITR_MINI160x80BGR) { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_80; } else { @@ -306,7 +327,7 @@ void Adafruit_ST7735::setRotation(uint8_t m) { if (tabcolor == INITR_144GREENTAB) { _width = ST7735_TFTHEIGHT_128; _height = ST7735_TFTWIDTH_128; - } else if (tabcolor == INITR_MINI160x80) { + } else if (tabcolor == INITR_MINI160x80 || tabcolor == INITR_MINI160x80BGR) { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_80; } else { @@ -326,7 +347,7 @@ void Adafruit_ST7735::setRotation(uint8_t m) { if (tabcolor == INITR_144GREENTAB) { _height = ST7735_TFTHEIGHT_128; _width = ST7735_TFTWIDTH_128; - } else if (tabcolor == INITR_MINI160x80) { + } else if (tabcolor == INITR_MINI160x80 || tabcolor == INITR_MINI160x80BGR) { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_80; } else { @@ -346,7 +367,7 @@ void Adafruit_ST7735::setRotation(uint8_t m) { if (tabcolor == INITR_144GREENTAB) { _width = ST7735_TFTHEIGHT_128; _height = ST7735_TFTWIDTH_128; - } else if (tabcolor == INITR_MINI160x80) { + } else if (tabcolor == INITR_MINI160x80 || tabcolor == INITR_MINI160x80BGR) { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_80; } else { @@ -360,3 +381,40 @@ void Adafruit_ST7735::setRotation(uint8_t m) { sendCommand(ST77XX_MADCTL, &madctl, 1); } + + +/**************************************************************************/ +/*! + @brief Only for ST7735S. Sets Vertical Scrolling Area basic config, VSA must be within TFA and BFA. + @param top_fix_height TFA Top Fixed Area in pixels, >= 1 + @param bottom_fix_height BFA Bottom Fixed Area in pixels, >=1 + @param bottom_to_top Scroll direction +*/ +/**************************************************************************/ +void Adafruit_ST7735::setVerticalScrollConfig(uint8_t top_fix_height, uint8_t bottom_fix_height, bool bottom_to_top) { + uint8_t scroll_height; + scroll_height = _height - top_fix_height - bottom_fix_height; // TFA + VSA + BFA = 162 + + uint8_t args [6] = {0x00, top_fix_height, 0x00, scroll_height, 0x00, bottom_fix_height}; + sendCommand(ST7735_SCRLAR, args, 6); + + if(bottom_to_top) + madctl |= ST77XX_MADCTL_ML; // sets ML bit = 1 + else + madctl &= ~ST77XX_MADCTL_ML; // sets ML bit = 0 + + sendCommand(ST77XX_MADCTL, &madctl, 1); +} + + +/**************************************************************************/ +/*! + @brief Only for ST7735S. Sets Vertical Scroll Pointer, vsp must be within TFA and BFA. + @param vsp Vertical Scroll Pointer +*/ +/**************************************************************************/ +void Adafruit_ST7735::setVerticalScrollPointer(uint8_t vsp) { + uint8_t args[2] = {0x00, vsp}; + sendCommand(ST7735_VSCSAD, args, 2); +} + diff --git a/Adafruit_ST7735.h b/Adafruit_ST7735.h index da1320a..b509737 100755 --- a/Adafruit_ST7735.h +++ b/Adafruit_ST7735.h @@ -13,6 +13,7 @@ #define INITR_144GREENTAB 0x01 #define INITR_MINI160x80 0x04 #define INITR_HALLOWING 0x05 +#define INITR_MINI160x80BGR 0x06 // ST7735S // Some register settings #define ST7735_MADCTL_BGR 0x08 @@ -36,6 +37,10 @@ #define ST7735_GMCTRP1 0xE0 #define ST7735_GMCTRN1 0xE1 +// Vertical Scrolling +#define ST7735_SCRLAR 0x33 +#define ST7735_VSCSAD 0x37 + // Some ready-made 16-bit ('565') color settings: #define ST7735_BLACK ST77XX_BLACK #define ST7735_WHITE ST77XX_WHITE @@ -63,8 +68,12 @@ class Adafruit_ST7735 : public Adafruit_ST77xx { void setRotation(uint8_t m); + void setVerticalScrollConfig(uint8_t top_fix_height = 1, uint8_t bottom_fix_height = 1, bool bottom_to_top = true); + void setVerticalScrollPointer(uint8_t vsp); + private: uint8_t tabcolor; + uint8_t madctl; }; #endif // _ADAFRUIT_ST7735H_ From 2e8c2197917514355eae51cb53c9a168afa4abc8 Mon Sep 17 00:00:00 2001 From: nekuneko Date: Mon, 6 Jul 2020 21:05:27 +0200 Subject: [PATCH 2/3] Added hardware vscroll test for ST7735S displays Also includes ST7735S 160x80 mini BGR color scheme test. --- examples/st7735s_vscrolltest/.cpb.test.skip | 0 .../st7735s_vscrolltest.ino | 384 ++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 examples/st7735s_vscrolltest/.cpb.test.skip create mode 100644 examples/st7735s_vscrolltest/st7735s_vscrolltest.ino diff --git a/examples/st7735s_vscrolltest/.cpb.test.skip b/examples/st7735s_vscrolltest/.cpb.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino b/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino new file mode 100644 index 0000000..c1f52af --- /dev/null +++ b/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino @@ -0,0 +1,384 @@ +/************************************************************************** + This is a library for displays based on ST775S driver. + + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional). + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by NeKuNeKo, based on Limor Fried/Ladyada graphictest script for Adafruit Industries. + MIT license, all text above must be included in any redistribution + **************************************************************************/ + +#include // Core graphics library +#include // Hardware-specific library for ST7735 +#include + +#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32 + #define TFT_CS 14 + #define TFT_RST 15 + #define TFT_DC 32 + +#elif defined(ESP8266) + #define TFT_CS 4 + #define TFT_RST 16 + #define TFT_DC 5 + +#else + // For the breakout board, you can use any 2 or 3 pins. + // These pins will also work for the 1.8" TFT shield. + #define TFT_CS 10 + #define TFT_RST 9 // Or set to -1 and connect to Arduino RESET pin + #define TFT_DC 8 +#endif + +// #define TFT_LITE A0 // Uncomment if needed, and check the propper pin + +// OPTION 1 (recommended) is to use the HARDWARE SPI pins, which are unique +// to each board and not reassignable. For Arduino Uno: MOSI = pin 11 and +// SCLK = pin 13. This is the fastest mode of operation and is required if +// using the breakout board's microSD card. + +// For 1.44" and 1.8" TFT with ST7735 use: +Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); + +// OPTION 2 lets you interface the display using ANY TWO or THREE PINS, +// tradeoff being that performance is not as fast as hardware SPI above. +//#define TFT_MOSI 11 // Data out +//#define TFT_SCLK 13 // Clock out + +// For ST7735-based displays, we will use this call +//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); + + +void setup(void) +{ + Serial.begin(9600); + //while(!Serial); + Serial.print(F("Hello! ST77xx TFT Test")); + + // Use this initializer if using a 1.8" TFT screen: + //tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab + + // OR use this initializer if using a 1.8" TFT screen with offset such as WaveShare: + // tft.initR(INITR_GREENTAB); // Init ST7735S chip, green tab + + // OR use this initializer (uncomment) if using a 0.96" 160x80 TFT: + //tft.initR(INITR_MINI160x80); // Init ST7735S mini display + + // OR use this initializer (uncomment) if using a 0.96" 160x80 BGR TFT: + tft.initR(INITR_MINI160x80BGR); // Init ST7735S BGR mini display + + // SPI speed defaults to SPI_DEFAULT_FREQ defined in the library, you can override it here + // Note that speed allowable depends on chip and quality of wiring, if you go too fast, you + // may end up with a black screen some times, or all the time. + //tft.setSPISpeed(40000000); + + Serial.println(F("Initialized")); + +#ifdef TFT_LITE + pinMode(TFT_LITE, OUTPUT); + digitalWrite(TFT_LITE, LOW); // Set LOW / HIGH depends on your config. + //analogWrite(TFT_LITE, 1023); // Use this if using PWM pin. +#endif + + // - Color Scheme config - + tft.invertDisplay(false); + tft.fillScreen(ST77XX_BLACK); // Color Background +} + +void loop() +{ + testBounds(); + testRotation(); + testColor(); + //testColorVscroll(); // infinite Loop + vscrolltest(); // infinite Loop + //hscrolltest(); // infinite Loop +} + + +void testBounds () +{ + tft.setTextSize(1); + tft.setTextWrap(true); + + tft.setRotation(0); + tft.fillScreen(ST77XX_BLACK); + tft.drawPixel(0, 0, ST77XX_WHITE); + tft.setRotation(0); + tft.setTextColor(ST77XX_WHITE); + tft.setCursor(0+20, 0+20); + tft.print("(0,0)"); + delay(2000); + + tft.setRotation(0); + tft.fillScreen(ST77XX_BLACK); + tft.drawPixel(tft.width()-1, 0, ST77XX_BLUE); + tft.setRotation(1); + tft.setTextColor(ST77XX_BLUE); + tft.setCursor(0+20, 0+20); + tft.print("(width,0)"); + delay(2000); + + tft.setRotation(0); + tft.fillScreen(ST77XX_BLACK); + tft.drawPixel(tft.width()-1, tft.height()-1, ST77XX_YELLOW); + tft.setRotation(2); + tft.setTextColor(ST77XX_YELLOW); + tft.setCursor(0+20, 0+20); + tft.print("(width,height)"); + delay(2000); + + tft.setRotation(0); + tft.fillScreen(ST77XX_BLACK); + tft.drawPixel(0, tft.height()-1, ST77XX_RED); + tft.setRotation(3); + tft.setTextColor(ST77XX_RED); + tft.setCursor(0+20, 0+20); + tft.print("(0,height)"); + delay(2000); +} + + +void testRotation () +{ + tft.setTextSize(1); + tft.setTextWrap(false); + + tft.setRotation(0); // 0 - Vertical + tft.fillScreen(ST77XX_BLACK); + tft.drawFastHLine(0, 0, tft.width(), ST77XX_RED); + tft.drawFastVLine(0, 0, tft.height(), ST77XX_CYAN); + tft.setCursor(10, 10); + tft.setTextColor(ST77XX_WHITE); + tft.print("Rotation 0"); + tft.setCursor(10, 30); + tft.setTextColor(ST77XX_RED); + tft.print("width"); + tft.setCursor(10, 50); + tft.setTextColor(ST77XX_CYAN); + tft.print("height"); + delay(2000); + + tft.setRotation(1); // 1 - Horizontal + tft.fillScreen(ST77XX_BLACK); + tft.drawFastHLine(0, 0, tft.width(), ST77XX_RED); + tft.drawFastVLine(0, 0, tft.height(), ST77XX_CYAN); + tft.setCursor(10, 10); + tft.setTextColor(ST77XX_WHITE); + tft.print("Rotation 1"); + tft.setCursor(10, 30); + tft.setTextColor(ST77XX_RED); + tft.print("width"); + tft.setCursor(10, 50); + tft.setTextColor(ST77XX_CYAN); + tft.print("height"); + delay(2000); + + tft.setRotation(2); // 2 - Inverse Vertical + tft.fillScreen(ST77XX_BLACK); + tft.drawFastHLine(0, 0, tft.width(), ST77XX_RED); + tft.drawFastVLine(0, 0, tft.height(), ST77XX_CYAN); + tft.setCursor(10, 10); + tft.setTextColor(ST77XX_WHITE); + tft.print("Rotation 2"); + tft.setCursor(10, 30); + tft.setTextColor(ST77XX_RED); + tft.print("width"); + tft.setCursor(10, 50); + tft.setTextColor(ST77XX_CYAN); + tft.print("height"); + delay(2000); + + tft.setRotation(3); // 3- Inverse Horizontal + tft.fillScreen(ST77XX_BLACK); + tft.drawFastHLine(0, 0, tft.width(), ST77XX_RED); + tft.drawFastVLine(0, 0, tft.height(), ST77XX_CYAN); + tft.setCursor(10, 10); + tft.setTextColor(ST77XX_WHITE); + tft.print("Rotation 3"); + tft.setCursor(10, 30); + tft.setTextColor(ST77XX_RED); + tft.print("width"); + tft.setCursor(10, 50); + tft.setTextColor(ST77XX_CYAN); + tft.print("height"); + delay(2000); +} + + +void testColor() +{ + tft.setRotation(0); + tft.fillScreen(ST77XX_BLACK); + tft.setTextSize(1); + tft.setTextWrap(false); + + tft.setCursor(0, 15); + tft.setTextColor(ST77XX_BLACK); + tft.print("BLACK"); + + tft.setCursor(0, 30); + tft.setTextColor(ST77XX_WHITE); + tft.print("WHITE"); + + tft.setCursor(0, 45); + tft.setTextColor(ST77XX_YELLOW); + tft.print("YELLOW"); + + tft.setCursor(0, 60); + tft.setTextColor(ST77XX_GREEN); + tft.print("GREEN"); + + tft.setCursor(0, 75); + tft.setTextColor(ST77XX_BLUE); + tft.print("BLUE"); + + tft.setCursor(0, 90); + tft.setTextColor(ST77XX_MAGENTA); + tft.print("MAGENTA"); + + tft.setCursor(0, 105); + tft.setTextColor(ST77XX_ORANGE); + tft.print("ORANGE"); + + tft.setCursor(0, 120); + tft.setTextColor(ST77XX_CYAN); + tft.print("CYAN"); + + tft.setCursor(0, 135); + tft.setTextColor(ST7735_RED); + tft.print("RED"); + + delay(2000); +} + + +void testColorVscroll () +{ + uint8_t TFA = 1; // Top Fixed Area. Minimum 1 pixel + uint8_t BFA = 1; // Bottom Fixed Area. Minimum 1 pixel + bool bottom_to_top = true; // Scroll direction + + testColor(); + tft.setVerticalScrollConfig(TFA, BFA, bottom_to_top); + + uint8_t scroll = 0; + while(true){ + tft.setVerticalScrollPointer(scroll + TFA); + scroll++; + if(scroll > (tft.height() - TFA - BFA)) + scroll = 0; + delay(25); + } +} + + +void vscrolltest () +{ + char txt[] = "ST7735 TFT vertical scrolling"; + char nbr[5]; // Number can be up to five digits + uint8_t scroll; // Vertical Scroll Area pointer + uint16_t number; + + tft.setRotation(0); // only valid 0 + tft.fillScreen(ST77XX_BLACK); + tft.setTextWrap(true); + + tft.setCursor(0, 0); + tft.setTextColor(ST77XX_WHITE); + tft.print(txt); + + strcpy (txt, "Line:"); + tft.setTextWrap(false); + + uint8_t TFA = 30; // Top Fixed Area. Minimum 1 pixel + uint8_t BFA = 1; // Bottom Fixed Area. Minimum 1 pixel + bool bottom_to_top = true; // Scroll direction + tft.setVerticalScrollConfig(TFA, BFA, bottom_to_top); + + scroll = 0; + number = 0; + while(true) + { + for(int i=0; i < 10; i++) + { + tft.setVerticalScrollPointer(scroll + TFA); + tft.drawFastHLine(0, scroll + TFA, tft.width(), ST7735_BLACK); // Delete lines which may appear in bottom of TFT + scroll++; + delay(25); // scroll speed + if(scroll >= (tft.height() - TFA)) + scroll = 0; + } + + sprintf(nbr,"%Lu",number); + + if(scroll == 0) + { + tft.setCursor(0, 150); + tft.setTextColor(ST7735_YELLOW); + tft.print(txt); + + tft.setCursor(40, 150); + tft.setTextColor(ST7735_GREEN); + tft.print(nbr); + } + else + { + tft.setCursor(0, 20 + scroll); + tft.setTextColor(ST7735_YELLOW); + tft.print(txt); + + tft.setCursor(40, 20 + scroll); + tft.setTextColor(ST7735_GREEN); + tft.print(nbr); + } + number++; + } +} + + +void hscrolltest() +{ + char message [] PROGMEM = "In a village of La Mancha, the name of which I have no\ + desire to call to mind, there lived not long since one of those gentlemen that keep\ + a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing."; + int x, minX; + + tft.setRotation(1); + tft.setTextWrap(false); + tft.setTextColor(ST77XX_WHITE); + tft.fillScreen(ST77XX_BLACK); + + tft.setTextSize(1); + tft.setCursor(0, 7); + tft.print("TEST SCROLLING TEXT"); + + tft.setTextSize(3); + tft.setCursor(0, 40); + tft.print("Hello world!"); + + tft.setTextSize(2); + x = tft.width(); + minX = -12 * strlen(message); // 12 = 6 pixels /character * textSize + while(true) + { + // Option 1: fastHLines + //for (int i = 0; i<= 20; ++i) + // tft.writeFastHLine(0, 20+i, tft.width(), ST77XX_BLACK); + + // Option 2: fastVLines + for (int i = 0; i< tft.width(); ++i) + tft.writeFastVLine(0+i, 20, 16, ST77XX_BLACK); + + tft.setCursor(x, 20); + tft.print(message); + + x = x-2; // scroll speed + if (x < minX) + x = tft.width(); + } +} From d415a73fed877ea652cdbc88aca1ca5a4db239f5 Mon Sep 17 00:00:00 2001 From: Neku Date: Mon, 6 Jul 2020 21:41:21 +0200 Subject: [PATCH 3/3] Update st7735s_vscrolltest.ino Changes to match esp8266 needs --- examples/st7735s_vscrolltest/st7735s_vscrolltest.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino b/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino index c1f52af..6e4bdf7 100644 --- a/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino +++ b/examples/st7735s_vscrolltest/st7735s_vscrolltest.ino @@ -343,9 +343,9 @@ void vscrolltest () void hscrolltest() { - char message [] PROGMEM = "In a village of La Mancha, the name of which I have no\ - desire to call to mind, there lived not long since one of those gentlemen that keep\ - a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing."; + char message [] = "In a village of La Mancha, the name of which I have no desire\ + to call to mind, there lived not long since one of those gentlemen that keep a lance\ + in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing."; int x, minX; tft.setRotation(1);