From 27bdf4b24e8da06ea7923b6382f38b5fb6292914 Mon Sep 17 00:00:00 2001
From: Serhiy-K <52166448+Serhiy-K@users.noreply.github.com>
Date: Mon, 28 Sep 2020 09:52:38 +0300
Subject: [PATCH] MarlinUI for SPI/I2C TFT-GLCD character-based display bridge
 (#19375)

---
 Marlin/Configuration.h                        |    8 +
 Marlin/Configuration_adv.h                    |    4 +-
 Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp   |    4 +
 Marlin/src/inc/Conditionals_LCD.h             |   24 +
 Marlin/src/inc/Conditionals_post.h            |    6 +-
 Marlin/src/inc/SanityCheck.h                  |    8 +-
 Marlin/src/lcd/TFTGLCD/lcdprint_TFTGLCD.cpp   | 1142 +++++++++++++++++
 Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.cpp   | 1018 +++++++++++++++
 Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.h     |   74 ++
 Marlin/src/lcd/menu/menu_ubl.cpp              |    8 +-
 Marlin/src/lcd/ultralcd.cpp                   |   14 +-
 Marlin/src/lcd/ultralcd.h                     |    6 +-
 Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h   |   16 +-
 Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h   |    8 +
 Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h   |    8 +
 Marlin/src/pins/lpc1768/pins_MKS_SBASE.h      |   15 +-
 Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h     |    9 +
 Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h   |    9 +
 Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h  |   11 +-
 Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h  |   53 +-
 Marlin/src/pins/pinsDebug_list.h              |    3 +
 Marlin/src/pins/ramps/pins_RAMPS.h            |    8 +
 Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h |    4 +-
 .../stm32f1/pins_BTT_SKR_MINI_E3_common.h     |   46 +-
 .../src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h |   11 +
 .../src/pins/stm32f1/pins_MKS_ROBIN_LITE3.h   |    6 +
 .../src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h |   13 +
 Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h  |    7 +
 .../pins/stm32f4/pins_BTT_SKR_PRO_common.h    |    9 +-
 buildroot/tests/LPC1769-tests                 |   14 +
 platformio.ini                                |    3 +-
 31 files changed, 2516 insertions(+), 53 deletions(-)
 create mode 100644 Marlin/src/lcd/TFTGLCD/lcdprint_TFTGLCD.cpp
 create mode 100644 Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.cpp
 create mode 100644 Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.h

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 35b45e7321e..bb724672b03 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -1957,6 +1957,14 @@
 //
 //#define FF_INTERFACEBOARD
 
+//
+// TFT GLCD Panel with Marlin UI
+// Panel connected to main board by SPI or I2C interface.
+// See https://github.com/Serhiy-K/TFTGLCDAdapter
+//
+//#define TFTGLCD_PANEL_SPI
+//#define TFTGLCD_PANEL_I2C
+
 //=============================================================================
 //=======================   LCD / Controller Selection  =======================
 //=========================      (Graphical LCDs)      ========================
diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 915714039fc..0435b6f97c9 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1106,7 +1106,7 @@
   #define BOOTSCREEN_TIMEOUT 4000        // (ms) Total Duration to display the boot screen(s)
 #endif
 
-#if EITHER(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY) && (HAS_MARLINUI_U8GLIB || HAS_MARLINUI_HD44780)
+#if EITHER(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY) && ANY(HAS_MARLINUI_U8GLIB, HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
   //#define SHOW_REMAINING_TIME       // Display estimated time to completion
   #if ENABLED(SHOW_REMAINING_TIME)
     //#define USE_M73_REMAINING_TIME  // Use remaining time from M73 command instead of estimation
@@ -1117,7 +1117,7 @@
     //#define PRINT_PROGRESS_SHOW_DECIMALS // Show progress with decimal digits
   #endif
 
-  #if HAS_MARLINUI_HD44780
+  #if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
     //#define LCD_PROGRESS_BAR            // Show a progress bar on HD44780 LCDs for SD printing
     #if ENABLED(LCD_PROGRESS_BAR)
       #define PROGRESS_BAR_BAR_TIME 2000  // (ms) Amount of time to show the bar
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
index 9fc9ec099e8..dc91b7d6b18 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
@@ -997,6 +997,10 @@
 
         if (do_ubl_mesh_map) display_map(g29_map_type);     // Display the current point
 
+        #if IS_TFTGLCD_PANEL
+          ui.ubl_plot(lpos.x, lpos.y);   // update plot screen
+        #endif
+
         ui.refresh();
 
         float new_z = z_values[lpos.x][lpos.y];
diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h
index af8ef73817d..fa65991c2f6 100644
--- a/Marlin/src/inc/Conditionals_LCD.h
+++ b/Marlin/src/inc/Conditionals_LCD.h
@@ -217,6 +217,28 @@
   #define LCD_WIDTH 16
   #define LCD_HEIGHT 2
 
+#elif EITHER(TFTGLCD_PANEL_SPI, TFTGLCD_PANEL_I2C)
+
+  #define IS_TFTGLCD_PANEL 1
+  #define IS_ULTIPANEL                      // Note that IS_ULTIPANEL leads to HAS_WIRED_LCD
+
+  #if ENABLED(SDSUPPORT) && DISABLED(LCD_PROGRESS_BAR)
+    #define LCD_PROGRESS_BAR
+  #endif
+  #if ENABLED(TFTGLCD_PANEL_I2C)
+    #define LCD_USE_I2C_BUZZER              // Enable buzzer on LCD for I2C and SPI buses (LiquidTWI2 not required)
+    #define LCD_I2C_ADDRESS           0x27  // Must be equal to panel's I2C slave addres
+  #endif
+  #define STD_ENCODER_PULSES_PER_STEP 2
+  #define STD_ENCODER_STEPS_PER_MENU_ITEM 1
+  #define LCD_WIDTH                   20    // 20 or 24 chars in line
+  #define LCD_HEIGHT                  10    // Character lines
+  #define LCD_CONTRAST_MIN            127
+  #define LCD_CONTRAST_MAX            255
+  #define DEFAULT_LCD_CONTRAST        250
+  #define CONVERT_TO_EXT_ASCII        // Use extended 128-255 symbols from ASCII table.
+                                      // At this time present conversion only for cyrillic - bg, ru and uk languages.
+                                      // First 7 ASCII symbols in panel font must be replaced with Marlin's special symbols.
 #endif
 
 #if ENABLED(IS_RRD_FG_SC)
@@ -459,6 +481,8 @@
   #define HAS_WIRED_LCD 1
   #if ENABLED(DOGLCD)
     #define HAS_MARLINUI_U8GLIB 1
+  #elif IS_TFTGLCD_PANEL
+    // Neither DOGM nor HD44780. Fully customized interface.
   #elif DISABLED(HAS_GRAPHICAL_TFT)
     #define HAS_MARLINUI_HD44780 1
   #endif
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index bf297b633f8..80c42955e92 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -318,6 +318,10 @@
   #define _LCD_CONTRAST_MIN   64
   #define _LCD_CONTRAST_INIT 128
   #define _LCD_CONTRAST_MAX  255
+#elif IS_TFTGLCD_PANEL
+  #define _LCD_CONTRAST_MIN    0
+  #define _LCD_CONTRAST_INIT 250
+  #define _LCD_CONTRAST_MAX  255
 #endif
 
 #ifdef _LCD_CONTRAST_INIT
@@ -2453,7 +2457,7 @@
 /**
  * Buzzer/Speaker
  */
-#if PIN_EXISTS(BEEPER) || EITHER(LCD_USE_I2C_BUZZER, PCA9632_BUZZER)
+#if PIN_EXISTS(BEEPER) || ANY(LCD_USE_I2C_BUZZER, PCA9632_BUZZER, IS_TFTGLCD_PANEL)
   #define HAS_BUZZER 1
   #if PIN_EXISTS(BEEPER)
     #define USE_BEEPER 1
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 7093d252196..5bd6ef7c786 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -693,8 +693,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
 #if ENABLED(LCD_PROGRESS_BAR)
   #if NONE(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY)
     #error "LCD_PROGRESS_BAR requires SDSUPPORT or LCD_SET_PROGRESS_MANUALLY."
-  #elif !HAS_MARLINUI_HD44780
-    #error "LCD_PROGRESS_BAR requires a character LCD."
+  #elif NONE(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
+    #error "LCD_PROGRESS_BAR only applies to HD44780 character LCD and TFTGLCD_PANEL_(SPI|I2C)."
   #elif HAS_MARLINUI_U8GLIB
     #error "LCD_PROGRESS_BAR does not apply to graphical displays."
   #elif ENABLED(FILAMENT_LCD_DISPLAY)
@@ -2274,7 +2274,9 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
   + ENABLED(TFT_LVGL_UI_FSMC) \
   + ENABLED(TFT_LVGL_UI_SPI) \
   + ENABLED(ANYCUBIC_LCD_I3MEGA) \
-  + ENABLED(ANYCUBIC_LCD_CHIRON)
+  + ENABLED(ANYCUBIC_LCD_CHIRON) \
+  + ENABLED(TFTGLCD_PANEL_SPI) \
+  + ENABLED(TFTGLCD_PANEL_I2C)
   #error "Please select only one LCD controller option."
 #endif
 
diff --git a/Marlin/src/lcd/TFTGLCD/lcdprint_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/lcdprint_TFTGLCD.cpp
new file mode 100644
index 00000000000..6cf660a6a99
--- /dev/null
+++ b/Marlin/src/lcd/TFTGLCD/lcdprint_TFTGLCD.cpp
@@ -0,0 +1,1142 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * @file    lcdprint_TFTGLCD.cpp
+ * @brief   LCD print API for TFT-GLCD interface
+ * @author  Yunhui Fu (yhfudev@gmail.com)
+ * @version 1.0
+ * @date    2016-08-19
+ * @copyright GPL/BSD
+ */
+
+/**
+ * The TFTGLCD only supports ??? languages.
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if IS_TFTGLCD_PANEL
+
+#include "../ultralcd.h"
+#include "../../MarlinCore.h"
+#include "../../libs/numtostr.h"
+
+#include "ultralcd_TFTGLCD.h"
+
+#include <string.h>
+
+int lcd_glyph_height(void) { return 1; }
+
+typedef struct _TFTGLCD_charmap_t {
+  wchar_t uchar; // the unicode char
+  uint8_t idx;   // the glyph of the char in the ROM
+  uint8_t idx2;  // the char used to be combined with the idx to simulate a single char
+} TFTGLCD_charmap_t;
+
+#ifdef __AVR__
+  #define IV(a) U##a
+#else
+  #define IV(a) L##a
+#endif
+
+static const TFTGLCD_charmap_t g_TFTGLCD_charmap_device[] PROGMEM = {
+  // sorted by uchar:
+  #if DISPLAY_CHARSET_HD44780 == JAPANESE
+
+    {IV('¢'), 0xEC, 0}, // A2
+    {IV('°'), 0xDF, 0}, // B0, Marlin special: '°'  LCD_STR_DEGREE (0x09)
+    {IV('ä'), 0xE1, 0}, // E4
+    {IV('ö'), 0xEF, 0}, // F6
+    {IV('÷'), 0xFD, 0}, // 00F7
+    {IV('ü'), 0xF5, 0}, // 00FC
+    {IV('ˣ'), 0xEB, 0}, // 02E3
+
+    {IV('·'), 0xA5, 0}, // 0387
+    {IV('Ώ'), 0xF4, 0}, // 038F
+    {IV('Θ'), 0xF2, 0}, // 0398, Theta
+    {IV('Ξ'), 0xE3, 0}, // 039E, Xi
+    {IV('Σ'), 0xF6, 0}, // 03A3, Sigma
+    {IV('Ω'), 0xF4, 0}, // 03A9, Omega
+    {IV('ά'), 0xE0, 0}, // 03AC
+    {IV('έ'), 0xE3, 0}, // 03AD
+    {IV('α'), 0xE0, 0}, // 03B1, alpha
+    {IV('β'), 0xE2, 0}, // 03B2, beta
+    {IV('ε'), 0xE3, 0}, // 03B5, epsilon
+    {IV('θ'), 0xF2, 0}, // 03B8, theta
+    {IV('μ'), 0xE4, 0}, // 03BC, mu
+    {IV('ξ'), 0xE3, 0}, // 03BE, xi
+    {IV('π'), 0xF7, 0}, // 03C0, pi
+    {IV('ρ'), 0xE6, 0}, // 03C1, rho
+    {IV('σ'), 0xE5, 0}, // 03C3, sigma
+
+    {IV('←'), 0x7F, 0}, // 2190
+    {IV('→'), 0x7E, 0}, // 2192, Marlin special: '⮈⮉⮊⮋➤→' LCD_STR_ARROW_RIGHT (0x03)
+    {IV('√'), 0xE8, 0}, // 221A
+    {IV('∞'), 0xF3, 0}, // 221E
+    {IV('█'), 0xFF, 0}, // 2588
+
+    //{IV(''), 0xA0, 0},
+    {IV('。'), 0xA1, 0},
+    {IV('「'), 0xA2, 0},
+    {IV('」'), 0xA3, 0},
+    {IV('゛'), 0xDE, 0}, // ‶
+    {IV('゜'), 0xDF, 0}, // '〫'
+    {IV('゠'), '=', 0},
+    {IV('ァ'), 0xA7, 0},
+    {IV('ア'), 0xB1, 0},
+    {IV('ィ'), 0xA8, 0},
+    {IV('イ'), 0xB2, 0},
+    {IV('ゥ'), 0xA9, 0},
+    {IV('ウ'), 0xB3, 0},
+    {IV('ェ'), 0xAA, 0},
+    {IV('エ'), 0xB4, 0},
+    {IV('ォ'), 0xAB, 0},
+
+    {IV('オ'), 0xB5, 0},
+    {IV('カ'), 0xB6, 0},
+    {IV('ガ'), 0xB6, 0xDE},
+    {IV('キ'), 0xB7, 0},
+    {IV('ギ'), 0xB7, 0xDE}, //
+    {IV('ク'), 0xB8, 0},
+    {IV('グ'), 0xB8, 0xDE},
+    {IV('ケ'), 0xB9, 0},
+    {IV('ゲ'), 0xB9, 0xDE},
+    {IV('コ'), 0xBA, 0},
+    {IV('ゴ'), 0xBA, 0xDE},
+    {IV('サ'), 0xBB, 0},
+    {IV('ザ'), 0xBB, 0xDE},
+    {IV('シ'), 0xBC, 0},
+    {IV('ジ'), 0xBC, 0xDE},
+    {IV('ス'), 0xBD, 0},
+    {IV('ズ'), 0xBD, 0xDE},
+    {IV('セ'), 0xBE, 0},
+    {IV('ゼ'), 0xBE, 0xDE},
+    {IV('ソ'), 0xBF, 0},
+    {IV('ゾ'), 0xBF, 0xDE},
+
+    {IV('タ'), 0xC0, 0},
+    {IV('ダ'), 0xC0, 0xDE},
+    {IV('チ'), 0xC1, 0},
+    {IV('ヂ'), 0xC1, 0xDE},
+    {IV('ッ'), 0xAF, 0},
+    {IV('ツ'), 0xC2, 0},
+    {IV('ヅ'), 0xC2, 0xDE},
+    {IV('テ'), 0xC3, 0},
+    {IV('デ'), 0xC3, 0xDE},
+    {IV('ト'), 0xC4, 0},
+    {IV('ド'), 0xC4, 0xDE},
+    {IV('ナ'), 0xC5, 0},
+    {IV('ニ'), 0xC6, 0},
+    {IV('ヌ'), 0xC7, 0},
+    {IV('ネ'), 0xC8, 0},
+    {IV('ノ'), 0xC9, 0},
+    {IV('ハ'), 0xCA, 0},
+    {IV('バ'), 0xCA, 0xDE},
+    {IV('パ'), 0xCA, 0xDF},
+    {IV('ヒ'), 0xCB, 0},
+    {IV('ビ'), 0xCB, 0xDE},
+    {IV('ピ'), 0xCB, 0xDF},
+    {IV('フ'), 0xCC, 0},
+    {IV('ブ'), 0xCC, 0xDE},
+    {IV('プ'), 0xCC, 0xDF},
+    {IV('ヘ'), 0xCD, 0},
+    {IV('ベ'), 0xCD, 0xDE},
+    {IV('ペ'), 0xCD, 0xDF},
+    {IV('ホ'), 0xCE, 0},
+    {IV('ボ'), 0xCE, 0xDE},
+    {IV('ポ'), 0xCE, 0xDF},
+    {IV('マ'), 0xCF, 0},
+
+    {IV('ミ'), 0xD0, 0},
+    {IV('ム'), 0xD1, 0},
+    {IV('メ'), 0xD2, 0},
+    {IV('モ'), 0xD3, 0},
+    {IV('ャ'), 0xAC, 0},
+    {IV('ヤ'), 0xD4, 0},
+    {IV('ュ'), 0xAD, 0},
+    {IV('ユ'), 0xD5, 0},
+    {IV('ョ'), 0xAE, 0},
+    {IV('ヨ'), 0xD6, 0},
+    {IV('ラ'), 0xD7, 0},
+    {IV('リ'), 0xD8, 0},
+    {IV('ル'), 0xD9, 0},
+    {IV('レ'), 0xDA, 0},
+    {IV('ロ'), 0xDB, 0},
+    {IV('ワ'), 0xDC, 0},
+    {IV('ヲ'), 0xA6, 0},
+    {IV('ン'), 0xDD, 0},
+    {IV('ヴ'), 0xB3, 0xDE},
+    {IV('ヷ'), 0xDC, 0xDE},
+    {IV('ヺ'), 0xA6, 0xDE},
+    {IV('・'), 0xA5, 0},
+    {IV('ー'), 0xB0, 0},
+    {IV('ヽ'), 0xA4, 0},
+
+    //{IV('g'), 0xE7, 0}, // error
+    //{IV(''), 0xE9, 0},
+    //{IV('j'), 0xEA, 0}, // error
+    //{IV(''), 0xED, 0},
+    //{IV(''), 0xEE, 0},
+
+    //{IV('p'), 0xF0, 0}, // error
+    //{IV('q'), 0xF1, 0}, // error
+    //{IV(''), 0xF8, 0},
+    //{IV('y'), 0xF9, 0}, // error
+    {IV('万'), 0xFB, 0},
+    {IV('円'), 0xFC, 0},
+    {IV('千'), 0xFA, 0},
+    //{IV(''), 0xFE, 0},
+
+    //、・ヲァィゥェォャュョッー
+    {IV('、'), 0xA4, 0}, //ヽ
+    {IV('・'), 0xA5, 0}, //・
+    {IV('ヲ'), 0xA6, 0}, //ヲ
+    {IV('ァ'), 0xA7, 0}, //ァ
+    {IV('ィ'), 0xA8, 0}, //ィ
+    {IV('ゥ'), 0xA9, 0}, //ゥ
+    {IV('ェ'), 0xAA, 0}, //ェ
+    {IV('ォ'), 0xAB, 0}, //ォ
+    {IV('ャ'), 0xAC, 0}, //ャ
+    {IV('ュ'), 0xAD, 0}, //ュ
+    {IV('ョ'), 0xAE, 0}, //ョ
+    {IV('ッ'), 0xAF, 0}, //ッ
+    {IV('ー'), 0xB0, 0}, //ー
+
+    //アイウエオカキクケコサシスセ
+    {IV('ア'), 0xB1, 0}, //ア
+    {IV('イ'), 0xB2, 0}, //イ
+    {IV('ウ'), 0xB3, 0}, //ウ
+    {IV('エ'), 0xB4, 0}, //エ
+    {IV('オ'), 0xB5, 0}, //オ
+    {IV('カ'), 0xB6, 0}, //カ
+    {IV('キ'), 0xB7, 0}, //キ
+    {IV('ク'), 0xB8, 0}, //ク
+    {IV('ケ'), 0xB9, 0}, //ケ
+    {IV('コ'), 0xBA, 0}, //コ
+    {IV('サ'), 0xBB, 0}, //サ
+    {IV('シ'), 0xBC, 0}, //シ
+    {IV('ス'), 0xBD, 0}, //ス
+    {IV('セ'), 0xBE, 0}, //セ
+
+    //ソタチツテトナニヌネノハヒフ
+    {IV('ソ'), 0xBF, 0}, //ソ
+    {IV('タ'), 0xC0, 0}, //タ
+    {IV('チ'), 0xC1, 0}, //チ
+    {IV('ツ'), 0xC2, 0}, //ツ
+    {IV('テ'), 0xC3, 0}, //テ
+    {IV('ト'), 0xC4, 0}, //ト
+    {IV('ナ'), 0xC5, 0}, //ナ
+    {IV('ニ'), 0xC6, 0}, //ニ
+    {IV('ヌ'), 0xC7, 0}, //ヌ
+    {IV('ネ'), 0xC8, 0}, //ネ
+    {IV('ノ'), 0xC9, 0}, //ノ
+    {IV('ハ'), 0xCA, 0}, //ハ
+    {IV('ヒ'), 0xCB, 0}, //ヒ
+    {IV('フ'), 0xCC, 0}, //フ
+
+    //ヘホマミムメモヤユヨラリルレロワン゙゚
+    {IV('ヘ'), 0xCD, 0}, //ヘ
+    {IV('ホ'), 0xCE, 0}, //ホ
+    {IV('マ'), 0xCF, 0}, //マ
+    {IV('ミ'), 0xD0, 0}, //ミ
+    {IV('ム'), 0xD1, 0}, //ム
+    {IV('メ'), 0xD2, 0}, //メ
+    {IV('モ'), 0xD3, 0}, //モ
+    {IV('ヤ'), 0xD4, 0}, //ヤ
+    {IV('ユ'), 0xD5, 0}, //ユ
+    {IV('ヨ'), 0xD6, 0}, //ヨ
+    {IV('ラ'), 0xD7, 0}, //ラ
+    {IV('リ'), 0xD8, 0}, //リ
+    {IV('ル'), 0xD9, 0}, //ル
+    {IV('レ'), 0xDA, 0}, //レ
+    {IV('ロ'), 0xDB, 0}, //ロ
+    {IV('ワ'), 0xDC, 0}, //ワ
+    {IV('ン'), 0xDD, 0}, //ン
+    {IV('゙'), 0xDE, 0}, // ゛
+    {IV('゚'), 0xDF, 0}, // ゜
+
+    {IV('¥'), 0x5C, 0},
+
+  #elif DISPLAY_CHARSET_HD44780 == WESTERN
+    // 0x10 -- 0x1F (except 0x1C)
+    // 0x80 -- 0xFF (except 0xA7,0xB0,0xB1,0xB3,0xB4,0xBF,0xD1,0xF8,0xFA,0xFC-0xFF)
+
+    {IV('¡'), 0xA9, 0},
+    {IV('¢'), 0xA4, 0},
+    {IV('£'), 0xA5, 0},
+    {IV('¥'), 0xA6, 0},
+    {IV('§'), 0xD2, 0}, // section sign
+    {IV('©'), 0xCF, 0},
+
+    {IV('ª'), 0x9D, 0},
+    {IV('«'), 0xBB, 0},
+    {IV('®'), 0xCE, 0},
+
+    {IV('°'), 0xB2, 0}, // Marlin special: '°'  LCD_STR_DEGREE (0x09)
+    //{IV(''), 0xD1, 0},
+    {IV('±'), 0x10, 0}, //∓±
+    //{'='), 0x1C, 0}, // error
+    {IV('²'), 0x1E, 0},
+    {IV('³'), 0x1F, 0},
+    {IV('¶'), 0xD3, 0}, // pilcrow sign
+    {IV('º'), 0x9E, 0},
+    {IV('»'), 0xBC, 0}, // 00BB
+    //{IV(''), 0xB3, 0}, // error
+    //{IV(''), 0xB4, 0}, // error
+    {IV('¼'), 0xB6, 0}, // 00BC
+    {IV('½'), 0xB5, 0}, // 00BD
+    //{IV('¾'), '3', 0}, // 00BE
+    {IV('¿'), 0x9F, 0}, // 00BF
+
+    {IV('Â'), 0x8F, 0},
+    {IV('Ã'), 0xAA, 0},
+    {IV('Ä'), 0x8E, 0},
+    {IV('Æ'), 0x92, 0},
+    {IV('Ç'), 0x80, 0},
+    {IV('É'), 0x90, 0},
+    {IV('Ñ'), 0x9C, 0},
+    {IV('Õ'), 0xAC, 0},
+    {IV('Ö'), 0x99, 0},
+    {IV('×'), 0xB7, 0},
+    {IV('Ø'), 0xAE, 0},
+    {IV('Ü'), 0x9A, 0},
+    {IV('à'), 0x85, 0},
+    {IV('á'), 0xA0, 0},
+    {IV('â'), 0x83, 0},
+    {IV('ã'), 0xAB, 0},
+    {IV('ä'), 0x84, 0},
+    {IV('å'), 0x86, 0},
+    {IV('æ'), 0x91, 0},
+    {IV('ç'), 0x87, 0},
+    {IV('è'), 0x8A, 0},
+    {IV('é'), 0x82, 0},
+    {IV('ê'), 0x88, 0},
+    {IV('ë'), 0x89, 0},
+    {IV('ì'), 0x8D, 0},
+    {IV('í'), 0xA1, 0},
+    {IV('î'), 0x8C, 0},
+    {IV('ï'), 0x8B, 0},
+
+    {IV('ñ'), 0x9B, 0},
+    {IV('ò'), 0x95, 0},
+    {IV('ó'), 0xA2, 0},
+    {IV('ô'), 0x93, 0},
+    {IV('õ'), 0xAD, 0},
+    {IV('ö'), 0x94, 0},
+    {IV('÷'), 0xB8, 0},
+    {IV('ø'), 0xAF, 0},
+    {IV('ù'), 0x97, 0},
+    {IV('ú'), 0xA3, 0},
+    {IV('û'), 0x96, 0},
+    {IV('ü'), 0x81, 0},
+    {IV('ÿ'), 0x98, 0},
+
+    //{IV(''), 0xB0, 0}, // error
+    //{IV(''), 0xB1, 0}, // error
+    {IV('ƒ'), 0xA8, 0}, // 0192
+
+    {IV('Ύ'), 0xDB, 0}, // 038E
+    {IV('Ώ'), 0xDE, 0}, // 038F
+    {IV('ΐ'), 0xE7, 0}, // 0390
+
+    {IV('Γ'), 0xD4, 0}, // 0393, Gamma
+    {IV('Δ'), 0xD5, 0}, // 0394, Delta, ◿
+    {IV('Θ'), 0xD6, 0}, // 0398, Theta
+    {IV('Λ'), 0xD7, 0}, // 039B, Lambda
+    {IV('Ξ'), 0xD8, 0}, // 039E, Xi
+    {IV('Π'), 0xD9, 0}, // Pi
+    {IV('Σ'), 0xDA, 0}, // Sigma
+    {IV('Υ'), 0xDB, 0}, // Upsilon
+    {IV('Φ'), 0xDC, 0}, // Phi
+    {IV('Ψ'), 0xDD, 0}, // Psi
+    {IV('Ω'), 0xDE, 0}, // Omega
+
+    {IV('ά'), 0xDF, 0}, // 03AC
+    {IV('έ'), 0xE3, 0}, // 03AD
+    {IV('ή'), 0xE5, 0}, // 03AE
+    {IV('ί'), 0xE7, 0}, // 03AF
+    {IV('ΰ'), 0xF1, 0}, // 03B0
+
+    {IV('α'), 0xDF, 0}, // alpha
+    {IV('β'), 0xE0, 0}, // beta
+    {IV('γ'), 0xE1, 0}, // gamma
+    {IV('δ'), 0xE2, 0}, // delta
+    {IV('ε'), 0xE3, 0}, // epsilon
+    {IV('ζ'), 0xE4, 0}, // zeta
+    {IV('η'), 0xE5, 0}, // eta
+    {IV('θ'), 0xE6, 0}, // theta
+    {IV('ι'), 0xE7, 0}, // lota
+    {IV('κ'), 0xE8, 0}, // kappa
+    {IV('λ'), 0xE9, 0}, // lambda
+    {IV('μ'), 0xEA, 0}, // mu
+    {IV('ν'), 0xEB, 0}, // nu
+    {IV('ξ'), 0xEC, 0}, // xi
+    {IV('π'), 0xED, 0}, // pi
+    {IV('ρ'), 0xEE, 0}, // rho
+    {IV('σ'), 0xEF, 0}, // sigma
+
+    {IV('τ'), 0xF0, 0}, // tau
+    {IV('υ'), 0xF1, 0}, // upsilon
+    {IV('χ'), 0xF2, 0}, // chi
+    {IV('ψ'), 0xF3, 0}, // psi
+    {IV('ω'), 0xF4, 0}, // 03C9, omega
+    {IV('ϊ'), 0xE7, 0}, // 03CA
+    {IV('ϋ'), 0xF1, 0}, // 03CB
+    {IV('ύ'), 0xF1, 0}, // 03CD
+    {IV('ώ'), 0xF4, 0}, // 03CE
+
+    {IV('•'), 0xCD, 0}, // ·
+    {IV('℞'), 0xA7, 0}, // ℞ Pt ASCII 158
+    {IV('™'), 0xD0, 0},
+    {IV('↤'), 0xF9, 0}, // ⟻
+    {IV('↵'), 0xC4, 0},
+    {IV('↻'), 0x04, 0}, // Marlin special: '↻↺⟳⟲'  LCD_STR_REFRESH (0x01)
+    {IV('⇥'), 0xFB, 0},
+    {IV('√'), 0xBE, 0}, // √
+    {IV('∞'), 0xC2, 0}, // infinity
+    {IV('∫'), 0x1B, 0},
+    {IV('∼'), 0x1D, 0},
+    {IV('≈'), 0x1A, 0},
+    {IV('≠'), 0xBD, 0},
+    {IV('≡'), 0x11, 0},
+    {IV('≤'), 0xB9, 0},// ≤≥ ⩽⩾
+    {IV('≥'), 0xBA, 0},
+    //{IV(''), 0xBF, 0}, // error
+
+    {IV('⌠'), 0xC0, 0},
+    {IV('⌡'), 0xC1, 0},
+
+    {IV('⎧'), 0x14, 0},
+    {IV('⎩'), 0x15, 0},
+    {IV('⎫'), 0x16, 0},
+    {IV('⎭'), 0x17, 0},
+    {IV('⎰'), 0x18, 0},
+    {IV('⎱'), 0x19, 0},
+    {IV('⎲'), 0x12, 0},
+    {IV('⎳'), 0x13, 0},
+
+    {IV('⏱'), 0x07, 0}, // Marlin special: '🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧 ⌚⌛⏰⏱⏳⧖⧗'  LCD_STR_CLOCK (0x05)
+    {IV('┌'), 0xC9, 0},
+    {IV('┐'), 0xCA, 0},
+    {IV('└'), 0xCB, 0},
+    {IV('┘'), 0xCC, 0},
+    {IV('◸'), 0xC3, 0}, // ◿
+    {IV('⭠'), 0xC8, 0},
+    {IV('⭡'), 0xC5, 0},
+    {IV('⭢'), 0xC7, 0},
+    {IV('⭣'), 0xC6, 0},
+
+
+    {IV('⯆'), 0xF5, 0},
+    {IV('⯇'), 0xF7, 0}, // ⯅
+    {IV('⯈'), 0xF6, 0},
+    //{IV(''), 0xF8, 0}, // error
+    //{IV(''), 0xFA, 0}, // error
+    //{IV(''), 0xFC, 0}, // error
+    //{IV(''), 0xFD, 0}, // error
+    //{IV(''), 0xFE, 0}, // error
+    //{IV(''), 0xFF, 0}, // error
+
+  #elif DISPLAY_CHARSET_HD44780 == CYRILLIC
+
+    #ifdef CONVERT_TO_EXT_ASCII
+      {IV('°'), 0x01, 0}, // 00B0, Marlin special: '°'  LCD_STR_DEGREE (0x09)
+      {IV('²'), 0x0e, 0}, // 0x32 if no special symbol in panel font
+      {IV('³'), 0x0f, 0}, // 0x33 if no special symbol in panel font
+
+      // translate to cp866 codepage
+      //first ASCII symbols in panel font must be replaced with Marlin special symbols
+      {IV('Ё'), 0xF0, 0}, // 0401
+      {IV('Є'), 0xF2, 0}, // 0404
+      {IV('І'), 'I', 0},  // 0406
+      {IV('Ї'), 0xF4, 0}, // 0407
+      {IV('Ў'), 0xF6, 0}, // 040E
+      {IV('А'), 0x80, 0}, // 0410
+      {IV('Б'), 0x81, 0},
+      {IV('В'), 0x82, 0},
+      {IV('Г'), 0x83, 0},
+      {IV('Д'), 0x84, 0},
+      {IV('Е'), 0x85, 0},
+      {IV('Ж'), 0x86, 0},
+      {IV('З'), 0x87, 0},
+      {IV('И'), 0x88, 0},
+      {IV('Й'), 0x89, 0},
+      {IV('К'), 0x8A, 0},
+      {IV('Л'), 0x8B, 0},
+      {IV('М'), 0x8C, 0},
+      {IV('Н'), 0x8D, 0},
+      {IV('О'), 0x8E, 0},
+      {IV('П'), 0x8F, 0},
+      {IV('Р'), 0x90, 0},
+      {IV('С'), 0x91, 0},
+      {IV('Т'), 0x92, 0},
+      {IV('У'), 0x93, 0},
+      {IV('Ф'), 0x94, 0},
+      {IV('Х'), 0x95, 0},
+      {IV('Ц'), 0x96, 0},
+      {IV('Ч'), 0x97, 0},
+      {IV('Ш'), 0x98, 0},
+      {IV('Щ'), 0x99, 0},
+      {IV('Ъ'), 0x9A, 0},
+      {IV('Ы'), 0x9B, 0},
+      {IV('Ь'), 0x9C, 0},
+      {IV('Э'), 0x9D, 0},
+      {IV('Ю'), 0x9E, 0},
+      {IV('Я'), 0x9F, 0},
+
+      {IV('а'), 0xA0, 0},
+      {IV('б'), 0xA1, 0},
+      {IV('в'), 0xA2, 0},
+      {IV('г'), 0xA3, 0},
+      {IV('д'), 0xA4, 0},
+      {IV('е'), 0xA5, 0},
+      {IV('ж'), 0xA6, 0},
+      {IV('з'), 0xA7, 0},
+      {IV('и'), 0xA8, 0},
+      {IV('й'), 0xA9, 0},
+      {IV('к'), 0xAA, 0},
+      {IV('л'), 0xAB, 0},
+      {IV('м'), 0xAC, 0},
+      {IV('н'), 0xAD, 0},
+      {IV('о'), 0xAE, 0},
+      {IV('п'), 0xAF, 0},
+      {IV('р'), 0xE0, 0},
+      {IV('с'), 0xE1, 0},
+      {IV('т'), 0xE2, 0},
+      {IV('у'), 0xE3, 0},
+      {IV('ф'), 0xE4, 0},
+      {IV('х'), 0xE5, 0},
+      {IV('ц'), 0xE6, 0},
+      {IV('ч'), 0xE7, 0},
+      {IV('ш'), 0xE8, 0},
+      {IV('щ'), 0xE9, 0},
+      {IV('ъ'), 0xEA, 0},
+      {IV('ы'), 0xEB, 0},
+      {IV('ь'), 0xEC, 0},
+      {IV('э'), 0xED, 0},
+      {IV('ю'), 0xEE, 0},
+      {IV('я'), 0xEF, 0}, // 044F
+      {IV('ё'), 0xF1, 0}, // 0451
+      {IV('є'), 0xF3, 0}, // 0454
+      {IV('і'), 'i', 0},  // 0456
+      {IV('ї'), 0xF5, 0}, // 0457
+      {IV('ў'), 0xF7, 0}, // 045E
+
+    #else
+
+      {IV('¢'), 0x5C, 0}, // 00A2
+      {IV('£'), 0xCF, 0}, // 00A3
+      {IV('°'), 0x01, 0}, // 00B0, Marlin special: '°'  LCD_STR_DEGREE (0x09)
+
+      //{IV(''), 0x80, 0},
+      //{IV(''), 0x81, 0},
+      //{IV(''), 0x82, 0},
+      //{IV(''), 0x83, 0},
+      //{IV(''), 0x84, 0},
+      //{IV(''), 0x85, 0},
+      //{IV(''), 0x86, 0},
+      //{IV(''), 0x87, 0},
+      //{IV(''), 0x88, 0},
+      //{IV(''), 0x89, 0},
+      //{IV(''), 0x8A, 0},
+      //{IV(''), 0x8B, 0},
+      //{IV(''), 0x8C, 0},
+      //{IV(''), 0x8D, 0},
+      //{IV(''), 0x8E, 0},
+      //{IV(''), 0x8F, 0},
+
+      //{IV(''), 0x90, 0},
+      //{IV(''), 0x91, 0},
+      //{IV(''), 0x92, 0},
+      //{IV(''), 0x93, 0},
+      //{IV(''), 0x94, 0},
+      //{IV(''), 0x95, 0},
+      //{IV(''), 0x96, 0},
+      //{IV(''), 0x97, 0},
+      //{IV(''), 0x98, 0},
+      //{IV(''), 0x99, 0},
+      //{IV(''), 0x9A, 0},
+      //{IV(''), 0x9B, 0},
+      //{IV(''), 0x9C, 0},
+      //{IV(''), 0x9D, 0},
+      //{IV(''), 0x9E, 0},
+      //{IV(''), 0x9F, 0},
+
+      {IV('¼'), 0xF0, 0}, // 00BC
+      {IV('⅓'), 0xF1, 0},
+      {IV('½'), 0xF2, 0}, // 00BD
+      {IV('¾'), 0xF3, 0}, // 00BE
+      {IV('¿'), 0xCD, 0}, // 00BF
+
+      {IV('Ё'), 0xA2, 0}, // 0401
+      {IV('А'), 'A', 0}, // 0410
+      {IV('Б'), 0xA0, 0},
+      {IV('В'), 'B', 0},
+      {IV('Г'), 0xA1, 0},
+      {IV('Д'), 0xE0, 0},
+      {IV('Е'), 'E', 0},
+      {IV('Ж'), 0xA3, 0},
+      {IV('З'), 0xA4, 0},
+      {IV('И'), 0xA5, 0},
+      {IV('Й'), 0xA6, 0},
+      {IV('К'), 'K', 0},
+      {IV('Л'), 0xA7, 0},
+      {IV('М'), 'M', 0},
+      {IV('Н'), 'H', 0},
+      {IV('О'), 'O', 0},
+      {IV('П'), 0xA8, 0},
+      {IV('Р'), 'P', 0},
+      {IV('С'), 'C', 0},
+      {IV('Т'), 'T', 0},
+      {IV('У'), 0xA9, 0},
+      {IV('Ф'), 0xAA, 0},
+      {IV('Х'), 'X', 0},
+      {IV('Ц'), 0xE1, 0},
+      {IV('Ч'), 0xAB, 0},
+      {IV('Ш'), 0xAC, 0},
+      {IV('Щ'), 0xE2, 0},
+      {IV('Ъ'), 0xAD, 0},
+      {IV('Ы'), 0xAE, 0},
+      {IV('Ь'), 'b', 0},
+      {IV('Э'), 0xAF, 0},
+      {IV('Ю'), 0xB0, 0},
+      {IV('Я'), 0xB1, 0},
+      {IV('а'), 'a', 0},
+
+      {IV('б'), 0xB2, 0},
+      {IV('в'), 0xB3, 0},
+      {IV('г'), 0xB4, 0},
+      {IV('д'), 0xE3, 0},
+      {IV('е'), 'e', 0},
+      {IV('ж'), 0xB6, 0},
+      {IV('з'), 0xB7, 0},
+      {IV('и'), 0xB8, 0},
+      {IV('й'), 0xB9, 0},
+      {IV('к'), 0xBA, 0},
+      {IV('л'), 0xBB, 0},
+      {IV('м'), 0xBC, 0},
+      {IV('н'), 0xBD, 0},
+      {IV('о'), 'o', 0},
+      {IV('п'), 0xBE, 0},
+      {IV('р'), 'p', 0},
+      {IV('с'), 'c', 0},
+      {IV('т'), 0xBF, 0},
+
+      {IV('у'), 'y', 0},
+      {IV('ф'), 0xE4, 0},
+      {IV('х'), 'x', 0},
+      {IV('ц'), 0xE5, 0},
+      {IV('ч'), 0xC0, 0},
+      {IV('ш'), 0xC1, 0},
+      {IV('щ'), 0xE6, 0},
+      {IV('ъ'), 0xC2, 0},
+      {IV('ы'), 0xC3, 0},
+      {IV('ь'), 0xC4, 0},
+      {IV('э'), 0xC5, 0},
+      {IV('ю'), 0xC6, 0},
+      {IV('я'), 0xC7, 0}, // 044F
+      {IV('ё'), 0xB5, 0}, // 0451
+      //{IV(''), 0xC8, 0},
+      //{IV(''), 0xC9, 0},
+      //{IV(''), 0xCA, 0},
+      //{IV(''), 0xCB, 0},
+      //{IV(''), 0xCC, 0},
+      //{IV(''), 0xCD, 0},
+      //{IV(''), 0xCE, 0},
+
+      //{IV(''), 0xD0, 0},
+      //{IV(''), 0xD1, 0},
+      //{IV(''), 0xD2, 0},
+      //{IV(''), 0xD3, 0},
+      //{IV(''), 0xD4, 0},
+      //{IV(''), 0xD5, 0},
+      //{IV(''), 0xD6, 0},
+      //{IV(''), 0xD7, 0},
+      //{IV(''), 0xD8, 0},
+      //{IV(''), 0xDB, 0},
+      //{IV(''), 0xDC, 0},
+      //{IV(''), 0xDD, 0},
+      //{IV(''), 0xDE, 0},
+      //{IV(''), 0xDF, 0},
+
+      //{IV(''), 0xE7, 0},
+      //{IV(''), 0xE8, 0},
+      //{IV(''), 0xE9, 0},
+      //{IV(''), 0xEA, 0},
+      //{IV(''), 0xEB, 0},
+      //{IV(''), 0xEC, 0},
+      //{IV(''), 0xED, 0},
+      //{IV(''), 0xEE, 0},
+      //{IV(''), 0xEF, 0},
+
+      //{IV(''), 0xF4, 0},
+      //{IV(''), 0xF5, 0},
+      //{IV(''), 0xF6, 0},
+      //{IV(''), 0xF7, 0},
+      //{IV(''), 0xF8, 0},
+      //{IV(''), 0xF9, 0},
+      //{IV(''), 0xFA, 0},
+      //{IV(''), 0xFB, 0},
+      //{IV(''), 0xFC, 0},
+      //{IV(''), 0xFD, 0},
+      //{IV(''), 0xFE, 0},
+      //{IV(''), 0xFF, 0},
+
+      {IV('↑'), 0xD9, 0}, // 2191 ←↑→↓
+      {IV('↓'), 0xDA, 0}, // 2193
+
+    #endif
+
+  #endif
+};
+
+// the plain ASCII replacement for various char
+static const TFTGLCD_charmap_t g_TFTGLCD_charmap_common[] PROGMEM = {
+  {IV('¡'), 'i', 0}, // A1
+  {IV('¢'), 'c', 0}, // A2
+  {IV('°'), 0x09, 0}, // B0 Marlin special: '°'  LCD_STR_DEGREE (0x09)
+
+  #ifndef CONVERT_TO_EXT_ASCII  //this time CONVERT_TO_EXT_ASCII works only with en, ru and uk languages
+
+    // map WESTERN code to the plain ASCII
+    {IV('Á'), 'A', 0}, // C1
+    {IV('Â'), 'A', 0}, // C2
+    {IV('Ã'), 'A', 0}, // C3
+    {IV('Ä'), 'A', 0}, // C4
+    {IV('Å'), 'A', 0}, // C5
+    {IV('Æ'), 'A', 'E'}, // C6
+    {IV('Ç'), 'C', 0}, // C7
+    {IV('È'), 'E', 0}, // C8
+    {IV('É'), 'E', 0}, // C9
+    {IV('Í'), 'I', 0}, // CD
+    {IV('Ñ'), 'N', 0}, // D1
+    {IV('Õ'), 'O', 0}, // D5
+    {IV('Ö'), 'O', 0}, // D6
+    {IV('×'), 'x', 0}, // D7
+    {IV('Ü'), 'U', 0}, // DC
+    {IV('Ý'), 'Y', 0}, // DD
+    {IV('à'), 'a', 0}, // E0
+    {IV('á'), 'a', 0},
+    {IV('â'), 'a', 0},
+    {IV('ã'), 'a', 0},
+    {IV('ä'), 'a', 0},
+    {IV('å'), 'a', 0},
+    {IV('æ'), 'a', 'e'},
+    {IV('ç'), 'c', 0},
+    {IV('è'), 'e', 0}, // 00E8
+    {IV('é'), 'e', 0},
+    {IV('ê'), 'e', 0},
+    {IV('ë'), 'e', 0},
+    {IV('ì'), 'i', 0}, // 00EC
+    {IV('í'), 'i', 0},
+    {IV('î'), 'i', 0},
+    {IV('ï'), 'i', 0}, // 00EF
+
+    {IV('ñ'), 'n', 0}, // 00F1
+    {IV('ò'), 'o', 0},
+    {IV('ó'), 'o', 0},
+    {IV('ô'), 'o', 0},
+    {IV('õ'), 'o', 0},
+    {IV('ö'), 'o', 0},
+    //{IV('÷'), 0xB8, 0},
+    {IV('ø'), 'o', 0},
+    {IV('ù'), 'u', 0},
+    {IV('ú'), 'u', 0},
+    {IV('û'), 'u', 0},
+    {IV('ü'), 'u', 0}, // FC
+    {IV('ý'), 'y', 0}, // FD
+    {IV('ÿ'), 'y', 0}, // FF
+
+    {IV('Ą'), 'A', 0}, // 0104
+    {IV('ą'), 'a', 0}, // 0105
+    {IV('Ć'), 'C', 0}, // 0106
+    {IV('ć'), 'c', 0}, // 0107
+    {IV('Č'), 'C', 0}, // 010C
+    {IV('č'), 'c', 0}, // 010D
+    {IV('Ď'), 'D', 0}, // 010E
+    {IV('ď'), 'd', 0}, // 010F
+    {IV('đ'), 'd', 0}, // 0111
+    {IV('ę'), 'e', 0}, // 0119
+    {IV('ğ'), 'g', 0}, // 011F
+    {IV('İ'), 'I', 0}, // 0130
+    {IV('ı'), 'i', 0}, // 0131
+
+    {IV('Ł'), 'L', 0}, // 0141
+    {IV('ł'), 'l', 0}, // 0142
+    {IV('Ń'), 'N', 0}, // 0143
+    {IV('ń'), 'n', 0}, // 0144
+    {IV('ň'), 'n', 0}, // 0148
+
+    {IV('ř'), 'r', 0}, // 0159
+    {IV('Ś'), 'S', 0}, // 015A
+    {IV('ś'), 's', 0}, // 015B
+    {IV('ş'), 's', 0}, // 015F
+    {IV('Š'), 'S', 0}, // 0160
+    {IV('š'), 's', 0}, // 0161
+    {IV('ť'), 't', 0}, // 0165
+    {IV('ů'), 'u', 0}, // 016F
+    {IV('ż'), 'z', 0}, // 017C
+    {IV('Ž'), 'Z', 0}, // 017D
+    {IV('ž'), 'z', 0}, // 017E
+    {IV('ƒ'), 'f', 0}, // 0192
+
+    {IV('ˣ'), 'x', 0}, // 02E3
+
+    {IV('΄'), '\'', 0}, // 0384
+    {IV('΅'), '\'', 0}, // 0385
+    {IV('Ά'), 'A', 0}, // 0386
+    {IV('·'), '.', 0}, // 0387
+    {IV('Έ'), 'E', 0}, // 0388
+    {IV('Ή'), 'H', 0}, // 0389
+    {IV('Ί'), 'I', 0}, // 038A
+    {IV('Ό'), 'O', 0}, // 038C
+    {IV('Ύ'), 'Y', 0}, // 038E
+    {IV('Ώ'), 'O', 0}, // 038F
+    {IV('ΐ'), 'i', 0}, // 0390
+    {IV('Α'), 'A', 0}, // 0391
+    {IV('Β'), 'B', 0}, // 0392
+    {IV('Γ'), 'T', 0}, // 0393, Gamma
+    {IV('Δ'), '4', 0}, // 0394, Delta, ◿
+    {IV('Ε'), 'E', 0}, // 0395
+    {IV('Ζ'), 'Z', 0}, // 0396
+    {IV('Η'), 'H', 0}, // 0397
+    {IV('Θ'), '0', 0}, // 0398, Theta
+    {IV('Ι'), 'I', 0}, // 0399
+    {IV('Κ'), 'K', 0}, // 039A
+    {IV('Λ'), '^', 0}, // 039B, Lambda
+    {IV('Μ'), 'M', 0}, // 039C
+    {IV('Ν'), 'N', 0}, // 039D
+    {IV('Ξ'), '3', 0}, // 039E, Xi
+    {IV('Ο'), 'O', 0}, // 039F
+    {IV('Π'), 'n', 0}, // 03A0, Pi
+    {IV('Ρ'), 'P', 0}, // 03A1
+    {IV('Σ'), 'E', 0}, // 03A3, Sigma
+    {IV('Τ'), 'T', 0}, // 03A4
+    {IV('Υ'), 'Y', 0}, // 03A5, Upsilon
+    {IV('Φ'), 'p', 0}, // 03A6, Phi
+    {IV('Χ'), 'X', 0}, // 03A7
+    {IV('Ψ'), 'P', 0}, // 03A8, Psi
+    {IV('Ω'), 'O', 0}, // 03A9, Omega
+    {IV('Ϊ'), 'I', 0}, // 03AA
+    {IV('Ϋ'), 'Y', 0}, // 03AB
+    {IV('ά'), 'a', 0}, // 03AC
+    {IV('έ'), 'e', 0}, // 03AD
+    {IV('ή'), 'n', 0}, // 03AE
+    {IV('ί'), 'i', 0}, // 03AF
+    {IV('ΰ'), 'v', 0}, // 03B0
+    {IV('α'), 'a', 0}, // 03B1, alpha
+    {IV('β'), 'B', 0}, // 03B2, beta
+    {IV('γ'), 'v', 0}, // 03B3, gamma
+    {IV('δ'), 'd', 0}, // 03B4, delta
+    {IV('ε'), 'e', 0}, // 03B5, epsilon
+    {IV('ζ'), 'Z', 0}, // 03B6, zeta
+    {IV('η'), 'n', 0}, // 03B7, eta
+    {IV('θ'), '0', 0}, // 03B8, theta
+    {IV('ι'), 'i', 0}, // 03B9, lota
+    {IV('κ'), 'k', 0}, // 03BA, kappa
+    {IV('λ'), 'L', 0}, // 03BB, lambda
+    {IV('μ'), 'u', 0}, // 03BC, mu
+    {IV('ν'), 'v', 0}, // 03BD, nu
+    {IV('ξ'), 'e', 0}, // 03BE, xi
+    {IV('ο'), 'o', 0}, // 03BF
+    {IV('π'), 'n', 0}, // 03C0, pi
+    {IV('ρ'), 'p', 0}, // 03C1, rho
+    {IV('ς'), 'c', 0}, // 03C2
+    {IV('σ'), 'o', 0}, // 03C3, sigma
+    {IV('τ'), 't', 0}, // 03C4, tau
+    {IV('υ'), 'v', 0}, // 03C5, upsilon
+    {IV('φ'), 'p', 0}, // 03C6
+    {IV('χ'), 'X', 0}, // 03C7, chi
+    {IV('ψ'), 'W', 0}, // 03C8, psi
+    {IV('ω'), 'w', 0}, // 03C9, omega
+    {IV('ϊ'), 'i', 0}, // 03CA
+    {IV('ϋ'), 'v', 0}, // 03CB
+    {IV('ό'), 'o', 0}, // 03CC
+    {IV('ύ'), 'v', 0}, // 03CD
+    {IV('ώ'), 'w', 0}, // 03CE
+
+    // map CYRILLIC code to the plain ASCII
+    {IV('А'), 'A', 0}, // 0410
+    {IV('Б'), 'b', 0}, // 0411
+    {IV('В'), 'B', 0}, // 0412
+    {IV('Г'), 'T', 0}, // 0413
+    {IV('Д'), 'Q', 0}, // 0414
+    {IV('Е'), 'E', 0}, // 0415
+    {IV('Ж'), '*', 0}, // 0416
+    {IV('З'), 'E', 0}, // 0417
+    {IV('И'), 'N', 0}, // 0418
+    {IV('Й'), 'N', 0}, // 0419
+    {IV('К'), 'K', 0}, // 041A
+    {IV('Л'), 'T', 0}, // 041B
+    {IV('М'), 'M', 0}, // 041C
+    {IV('Н'), 'H', 0}, // 041D
+    {IV('О'), 'O', 0}, // 041E
+    {IV('П'), 'n', 0}, // 041F
+    {IV('Р'), 'P', 0}, // 0420
+    {IV('С'), 'C', 0}, // 0421
+    {IV('Т'), 'T', 0}, // 0422
+    {IV('У'), 'Y', 0},
+    {IV('Ф'), 'o', 0},
+    {IV('Х'), 'X', 0},
+    {IV('Ц'), 'U', 0},
+    {IV('Ч'), 'y', 0},
+    {IV('Ш'), 'W', 0},
+    {IV('Щ'), 'W', 0},
+    {IV('Ъ'), 'b', 0},
+    {IV('Ы'), 'b', '|'},
+    {IV('Ь'), 'b'},
+    {IV('Э'), 'e'},
+    {IV('Ю'), '|', 'O'},
+    {IV('Я'), '9', '|'}, // 042F
+
+    {IV('а'), 'a', 0}, // 0430
+    {IV('б'), '6', 0}, // 0431
+    {IV('в'), 'B', 0}, // 0432,
+    {IV('г'), 'r', 0}, // 0433
+    {IV('д'), 'a', 0}, // 0434,
+    {IV('е'), 'e', 0}, // 0435
+    {IV('ж'), '*', 0}, // 0436
+    {IV('з'), 'e', 0}, // 0437,
+    {IV('и'), 'u', 0}, // 0438
+    {IV('й'), 'u', 0}, // 0439,
+    {IV('к'), 'k', 0}, // 043A
+    {IV('л'), 'n', 0},
+    {IV('м'), 'm', 0},
+    {IV('н'), 'H', 0},
+    {IV('о'), 'o', 0},
+    {IV('п'), 'n', 0},
+    {IV('р'), 'p', 0},
+    {IV('с'), 'c', 0},
+    {IV('т'), 't', 0},
+    {IV('у'), 'y', 0},
+    {IV('ф'), 'q', 'p'},
+    {IV('х'), 'x', 0},
+    {IV('ц'), 'u', 0},
+    {IV('ч'), 'y', 0},
+    {IV('ш'), 'w', 0},
+    {IV('щ'), 'w', 0},
+    {IV('ъ'), 'b', 0},
+    {IV('ы'), 'b', '|'},
+    {IV('ь'), 'b', 0},
+    {IV('э'), 'e', 0},
+    {IV('ю'), '|', 'o'},
+    {IV('я'), 'g', 0}, // 044F
+
+  #endif
+
+  {IV('•'), '.', 0}, // 2022 ·
+  {IV('℞'), 'P', 'x'}, // 211E ℞ Pt ASCII 158
+  {IV('™'), 'T', 'M'}, // 2122
+  {IV('←'), '<', '-'}, // 2190
+  {IV('→'), '-', '>'}, // 2192, Marlin special: '⮈⮉⮊⮋➤→⏵➟➠➡' LCD_STR_ARROW_RIGHT (0x03)
+  //{IV('↰'), '<', 0}, // 21B0, Marlin special: '⮥⮭⮉⇧↑↰⤴'  LCD_STR_UPLEVEL (0x04)
+  {IV('↰'), 0x03, 0}, // 21B0, Marlin special: '⮥⮭⮉⇧↑↰⤴'  LCD_STR_UPLEVEL (0x04)
+  {IV('↻'), 0x04, 0}, // 21BB Marlin special: '↻↺⟳⟲'  LCD_STR_REFRESH (0x01)
+  {IV('∼'), '~', 0}, // 223C
+  {IV('≈'), '~', '='}, // 2248
+  {IV('≠'), '!', '='}, // 2260
+  {IV('≡'), '=', 0}, // 2261
+  {IV('≤'), '<', '='},// 2264, ≤≥ ⩽⩾
+  {IV('≥'), '>', '='}, // 2265
+  {IV('⏱'), 0x07, 0}, // 23F1, Marlin special: '🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧 ⌚⌛⏰⏱⏳⧖⧗'  LCD_STR_CLOCK (0x05)
+
+  {IV('゠'), '=', 0}, // 30A0
+
+  // ⏰⏱⏲⏳◴◵◶◷
+  // ⏻⏼♁♂
+  //{IV(''), 0x00, 0}, // Marlin special: ''  LCD_STR_BEDTEMP (0x07)
+  {IV('🌡'), 0x02, 0}, // D83CDF21 Marlin special: '🌡'  LCD_STR_THERMOMETER (0x08)
+  {IV('📂'), 0x05, 0}, // D83DDCC2 Marlin special: '📁📂'  LCD_STR_FOLDER (0x02)
+  //{IV(''), 0x06, 0}, // Marlin special: ''  LCD_STR_FEEDRATE (0x06)
+};
+
+/* return v1 - v2 */
+static int TFTGLCD_charmap_compare(TFTGLCD_charmap_t * v1, TFTGLCD_charmap_t * v2) {
+  return (v1->uchar < v2->uchar) ? -1 : (v1->uchar > v2->uchar) ? 1 : 0;
+}
+
+static int pf_bsearch_cb_comp_hd4map_pgm(void *userdata, size_t idx, void * data_pin) {
+  TFTGLCD_charmap_t localval;
+  TFTGLCD_charmap_t *p_TFTGLCD_charmap = (TFTGLCD_charmap_t *)userdata;
+  memcpy_P(&localval, p_TFTGLCD_charmap + idx, sizeof(localval));
+  return TFTGLCD_charmap_compare(&localval, (TFTGLCD_charmap_t *)data_pin);
+}
+
+void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) { lcd.setCursor(col, row); }
+
+void lcd_put_int(const int i) {
+  const char* str = i16tostr3left(i);
+  while (*str) lcd.write(*str++);
+}
+
+// return < 0 on error
+// return the advanced cols
+int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
+
+  // find the HD44780 internal ROM first
+  int ret;
+  size_t idx = 0;
+  TFTGLCD_charmap_t pinval;
+  TFTGLCD_charmap_t *copy_address = nullptr;
+  pinval.uchar = c;
+  pinval.idx = -1;
+
+  if (max_length < 1) return 0;
+
+  if (c < 128) {
+    lcd.write((uint8_t)c);
+    return 1;
+  }
+  copy_address = nullptr;
+  ret = pf_bsearch_r((void *)g_TFTGLCD_charmap_device, COUNT(g_TFTGLCD_charmap_device), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+  if (ret >= 0) {
+    copy_address = (TFTGLCD_charmap_t *)(g_TFTGLCD_charmap_device + idx);
+  }
+  else {
+    ret = pf_bsearch_r((void *)g_TFTGLCD_charmap_common, COUNT(g_TFTGLCD_charmap_common), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+    if (ret >= 0) copy_address = (TFTGLCD_charmap_t *)(g_TFTGLCD_charmap_common + idx);
+  }
+
+  if (ret >= 0) {
+    TFTGLCD_charmap_t localval;
+    // found
+    memcpy_P(&localval, copy_address, sizeof(localval));
+    lcd.write(localval.idx);
+    if (max_length >= 2 && localval.idx2 > 0) {
+      lcd.write(localval.idx2);
+      return 2;
+    }
+    return 1;
+  }
+
+  // Not found, print '?' instead
+  lcd.write((uint8_t)'?');
+  return 1;
+}
+
+/**
+ * @brief Draw a UTF-8 string
+ *
+ * @param utf8_str : the UTF-8 string
+ * @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM)
+ * @param max_length : the pixel length of the string allowed (or number of slots in HD44780)
+ *
+ * @return the number of pixels advanced
+ *
+ * Draw a UTF-8 string
+ */
+static int lcd_put_u8str_max_cb(const char * utf8_str, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) {
+  pixel_len_t ret = 0;
+  uint8_t *p = (uint8_t *)utf8_str;
+  while (ret < max_length) {
+    wchar_t ch = 0;
+    p = get_utf8_value_cb(p, cb_read_byte, &ch);
+    if (!ch) break;
+    ret += lcd_put_wchar_max(ch, max_length - ret);
+  }
+  return (int)ret;
+}
+
+int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
+  return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length);
+}
+
+int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
+  return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length);
+}
+
+#if ENABLED(DEBUG_LCDPRINT)
+
+  int test_TFTGLCD_charmap(TFTGLCD_charmap_t *data, size_t size, char *name, char flg_show_contents) {
+    int ret;
+    size_t idx = 0;
+    TFTGLCD_charmap_t preval = {0, 0, 0};
+    TFTGLCD_charmap_t pinval = {0, 0, 0};
+    char flg_error = 0;
+
+    int i;
+
+    TRACE("Test %s\n", name);
+
+    for (i = 0; i < size; i ++) {
+      memcpy_P(&pinval, &(data[i]), sizeof(pinval));
+
+      if (flg_show_contents) {
+        #if 1
+          TRACE("[% 4d] % 6" PRIu32 "(0x%04" PRIX32 ") --> 0x%02X,0x%02X%s\n", i, pinval.uchar, pinval.uchar, (unsigned int)(pinval.idx), (unsigned int)(pinval.idx2), (preval.uchar < pinval.uchar?"":" <--- ERROR"));
+        #else
+          TRACE("[% 4d]", i);
+          TRACE("% 6" PRIu32 "(0x%04" PRIX32 "),", pinval.uchar, pinval.uchar);
+          TRACE("0x%02X,", (unsigned int)(pinval.idx));
+          TRACE("0x%02X,", (unsigned int)(pinval.idx2));
+          TRACE("%s", (preval.uchar < pinval.uchar?"":" <--- ERROR"));
+        #endif
+      }
+      if (preval.uchar >= pinval.uchar) {
+        flg_error = 1;
+        //TRACE("Error: out of order in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+        //return -1;
+      }
+      memcpy(&preval, &pinval, sizeof(pinval));
+
+      ret = pf_bsearch_r((void *)data, size, pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+      if (ret < 0) {
+        flg_error = 1;
+        TRACE("Error: not found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+        //return -1;
+      }
+      if (idx != i) {
+        flg_error = 1;
+        TRACE("Error: wrong index found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+        //return -1;
+      }
+    }
+    if (flg_error) {
+      TRACE("\nError: in array %s\n\n", name);
+      return -1;
+    }
+    TRACE("\nPASS array %s\n\n", name);
+    return 0;
+  }
+
+  int test_TFTGLCD_charmap_all(void) {
+    int flg_error = 0;
+    if (test_TFTGLCD_charmap(g_TFTGLCD_charmap_device, COUNT(g_TFTGLCD_charmap_device), "g_TFTGLCD_charmap_device", 0) < 0) {
+      flg_error = 1;
+      test_TFTGLCD_charmap(g_TFTGLCD_charmap_device, COUNT(g_TFTGLCD_charmap_device), "g_TFTGLCD_charmap_device", 1);
+    }
+    if (test_TFTGLCD_charmap(g_TFTGLCD_charmap_common, COUNT(g_TFTGLCD_charmap_common), "g_TFTGLCD_charmap_common", 0) < 0) {
+      flg_error = 1;
+      test_TFTGLCD_charmap(g_TFTGLCD_charmap_common, COUNT(g_TFTGLCD_charmap_common), "g_TFTGLCD_charmap_common", 1);
+    }
+    if (flg_error) {
+      TRACE("\nFAILED in hd44780 tests!\n");
+      return -1;
+    }
+    TRACE("\nPASS in hd44780 tests.\n");
+    return 0;
+  }
+
+#endif // DEBUG_LCDPRINT
+
+#endif // IS_TFTGLCD_PANEL
diff --git a/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.cpp b/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.cpp
new file mode 100644
index 00000000000..c9a5b2525ab
--- /dev/null
+++ b/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.cpp
@@ -0,0 +1,1018 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if IS_TFTGLCD_PANEL
+
+/**
+ * ultralcd_TFTGLCD.cpp
+ *
+ * Implementation of the LCD display routines for a TFT GLCD displays with external controller.
+ * This display looks as a REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER but has good text font
+ * and supports color output.
+ */
+
+#if NONE(__AVR__, MCU_LPC1768, __STM32F1__, STM32F4xx)
+  #warning "Selected platform not yet tested. Please contribute your good pin mappings."
+#endif
+
+#if ENABLED(TFTGLCD_PANEL_SPI)
+  #include <SPI.h>
+#else
+  #include <Wire.h>
+#endif
+
+#include "ultralcd_TFTGLCD.h"
+#include "../ultralcd.h"
+#include "../../libs/numtostr.h"
+
+#include "../../sd/cardreader.h"
+#include "../../module/temperature.h"
+#include "../../module/printcounter.h"
+#include "../../module/planner.h"
+#include "../../module/motion.h"
+
+#if DISABLED(LCD_PROGRESS_BAR) && BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
+  #include "../../feature/filwidth.h"
+  #include "../../gcode/parser.h"
+#endif
+
+#if ENABLED(AUTO_BED_LEVELING_UBL)
+  #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+TFTGLCD lcd;
+
+#define ICON_LOGO       B00000001
+#define ICON_TEMP1      B00000010    //hotend 1
+#define ICON_TEMP2      B00000100    //hotend 2
+#define ICON_TEMP3      B00001000    //hotend 3
+#define ICON_BED        B00010000
+#define ICON_FAN        B00100000
+#define ICON_HOT        B01000000    //when any T > 50deg
+#define PIC_MASK        0x7f
+
+//LEDs not used, for compatibility with Smoothieware
+#define LED_HOTEND_ON   B00000001
+#define LED_BED_ON      B00000010
+#define LED_FAN_ON      B00000100
+#define LED_HOT         B00001000
+#define LED_MASK        0x0f
+
+#define FBSIZE      (LCD_WIDTH * LCD_HEIGHT + 2)
+
+//markers for change line color
+#define COLOR_EDIT      '#'
+#define COLOR_ERROR     '!'
+
+#ifdef CONVERT_TO_EXT_ASCII   //use standart pseudographic symbols in ASCII table
+  #define LR            179   //vertical line
+  #define TRC           191   //top right corner
+  #define BLC           192   //bottom left corner
+  #define GL            196   //horizontal line
+  #define BRC           217   //bottom right corner, should be replaced to 12 for some languages
+  #define TLC           218   //top left corner, should be replaced to 13 for some languages
+#else //next symbols must be present in panel font
+  #define LR            8     //equal to 179
+  #define TRC           9     //equal to 191
+  #define BLC           10    //equal to 192
+  #define GL            11    //equal to 196
+  #define BRC           12    //equal to 217
+  #define TLC           13    //equal to 218
+#endif
+
+#define Marlin  0x01
+
+enum Commands {         // based on Smoothieware commands
+  GET_SPI_DATA = 0,
+  READ_BUTTONS,         // read buttons
+  READ_ENCODER,         // read encoder
+  LCD_WRITE,            // write all screen to LCD
+  BUZZER,               // beep buzzer
+  CONTRAST,             // set contrast (brightnes)
+  // Other commands... 0xE0 thru 0xFF
+  GET_LCD_ROW = 0xE0,   // for detect panel
+  GET_LCD_COL,          // reserved for compatibility with Smoothieware, not used
+	LCD_PUT,		          // write one line to LCD
+	INIT_SCREEN = 0xFE,   // clear panel buffer
+};
+
+static unsigned char framebuffer[FBSIZE];
+static unsigned char *fb;
+static uint8_t cour_line;
+static uint8_t picBits, ledBits, hotBits;
+static uint8_t PanelDetected = 0;
+
+// Constructor
+TFTGLCD::TFTGLCD() {}
+
+//clearing local buffer
+void TFTGLCD::clear_buffer() {
+  memset(&framebuffer[0], ' ', FBSIZE - 2);
+  framebuffer[FBSIZE - 1] = framebuffer[FBSIZE - 2] = 0;
+  picBits = ledBits = 0;
+}
+
+//set new text cursor position
+void TFTGLCD::setCursor(uint8_t col, uint8_t row) {
+  fb = &framebuffer[0] + col + row * LCD_WIDTH;
+  cour_line = row;
+}
+
+//send char to buffer
+void TFTGLCD::write(char c) {
+  *fb++ = c;
+}
+
+//send text line to buffer
+void TFTGLCD::print(const char *line) {
+  while (*line) *fb++ = *line++;
+}
+
+// For menu
+void TFTGLCD::print_line() {
+  if (!PanelDetected) return;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    WRITE(TFTGLCD_CS, LOW);
+    #ifdef __AVR__
+      SPI.transfer(LCD_PUT);
+      SPI.transfer(cour_line);
+      SPI.transfer(&framebuffer[cour_line * LCD_WIDTH], LCD_WIDTH);
+    #elif EITHER(MCU_LPC1768, __STM32F1__)
+      SPI.transfer(LCD_PUT);
+      SPI.transfer(cour_line);
+      for (uint16_t i = 0; i < LCD_WIDTH; i++)  SPI.transfer(framebuffer[cour_line * LCD_WIDTH + i]);
+    #elif defined(STM32F4xx)
+      SPI.transfer(LCD_PUT, SPI_CONTINUE);
+      SPI.transfer(cour_line, SPI_CONTINUE);
+      SPI.transfer(&framebuffer[cour_line * LCD_WIDTH], LCD_WIDTH, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(LCD_PUT);
+      SPI.transfer(cour_line);
+      SPI.transfer(&framebuffer[cour_line * LCD_WIDTH], LCD_WIDTH);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.write(LCD_PUT);
+      SPI.write(cour_line);
+      for (uint16_t i = 0; i < LCD_WIDTH; i++) SPI.write(framebuffer[cour_line * LCD_WIDTH + i]);
+    #endif
+    WRITE(TFTGLCD_CS, HIGH);
+  #else
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);  //set I2C device address
+    Wire.write(LCD_PUT);
+    Wire.write(cour_line);
+    Wire.write(&framebuffer[cour_line * LCD_WIDTH], LCD_WIDTH);  //transfer 1 line to txBuffer
+    Wire.endTransmission(); //transmit data
+    safe_delay(1);
+  #endif
+}
+
+void TFTGLCD::print_screen(){
+  if (!PanelDetected) return;
+  framebuffer[FBSIZE - 2] = picBits & PIC_MASK;
+  framebuffer[FBSIZE - 1] = ledBits;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    // Send all framebuffer to panel
+    WRITE(TFTGLCD_CS, LOW);
+    #ifdef __AVR__
+      SPI.transfer(LCD_WRITE);
+      SPI.transfer(&framebuffer[0], FBSIZE);
+    #elif EITHER(MCU_LPC1768, __STM32F1__)
+      SPI.transfer(LCD_WRITE);
+      for (uint16_t i = 0; i < FBSIZE; i++) SPI.transfer(framebuffer[i]);
+    #elif defined(STM32F4xx)
+      SPI.transfer(LCD_WRITE, SPI_CONTINUE);
+      SPI.transfer(&framebuffer[0], FBSIZE, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(LCD_WRITE);
+      SPI.transfer(&framebuffer[0], FBSIZE);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.write(LCD_WRITE);
+      for (uint16_t i = 0; i < FBSIZE; i++) SPI.write(framebuffer[i]);
+    #endif
+    WRITE(TFTGLCD_CS, HIGH);
+  #else
+    uint8_t r;
+    // Send framebuffer to panel by line
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    // First line
+    Wire.write(LCD_WRITE);
+    Wire.write(&framebuffer[0], LCD_WIDTH);
+    Wire.endTransmission();
+    for (r = 1; r < (LCD_HEIGHT - 1); r++) {
+      Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+      Wire.write(&framebuffer[r * LCD_WIDTH], LCD_WIDTH);
+      Wire.endTransmission();
+    }
+    // Last line
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    Wire.write(&framebuffer[r * LCD_WIDTH], LCD_WIDTH);
+    Wire.write(&framebuffer[FBSIZE - 2], 2);
+    Wire.endTransmission();
+  #endif
+}
+
+void TFTGLCD::setContrast(uint16_t contrast) {
+  if (!PanelDetected) return;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    WRITE(TFTGLCD_CS, LOW);
+    #if ANY(__AVR__, MCU_LPC1768, __STM32F1__)
+      SPI.transfer(CONTRAST);
+      SPI.transfer((uint8_t)contrast);
+    #elif defined(STM32F4xx)
+      SPI.transfer(CONTRAST, SPI_CONTINUE);
+      SPI.transfer((uint8_t)contrast, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(CONTRAST);
+      SPI.transfer((uint8_t)contrast);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.write(CONTRAST);
+      SPI.write((uint8_t)contrast);
+    #endif
+    WRITE(TFTGLCD_CS, HIGH);
+  #else
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    Wire.write(CONTRAST);
+    Wire.write((uint8_t)contrast);
+    Wire.endTransmission();
+  #endif
+}
+
+//reading buttons and encoder states
+extern volatile int8_t encoderDiff;
+
+uint8_t MarlinUI::read_slow_buttons(void) {
+  if (!PanelDetected)    return 0;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    uint8_t b = 0;
+    WRITE(TFTGLCD_CS, LOW);
+    #if ANY(__AVR__, MCU_LPC1768, __STM32F1__)
+      SPI.transfer(READ_ENCODER);
+      WRITE(TFTGLCD_CS, LOW); //for delay
+      encoderDiff += SPI.transfer(READ_BUTTONS);
+      WRITE(TFTGLCD_CS, LOW); //for delay
+      b = SPI.transfer(GET_SPI_DATA);
+    #elif defined(STM32F4xx)
+      SPI.transfer(READ_ENCODER, SPI_CONTINUE);
+      encoderDiff += SPI.transfer(READ_BUTTONS, SPI_CONTINUE);
+      b = SPI.transfer(GET_SPI_DATA, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(READ_ENCODER);
+      WRITE(TFTGLCD_CS, LOW); //for delay ????
+      encoderDiff += SPI.transfer(READ_BUTTONS);
+      WRITE(TFTGLCD_CS, LOW); //for delay ????
+      b = SPI.transfer(GET_SPI_DATA);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.transfer(READ_ENCODER);
+      WRITE(TFTGLCD_CS, LOW); //for delay ????
+      encoderDiff += SPI.transfer(READ_BUTTONS);
+      WRITE(TFTGLCD_CS, LOW); //for delay ????
+      b = SPI.transfer(GET_SPI_DATA);
+    #endif
+    WRITE(TFTGLCD_CS, HIGH);
+    return b;
+  #else
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    Wire.write(READ_ENCODER);
+    Wire.endTransmission();
+    #ifdef __AVR__
+      Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, 2, 0, 0, 1);
+    #elif defined(__STM32F1__)
+      Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, (uint8_t)2);
+    #elif EITHER(STM32F4xx, MCU_LPC1768)
+      Wire.requestFrom(LCD_I2C_ADDRESS, 2);
+    #endif
+    encoderDiff += Wire.read();
+    return Wire.read();   //buttons
+  #endif
+}
+
+// duration in ms, freq in Hz
+void MarlinUI::buzz(const long duration, const uint16_t freq) {
+  if (!PanelDetected) return;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    WRITE(TFTGLCD_CS, LOW);
+    #if ANY(__AVR__, MCU_LPC1768, __STM32F1__)
+      SPI.transfer(BUZZER);
+      SPI.transfer16((uint16_t)duration);
+      SPI.transfer16(freq);
+    #elif defined(STM32F4xx)
+      SPI.transfer(BUZZER, SPI_CONTINUE);
+      SPI.transfer16((uint16_t)duration, SPI_CONTINUE);
+      SPI.transfer16(freq, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(BUZZER);
+      SPI.transfer16((uint16_t)duration);
+      SPI.transfer16(freq);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.write(BUZZER);
+      SPI.write16((uint16_t)duration);
+      SPI.write16(freq);
+    #endif
+    WRITE(TFTGLCD_CS, HIGH);
+  #else
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    Wire.write(BUZZER);
+    Wire.write((uint8_t)(duration >> 8));
+    Wire.write((uint8_t)duration);
+    Wire.write((uint8_t)(freq >> 8));
+    Wire.write((uint8_t)freq);
+    Wire.endTransmission();
+  #endif
+}
+
+void MarlinUI::init_lcd() {
+  uint8_t t;
+  lcd.clear_buffer();
+  t = 0;
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    // SPI speed must be less 10MHz
+    OUT_WRITE(TFTGLCD_CS, HIGH);
+    spiInit(TERN(__STM32F1__, SPI_QUARTER_SPEED, SPI_FULL_SPEED));
+    WRITE(TFTGLCD_CS, LOW);
+    #if ANY(__AVR__, MCU_LPC1768, __STM32F1__)
+      SPI.transfer(GET_LCD_ROW);
+      t = SPI.transfer(GET_SPI_DATA);
+    #elif defined(STM32F4xx)
+      SPI.transfer(GET_LCD_ROW, SPI_CONTINUE);
+      t = SPI.transfer(GET_SPI_DATA, SPI_CONTINUE);
+    #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+      SPI.transfer(GET_LCD_ROW);
+      t = SPI.transfer(GET_SPI_DATA);
+    #elif defined(ARDUINO_ARCH_ESP32)
+      SPI.write(GET_LCD_ROW);
+      t = SPI.transfer(GET_SPI_DATA);
+    #endif
+  #else
+    #ifdef MCU_LPC1768
+      Wire.begin();   //init twi/I2C
+    #else
+      Wire.begin((uint8_t)LCD_I2C_ADDRESS); //init twi/I2C
+    #endif
+    Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+    Wire.write((uint8_t)GET_LCD_ROW); // put command to buffer
+    Wire.endTransmission(); // send buffer
+    #ifdef __AVR__
+      Wire.requestFrom((uint8_t)LCD_I2C_ADDRESS, 1, 0, 0, 1);
+    #elif ANY(__STM32F1__, STM32F4xx, MCU_LPC1768)
+      Wire.requestFrom(LCD_I2C_ADDRESS, 1);
+    #endif
+    t = (uint8_t)Wire.read();
+  #endif
+
+  if (t == LCD_HEIGHT) {
+    PanelDetected = 1;
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      PanelDetected = 1;
+      #if ANY(__AVR__, MCU_LPC1768, __STM32F1__)
+        SPI.transfer(INIT_SCREEN);
+        SPI.transfer(Marlin);
+      #elif defined(STM32F4xx)
+        SPI.transfer(INIT_SCREEN, SPI_CONTINUE);
+        SPI.transfer(Marlin, SPI_CONTINUE);
+      #elif ANY(ARDUINO_ARCH_SAM, __SAMD51__, __MK20DX256__, __MK64FX512__)
+        SPI.transfer(INIT_SCREEN);
+        SPI.transfer(Marlin);
+      #elif defined(ARDUINO_ARCH_ESP32)
+        SPI.write(INIT_SCREEN);
+        SPI.write(Marlin);
+      #endif
+      WRITE(TFTGLCD_CS, HIGH);
+    #else
+      Wire.beginTransmission((uint8_t)LCD_I2C_ADDRESS);
+      Wire.write((uint8_t)INIT_SCREEN);
+      Wire.write(Marlin);
+      Wire.endTransmission();
+    #endif
+  }
+  else
+    PanelDetected = 0;
+  safe_delay(100);
+}
+
+bool MarlinUI::detected() {
+  return PanelDetected;
+}
+
+void MarlinUI::clear_lcd() {
+  if (!PanelDetected) return;
+  lcd.clear_buffer();
+  lcd.print_screen();
+}
+
+int16_t MarlinUI::contrast; // Initialized by settings.load()
+
+void MarlinUI::set_contrast(const int16_t value) {
+  contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX);
+  lcd.setContrast(contrast);
+}
+
+static void center_text_P(PGM_P pstart, uint8_t y) {
+  uint8_t len = utf8_strlen_P(pstart);
+  if (len < LCD_WIDTH)
+    lcd.setCursor((LCD_WIDTH - len) / 2, y);
+  else
+    lcd.setCursor(0, y);
+  lcd_put_u8str_P(pstart);
+}
+
+#if ENABLED(SHOW_BOOTSCREEN)
+
+  void MarlinUI::show_bootscreen() {
+    if (!PanelDetected) return;
+    //
+    // Show the Marlin logo, splash line1, and splash line 2
+    //
+    uint8_t indent = (LCD_WIDTH - 8) / 2;
+    // symbols 217 (bottom right corner) and 218 (top left corner) are using for letters in some languages
+    // and they should be moved to begining ASCII table as spetial symbols
+    lcd.setCursor(indent, 0); lcd.write(TLC); lcd_put_u8str_P(PSTR("------"));  lcd.write(TRC);
+    lcd.setCursor(indent, 1); lcd.write(LR);  lcd_put_u8str_P(PSTR("Marlin"));  lcd.write(LR);
+    lcd.setCursor(indent, 2); lcd.write(BLC); lcd_put_u8str_P(PSTR("------"));  lcd.write(BRC);
+    center_text_P(PSTR(SHORT_BUILD_VERSION), 3);
+    center_text_P(PSTR(MARLIN_WEBSITE_URL), 4);
+    picBits = ICON_LOGO;
+    lcd.print_screen();
+    safe_delay(1500);
+  }
+
+#endif // SHOW_BOOTSCREEN
+
+void MarlinUI::draw_kill_screen() {
+  if (!PanelDetected) return;
+  lcd.clear_buffer();
+  lcd.setCursor(0, 3);  lcd.write(COLOR_ERROR);
+  lcd.setCursor((LCD_WIDTH - utf8_strlen(status_message)) / 2 + 1, 3);
+  lcd_put_u8str(status_message);
+  center_text_P(GET_TEXT(MSG_HALTED), 5);
+  center_text_P(GET_TEXT(MSG_PLEASE_RESET), 6);
+  lcd.print_screen();
+}
+
+//
+// Before homing, blink '123' <-> '???'.
+// Homed but unknown... '123' <-> '   '.
+// Homed and known, display constantly.
+//
+FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink) {
+  lcd.write('X' + uint8_t(axis));
+  if (blink)
+    lcd.print(value);
+  else {
+    if (!TEST(axis_homed, axis))
+      while (const char c = *value++) lcd.write(c <= '.' ? c : '?');
+    else {
+      #if NONE(HOME_AFTER_DEACTIVATE, DISABLE_REDUCED_ACCURACY_WARNING)
+        if (!TEST(axis_known_position, axis))
+          lcd_put_u8str_P(axis == Z_AXIS ? PSTR("       ") : PSTR("    "));
+        else
+      #endif
+          lcd_put_u8str(value);
+    }
+  }
+}
+
+FORCE_INLINE void _draw_heater_status(const heater_id_t heater_id, const char *prefix, const bool blink) {
+  uint8_t pic_hot_bits;
+  #if HAS_HEATED_BED
+    const bool isBed = heater_id < 0;
+    const float t1 = (isBed ? thermalManager.degBed() : thermalManager.degHotend(heater_id));
+    const float t2 = (isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater_id));
+  #else
+    const float t1 = thermalManager.degHotend(heater_id);
+    const float t2 = thermalManager.degTargetHotend(heater_id);
+  #endif
+
+  #if HOTENDS < 2
+    if (heater_id == H_E0) {
+      lcd.setCursor(2, 5);  lcd.print(prefix); //HE
+      lcd.setCursor(1, 6);  lcd.print(i16tostr3rj(t1 + 0.5));
+      lcd.setCursor(1, 7);
+    }
+    else {
+      lcd.setCursor(6, 5);  lcd.print(prefix); //BED
+      lcd.setCursor(6, 6);  lcd.print(i16tostr3rj(t1 + 0.5));
+      lcd.setCursor(6, 7);
+    }
+  #else
+    if (heater_id > H_BED) {
+      lcd.setCursor(heater_id * 4, 5);  lcd.print(prefix); //HE1 or HE2 or HE3
+      lcd.setCursor(heater_id * 4, 6);  lcd.print(i16tostr3rj(t1 + 0.5));
+      lcd.setCursor(heater_id * 4, 7);
+    }
+    else {
+      lcd.setCursor(13, 5);  lcd.print(prefix); //BED
+      lcd.setCursor(13, 6);  lcd.print(i16tostr3rj(t1 + 0.5));
+      lcd.setCursor(13, 7);
+    }
+  #endif // HOTENDS <= 1
+
+  #if !HEATER_IDLE_HANDLER
+    UNUSED(blink);
+  #else
+    if (!blink && thermalManager.heater_idle[thermalManager.idle_index_for_id(heater_id)].timed_out) {
+      lcd.write(' ');
+      if (t2 >= 10) lcd.write(' ');
+      if (t2 >= 100) lcd.write(' ');
+    }
+    else
+  #endif // !HEATER_IDLE_HANDLER
+      lcd.print(i16tostr3rj(t2 + 0.5));
+
+  switch (heater_id) {
+    case H_BED: pic_hot_bits = ICON_BED;   break;
+    case H_E0:  pic_hot_bits = ICON_TEMP1; break;
+    case H_E1:  pic_hot_bits = ICON_TEMP2; break;
+    case H_E2:  pic_hot_bits = ICON_TEMP3;
+    default:    break;
+  }
+
+  if (t2) picBits |= pic_hot_bits;
+  else    picBits &= ~pic_hot_bits;
+
+  if (t1 > 50)  hotBits |= pic_hot_bits;
+  else          hotBits &= ~pic_hot_bits;
+
+  if (hotBits)  picBits |= ICON_HOT;
+  else          picBits &= ~ICON_HOT;
+}
+
+#if HAS_PRINT_PROGRESS
+
+  FORCE_INLINE void _draw_print_progress() {
+    if (!PanelDetected) return;
+    const uint8_t progress = ui._get_progress();
+    #if ENABLED(SDSUPPORT)
+      lcd_put_u8str_P(PSTR("SD"));
+    #elif ENABLED(LCD_SET_PROGRESS_MANUALLY)
+      lcd_put_u8str_P(PSTR("P:"));
+    #endif
+    if (progress)
+      lcd.print(ui8tostr3rj(progress));
+    else
+      lcd_put_u8str_P(PSTR("---"));
+    lcd.write('%');
+  }
+
+#endif // HAS_PRINT_PROGRESS
+
+#if ENABLED(LCD_PROGRESS_BAR)
+
+  void MarlinUI::draw_progress_bar(const uint8_t percent) {
+    if (!PanelDetected) return;
+    if (fb == &framebuffer[0] + LCD_WIDTH * 2) {  // For status screen
+      lcd.write('%'); lcd.write(percent);
+    }
+    else { // For progress bar test
+      lcd.setCursor(LCD_WIDTH / 2 - 2, LCD_HEIGHT / 2 - 2);
+      lcd.print(i16tostr3rj(percent));  lcd.write('%');
+      lcd.print_line();
+      lcd.setCursor(0, LCD_HEIGHT / 2 - 1);
+      lcd.write('%'); lcd.write(percent);
+      lcd.print_line();
+    }
+  }
+
+#endif
+
+void MarlinUI::draw_status_message(const bool blink) {
+  if (!PanelDetected) return;
+  lcd.setCursor(0, 3);
+  #if BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
+
+    // Alternate Status message and Filament display
+    if (ELAPSED(millis(), next_filament_display)) {
+      lcd_put_u8str_P(PSTR("Dia "));
+      lcd.print(ftostr12ns(filament_width_meas));
+      lcd_put_u8str_P(PSTR(" V"));
+      lcd.print(i16tostr3rj(100.0 * (
+          parser.volumetric_enabled
+            ? planner.volumetric_area_nominal / planner.volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
+            : planner.volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
+        )
+      ));
+      lcd.write('%');
+      return;
+    }
+
+  #endif // FILAMENT_LCD_DISPLAY && SDSUPPORT
+
+  // Get the UTF8 character count of the string
+  uint8_t slen = utf8_strlen(status_message);
+
+  #if ENABLED(STATUS_MESSAGE_SCROLLING)
+
+    static bool last_blink = false;
+
+    // If the string fits into the LCD, just print it and do not scroll it
+    if (slen <= LCD_WIDTH) {
+
+      // The string isn't scrolling and may not fill the screen
+      lcd_put_u8str(status_message);
+
+      // Fill the rest with spaces
+      while (slen < LCD_WIDTH) { lcd.write(' '); ++slen; }
+    }
+    else {
+      // String is larger than the available space in screen.
+
+      // Get a pointer to the next valid UTF8 character
+      // and the string remaining length
+      uint8_t rlen;
+      const char *stat = status_and_len(rlen);
+      lcd_put_u8str_max(stat, LCD_WIDTH);     // The string leaves space
+
+      // If the remaining string doesn't completely fill the screen
+      if (rlen < LCD_WIDTH) {
+        lcd.write('.');                       // Always at 1+ spaces left, draw a dot
+        uint8_t chars = LCD_WIDTH - rlen;     // Amount of space left in characters
+        if (--chars) {                        // Draw a second dot if there's space
+          lcd.write('.');
+          if (--chars)
+            lcd_put_u8str_max(status_message, chars); // Print a second copy of the message
+        }
+      }
+      if (last_blink != blink) {
+        last_blink = blink;
+        advance_status_scroll();
+      }
+    }
+
+  #else
+
+    UNUSED(blink);
+
+    // Just print the string to the LCD
+    lcd_put_u8str_max(status_message, LCD_WIDTH);
+
+    // Fill the rest with spaces if there are missing spaces
+    while (slen < LCD_WIDTH) {
+      lcd.write(' ');
+      ++slen;
+    }
+
+  #endif
+}
+
+/**
+Possible status screens:
+
+Equal to 20x10 text LCD
+
+|X 000 Y 000 Z 000.00|
+|FR100% SD100% C--:--|
+| Progress bar line  |
+|Status message      |
+|                    |
+|  HE  BED  FAN      |
+| ttc  ttc   %       | ttc - current temperature
+| tts  tts  %%%      | tts - setted temperature, %%% - percent for FAN
+| ICO  ICO  ICO  ICO | ICO - icon 48x48, placed in 2 text lines
+| ICO  ICO  ICO  ICO | ICO /
+
+or
+
+|X 000 Y 000 Z 000.00|
+|FR100% SD100% C--:--|
+| Progress bar line  |
+|Status message      |
+|                    |
+|HE1 HE2 HE3  BED ICO|
+|ttc ttc ttc  ttc ICO|
+|tts tts tts  tts %%%|
+|ICO ICO ICO  ICO ICO|
+|ICO ICO ICO  ICO ICO|
+
+or
+
+Equal to 24x10 text LCD
+
+|X 000 Y 000 Z 000.00    |
+|FR100%   SD100%   C--:--|
+|   Progress bar line    |
+|Status message          |
+|                        |
+|HE1 HE2 HE3  BED FAN    |
+|ttc ttc ttc  ttc  %     |
+|tts tts tts  tts %%%    |
+|ICO ICO ICO  ICO ICO ICO|
+|ICO ICO ICO  ICO ICO ICO|
+*/
+
+void MarlinUI::draw_status_screen() {
+  if (!PanelDetected) return;
+
+  const bool blink = get_blink();
+
+  lcd.clear_buffer();
+
+  //
+  // Line 1 - XYZ coordinates
+  //
+
+  lcd.setCursor(0, 0);
+  _draw_axis_value(X_AXIS, ftostr4sign(LOGICAL_X_POSITION(current_position[X_AXIS])), blink);  lcd.write(' ');
+  _draw_axis_value(Y_AXIS, ftostr4sign(LOGICAL_Y_POSITION(current_position[Y_AXIS])), blink);  lcd.write(' ');
+  _draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position[Z_AXIS])), blink);
+
+  #if HAS_LEVELING && !HAS_HEATED_BED
+    lcd.write(planner.leveling_active || blink ? '_' : ' ');
+  #endif
+
+  //
+  // Line 2 - feedrate, , time
+  //
+
+  lcd.setCursor(0, 1);
+  lcd_put_u8str_P(PSTR("FR")); lcd.print(i16tostr3rj(feedrate_percentage)); lcd.write('%');
+
+  #if BOTH(SDSUPPORT, HAS_PRINT_PROGRESS)
+    lcd.setCursor(LCD_WIDTH / 2 - 3, 1);
+    _draw_print_progress();
+  #endif
+
+  char buffer[10];
+  duration_t elapsed = print_job_timer.duration();
+  uint8_t len = elapsed.toDigital(buffer);
+
+  lcd.setCursor((LCD_WIDTH - 1) - len, 1);
+  lcd.write(0x07); lcd.print(buffer); // LCD_CLOCK_CHAR
+
+  //
+  // Line 3 - progressbar
+  //
+
+  lcd.setCursor(0, 2);
+  #if ENABLED(LCD_PROGRESS_BAR)
+    draw_progress_bar(_get_progress());
+  #else
+    lcd.write('%'); lcd.write(0);
+  #endif
+
+  //
+  // Line 4 - Status Message (which may be a Filament display)
+  //
+
+  draw_status_message(blink);
+
+  //
+  // Line 5
+  //
+
+  #if HOTENDS <= 1 || (HOTENDS <= 2 && !HAS_HEATED_BED)
+    #if DUAL_MIXING_EXTRUDER
+      lcd.setCursor(0, 4);
+      // Two-component mix / gradient instead of XY
+      char mixer_messages[12];
+      const char *mix_label;
+      #if ENABLED(GRADIENT_MIX)
+        if (mixer.gradient.enabled) {
+          mixer.update_mix_from_gradient();
+          mix_label = "Gr";
+        }
+        else
+      #endif
+        {
+          mixer.update_mix_from_vtool();
+          mix_label = "Mx";
+        }
+      sprintf_P(mixer_messages, PSTR("%s %d;%d%% "), mix_label, int(mixer.mix[0]), int(mixer.mix[1]));
+      lcd_put_u8str(mixer_messages);
+    #endif
+  #endif
+
+  //
+  // Line 6..8 Temperatures, FAN
+  //
+
+  #if HOTENDS < 2
+    _draw_heater_status(H_E0, "HE", blink);    // Hotend Temperature
+  #else
+    _draw_heater_status(H_E0, "HE1", blink);   // Hotend 1 Temperature
+    _draw_heater_status(H_E1, "HE2", blink);   // Hotend 2 Temperature
+    #if HOTENDS > 2
+      _draw_heater_status(H_E2, "HE3", blink); // Hotend 3 Temperature
+    #endif
+  #endif // HOTENDS <= 1
+
+  #if HAS_HEATED_BED
+    #if HAS_LEVELING
+      _draw_heater_status(H_BED, (planner.leveling_active && blink ? "___" : "BED"), blink);
+    #else
+      _draw_heater_status(H_BED, "BED", blink);
+    #endif
+  #endif // HAS_HEATED_BED
+
+  #if FAN_COUNT > 0
+    uint16_t spd = thermalManager.fan_speed[0];
+
+    #if ENABLED(ADAPTIVE_FAN_SLOWING)
+      if (!blink) spd = thermalManager.scaledFanSpeed(0, spd);
+    #endif
+
+    uint16_t per = thermalManager.fanPercent(spd);
+    #if HOTENDS < 2
+      #define FANX 11
+    #else
+      #define FANX 17
+    #endif
+    lcd.setCursor(FANX, 5); lcd_put_u8str_P(PSTR("FAN"));
+    lcd.setCursor(FANX + 1, 6); lcd.write('%');
+    lcd.setCursor(FANX, 7);
+    lcd.print(i16tostr3rj(per));
+
+    if (TERN0(HAS_FAN0, thermalManager.fan_speed[0]) || TERN0(HAS_FAN1, thermalManager.fan_speed[1]) || TERN0(HAS_FAN2, thermalManager.fan_speed[2]))
+      picBits |= ICON_FAN;
+    else
+      picBits &= ~ICON_FAN;
+
+  #endif // FAN_COUNT > 0
+
+  //
+  // Line 9, 10 - icons
+  //
+  lcd.print_screen();
+}
+
+#if HAS_LCD_MENU
+
+  #include "../menu/menu.h"
+
+  #if ENABLED(ADVANCED_PAUSE_FEATURE)
+
+    void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
+      if (!PanelDetected) return;
+      lcd.setCursor((LCD_WIDTH - 14) / 2, row + 1);
+      lcd.write(0x02);  lcd_put_u8str_P(" E"); lcd.write('1' + extruder); lcd.write(' ');
+      lcd.print(i16tostr3rj(thermalManager.degHotend(extruder))); lcd.write(0x01);  lcd.write('/');
+      lcd.print(i16tostr3rj(thermalManager.degTargetHotend(extruder)));  lcd.write(0x01);
+      lcd.print_line();
+    }
+
+  #endif // ADVANCED_PAUSE_FEATURE
+
+  // Draw a static item with no left-right margin required. Centered by default.
+  void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const valstr/*=nullptr*/) {
+    if (!PanelDetected) return;
+    uint8_t n = LCD_WIDTH;
+    lcd.setCursor(0, row);
+    if ((style & SS_CENTER) && !valstr) {
+      int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2;
+      while (--pad >= 0) { lcd.write(' '); n--; }
+    }
+    n = lcd_put_u8str_ind_P(pstr, itemIndex, itemString, n);
+    if (valstr) n -= lcd_put_u8str_max(valstr, n);
+    for (; n; --n) lcd.write(' ');
+    lcd.print_line();
+  }
+
+  // Draw a generic menu item with pre_char (if selected) and post_char
+  void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
+    if (!PanelDetected) return;
+    lcd.setCursor(0, row);
+    lcd.write(sel ? pre_char : ' ');
+    uint8_t n = lcd_put_u8str_ind_P(pstr, itemIndex, itemString, LCD_WIDTH - 2);
+    for (; n; --n) lcd.write(' ');
+    lcd.write(post_char);
+    lcd.print_line();
+  }
+
+  // Draw a menu item with a (potentially) editable value
+  void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
+    if (!PanelDetected) return;
+    const uint8_t vlen = data ? (pgm ? utf8_strlen_P(data) : utf8_strlen(data)) : 0;
+    lcd.setCursor(0, row);
+    lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
+    uint8_t n = lcd_put_u8str_ind_P(pstr, itemIndex, itemString, LCD_WIDTH - 2 - vlen);
+    if (vlen) {
+      lcd.write(':');
+      for (; n; --n) lcd.write(' ');
+      if (pgm) lcd_put_u8str_P(data); else lcd_put_u8str(data);
+    }
+    lcd.print_line();
+  }
+
+  // Low-level draw_edit_screen can be used to draw an edit screen from anyplace
+  void MenuEditItemBase::draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
+    if (!PanelDetected) return;
+    ui.encoder_direction_normal();
+    lcd.setCursor(0, LCD_HEIGHT - 1);  //last line is free most time
+    lcd.write(COLOR_EDIT);
+    lcd_put_u8str_P(pstr);
+    if (value != nullptr) {
+      lcd.write(':');
+      lcd.setCursor((LCD_WIDTH - 1) - (utf8_strlen(value) + 1), LCD_HEIGHT - 1);  // Right-justified, padded by spaces
+      lcd.write(' ');                                                // Overwrite char if value gets shorter
+      lcd.print(value);
+      lcd.write(' ');
+      lcd.print_line();
+    }
+  }
+
+  // The Select Screen presents a prompt and two "buttons"
+  void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string, PGM_P const suff) {
+    if (!PanelDetected) return;
+    ui.draw_select_screen_prompt(pref, string, suff);
+    lcd.setCursor(0, LCD_HEIGHT - 1);
+    lcd.write(COLOR_EDIT);
+    lcd.write(yesno ? ' ' : '['); lcd_put_u8str_P(no); lcd.write(yesno ? ' ' : ']');
+    lcd.setCursor(LCD_WIDTH - utf8_strlen_P(yes) - 3, LCD_HEIGHT - 1);
+    lcd.write(yesno ? '[' : ' '); lcd_put_u8str_P(yes); lcd.write(yesno ? ']' : ' ');
+    lcd.print_line();
+  }
+
+  #if ENABLED(SDSUPPORT)
+
+    void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
+      if (!PanelDetected) return;
+      lcd.setCursor(0, row);
+      lcd.write(sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
+      constexpr uint8_t maxlen = LCD_WIDTH - 2;
+      uint8_t n = maxlen - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
+      for (; n; --n) lcd.write(' ');
+      lcd.write(isDir ? LCD_STR_FOLDER[0] : ' ');
+      lcd.print_line();
+    }
+
+  #endif // SDSUPPORT
+
+  #if ENABLED(LCD_HAS_STATUS_INDICATORS)
+
+    void MarlinUI::update_indicators() {}
+
+  #endif  // LCD_HAS_STATUS_INDICATORS
+
+  #if ENABLED(AUTO_BED_LEVELING_UBL)
+    /**
+     * Map screen:
+     * |/---------\ (00,00) |
+     * || . . . . | X:000.00|
+     * || . . . . | Y:000.00|
+     * || . . . . | Z:00.000|
+     * || . . . . |         |
+     * || . . . . |         |
+     * || . . . . |         |
+     * |+---------/         |
+     * |                    |
+     * |____________________|
+     */
+    void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
+      if (!PanelDetected) return;
+
+      #define _LCD_W_POS 12
+
+      lcd.clear_buffer();
+
+      //print only top left corner. All frame with grid points will be printed by panel
+      lcd.setCursor(0, 0);
+      *fb++ = TLC;   //top left corner - marker for plot parameters
+      *fb = (GRID_MAX_POINTS_X << 4) + GRID_MAX_POINTS_Y; //set mesh size
+
+      // Print plot position
+      lcd.setCursor(_LCD_W_POS, 0);
+      *fb++ = '(';  lcd.print(i16tostr3left(x_plot));
+      *fb++ = ',';  lcd.print(i16tostr3left(y_plot)); *fb = ')';
+
+      // Show all values
+      lcd.setCursor(_LCD_W_POS, 1); lcd_put_u8str_P(PSTR("X:"));
+      lcd.print(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
+      lcd.setCursor(_LCD_W_POS, 2); lcd_put_u8str_P(PSTR("Y:"));
+      lcd.print(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
+
+      // Show the location value
+      lcd.setCursor(_LCD_W_POS, 3); lcd_put_u8str_P(PSTR("Z:"));
+
+      if (!isnan(ubl.z_values[x_plot][y_plot]))
+        lcd.print(ftostr43sign(ubl.z_values[x_plot][y_plot]));
+      else
+        lcd_put_u8str_P(PSTR(" -----"));
+
+      center_text_P(GET_TEXT(MSG_UBL_FINE_TUNE_MESH), 8);
+
+      lcd.print_screen();
+    }
+
+  #endif // AUTO_BED_LEVELING_UBL
+
+#endif // HAS_LCD_MENU
+
+#endif // IS_TFTGLCD_PANEL
diff --git a/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.h b/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.h
new file mode 100644
index 00000000000..9f54730c3c8
--- /dev/null
+++ b/Marlin/src/lcd/TFTGLCD/ultralcd_TFTGLCD.h
@@ -0,0 +1,74 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * Implementation of the LCD display routines for a TFT GLCD displays with external controller.
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if IS_TFTGLCD_PANEL
+
+#include "../../libs/duration_t.h"
+
+////////////////////////////////////
+// Set up button and encode mappings for each panel (into 'buttons' variable)
+//
+// This is just to map common functions (across different panels) onto the same
+// macro name. The mapping is independent of whether the button is directly connected or
+// via a shift/i2c register.
+
+////////////////////////////////////
+// Create LCD class instance and chipset-specific information
+class TFTGLCD {
+  private:
+  public:
+    TFTGLCD();
+    void clear_buffer();
+    void setCursor(uint8_t col, uint8_t row);
+    void write(char c);
+    void print(const char *line);
+    void print_line();
+    void print_screen();
+    void redraw_screen();
+    void setContrast(uint16_t contrast);
+};
+
+extern TFTGLCD lcd;
+
+#include "../fontutils.h"
+#include "../lcdprint.h"
+
+// Use panel encoder - free old encoder pins
+#undef  BTN_EN1
+#undef  BTN_EN2
+#undef  BTN_ENC
+#define BTN_EN1     -1
+#define BTN_EN2     -1
+#define BTN_ENC     -1
+
+#ifndef EN_C
+  #define EN_C       4 //for click
+#endif
+
+#endif // IS_TFTGLCD_PANEL
diff --git a/Marlin/src/lcd/menu/menu_ubl.cpp b/Marlin/src/lcd/menu/menu_ubl.cpp
index d034de09521..2cd300958f8 100644
--- a/Marlin/src/lcd/menu/menu_ubl.cpp
+++ b/Marlin/src/lcd/menu/menu_ubl.cpp
@@ -59,10 +59,14 @@ inline float rounded_mesh_value() {
 static void _lcd_mesh_fine_tune(PGM_P const msg) {
   ui.defer_status_screen();
   if (ubl.encoder_diff) {
-    mesh_edit_accumulator += ubl.encoder_diff > 0 ? 0.005f : -0.005f;
+    mesh_edit_accumulator += TERN(IS_TFTGLCD_PANEL,
+      ubl.encoder_diff * 0.005f / ENCODER_PULSES_PER_STEP,
+      ubl.encoder_diff > 0 ? 0.005f : -0.005f
+    );
     ubl.encoder_diff = 0;
-    ui.refresh(LCDVIEW_CALL_REDRAW_NEXT);
+    TERN(IS_TFTGLCD_PANEL,,ui.refresh(LCDVIEW_CALL_REDRAW_NEXT));
   }
+  TERN_(IS_TFTGLCD_PANEL, ui.refresh(LCDVIEW_CALL_REDRAW_NEXT));
 
   if (ui.should_draw()) {
     const float rounded_f = rounded_mesh_value();
diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp
index 89dc0adaf32..de534e40236 100644
--- a/Marlin/src/lcd/ultralcd.cpp
+++ b/Marlin/src/lcd/ultralcd.cpp
@@ -506,7 +506,7 @@ bool MarlinUI::get_blink() {
  * This is very display-dependent, so the lcd implementation draws this.
  */
 
-#if ENABLED(LCD_PROGRESS_BAR)
+#if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL
   millis_t MarlinUI::progress_bar_ms; // = 0
   #if PROGRESS_MSG_EXPIRE > 0
     millis_t MarlinUI::expire_status_ms; // = 0
@@ -517,7 +517,7 @@ void MarlinUI::status_screen() {
 
   TERN_(HAS_LCD_MENU, ENCODER_RATE_MULTIPLY(false));
 
-  #if ENABLED(LCD_PROGRESS_BAR)
+  #if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL
 
     //
     // HD44780 implements the following message blinking and
@@ -915,7 +915,7 @@ void MarlinUI::update() {
 
       const bool encoderPastThreshold = (abs_diff >= epps);
       if (encoderPastThreshold || lcd_clicked) {
-        if (encoderPastThreshold) {
+        if (encoderPastThreshold && TERN1(IS_TFTGLCD_PANEL, !external_control)) {
 
           #if BOTH(HAS_LCD_MENU, ENCODER_RATE_MULTIPLIER)
 
@@ -1260,6 +1260,12 @@ void MarlinUI::update() {
         TERN(REPRAPWORLD_KEYPAD, keypad_buttons, buttons) = ~val;
       #endif
 
+      #if IS_TFTGLCD_PANEL
+        next_button_update_ms = now + (LCD_UPDATE_INTERVAL / 2);
+        buttons = slow_buttons;
+        TERN_(AUTO_BED_LEVELING_UBL, external_encoder());
+      #endif
+
     } // next_button_update_ms
 
     #if HAS_ENCODER_WHEEL
@@ -1331,7 +1337,7 @@ void MarlinUI::update() {
       const millis_t ms = millis();
     #endif
 
-    #if ENABLED(LCD_PROGRESS_BAR)
+    #if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL
       progress_bar_ms = ms;
       #if PROGRESS_MSG_EXPIRE > 0
         expire_status_ms = persist ? 0 : ms + PROGRESS_MSG_EXPIRE;
diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h
index c23dc5d84e4..c7ef41596df 100644
--- a/Marlin/src/lcd/ultralcd.h
+++ b/Marlin/src/lcd/ultralcd.h
@@ -34,7 +34,7 @@
 #if EITHER(HAS_LCD_MENU, ULTIPANEL_FEEDMULTIPLY)
   #define HAS_ENCODER_ACTION 1
 #endif
-#if (!HAS_ADC_BUTTONS && ENABLED(NEWPANEL)) || BUTTONS_EXIST(EN1, EN2)
+#if ((!HAS_ADC_BUTTONS && ENABLED(NEWPANEL)) || BUTTONS_EXIST(EN1, EN2)) && !IS_TFTGLCD_PANEL
   #define HAS_ENCODER_WHEEL 1
 #endif
 #if HAS_ENCODER_WHEEL || ANY_BUTTON(ENC, BACK, UP, DWN, LFT, RT)
@@ -45,7 +45,7 @@
 #endif
 
 // I2C buttons must be read in the main thread
-#if EITHER(LCD_I2C_VIKI, LCD_I2C_PANELOLU2)
+#if ANY(LCD_I2C_VIKI, LCD_I2C_PANELOLU2, IS_TFTGLCD_PANEL)
   #define HAS_SLOW_BUTTONS 1
 #endif
 
@@ -215,7 +215,7 @@
 
 #endif
 
-#if BUTTON_EXISTS(BACK) || HAS_TOUCH_XPT2046
+#if BUTTON_EXISTS(BACK) || EITHER(HAS_TOUCH_XPT2046, IS_TFTGLCD_PANEL)
   #define BLEN_D 3
   #define EN_D _BV(BLEN_D)
   #define LCD_BACK_CLICKED() (buttons & EN_D)
diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h
index 4165bb35038..0701e45992e 100644
--- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h
+++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_1.h
@@ -65,7 +65,16 @@
  * by redrawing the screen after SD card accesses.
  */
 
-#if HAS_WIRED_LCD
+#if IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define TFTGLCD_CS                     P3_26
+  #endif
+
+  #define SD_DETECT_PIN                    P1_31
+
+#elif HAS_WIRED_LCD
+
   #define BTN_EN1                          P3_26
   #define BTN_EN2                          P3_25
   #define BTN_ENC                          P2_11
@@ -80,7 +89,8 @@
     #define DOGLCD_CS                      P2_06
     #define DOGLCD_A0                      P0_16
   #endif
-#endif
+
+#endif // HAS_WIRED_LCD
 
 //
 // SD Support
@@ -89,7 +99,7 @@
 // requires jumpers on the SKR V1.1 board as documented here:
 // https://www.facebook.com/groups/505736576548648/permalink/630639874058317/
 #ifndef SDCARD_CONNECTION
-  #if EITHER(MKS_MINI_12864, ENDER2_STOCKDISPLAY)
+  #if ANY(MKS_MINI_12864, ENDER2_STOCKDISPLAY, IS_TFTGLCD_PANEL)
     #define SDCARD_CONNECTION                LCD
   #else
     #define SDCARD_CONNECTION            ONBOARD
diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h
index e8983c7f542..31373fedff6 100644
--- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h
+++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_3.h
@@ -265,6 +265,14 @@
 
     #error "ADC BUTTONS do not work unmodifed on SKR 1.3, The ADC ports cannot take more than 3.3v."
 
+  #elif IS_TFTGLCD_PANEL
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS            EXPA2_08_PIN
+    #endif
+
+    #define SD_DETECT_PIN           EXPA2_04_PIN
+
   #else                                           // !CR10_STOCKDISPLAY
 
     #define LCD_PINS_RS             EXPA1_07_PIN
diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
index 3bdd3061b75..6f9f4bcf636 100644
--- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
+++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
@@ -309,6 +309,14 @@
       #define XPT2046_Y_OFFSET             -285
     #endif
 
+  #elif IS_TFTGLCD_PANEL
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS                   P3_26
+    #endif
+
+    #define SD_DETECT_PIN                  P1_31
+
   #else
 
     #define BTN_ENC                        P0_28  // (58) open-drain
diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
index 1cb6774a41f..1290200e55c 100644
--- a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
+++ b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
@@ -217,7 +217,18 @@
  * that the garbage/lines are erased immediately after the SD card accesses are completed.
  */
 
-#if HAS_WIRED_LCD
+#if IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define   TFTGLCD_CS                   P3_25  // EXP2.3
+  #endif
+
+  #if SD_CONNECTION_IS(LCD)
+    #define SD_DETECT_PIN                  P0_28  // EXP2.4
+  #endif
+
+#elif HAS_WIRED_LCD
+
   #define BEEPER_PIN                       P1_31  // EXP1.1
   #define BTN_ENC                          P1_30  // EXP1.2
   #define BTN_EN1                          P3_26  // EXP2.5
@@ -273,7 +284,7 @@
     //#define LCD_SCREEN_ROT_270
   #endif
 
-#endif
+#endif // HAS_WIRED_LCD
 
 /**
  * Example for trinamic drivers using the J8 connector on MKs Sbase.
diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h
index 02fdaafd306..d269ecbdc90 100644
--- a/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h
+++ b/Marlin/src/pins/lpc1768/pins_MKS_SGEN_L.h
@@ -249,6 +249,15 @@
     #define LCD_PINS_ENABLE                P1_22
     #define LCD_PINS_D4                    P0_17
 
+  #elif IS_TFTGLCD_PANEL
+
+    #undef BEEPER_PIN
+    #undef BTN_ENC
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS                   P3_25
+    #endif
+
   #else
 
     #define BTN_EN1                        P3_25
diff --git a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
index 097f8be22ac..41763fb33c3 100644
--- a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
+++ b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
@@ -326,6 +326,15 @@
   #define LCD_PINS_ENABLE                  P0_18  // J3-10 & AUX-3 (SID, MOSI)
   #define LCD_PINS_D4                      P2_06  // J3-8 & AUX-3 (SCK, CLK)
 
+#elif IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define TFTGLCD_CS                     P3_26  // (31) J3-2 & AUX-4
+  #endif
+
+  #define SD_DETECT_PIN                    P1_31  // (49) J3-1 & AUX-3 (NOT 5V tolerant)
+  #define KILL_PIN                         P1_22  // (41) J5-4 & AUX-4
+
 #elif HAS_WIRED_LCD
 
   //#define SCK_PIN                        P0_15  // (52)  system defined J3-9 & AUX-3
diff --git a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h
index a073a6fe302..cbbe8a9416d 100644
--- a/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h
+++ b/Marlin/src/pins/lpc1769/pins_MKS_SGEN_L_V2.h
@@ -241,7 +241,16 @@
  *                -----                                            -----
  *                EXP1                                             EXP2
  */
-#if HAS_WIRED_LCD
+#if IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define TFTGLCD_CS                     P3_25
+  #endif
+
+  #define SD_DETECT_PIN                    P0_27
+
+#elif HAS_WIRED_LCD
+
   #define BEEPER_PIN                       P1_31
   #define BTN_ENC                          P1_30
 
diff --git a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h
index 33975df8ee1..f2811b14abd 100644
--- a/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h
+++ b/Marlin/src/pins/lpc1769/pins_SMOOTHIEBOARD.h
@@ -111,16 +111,33 @@
 
 #elif HAS_WIRED_LCD
 
-  /*
-    The Smoothieboard supports the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER with either
-    a custom cable with breakouts to the pins indicated below or the RRD GLCD Adapter board
-    found at http://smoothieware.org/rrdglcdadapter
+  /**
+   * SD Support
+   *
+   * For the RRD GLCD it CANNOT share the same SPI as the LCD so it must be
+   * hooked up to the onboard SDCard SPI and use a spare pin for the SDCS.
+   * Also note that an external SDCard sharing the SPI port with the
+   * onboard/internal SDCard must be ejected before rebooting as the bootloader
+   * does not like the external card. NOTE Smoothie will not boot if the external
+   * sdcard is inserted in the RRD LCD sdcard slot at boot time, it must be
+   * inserted after it has booted.
+   */
+  #define SD_DETECT_PIN                    P0_27  // EXP2 Pin 7 (SD_CD, SD_DET)
 
-    Other links to information about setting up a display panel with Smoothieboard
-    http://chibidibidiwah.wdfiles.com/local--files/panel/smoothieboard2sd.jpg
-    http://smoothieware.org/panel
-  */
+  #define MISO_PIN                         P0_08  // EXP2 Pin 1 (PB3, SD_MISO)
+  #define SCK_PIN                          P0_07  // EXP2 Pin 2 (SD_SCK)
+  #define SS_PIN                           P0_28  // EXP2 Pin 4 (SD_CSEL, SD_CS)
+  #define MOSI_PIN                         P0_09  // EXP2 Pin 6 (PB2, SD_MOSI)
 
+  /**
+   * The Smoothieboard supports the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER with either
+   * a custom cable with breakouts to the pins indicated below or the RRD GLCD Adapter board
+   * found at http://smoothieware.org/rrdglcdadapter
+   *
+   * Other links to information about setting up a display panel with Smoothieboard
+   * http://chibidibidiwah.wdfiles.com/local--files/panel/smoothieboard2sd.jpg
+   * http://smoothieware.org/panel
+   */
   #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER)
     //  EXP1 Pins
     #define BEEPER_PIN                     P1_31  // EXP1 Pin 1
@@ -132,24 +149,14 @@
     #define BTN_EN2                        P3_26  // EXP2 Pin 3
     #define BTN_EN1                        P3_25  // EXP2 Pin 5
 
-    /*
-      SD Support
+  #elif IS_TFTGLCD_PANEL
 
-      For the RRD GLCD it CANNOT share the same SPI as the LCD so it must be
-      hooked up to the onboard SDCard SPI and use a spare pin for the SDCS.
-      Also note that an external SDCard sharing the SPI port with the
-      onboard/internal SDCard must be ejected before rebooting as the bootloader
-      does not like the external card. NOTE Smoothie will not boot if the external
-      sdcard is inserted in the RRD LCD sdcard slot at boot time, it must be
-      inserted after it has booted.
-    */
-
-    #define MISO_PIN                       P0_08  // EXP2 Pin 1 (PB3, SD_MISO)
-    #define SCK_PIN                        P0_07  // EXP2 Pin 2 (SD_SCK)
-    #define SS_PIN                         P0_28  // EXP2 Pin 4 (SD_CSEL, SD_CS)
-    #define MOSI_PIN                       P0_09  // EXP2 Pin 6 (PB2, SD_MOSI)
     #define SD_DETECT_PIN                  P0_27  // EXP2 Pin 7 (SD_CD, SD_DET)
 
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS                   P3_26  // EXP2 Pin 3
+    #endif
+
   #else
     #error "Marlin's Smoothieboard support cannot drive your LCD."
   #endif
diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h
index ac15a3c9bae..704f2a487fb 100644
--- a/Marlin/src/pins/pinsDebug_list.h
+++ b/Marlin/src/pins/pinsDebug_list.h
@@ -261,6 +261,9 @@
 #if defined(TMC_SW_SCK) && TMC_SW_SCK >= 0
   REPORT_NAME_DIGITAL(__LINE__, TMC_SW_SCK)
 #endif
+#if defined(TFTGLCD_CS) && TFTGLCD_CS >= 0
+  REPORT_NAME_DIGITAL(__LINE__, TFTGLCD_CS)
+#endif
 #if PIN_EXISTS(E_MUX0)
   REPORT_NAME_DIGITAL(__LINE__, E_MUX0_PIN)
 #endif
diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h
index aa73aabbc1d..de56d2b59d9 100644
--- a/Marlin/src/pins/ramps/pins_RAMPS.h
+++ b/Marlin/src/pins/ramps/pins_RAMPS.h
@@ -450,6 +450,10 @@
     #define LCD_PINS_D6                       44
     #define LCD_PINS_D7                       64
 
+  #elif ENABLED(TFTGLCD_PANEL_SPI)
+
+    #define TFTGLCD_CS                        33
+
   #else
 
     #if ENABLED(CR10_STOCKDISPLAY)
@@ -682,6 +686,10 @@
 
       // Pins only defined for RAMPS_SMART currently
 
+    #elif IS_TFTGLCD_PANEL
+
+      #define SD_DETECT_PIN                   49
+
     #else
 
       // Beeper on AUX-4
diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h
index fd741d296d3..2bc94c45c5e 100644
--- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h
+++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_E3_DIP.h
@@ -279,9 +279,7 @@
 
 #if SD_CONNECTION_IS(ONBOARD)
   #define SD_DETECT_PIN                     PC4
-#endif
-
-#if BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050) && SD_CONNECTION_IS(LCD)
+#elif SD_CONNECTION_IS(LCD) && BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050)
   #define SD_DETECT_PIN                     PA15
   #define SS_PIN                            PA10
 #elif SD_CONNECTION_IS(CUSTOM_CABLE)
diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
index 30d057d9007..09e47875ed6 100644
--- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
+++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_E3_common.h
@@ -169,8 +169,48 @@
     #define FORCE_SOFT_SPI
     #define LCD_BACKLIGHT_PIN               -1
 
+  #elif IS_TFTGLCD_PANEL
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+
+      #error "CAUTION! TFTGLCD_PANEL_SPI requires wiring modifications. See 'pins_BTT_SKR_MINI_E3_common.h' for details. Comment out this line to continue."
+
+      /**
+       * TFTGLCD_PANEL_SPI display pinout
+       *
+       *               Board                                      Display
+       *               _____                                       _____
+       *           5V | 1 2 | GND                (SPI1-MISO) MISO | 1 2 | SCK   (SPI1-SCK)
+       * (FREE)   PB7 | 3 4 | PB8  (LCD_CS)      (PA9)    GLCD_CS | 3 4 | SD_CS (PA10)
+       * (FREE)   PB9 | 5 6 | PA10 (SD_CS)                 (FREE) | 5 6 | MOSI  (SPI1-MOSI)
+       *        RESET | 7 8 | PA9  (MOD_RESET)   (PB5)     SD_DET | 7 8 | (FREE)
+       * (BEEPER) PB6 | 9 10| PB5  (SD_DET)                   GND | 9 10| 5V
+       *               -----                                       -----
+       *                EXP1                                        EXP1
+       *
+       * Needs custom cable:
+       *
+       *    Board   Adapter   Display
+       *           _________
+       *   EXP1-1 ----------- EXP1-10
+       *   EXP1-2 ----------- EXP1-9
+       *   SPI1-4 ----------- EXP1-6
+       *   EXP1-4 ----------- FREE
+       *   SPI1-3 ----------- EXP1-2
+       *   EXP1-6 ----------- EXP1-4
+       *   EXP1-7 ----------- FREE
+       *   EXP1-8 ----------- EXP1-3
+       *   SPI1-1 ----------- EXP1-1
+       *  EXP1-10 ----------- EXP1-7
+       *
+       */
+
+      #define TFTGLCD_CS                    PA9
+
+    #endif
+
   #else
-    #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, and MKS_MINI_12864 are currently supported on the BIGTREE_SKR_MINI_E3."
+    #error "Only CR10_STOCKDISPLAY, ZONESTAR_LCD, ENDER2_STOCKDISPLAY, MKS_MINI_12864, and TFTGLCD_PANEL_(SPI|I2C) are currently supported on the BIGTREE_SKR_MINI_E3."
   #endif
 
 #endif // HAS_WIRED_LCD
@@ -227,9 +267,7 @@
 
 #if SD_CONNECTION_IS(ONBOARD)
   #define SD_DETECT_PIN                     PC4
-#endif
-
-#if BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050) && SD_CONNECTION_IS(LCD)
+#elif SD_CONNECTION_IS(LCD) && (BOTH(TOUCH_UI_FTDI_EVE, LCD_FYSETC_TFT81050) || IS_TFTGLCD_PANEL)
   #define SD_DETECT_PIN                     PB5
   #define SS_PIN                            PA10
 #elif SD_CONNECTION_IS(CUSTOM_CABLE)
diff --git a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h
index 3397c34f33a..47fff4467c7 100644
--- a/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h
+++ b/Marlin/src/pins/stm32f1/pins_BTT_SKR_MINI_V1_1.h
@@ -123,6 +123,17 @@
     #define LCD_PINS_ENABLE                 PC14
     #define LCD_PINS_D4                     PB7
 
+  #elif IS_TFTGLCD_PANEL
+
+    #undef BEEPER_PIN
+    #undef BTN_ENC
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS                    PD2
+    #endif
+
+    #define SD_DETECT_PIN                   PB9
+
   #else
 
     #define LCD_PINS_RS                     PC12
diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_LITE3.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_LITE3.h
index 5cdeda3a835..d5318b8e878 100644
--- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_LITE3.h
+++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_LITE3.h
@@ -115,6 +115,12 @@
     #define DOGLCD_SCK                      PB13
     #define DOGLCD_MOSI                     PB15
 
+  #elif IS_TFTGLCD_PANEL
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define TFTGLCD_CS                    PB11
+    #endif
+
   #else                                           // !MKS_MINI_12864
 
     #define LCD_PINS_D4                     PA6
diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
index caa5e2b8fc9..4e782649d3f 100644
--- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
+++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
@@ -356,6 +356,19 @@
     #define DOGLCD_SCK                      PA5
     #define DOGLCD_MOSI                     PA7
 
+  #elif IS_TFTGLCD_PANEL
+
+    #if ENABLED(TFTGLCD_PANEL_SPI)
+      #define PIN_SPI_SCK                   PA5
+      #define PIN_TFT_MISO                  PA6
+      #define PIN_TFT_MOSI                  PA7
+      #define TFTGLCD_CS                    PE8
+    #endif
+
+    #ifndef BEEPER_PIN
+      #define BEEPER_PIN                    -1
+    #endif
+
   #else                                           // !MKS_MINI_12864
 
     #define LCD_PINS_D4                     PE14
diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h
index 93f0de33dae..12c40b31b37 100644
--- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h
+++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_PRO.h
@@ -225,6 +225,12 @@
     #define BTN_EN2                         PG4
   #endif
 
+#elif IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define TFTGLCD_CS                      PG5
+  #endif
+
 #elif HAS_WIRED_LCD
 
   #define BEEPER_PIN                        PC5
@@ -254,6 +260,7 @@
     #endif
 
   #endif // !MKS_MINI_12864 && !ENDER2_STOCKDISPLAY
+
 #endif
 
 #ifndef BOARD_ST7920_DELAY_1
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
index 83972761447..1cd7e9dd89a 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
@@ -286,7 +286,14 @@
 //
 // LCDs and Controllers
 //
-#if HAS_WIRED_LCD
+#if IS_TFTGLCD_PANEL
+
+  #if ENABLED(TFTGLCD_PANEL_SPI)
+    #define TFTGLCD_CS                      PG10
+  #endif
+
+#elif HAS_WIRED_LCD
+
   #define BEEPER_PIN                        PG4
   #define BTN_ENC                           PA8
 
diff --git a/buildroot/tests/LPC1769-tests b/buildroot/tests/LPC1769-tests
index 9c7a1ba10e8..a7a6456d026 100755
--- a/buildroot/tests/LPC1769-tests
+++ b/buildroot/tests/LPC1769-tests
@@ -26,6 +26,20 @@ opt_enable VIKI2 SDSUPPORT ADAPTIVE_FAN_SLOWING NO_FAN_SLOWING_IN_PID_TUNING \
 opt_set GRID_MAX_POINTS_X 16
 exec_test $1 $2 "Smoothieboard with many features"
 
+restore_configs
+opt_set MOTHERBOARD BOARD_SMOOTHIEBOARD
+opt_set EXTRUDERS 2
+opt_set TEMP_SENSOR_1 -1
+opt_set TEMP_SENSOR_BED 5
+opt_enable TFTGLCD_PANEL_SPI SDSUPPORT ADAPTIVE_FAN_SLOWING NO_FAN_SLOWING_IN_PID_TUNING \
+           FIX_MOUNTED_PROBE AUTO_BED_LEVELING_BILINEAR G29_RETRY_AND_RECOVER Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \
+           BABYSTEPPING BABYSTEP_XY BABYSTEP_ZPROBE_OFFSET \
+           PRINTCOUNTER NOZZLE_PARK_FEATURE NOZZLE_CLEAN_FEATURE SLOW_PWM_HEATERS PIDTEMPBED EEPROM_SETTINGS INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT \
+           Z_SAFE_HOMING ADVANCED_PAUSE_FEATURE PARK_HEAD_ON_PAUSE \
+           LCD_INFO_MENU ARC_SUPPORT BEZIER_CURVE_SUPPORT EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES SDCARD_SORT_ALPHA EMERGENCY_PARSER
+opt_set GRID_MAX_POINTS_X 16
+exec_test $1 $2 "Smoothieboard with TFTGLCD_PANEL_SPI"
+
 #restore_configs
 #opt_set MOTHERBOARD BOARD_AZTEEG_X5_MINI_WIFI
 #opt_enable COREYX USE_XMAX_PLUG DAC_MOTOR_CURRENT_DEFAULT \
diff --git a/platformio.ini b/platformio.ini
index ff3c0fb810a..c426c5223b3 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -26,7 +26,7 @@ include_dir  = Marlin
 #
 [common]
 default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
-  -<src/lcd/HD44780> -<src/lcd/dwin> -<src/lcd/dogm> -<src/lcd/tft>
+  -<src/lcd/HD44780> -<src/lcd/TFTGLCD> -<src/lcd/dwin> -<src/lcd/dogm> -<src/lcd/tft>
   -<src/lcd/menu>
   -<src/lcd/menu/game/game.cpp> -<src/lcd/menu/game/brickout.cpp> -<src/lcd/menu/game/invaders.cpp>
   -<src/lcd/menu/game/maze.cpp> -<src/lcd/menu/game/snake.cpp>
@@ -216,6 +216,7 @@ HAS_MARLINUI_U8GLIB     = U8glib-HAL@~0.4.1
                           src_filter=+<src/lcd/dogm>
 HAS_GRAPHICAL_TFT       = src_filter=+<src/lcd/tft>
 DWIN_CREALITY_LCD       = src_filter=+<src/lcd/dwin>
+IS_TFTGLCD_PANEL        = src_filter=+<src/lcd/TFTGLCD>
 HAS_LCD_MENU            = src_filter=+<src/lcd/menu>
 HAS_GAMES               = src_filter=+<src/lcd/menu/game/game.cpp>
 MARLIN_BRICKOUT         = src_filter=+<src/lcd/menu/game/brickout.cpp>