Бортовой компьютер для Опель Зафира.

viki13viki
Offline
Зарегистрирован: 14.11.2016

Завтра попробую просто в луп закинуть заголовки. Это простой вывод текста, а данные закоменчу. Хорошая идея Командир. Так с узится круг поиска.

viki13viki
Offline
Зарегистрирован: 14.11.2016

короче убрал закинул вот такой голый скетч

#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 MCUFRIEND_kbv tft;
 #include "C:\Users\ViktorY\Desktop\arduino-1.8.9\libraries\Adafruit-GFX\Fonts/Gobold_Bold14pt7b.h";
#define MINPRESSURE 200
#define MAXPRESSURE 1000

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 const int XP = 6, XM = A2, YP = A1, YM = 7; 
 const int TS_LEFT = 136, TS_RT = 907, TS_TOP = 139, TS_BOT = 942;
 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
 uint16_t ID;
 int x, y;
 char currentPage;
 float h;
 float t;
 bool Dvoet = 0;
 bool reNew = 0;
 #define BLACK 0x0000
 #define WHITE 0xFFFF

 void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setFont(&Gobold_Bold14pt7b);
   myGLCD.setTextColor(WHITE, BLACK); 

   drawHomeScreen(); 
   }

   void loop() 
                {
     drawHomeScreen();
     }

 void drawHomeScreen() {
 
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setColor(255, 0, 0); // цвет линии и текста красный
    myGLCD.drawLine(295,35,295,248); // линия вертикальная
    myGLCD.drawLine(145,35,145,178); // линия вертикальная
    myGLCD.drawLine(80,178,80,247); // линия вертикальная
    myGLCD.print("L/H", 10, 40);
    myGLCD.print("L/A", 148, 40);
    myGLCD.print("L/V", 10, 75);
    myGLCD.print("L/M", 148, 75);
    myGLCD.print("D/K", 10, 110);
    myGLCD.print("D/L", 148, 110);
    myGLCD.print("V/K", 10, 145);
    myGLCD.print("V/L", 148, 145);
    myGLCD.print("PUMP RPM", 82, 180);
    myGLCD.print("ENGI   RPM", 82, 215);
    myGLCD.print("D/La", 10, 180);
    myGLCD.print("Motor C", 300, 40);
    myGLCD.print("OIL       C", 300, 75);
    myGLCD.print("FUEL    C", 300, 110);
    myGLCD.print("INTER  C", 300, 145);
    myGLCD.print("EXTER  C", 300, 180);
    myGLCD.print("INTAIR C", 300, 215); 
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
  }
                

Моргает зараза. Всетаки фруктовая библа корявая полностью. нужно искать косяки в библе.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Все надписи моргают ?

viki13viki
Offline
Зарегистрирован: 14.11.2016

да. как бы пробегающее моргание. с первого отображаемого слова и до последнего и так циклично

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Заархивируй и пришли мне все используемые сейчас библиотеки на e-mail 4124275@mail.ru. Именно с компа своего.

viki13viki
Offline
Зарегистрирован: 14.11.2016

залил простенький

#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 MCUFRIEND_kbv tft;
 #include "C:\Users\ViktorY\Desktop\arduino-1.8.9\libraries\Adafruit-GFX\Fonts/Gobold_Bold14pt7b.h";

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 
 void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setFont(&Gobold_Bold14pt7b);
   }

   void loop() 
                {
  myGLCD.print("PROBA LCD", 10, 40);
    
     }

не мигает. может тачь? ща подкину и гляну

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Так тут шрифт простой ! Могать начинает из-за принципа вывода сложного шрифта. Сначала вычисляется область куда будет вывод, потом она закрашивается фоном и потом рисуются видимые точки символов шрифта.

viki13viki
Offline
Зарегистрирован: 14.11.2016

шрифт тут тот что я использую, не стандартный #include "C:\Users\ViktorY\Desktop\arduino-1.8.9\libraries\Adafruit-GFX\Fonts/Gobold_Bold14pt7b.h";

добавил тач кнопку, кнопка очищет экран и появляется сново слово и ни че не моргает. Получается что с библой все хорошо? значит косяк гдето в скетче..... думаю нужно все по тихоньку добавлять и когда пойдет косяк то последняя добавка и буедт косяк. ща попробую и будем видеть

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

может setcolor ?

viki13viki
Offline
Зарегистрирован: 14.11.2016

ща, я по техоньку все закидываю. ща будем видеть что косячит

MaksVV
Offline
Зарегистрирован: 06.08.2015

скорее всего это тормозит

myGLCD.drawLine(80,178,80,247);

myGLCD.drawRoundRect (15, 255, 145, 310);

viki13viki
Offline
Зарегистрирован: 14.11.2016

не Макс, убрал все дравы и даже убрал тач, тот же эфект. все таки гдето проблема связаная с запросами и выводом. чтото их связывает раз без вывода идут быстро запросы а с выводом на экран затормаживается. где то сдесь я так думаю нужно искать

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

А ничего там за "край" экрана не лезет ?

в 1752 - закомментируй все стороки с 47 по 78 и по одной расскоментируй потом

 

viki13viki
Offline
Зарегистрирован: 14.11.2016

не все нормально расположено, единственное что уже говорил, что когда заваливает за 100 км в час то на надпись km/h налипает последняя скорость выше ста, тоесть скорость реальная а рядом на km/h налеплена последняя скорость за 100 км в час. ща по закоментирую

MaksVV
Offline
Зарегистрирован: 06.08.2015

viki13viki пишет:

не Макс, убрал все дравы и даже убрал тач, тот же эфект. все таки гдето проблема связаная с запросами и выводом. чтото их связывает раз без вывода идут быстро запросы а с выводом на экран затормаживается. где то сдесь я так думаю нужно искать

 

дак вроде 1752 тоже у тебя мигает. Там же нет никаких запросов. Проблема именно с выводом на экран , а не с запросами

viki13viki
Offline
Зарегистрирован: 14.11.2016

Командир ты сново оказался прав ....красавчик :) - тормозил myGLCD.setColor(255, 0, 0); заменил на myGLCD.setTextColor(WHITE); и все заработало. но одна проблема эта строчка myGLCD.setTextColor(WHITE, BLACK); не делает затирание, идет налепка сиволов. а также  myGLCD.drawLine(1,35,479,35); и myGLCD.drawRoundRect (15, 255, 145, 310); не подчиняются myGLCD.setTextColor(RED);, они подчиняются myGLCD.setColor(RED); но сново моргание. Рою....

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

А если цвета вынести в Setup или туда где выводится статическая иноформация ? Налепку исправим в либе - главное убрать моргание ...

viki13viki
Offline
Зарегистрирован: 14.11.2016

дык моргания уже нету :) вот подправленый скетч

#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 MCUFRIEND_kbv tft;
 #include "C:\Users\ViktorY\Desktop\arduino-1.8.9\libraries\Adafruit-GFX\Fonts/Gobold_Bold14pt7b.h";

#define MINPRESSURE 200
#define MAXPRESSURE 1000

//pin 20 SCL , 21 SDA датчик реального времени
 #include <Wire.h>
 #include "RTClib.h"
 RTC_DS3231 rtc;       

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 const int XP = 6, XM = A2, YP = A1, YM = 7; 
 const int TS_LEFT = 136, TS_RT = 907, TS_TOP = 139, TS_BOT = 942;
 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
 uint16_t ID;
 int x, y;
 char currentPage;
 float h;
 float t;
 bool Dvoet = 0;
 bool reNew = 0;
 #define BLACK 0x0000
 #define WHITE 0xFFFF
 #define RED   0xF800
 #define GREEN 0x07E0

#include <SoftwareSerial.h>
 #define TX_PCM 13
 SoftwareSerial K_LINE_PCM   (12, TX_PCM); //RХ,TХ

#define PCM_address  0x11        // адрес PCM 
#define DIAG_address 0xF1        // адрес диагностики

#define debugPCM                 // раскоментировать эту строку для отладки в Serial порту обмена с PCM
//#define debugGAUGE             // раскоментировать эту строку для отладки в Serial порту обмена co щитком приборов

 
 uint32_t curmillis = 0;         // снимок текущего времени 
 uint32_t prevRequest  = 0;      // таймер периодических запосов на PCM
 uint16_t RequestPeriod = 3500;  // периодичность запросов на PCM

 uint32_t prevRESETheader=0; // таймер сброса сообщения, если данные оборвались посередине сообщения 
 bool RESETheader_timer;     // таймер сброса сообщения, если данные оборвались посередине сообщения 
 
 uint32_t prev_NOanswer=0;   // таймер контроля неответов от ЭБУ после подачи запросов
 bool NOanswer_timer = 0;    // таймер контроля неответов от ЭБУ после подачи запросов
 byte noanswers = 0;         // количество подряд неответов от ЭБУ 
 
  
 uint32_t timerdelay = 0;    // таймер ожидания байт (для успевания появления данных в буфере UART)
 bool Delay = 0;             // таймер ожидания байт (для успевания появления данных в буфере UART)
 byte waitbyte_RX = 1;       // задержка, мс для успевания появления данных в буфере RX 
                             // (подрегулировать в зависимости от уровня жизнидеятельности на Марсе) 
 #define TIMER_DELAY Delay = 0; timerdelay = curmillis  // включение этого таймера
  
byte delaybyte_TX  = 1;   // задержка между отправкой байт в запросах, мс
byte header = 0;          // состояние заголовка
byte message_size = 0;    // размер тела сообщения
byte j = 3;               // инкремент
byte n = 3;               // количество старт байт
const byte bufsize = 150; // размер буфера принятого сообщения
byte MessageRx_PCM [bufsize] = {0}; // буфер принятого сообщения
byte crc =0;              // байт контрольной суммы 

  
// возможные варианты запросов на ЭБУ:
enum REQUEST {
 INIT,    
 PID,     
 DTCERASE,
 DTCREAD,
 PRESENT,
 };

// текстовки запросов для отладки 
char* textRequest[] = {
 "INIT",    
 "PID_2101",     
 "DTC_ERASE",
 "DTC_READ",
 "PRESENT",
    } ;

 // сами запросы
 byte PCM_Message_TX[][5] = {
 {1,  0x81,           0,0,0},      // запрос инициализации
 {2,  0x21,0x01,        0,0},      // запрос пид 2101
 {3,  0x14,0xFF,0x00,     0},      // запрос на стирание ошибок
 {4,  0x18,0x00,0xFF,0x00  },      // запрос на чтение ошибок
 {1,  0x3E,           0,0,0},      // запрос присутствия 
                            };

byte request = INIT;               // переменная, показывающая какой запрос будем делать

//-------------------------------------------переменные бортовика

 float L100M = 0;           //расход на 100 км измеренный за поездку
 float L100 = 0;            //мгновенный расход литров на 100км
 float LHor = 0;           //мгновенный расход топлива литров в час
 float L100SR = 0;         //расход литров на 100км измеренный раз в интервал kmL  
 float L100SR_TFT = 0;     // самый средний из расходов на 100км, он выводится на экран

 int L100_Eeprom[11]= {10,10,10,10,10,10,10,10,10,10,10};
 int FuelZamer[10]= {0};  // массив для измерения уровня (количества) топлива 
 int ZamerNumber = 0;     // номер замера уровня (количества) топлива 
 int n_eeprom = 0;        // текущий адрес ячейки еепром для записи расхода
 
 int MAF = 0;              //26,27 байты   Sensor de flujo de aire en masa
 float BoostPres = 0;      //28,29 байты   Presión de refuerzo
 int RPM = 0;              //32,33 байты   Velocidad del motor
 int EGRmg = 0;            //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
 float BoostPresCom = 0;   //38,39 байты   Comando de presión de refuerzo
 int Speed = 0;            //44,45 байты   Velocidad del vehículo
 float DesaInjQua = 0;     //50,51 байты   Cantidad de inyección deseada
 float InjQua = 0;         //52,53 байты   Cantidad de la inyección
 float StaDaliv = 0;       //54,55 байты   Inicio de la entrega
 int PumpRPM = 0;          //56,57 байты   Velocidad de la bomba
 float EGRPul = 0;         //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
 float SolenPul = 0;       //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
 float SolenPre = 0;       //70,71 байты   Relación de impulsos Presión Electroválvula de presión
 float DesInj = 0;         //72,73 байты   Inyección deseada Inicio
 float ActInj = 0;         //16,17 байты   Inicio de la inyección real
 int TempAir = 0;          //74,75 байты   Temperatura del aire de admisión
 int Temp = 0;             //14,15 байты   Temperatura del refrigerante
 int TempOil = 0;          //18,19 байты   Temperatura del aceite del motor
 int TempFuel = 0;         //58,59 байты   Temperatura del combustible
 
 //все что касается топлива
 float Fuel = 0;  //остаток топлива 
 float Fuel2 = 0;  //остаток мгновенного топлива байт 16 , датчика в баке
 int FuelIGN = 0;      // количество топлвива в баке на момент включения зажигания
 int Fuel_last = 0;   // для формул
 bool flagFuelIGN = 0; // флаг записан ли остаток топлива в момент вкл. зажигания 
 float FuelTrip = 0;     // количество литров топлива, израсходованное за один цикл включения зажигания
 
 //все что касается километража
 float kmAge = 0;             //пробег, полученный со щитка приборов
 int kmAgeIGN = 0;          //пробег который был в момент включения зажигания 
 int kmAge_last = 0;       // для формул
 bool flagkmAgeIGN = 0;     //флаг записан ли пробег в момент вкл. зажигания 
 float kmTrip = 0;            //пробег за один цикл включения зажигания
 int kmL = 10;               // интервал, через который будет происходить обновление среднего расхода на 100км
 int km = 0;              // переменная для расчетов
 int kmeeprom = 10;         // интервал, через который будет происходить подсчет среднеарифмитического расхода  L100SR_TFT
 int kmTFT =  0;     // переменная для расчетов периодического подсчета среднеарифмитического расхода топлива L100SR_TFT
 int kmREFUELING = 0;            // пробег до заправки на остатке топлива 
 
 unsigned long prevWatch = 0;
 unsigned long prevDvoet = 0;
 unsigned long prevData  = 0;

 
void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setFont(&Gobold_Bold14pt7b);
   //myGLCD.setTextColor(WHITE, BLACK);  

   Wire.begin();
   rtc.begin();
   
   //загрузка стартовой страницы
   currentPage = '0';       
   drawHomeScreen();  

   //подсчет среднеарифметического усредненного расхода
   for (int i = 0; i < 11; i++) L100_Eeprom [i]= EEPROM.read(i);
   for (int i = 0; i < 11; i++) L100SR_TFT = L100SR_TFT +  L100_Eeprom [i];
   L100SR_TFT = (float)L100SR_TFT/110.0;
   if (L100SR_TFT<0) L100SR_TFT = 0;
   if (L100SR_TFT>99) L100SR_TFT = 99;
  
   // строка ниже используется для настройки даты и времени часов 
   // раскоментировать, выставить времая и дату, залить в ардуино. в скетче закоментировать
   // обратно и залить еще раз, иначе каждый раз будет по новой выствлятся это же время и дата
   // (год, месяц, день, часы, минуты, секунды)
   //rtc.adjust(DateTime(2017, 7, 21, 13, 57, 0));
 
 
 #if defined debugPCM or debugGAUGE   
   Serial.begin(115200);
 #endif
   K_LINE_PCM.begin(10400);
   pinMode(TX_PCM, OUTPUT);
  
             }


    void loop() 
                {
curmillis = millis();              // снимок текущего времени

if (curmillis - prevRequest > RequestPeriod && header == 0 ) 
    {
  if (request == INIT) fastinit();                                          // при необходимости делаем переподключение к PCM
  else {sendMessagePCM(request);                                            // отправляем на PCM текущий запрос
         if (request == PID) RequestPeriod = 600; 
         if (request == DTCERASE || request == DTCREAD) RequestPeriod = 2500;} 
  prevRequest = curmillis;
    }

receivePCM (); // приём сообщений от PCM

if (header == 0) Menu ();         
  if (curmillis - prevWatch > 3000)  { Watch (); prevWatch = curmillis;}
  if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.setTextColor(WHITE); } else {myGLCD.setTextColor(BLACK); }  myGLCD.print(":", 290, 5); prevDvoet = curmillis; Dvoet=!Dvoet;}               
  
                }// end loop



 void fastinit() {
   digitalWrite (TX_PCM, HIGH);  // bus idle
   delay(1500);              
   digitalWrite (TX_PCM, LOW);  // first part fastinit  (25 ms LOW)
   delay(25);
   digitalWrite (TX_PCM, HIGH); // second part fastinit (25 ms HIGH)
   delay(25);               
   K_LINE_PCM.begin(10400);
   sendMessagePCM(INIT);        // send start communication message 
      }  
 
  
  void receivePCM () {

 if (K_LINE_PCM.available() ){
    
 // первый старт байт
 if (header == 0 && Delay){TIMER_DELAY ; MessageRx_PCM[0]=K_LINE_PCM.read();  
         if (MessageRx_PCM[0]!=0xFF && bitRead (MessageRx_PCM[0],7)){header = 1; RESETheader_timer = 1; prevRESETheader = curmillis; 
               #ifdef debugPCM
                  Serial.print (F("Receive PCM: ")); printDebugRX(MessageRx_PCM[0]);
               #endif               
                                                }
                          }                  

 // второй старт байт
 if (header == 1 && Delay){TIMER_DELAY ; MessageRx_PCM[1]=K_LINE_PCM.read(); 
 #ifdef debugPCM
      printDebugRX (MessageRx_PCM[1]);
 #endif
      if (MessageRx_PCM[1]==DIAG_address){ header = 2;} 
      else {
        #ifdef debugPCM 
        Serial.println(F(" PCM Message fail address")); 
        #endif
        header = 0; RESETheader_timer = 0;}} 

 // третий старт байт
 if (header == 2 && Delay){ 
  TIMER_DELAY ;
  MessageRx_PCM[2]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX (MessageRx_PCM[2]);
  #endif
  if (MessageRx_PCM[2]==PCM_address){ message_size = MessageRx_PCM[0]; prevRESETheader = curmillis;
       if (MessageRx_PCM[0] !=0x80) {header = 4;  bitWrite (message_size, 7 , 0);j=3;n=3;}
       else {header = 3; j=4;n=4;}
       if (message_size > bufsize) message_size = bufsize;  crc = 0;} 
  else {header = 0; 
        #ifdef debugPCM 
        Serial.println(F("PCM Message fail address")); 
        #endif
        RESETheader_timer = 0;}
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
  TIMER_DELAY ; prevRESETheader = curmillis;
  MessageRx_PCM[3]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX(MessageRx_PCM[3]);
  #endif
  message_size = MessageRx_PCM[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  crc = 0; header = 4;  
                         }

  // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size+n+1) {
 MessageRx_PCM[j] = K_LINE_PCM.read(); prevRESETheader = curmillis;
 if (j<message_size+n) crc+= MessageRx_PCM[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 TIMER_DELAY ; 
 #ifdef debugPCM
 printDebugRX(MessageRx_PCM[j]);
 #endif  
 j++;                                             } 
 }

 // сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  
 #ifdef debugPCM
 Serial.println();
 #endif  
 NOanswer_timer = 0; noanswers = 0;              // сбрасываем таймер контроля неответов 
  
for(byte i = 0; i<n; i++) crc+=MessageRx_PCM[i]; // прибавляем к контрольной сумме старт байты

 // если контрольная сумма верна: 
if ( crc == MessageRx_PCM[message_size+n]) 
{  
  #ifdef debugPCM
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  printDebugRX_CSgood(); 
  #endif
      if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {
              if (currentPage!=3) {request = PID; RequestPeriod = 70;} else request = PRESENT, RequestPeriod = 4000; prevRequest = curmillis; // receive good INIT
                                                                                          }
 else if (MessageRx_PCM[n]==0x58) Troublecodes (); // DTC
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){ request = PRESENT; RequestPeriod = 4000; prevRequest = curmillis;} // DTC are cleared
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {dataVars() ; RequestPeriod = 70; prevRequest = curmillis; }           // receive DataStream
 
 
 }   

// если контрольная сумма не совпала: 
#ifdef debugPCM
  else Serial.println("CRC fail!!!" );
#endif
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}

// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1; 

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timer && curmillis - prevRESETheader > 200) { 
  #ifdef debugPCM 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timer = 0; header = 0;}   

 
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.  
if (request!=INIT && NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/10) 
         {
     NOanswer_timer = 0; noanswers++; 
     if (noanswers>=6) { noanswers = 0; request = INIT; RequestPeriod = 3500;}
         }
}// end receivePCM


void Troublecodes () 
{
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00){
    myGLCD.clrScr();             
    drawscreen_three();      
    myGLCD.print("NO DTC", 165, 145);
    
                         }
 
  // при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]>0){
     
     myGLCD.clrScr();             
     drawscreen_three();       

  for (int i=0; i<MessageRx_PCM[n+8-7]; i++ ) {
     int y = i*35;
     bool nolA=0; bool nolB =0;
  if (!bitRead(MessageRx_PCM[n+11-7+(i*3)],6) && bitRead(MessageRx_PCM[n+11-7+(i*3)],7)){ myGLCD.setTextColor(GREEN); 
     myGLCD.print(" -Passive-", 300, (75+y));} // если DTC пасивныый делаем цвет зеленый 
  if (bitRead(MessageRx_PCM[n+11-7+(i*3)],7) && bitRead(MessageRx_PCM[n+11-7+(i*3)],6)) { myGLCD.setTextColor(RED);  
     myGLCD.print(" -Active-", 300, (75+y));} // если DTC активный, делаем цвет красный 
     myGLCD.print("ERROR ", 50, (75+y));
     myGLCD.printNumI((i+1), 150, (75+y));
     
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": P", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": C", 170, (75+y));
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": B", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": U", 170, (75+y));

  if (MessageRx_PCM[n+9-7+(i*3)]==0x00) {myGLCD.print("00", 230, (75+y)); nolA = 1;}
  if (MessageRx_PCM[n+9-7+(i*3)]<=0x0F&&MessageRx_PCM[n+9-7+(i*3)]!=0) {myGLCD.print("0", 230, (75+y)); nolA = 1;} 
  if (nolA)myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 246, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 230, (75+y));

  if (MessageRx_PCM[n+10-7+(i*3)]==0x00) {myGLCD.print("00", 262, (75+y)); nolB = 1;}
  if (MessageRx_PCM[n+10-7+(i*3)]<=0x0F&&MessageRx_PCM[n+10-7+(i*3)]!=0) {myGLCD.print("0", 262, (75+y)); nolB = 1;}
  if (nolB)myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)]),HEX, 278, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)],HEX), 262, (75+y));}} 

request = PRESENT; RequestPeriod = 4000;  prevRequest = curmillis;

}



void dataVars() 
{
  //Barom = MessageRx_PCM[39];
   L100 = (float)LHor*100.0/(float)Speed;
   LHor = (float)RPM* (float)InjQua*2.00/1000.0*60.00/1000.0/0.85;
   MAF =  ((MessageRx_PCM[n+22]*256)+MessageRx_PCM[n+23])/10;
   BoostPres =  ((MessageRx_PCM[n+24]*256)+MessageRx_PCM[n+25])/1000.0;
   RPM =  (MessageRx_PCM[n+35-7]*256)+MessageRx_PCM[n+36-7];
   EGRmg =  ((MessageRx_PCM[n+37-7]*256)+MessageRx_PCM[n+38-7])/10.0;
   BoostPresCom =  ((MessageRx_PCM[n+41-7]*256)+MessageRx_PCM[n+42-7])/1000.0;
   Speed =  ((MessageRx_PCM[n+47-7]*256)+MessageRx_PCM[n+48-7])/100;
   DesaInjQua =  ((MessageRx_PCM[n+53-7]*256)+MessageRx_PCM[n+54-7])/100.0;
   InjQua =  ((MessageRx_PCM[n+55-7]*256)+MessageRx_PCM[n+56-7])/100.0;
   StaDaliv =  ((MessageRx_PCM[n+57-7]*256)+MessageRx_PCM[n+58-7])/100.0;
   PumpRPM =  (MessageRx_PCM[n+59-7]*256)+MessageRx_PCM[n+60-7];
   EGRPul =  ((MessageRx_PCM[n+65-7]*256)+MessageRx_PCM[n+66-7])/100.0;
   SolenPul =  ((MessageRx_PCM[n+67-7]*256)+MessageRx_PCM[n+68-7])/100.0;
   SolenPre =  ((MessageRx_PCM[n+73-7]*256)+MessageRx_PCM[n+74-7])/100.0;
   DesInj =  ((MessageRx_PCM[n+75-7]*3)+(MessageRx_PCM[n+76-7])/100.0)+0.3;
   ActInj =  ((MessageRx_PCM[n+19-7]*3)+(MessageRx_PCM[n+20-7])/100.0)+0.3;
   //TempAir =  ((MessageRx_PCM[n+77-7]*26)-278)+MessageRx_PCM[n+78-7]/10.0;
   //Temp =  ((MessageRx_PCM[n+17-7]*26)-278)+MessageRx_PCM[n+18-7]/10.0;
   //TempOil =  ((MessageRx_PCM[n+21-7]*26)-278)+MessageRx_PCM[n+22-7]/10.0;
   //TempFuel =  ((MessageRx_PCM[n+61-7]*26)-278)+MessageRx_PCM[n+62-7]/10.0;
   //ниже идут расчетные формулы более точные чем те что закоментированы выше
   int A = 0;
   if  (MessageRx_PCM[n+77-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+77-7]==0x0B || MessageRx_PCM[n+77-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+77-7]>=0x0D) A = 279;
   double B = MessageRx_PCM[n+78-7]/10.0;
   double cel , drob ;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempAir =  ((MessageRx_PCM[n+77-7]*26)-A)+cel;
   
   if  (MessageRx_PCM[n+17-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+17-7]==0x0B || MessageRx_PCM[n+17-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+17-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+18-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     Temp =  ((MessageRx_PCM[n+17-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+21-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+21-7]==0x0B || MessageRx_PCM[n+21-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+21-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+22-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempOil =  ((MessageRx_PCM[n+21-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+61-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+61-7]==0x0B || MessageRx_PCM[n+61-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+61-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+62-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempFuel =  ((MessageRx_PCM[n+61-7]*26)-A)+cel;   

     myGLCD.setTextColor(WHITE);
     myGLCD.printNumI(Speed, 350, 7, 3);
  //----------------------------------------------------------
  //страниц HOME
  //----------------------------------------------------------
  if (currentPage == '0') {
     myGLCD.printNumF(LHor, 1, 60, 40, '.',5);
     myGLCD.printNumF(L100, 1, 210, 40,'.',5 );
     myGLCD.printNumF(L100M, 1, 60, 75,'.',5 );
     myGLCD.printNumF(L100SR_TFT, 1, 210, 75,'.',5 );
     myGLCD.printNumI(kmREFUELING, 60, 110,5 ); 
     //if (Fuel<53) 
     myGLCD.printNumF(Fuel, 1, 210, 110,'.',5);
     //else myGLCD.print("MAX", 210, 110); 
     myGLCD.printNumF(kmTrip, 1, 60, 145,'.',5);
     myGLCD.printNumF(FuelTrip, 1, 210, 145,'.',5);
     myGLCD.printNumI(PumpRPM, 210, 180,5);
     myGLCD.printNumI(RPM, 210, 215,5);
     myGLCD.printNumF(Fuel2, 1, 0, 215,'.',5);      
     myGLCD.printNumI(Temp, 415, 40, 3);
     myGLCD.printNumI(TempOil, 415, 75, 3);
     myGLCD.printNumI(TempFuel, 415, 110,3); 
     //myGLCD.printNumI(sensors.getTempCByIndex(0), 415, 145 , 3);
     myGLCD.printNumI(t, 415, 180, 3);
     myGLCD.printNumI(TempAir, 415, 215, 3); }
   //----------------------------------------------------------
   //страниц INF1
   //----------------------------------------------------------
   if (currentPage == '1') {
     myGLCD.printNumF(StaDaliv,1, 360, 40,'.', 3);
     myGLCD.printNumF(DesInj,1, 395, 75, '.', 4);
     myGLCD.printNumF(ActInj,1, 395, 110,'.', 4); 
     myGLCD.printNumF(DesaInjQua,1, 395, 145,'.', 4);  
     myGLCD.printNumF(InjQua,1, 395, 180,'.', 4); 
     myGLCD.printNumI(MAF, 170, 215, 4);
     myGLCD.printNumF(h, 1, 418, 215); }
   //----------------------------------------------------------
   //страниц INF2
   //----------------------------------------------------------
   if (currentPage == '2') {    
     myGLCD.printNumF(BoostPres,1, 395, 40,'.', 4);  
     myGLCD.printNumF(BoostPresCom,1, 395, 75,'.', 4); 
     myGLCD.printNumI(EGRmg, 395, 110, 4);  
     myGLCD.printNumF(EGRPul,1, 410, 145,'.', 3);  
     myGLCD.printNumF(SolenPul, 1, 395, 180,'.', 4);  
     myGLCD.printNumF(SolenPre, 0, 410, 215,'.', 3); }
 
}



 void sendMessagePCM(const byte &command)
{
 #ifdef debugPCM                         
Serial.print (F("Send request "));  Serial.print (textRequest[command]); Serial.print (F(" to PCM  ")); Serial.println (millis());
 #endif
if (command != INIT) {NOanswer_timer = 1; prev_NOanswer = curmillis;}  //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов 
  byte size =  PCM_Message_TX[command][0];
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCM_address;
    if (i==2) Mes[i] = DIAG_address;    
    if (i==3) {for (byte t=1; t<size+1; t++ ) {
           Mes[i]=PCM_Message_TX [command][t]; 
           Checksum+=Mes[i] ; 
           K_LINE_PCM.write (Mes[i]); 
           if (command == INIT) delay (5); else delay (delaybyte_TX);  
           K_LINE_PCM.read(); 
           i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE_PCM.write (Mes[i]);
   if (command == INIT) delay (5); else delay (delaybyte_TX);
    K_LINE_PCM.read();
                             }
}// end sendMessagePCM



#if defined debugPCM or debugGAUGE
void printDebugRX (const byte &inbyte) {if (inbyte<=15) Serial.print(F("0")); Serial.print (inbyte, HEX);  Serial.print (F(" "));}
#endif

#ifdef debugPCM
void printDebugRX_CSgood(){
if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {Serial.println (F("   Initialization OK!!!!")); }
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00) {Serial.println (F("     NO DTC  "));}
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1] >0x00) {Serial.println (F("     DTC is found!"));} 
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){Serial.println (F("     DTC CLEARED  "));}
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {Serial.println (F("     Receive PCM DATAstream"));}}
#endif                          



void Menu () {
     TouchHOME();
    if (currentPage == '0') {
     
     TouchINF1();
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '1') { 
     
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '2') { 
     
     TouchINF1();
     TouchCHECK(); }
    if (currentPage == '3') { 
     
     TouchREAD();
     TouchERASE(); }}   
 
 
  void drawHomeScreen() {
    reNew = 1;
    line() ;
    Watch ();
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED); // цвет линии и текста красный
    myGLCD.drawLine(295,35,295,248); // линия вертикальная
    myGLCD.drawLine(145,35,145,178); // линия вертикальная
    myGLCD.drawLine(80,178,80,247); // линия вертикальная
    myGLCD.print("L/H", 10, 40);
    myGLCD.print("L/A", 148, 40);
    myGLCD.print("L/V", 10, 75);
    myGLCD.print("L/M", 148, 75);
    myGLCD.print("D/K", 10, 110);
    myGLCD.print("D/L", 148, 110);
    myGLCD.print("V/K", 10, 145);
    myGLCD.print("V/L", 148, 145);
    myGLCD.print("PUMP RPM", 82, 180);
    myGLCD.print("ENGI   RPM", 82, 215);
    myGLCD.print("D/La", 10, 180);
    myGLCD.print("Motor C", 300, 40);
    myGLCD.print("OIL       C", 300, 75);
    myGLCD.print("FUEL    C", 300, 110);
    myGLCD.print("INTER  C", 300, 145);
    myGLCD.print("EXTER  C", 300, 180);
    myGLCD.print("INTAIR C", 300, 215);
    //myGLCD.setTextColor(RED); 
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
  }
 //-------------------------------------------------
   void drawscreen_one() {
    reNew = 1;
    line() ;
    Watch ();
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED); // цвет линии и текста красный
    myGLCD.print("Start of Delivery   *CA:", 10, 40);
    myGLCD.print("Desir inject Start  *CA:", 10, 75);
    myGLCD.print("Actua Inject Start *CA:", 10, 110);
    myGLCD.print("Desir Inject Quan  mg/s:", 10, 145);
    myGLCD.print("Actu Inject Quant mg/s:", 10, 180);
    myGLCD.print("MAF  mg/s:", 10, 215);
    myGLCD.print("Humedad %:", 255, 215);
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    }
 //-------------------------------------------------
  void drawscreen_two() {
    reNew = 1;
    line() ;
    Watch ();
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED); // цвет линии и текста красный
    myGLCD.print("Boost Press          Bar:", 10, 40);
    myGLCD.print("Boost Press Com  Bar:", 10, 75);
    myGLCD.print("EGR command     mg/s:", 10, 110);
    myGLCD.print("EGR Pulse Ratio      %:", 10, 145);
    myGLCD.print("Solenoide Pulse      %:", 10, 180);
    myGLCD.print("Solenoide Boost      %:", 10, 215);
    //myGLCD.setColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    }
 //----------------------------------------------------------------------------
  void drawscreen_three() {
    reNew = 1;
    Watch ();
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("ERASE", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("READ", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 5);
   }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//кнопки тач . координаты и переходы
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TouchHOME(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {if (p.x > 140 && p.x < 320 && p.y > 140 && p.y < 260 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (1, 1, 77, 37);
        currentPage = '0';     
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров
        myGLCD.clrScr();             
        drawHomeScreen();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchINF1(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
      if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (15, 255, 145, 310);
        currentPage = '1';    
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров       
        myGLCD.clrScr();             
        drawscreen_one();
        x = 0;
        y = 0;
        p.z = 0;}}}
    
void TouchINF2(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
    if (p.x > 450 && p.x < 680 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (175, 255, 305, 310);
        currentPage = '2';     
        request = PID; RequestPeriod = 600; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров      
        myGLCD.clrScr();             
        drawscreen_two();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchCHECK(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        currentPage = '3';  
  //     request = DTCREAD; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос чтения ошибок  
        myGLCD.clrScr();             
        drawscreen_three();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchREAD(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        request = DTCREAD; RequestPeriod = 300; prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос чтения ошибок  
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchERASE(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      {myGLCD.drawRoundRect (15, 255, 145, 310);
       request = DTCERASE; RequestPeriod = 300;  prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос удаления ошибок 
        x = 0;
        y = 0;
        p.z = 0;}}}
 ////////////////////////////////////////////////////////////////////////////////////////
 //прорисовка линий
 ///////////////////////////////////////////////////////////////////////////////////////
 void line() {
    myGLCD.setTextColor(RED); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,73,479,73); // линия горизонтальная
    myGLCD.drawLine(1,108,479,108); // линия горизонтальная
    myGLCD.drawLine(1,143,479,143); // линия горизонтальная
    myGLCD.drawLine(1,178,479,178); // линия горизонтальная
    myGLCD.drawLine(1,212,479,212); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
             }


void Watch (){
   DateTime now = rtc.now();
   int minut = now.minute(); 
   int hour = now.hour();
   int mon = now.month();
   int date = now.day();
   int Year = now.year();
 static  int minut_last; 
 static  int hour_last;
 static  int mon_last;
 static  int date_last;
 static  int Year_last;
 myGLCD.setTextColor(WHITE); //белый цвет цифры

 if (date != date_last || reNew){
   if (date<10 ) { 
   myGLCD.print("0", 85, 7); 
   myGLCD.printNumI(date, 100, 7); } 
   else if (date >=10) {
   myGLCD.printNumI(date, 85, 7); }
date_last = date;
 }
  
 if (mon!=mon_last || reNew){ 
   if ( mon<10) {
   myGLCD.print("0", 130, 7); 
   myGLCD.printNumI(mon, 145, 7);} 
   else if (mon >=10) {
      myGLCD.printNumI(mon, 130, 7);}  
mon_last = mon;
 }
   
  
if (Year!=Year_last || reNew) {  myGLCD.printNumI(Year, 175, 7); Year_last = Year;}
   
if (hour!=hour_last || reNew){
   if (hour<10) {
   myGLCD.print("0",255, 7); 
   myGLCD.printNumI(hour, 270, 7); } 
   else if(hour>=10){ 
   myGLCD.printNumI(hour, 255, 7); } 
hour_last = hour;
}
   
if (minut!=minut_last || reNew ){   
   if (minut<10) {
   myGLCD.print("0",300, 7); 
   myGLCD.printNumI(minut, 315, 7); } 
   else if (minut>=10){ 
   myGLCD.printNumI(minut, 300, 7); }
minut_last = minut;
}
reNew = 0; 
    }          

ща две проблемы 1. затирание и 2. и дать цвет drawLine и drawRoundRect. выше писал

myGLCD.setTextColor(RED); рулит но не на все, только на текст

читаю про функцию setBackColor вроде затирание при печати

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Так вот и поставь setColor(RED) ТОЛЬКО в SETUPе после инициализвции экрана - у тебя же все фигуры красные - какой смысл вызывать ее в других местах ?

viki13viki
Offline
Зарегистрирован: 14.11.2016

так по всему скетчу идет чередование то красный то белый. инфа белая, полоски красные, заголовки красные, если дать в сетапе общий белый а везде убрать, то все будет белое. просмотри прорисовку данных потом ниже прорисовку страниц почти в конце скетча, а еще ниже часы

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

setColor в Setup

setTextColor Red и White только в drawscreen...home 1 2 3 ... последним должен быть White

убрать SetTextColor в 464 строке 

viki13viki
Offline
Зарегистрирован: 14.11.2016

setColor дает мигание только SetTextColor. и ты удивишься, когда я занес myGLCD.setTextColor(WHITE); в сетап, угадай :) вернулось моргание..... так что пусть будет так это не критично, нужно налипание побороть

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Для борьбы с налипанием - прицепи сюда содержимое твоего текущего UTFTGLUE.cpp

Подозреваю что ещё возможно везде надо писать в SetTextColor два цвета !!! WHITE,BLACK RED,BLACK GREEN,BLACK BLACK,BLACK !!!

viki13viki
Offline
Зарегистрирован: 14.11.2016

вот утфглю

/*
 * utftglue.h   @@@@@@@@@@@@@@@@@@@@@@@@ LIBRARY @@@@@@@@@@@@@@@@@@@@@@@@@
 *
 * Created: 12/05/2019 14:25:06
 *  Author: David Prentice
 *  
 *  Might just as well ALWAYS use FreeFonts.
 *  knows FreeSmallFont, FreeBigFont and FreeSevenSegNumFont
 *  any other Fonts just need to #include "FreeOtherXXX.h"
 *  and #define OtherXXX &FreeOtherXXX
 */ 

#warning   @@@@@@@@@@@@@@@@@@@@@@@@@ <UTFTGLUE.h> @@@@@@@@@@@@@@@@@@@@@@@@@@

#ifndef UTFTGLUE_H_
#define UTFTGLUE_H_

#define LEFT 0
#define RIGHT 9999
#define CENTER 9998

#define PORTRAIT 0
#define LANDSCAPE 1

#include <MCUFRIEND_kbv.h>

#include <Adafruit_GFX.h>
#if defined(__arm)
#include <avr/dtostrf.h>
#endif

#include <FreeDefaultFonts.h>
#define SmallFont &FreeSmallFont
#define BigFont   &FreeBigFont
#define SevenSegNumFont &FreeSevenSegNumFont

class UTFTGLUE : public MCUFRIEND_kbv
{
    public:
//  UTFTGLUE() : MCUFRIEND_kbv() {}
    UTFTGLUE(byte model, int RS, int WR,int CS, int RST, int RD = A0)
             : MCUFRIEND_kbv(CS, RS, WR, RD, RST) {}
    void InitLCD(byte orientation=LANDSCAPE) {
        MCUFRIEND_kbv::reset();
        uint16_t ID = MCUFRIEND_kbv::readID();
//       if (ID == 0) ID = 0x9341;        //DealExtreme with EXTC=0
//       if (ID == 0x8989) ID = 0x1289;
//       if (ID == 0xD3D3) ID = 0x9481;   //write-only controller
//       if (ID == 0xD3D3) ID = 0x9486;   //write-only controller
         if (ID == 0xD3D3) ID = 0x9090;   //write-only controller HX8357-D
//         if (ID == 0x9327 && orientation == LANDSCAPE) orientation = 3;
        MCUFRIEND_kbv::begin(ID);
        MCUFRIEND_kbv::setRotation(_orient = orientation);
        _radius = 4;
    }
    void clrScr() { MCUFRIEND_kbv::fillScreen(0x0000);}
    void drawPixel(int x, int y) { MCUFRIEND_kbv::drawPixel(x, y, _fcolor);}
    void drawLine(int x1, int y1, int x2, int y2) { MCUFRIEND_kbv::drawLine(x1, y1, x2, y2, _fcolor);}
    void fillScr(byte r, byte g, byte b) { MCUFRIEND_kbv::fillScreen(setrgb(r, g, b));}
    void drawRect(int x1, int y1, int x2, int y2) {
        int w = x2 - x1 + 1, h = y2 - y1 + 1;
        if (w < 0) { x1 = x2; w = -w; }
        if (h < 0) { y1 = y2; h = -h; }
        MCUFRIEND_kbv::drawRect(x1, y1, w, h, _fcolor);
    }
    void drawRoundRect(int x1, int y1, int x2, int y2) {
        int w = x2 - x1 + 1, h = y2 - y1 + 1;
        if (w < 0) { x1 = x2; w = -w; }
        if (h < 0) { y1 = y2; h = -h; }
        MCUFRIEND_kbv::drawRoundRect(x1, y1, w, h, _radius, _fcolor);
    }
    void fillRect(int x1, int y1, int x2, int y2) {
        int w = x2 - x1 + 1, h = y2 - y1 + 1;
        if (w < 0) { x1 = x2; w = -w; }
        if (h < 0) { y1 = y2; h = -h; }
        MCUFRIEND_kbv::fillRect(x1, y1, w, h, _fcolor);
    }
    void fillRoundRect(int x1, int y1, int x2, int y2) {
        int w = x2 - x1 + 1, h = y2 - y1 + 1;
        if (w < 0) { x1 = x2; w = -w; }
        if (h < 0) { y1 = y2; h = -h; }
        MCUFRIEND_kbv::fillRoundRect(x1, y1, w, h, _radius, _fcolor);
    }
    void drawCircle(int x, int y, int radius) { MCUFRIEND_kbv::drawCircle(x, y, radius, _fcolor);}
    void fillCircle(int x, int y, int radius) { MCUFRIEND_kbv::fillCircle(x, y, radius, _fcolor);}
    void setColor(byte r, byte g, byte b)  { setColor(setrgb(r, g, b));}
    void setColor(uint16_t c)  { MCUFRIEND_kbv::setTextColor(_fcolor = c, _bcolor); }
    void setBackColor(byte r, byte g, byte b)  { setBackColor(setrgb(r, g, b)); }
    void setBackColor(uint32_t c)  { 
        if (c == 0xFFFFFFFF) _bcolor = _fcolor; 
        else _bcolor = c;
        MCUFRIEND_kbv::setTextColor(_fcolor, _bcolor);
    }
    void print(const char *st, int x, int y, int deg=0)  {
        settextcursor((char*)st, x, y); MCUFRIEND_kbv::print(st);}
    void print(char *st, int x, int y, int deg=0)  {
        settextcursor(st, x, y); MCUFRIEND_kbv::print(st);}
    void print(String st, int x, int y, int deg=0) {
        settextcursor((char*)(st.c_str()), x, y); MCUFRIEND_kbv::print(st);}
    void printNumI(long num, int x, int y, int length=0, char filler=' ') {
        printNumF(num, 0, x, y, '.', length, filler);
    }
    void printNumF(double num, byte dec, int x, int y, char divider='.', int length=0, char filler=' ') {
        char buf[20];
        dtostrf(num, length, dec, buf); 
        for (int i = 0; buf[i] == ' '; i++) buf[i] = filler;
        settextcursor(buf, x, y, length * _dig_wid * MCUFRIEND_kbv::textsize); 
        MCUFRIEND_kbv::print(buf);
    }
    void setTextSize(int sz) { MCUFRIEND_kbv::setTextSize(gfxFont == NULL ? sz : 1); } // ####### GFX ########
    void setFont(GFXfont* font) {
        MCUFRIEND_kbv::setFont(font);
        _ascend = 8;
        _descend = 1;
        _dig_wid = 6;
        if (font != NULL) {
            int16_t x = 0, y = 0, x1, y1 = 0, x2, y2 = 0;
            MCUFRIEND_kbv::setTextSize(1);
            charBounds('0', &x, &y, &x1, &y1, &x2, &y2);
            _ascend = y2 - y1;    //yAdvance
            _dig_wid = x;   //xAdvance
        }
    }
    void drawBitmap(int x, int y, int sx, int sy, const uint16_t *data, int scale=1) {
        uint16_t color;
        MCUFRIEND_kbv::setAddrWindow(x, y, x + sx*scale - 1, y + sy*scale - 1);
        if (scale == 1) MCUFRIEND_kbv::pushColors((const uint8_t*)data, sx * sy, 1);
        else {
            for (int row = 0; row < sy; row++) {
                for (int col = 0; col < sx; col++) {
                    color = pgm_read_word(data + (row*sx + col)*1);
                    MCUFRIEND_kbv::fillRect(x+col*scale, y+row*scale, scale, scale, color);
                }
            }
        }
    }
//  void drawBitmap(int x, int y, int sx, int sy, bitmapdatatype data, int deg, int rox, int roy);
//  void lcdOff();
//  void lcdOn();
//  void setContrast(char c);
    int  getDisplayXSize() { return MCUFRIEND_kbv::width(); }
    int  getDisplayYSize() { return MCUFRIEND_kbv::height(); }
//  void LCD_Write_DATA(char VH,char VL);
//  void dispBitmap(File inFile);
    uint8_t _ascend, _descend, _dig_wid;

    protected:
    uint16_t _fcolor;
    uint16_t _bcolor;
//    uint8_t _ascend, _descend, _dig_wid;
    uint8_t _radius;
    uint8_t _orient;
    void settextcursor(char *st, int x, int y, int pad = 0) {
        int16_t pos, x1, y1;
        uint16_t len, w, h;
        bool is_gfx = (MCUFRIEND_kbv::gfxFont != NULL);
        getTextBounds(st, 0, 0, &x1, &y1, &w, &h);   //always
        len = x1 + w + 0;    // assumes the final right padding = 1.
        if (pad >= len) pad = pad - len;
        pos = (MCUFRIEND_kbv::width() - len - pad);
        if (x == CENTER) x = pos/2;
        else if (x == RIGHT) x = pos - 1;
        if (is_gfx) {    //only GFX fonts need to paint background
            h = _ascend + _descend; //pgm_read_byte(&gfxFont->yAdvance);
            if (_fcolor != _bcolor) MCUFRIEND_kbv::fillRect(x, y, len + pad + 1, h, _bcolor);
            y += h;
        }
        MCUFRIEND_kbv::setCursor(x + pad, y);
    }
    uint16_t setrgb(byte r, byte g, byte b)  { return ((r&0xF8) << 8) | ((g&0xFC) << 3) | (b>>3);}
};

#define VGA_BLACK       0x0000
#define VGA_WHITE       0xFFFF
#define VGA_RED         0xF800
#define VGA_GREEN       0x0400
#define VGA_BLUE        0x001F
#define VGA_SILVER      0xC618
#define VGA_GRAY        0x8410
#define VGA_MAROON      0x8000
#define VGA_YELLOW      0xFFE0
#define VGA_OLIVE       0x8400
#define VGA_LIME        0x07E0
#define VGA_AQUA        0x07FF
#define VGA_TEAL        0x0410
#define VGA_NAVY        0x0010
#define VGA_FUCHSIA     0xF81F
#define VGA_PURPLE      0x8010
#define VGA_TRANSPARENT 0xFFFFFFFF

#endif /* UTFTGLUE_H_ */

да там пишется два цвета, цвет текста и цвет фона, пробовал, не затирает.

глю у меня только h, есть cpp такой MCUFRIEND_kbv.cpp

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Не .h, а .cpp

viki13viki
Offline
Зарегистрирован: 14.11.2016

оно же с этой библы кормится MCUFRIEND_kbv. там только глю h  и MCUFRIEND_kbv.cpp вот он

//#define SUPPORT_0139              //S6D0139 +280 bytes
#define SUPPORT_0154              //S6D0154 +320 bytes
//#define SUPPORT_1289              //SSD1289,SSD1297 (ID=0x9797) +626 bytes, 0.03s
//#define SUPPORT_1580              //R61580 Untested
#define SUPPORT_1963              //only works with 16BIT bus anyway
//#define SUPPORT_4532              //LGDP4532 +120 bytes.  thanks Leodino
#define SUPPORT_4535              //LGDP4535 +180 bytes
#define SUPPORT_68140             //RM68140 +52 bytes defaults to PIXFMT=0x55
//#define SUPPORT_7735
#define SUPPORT_7781              //ST7781 +172 bytes
//#define SUPPORT_8230              //UC8230 +118 bytes
//#define SUPPORT_8347D             //HX8347-D, HX8347-G, HX8347-I, HX8367-A +520 bytes, 0.27s
//#define SUPPORT_8347A             //HX8347-A +500 bytes, 0.27s
//#define SUPPORT_8352A             //HX8352A +486 bytes, 0.27s
//#define SUPPORT_8352B             //HX8352B
//#define SUPPORT_8357D_GAMMA       //monster 34 byte 
//#define SUPPORT_9163              //
//#define SUPPORT_9225              //ILI9225-B, ILI9225-G ID=0x9225, ID=0x9226, ID=0x6813 +380 bytes
//#define SUPPORT_9326_5420         //ILI9326, SPFD5420 +246 bytes
//#define SUPPORT_9342              //costs +114 bytes
//#define SUPPORT_9806              //UNTESTED
#define SUPPORT_9488_555          //costs +230 bytes, 0.03s / 0.19s
#define SUPPORT_B509_7793         //R61509, ST7793 +244 bytes
#define OFFSET_9327 32            //costs about 103 bytes, 0.08s

#include "MCUFRIEND_kbv.h"
#if defined(USE_SERIAL)
#include "utility/mcufriend_serial.h"
 //uint8_t running;
#elif defined(__MBED__)
#include "utility/mcufriend_mbed.h"
#elif defined(__CC_ARM) || defined(__CROSSWORKS_ARM)
#include "utility/mcufriend_keil.h"
#else
#include "utility/mcufriend_shield.h"
#endif

#define MIPI_DCS_REV1   (1<<0)
#define AUTO_READINC    (1<<1)
#define READ_BGR        (1<<2)
#define READ_LOWHIGH    (1<<3)
#define READ_24BITS     (1<<4)
#define XSA_XEA_16BIT   (1<<5)
#define READ_NODUMMY    (1<<6)
#define INVERT_GS       (1<<8)
#define INVERT_SS       (1<<9)
#define MV_AXIS         (1<<10)
#define INVERT_RGB      (1<<11)
#define REV_SCREEN      (1<<12)
#define FLIP_VERT       (1<<13)
#define FLIP_HORIZ      (1<<14)

#if (defined(USES_16BIT_BUS))   //only comes from SPECIALs
#define USING_16BIT_BUS 1
#else
#define USING_16BIT_BUS 0
#endif

MCUFRIEND_kbv::MCUFRIEND_kbv(int CS, int RS, int WR, int RD, int _RST):Adafruit_GFX(240, 320)
{
    // we can not access GPIO pins until AHB has been enabled.
}

static uint8_t done_reset, is8347, is555, is9797;
static uint16_t color565_to_555(uint16_t color) {
    return (color & 0xFFC0) | ((color & 0x1F) << 1) | ((color & 0x01));  //lose Green LSB, extend Blue LSB
}
static uint16_t color555_to_565(uint16_t color) {
    return (color & 0xFFC0) | ((color & 0x0400) >> 5) | ((color & 0x3F) >> 1); //extend Green LSB
}
static uint8_t color565_to_r(uint16_t color) {
    return ((color & 0xF800) >> 8);  // transform to rrrrrxxx
}
static uint8_t color565_to_g(uint16_t color) {
    return ((color & 0x07E0) >> 3);  // transform to ggggggxx
}
static uint8_t color565_to_b(uint16_t color) {
    return ((color & 0x001F) << 3);  // transform to bbbbbxxx
}
static void write24(uint16_t color) {
    uint8_t r = color565_to_r(color);
    uint8_t g = color565_to_g(color);
    uint8_t b = color565_to_b(color);
    write8(r);
    write8(g);
    write8(b);
}

void MCUFRIEND_kbv::reset(void)
{
    done_reset = 1;
    setWriteDir();
    CTL_INIT();
    CS_IDLE;
    RD_IDLE;
    WR_IDLE;
    RESET_IDLE;
    delay(50);
    RESET_ACTIVE;
    delay(100);
    RESET_IDLE;
    delay(100);
	WriteCmdData(0xB0, 0x0000);   //R61520 needs this to read ID
}

static void writecmddata(uint16_t cmd, uint16_t dat)
{
    CS_ACTIVE;
    WriteCmd(cmd);
    WriteData(dat);
    CS_IDLE;
}

void MCUFRIEND_kbv::WriteCmdData(uint16_t cmd, uint16_t dat) { writecmddata(cmd, dat); }

static void WriteCmdParamN(uint16_t cmd, int8_t N, uint8_t * block)
{
    CS_ACTIVE;
    WriteCmd(cmd);
    while (N-- > 0) {
        uint8_t u8 = *block++;
        write8(u8);
        if (N && is8347) {
            cmd++;
            WriteCmd(cmd);
        }
    }
    CS_IDLE;
}

static inline void WriteCmdParam4(uint8_t cmd, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4)
{
    uint8_t d[4];
    d[0] = d1, d[1] = d2, d[2] = d3, d[3] = d4;
    WriteCmdParamN(cmd, 4, d);
}

//#define WriteCmdParam4(cmd, d1, d2, d3, d4) {uint8_t d[4];d[0] = d1, d[1] = d2, d[2] = d3, d[3] = d4;WriteCmdParamN(cmd, 4, d);}
void MCUFRIEND_kbv::pushCommand(uint16_t cmd, uint8_t * block, int8_t N) { WriteCmdParamN(cmd, N, block); }

static uint16_t read16bits(void)
{
    uint16_t ret;
    uint8_t lo;
#if USING_16BIT_BUS
    READ_16(ret);               //single strobe to read whole bus
    if (ret > 255)              //ID might say 0x00D3
        return ret;
#else
    READ_8(ret);
#endif
    //all MIPI_DCS_REV1 style params are 8-bit
    READ_8(lo);
    return (ret << 8) | lo;
}

uint16_t MCUFRIEND_kbv::readReg(uint16_t reg, int8_t index)
{
    uint16_t ret;
    uint8_t lo;
    if (!done_reset)
        reset();
    CS_ACTIVE;
    WriteCmd(reg);
    setReadDir();
    delay(1);    //1us should be adequate
    //    READ_16(ret);
    do { ret = read16bits(); }while (--index >= 0);  //need to test with SSD1963
    RD_IDLE;
    CS_IDLE;
    setWriteDir();
    return ret;
}

uint32_t MCUFRIEND_kbv::readReg32(uint16_t reg)
{
    uint16_t h = readReg(reg, 0);
    uint16_t l = readReg(reg, 1);
    return ((uint32_t) h << 16) | (l);
}

uint32_t MCUFRIEND_kbv::readReg40(uint16_t reg)
{
    uint16_t h = readReg(reg, 0);
    uint16_t m = readReg(reg, 1);
    uint16_t l = readReg(reg, 2);
    return ((uint32_t) h << 24) | (m << 8) | (l >> 8);
}

uint16_t MCUFRIEND_kbv::readID(void)
{
    uint16_t ret, ret2;
    uint8_t msb;
    ret = readReg(0);           //forces a reset() if called before begin()
    if (ret == 0x5408)          //the SPFD5408 fails the 0xD3D3 test.
        return 0x5408;
    if (ret == 0x5420)          //the SPFD5420 fails the 0xD3D3 test.
        return 0x5420;
    if (ret == 0x8989)          //SSD1289 is always 8989
        return 0x1289;
    ret = readReg(0x67);        //HX8347-A
    if (ret == 0x4747)
        return 0x8347;
//#if defined(SUPPORT_1963) && USING_16BIT_BUS 
    ret = readReg32(0xA1);      //SSD1963: [01 57 61 01]
    if (ret == 0x6101)
        return 0x1963;
    if (ret == 0xFFFF)          //R61526: [xx FF FF FF]
        return 0x1526;          //subsequent begin() enables Command Access
//    if (ret == 0xFF00)          //R61520: [xx FF FF 00]
//        return 0x1520;          //subsequent begin() enables Command Access
//#endif
	ret = readReg40(0xBF);
	if (ret == 0x8357)          //HX8357B: [xx 01 62 83 57 FF]
        return 0x8357;
	if (ret == 0x9481)          //ILI9481: [xx 02 04 94 81 FF]
        return 0x9481;
    if (ret == 0x1511)          //?R61511: [xx 02 04 15 11] not tested yet
        return 0x1511;
    if (ret == 0x1520)          //?R61520: [xx 01 22 15 20]
        return 0x1520;
    if (ret == 0x1526)          //?R61526: [xx 01 22 15 26]
        return 0x1526;
    if (ret == 0x1581)          //R61581:  [xx 01 22 15 81]
        return 0x1581;
    if (ret == 0x1400)          //?RM68140:[xx FF 68 14 00] not tested yet
        return 0x6814;
    ret = readReg32(0xD4);
    if (ret == 0x5310)          //NT35310: [xx 01 53 10]
        return 0x5310;
    ret = readReg32(0xD7);
    if (ret == 0x8031)          //weird unknown from BangGood [xx 20 80 31] PrinceCharles
        return 0x8031;
    ret = readReg40(0xEF);      //ILI9327: [xx 02 04 93 27 FF] 
    if (ret == 0x9327)
        return 0x9327;
    ret = readReg32(0xFE) >> 8; //weird unknown from BangGood [04 20 53] 
    if (ret == 0x2053)
        return 0x2053;
    uint32_t ret32 = readReg32(0x04);
    msb = ret32 >> 16;
    ret = ret32;	
//    if (msb = 0x38 && ret == 0x8000) //unknown [xx 38 80 00] with D3 = 0x1602
    if (msb == 0x00 && ret == 0x8000) { //HX8357-D [xx 00 80 00]
#if 1
        uint8_t cmds[] = {0xFF, 0x83, 0x57};
        pushCommand(0xB9, cmds, 3);
        msb = readReg(0xD0);
        if (msb == 0x99) return 0x0099; //HX8357-D from datasheet
        if (msb == 0x90)        //HX8357-C undocumented  
#endif
            return 0x9090;      //BIG CHANGE: HX8357-D was 0x8357
    }
//    if (msb == 0xFF && ret == 0xFFFF) //R61526 [xx FF FF FF]
//        return 0x1526;          //subsequent begin() enables Command Access
    if (ret == 0x1526)          //R61526 [xx 06 15 26] if I have written NVM
        return 0x1526;          //subsequent begin() enables Command Access
	if (ret == 0x89F0)          //ST7735S: [xx 7C 89 F0]
        return 0x7735;
	if (ret == 0x8552)          //ST7789V: [xx 85 85 52]
        return 0x7789;
    if (ret == 0xAC11)          //?unknown [xx 61 AC 11]
        return 0xAC11;
    ret32 = readReg32(0xD3);      //[xx 91 63 00]
    ret = ret32 >> 8;
    if (ret == 0x9163) return ret;
    ret = readReg32(0xD3);      //for ILI9488, 9486, 9340, 9341
    msb = ret >> 8;
    if (msb == 0x93 || msb == 0x94 || msb == 0x98 || msb == 0x77 || msb == 0x16)
        return ret;             //0x9488, 9486, 9340, 9341, 7796
    if (ret == 0x00D3 || ret == 0xD3D3)
        return ret;             //16-bit write-only bus
/*
	msb = 0x12;                 //read 3rd,4th byte.  does not work in parallel
	pushCommand(0xD9, &msb, 1);
	ret2 = readReg(0xD3);
    msb = 0x13;
	pushCommand(0xD9, &msb, 1);
	ret = (ret2 << 8) | readReg(0xD3);
//	if (ret2 == 0x93)
    	return ret2;
*/
	return readReg(0);          //0154, 7783, 9320, 9325, 9335, B505, B509
}

 // independent cursor and window registers.   S6D0154, ST7781 increments.  ILI92320/5 do not.  
int16_t MCUFRIEND_kbv::readGRAM(int16_t x, int16_t y, uint16_t * block, int16_t w, int16_t h)
{
    uint16_t ret, dummy, _MR = _MW;
    int16_t n = w * h, row = 0, col = 0;
    uint8_t r, g, b, tmp;
    if (!is8347 && _lcd_capable & MIPI_DCS_REV1) // HX8347 uses same register
        _MR = 0x2E;
    if (_lcd_ID == 0x1602) _MR = 0x2E;
    setAddrWindow(x, y, x + w - 1, y + h - 1);
    while (n > 0) {
        if (!(_lcd_capable & MIPI_DCS_REV1)) {
            WriteCmdData(_MC, x + col);
            WriteCmdData(_MP, y + row);
        }
        CS_ACTIVE;
        WriteCmd(_MR);
        setReadDir();
        if (_lcd_capable & READ_NODUMMY) {
            ;
        } else if ((_lcd_capable & MIPI_DCS_REV1) || _lcd_ID == 0x1289) {
            READ_8(r);
        } else {
            READ_16(dummy);
        }
		if (_lcd_ID == 0x1511) READ_8(r);   //extra dummy for R61511
        while (n) {
            if (_lcd_capable & READ_24BITS) {
                READ_8(r);
                READ_8(g);
                READ_8(b);
                if (_lcd_capable & READ_BGR)
                    ret = color565(b, g, r);
                else
                    ret = color565(r, g, b);
            } else {
                READ_16(ret);
                if (_lcd_capable & READ_LOWHIGH)
                    ret = (ret >> 8) | (ret << 8);
                if (_lcd_capable & READ_BGR)
                    ret = (ret & 0x07E0) | (ret >> 11) | (ret << 11);
            }
#if defined(SUPPORT_9488_555)
    if (is555) ret = color555_to_565(ret);
#endif
            *block++ = ret;
            n--;
            if (!(_lcd_capable & AUTO_READINC))
                break;
        }
        if (++col >= w) {
            col = 0;
            if (++row >= h)
                row = 0;
        }
        RD_IDLE;
        CS_IDLE;
        setWriteDir();
    }
    if (!(_lcd_capable & MIPI_DCS_REV1))
        setAddrWindow(0, 0, width() - 1, height() - 1);
    return 0;
}

void MCUFRIEND_kbv::setRotation(uint8_t r)
{
    uint16_t GS, SS_v, ORG, REV = _lcd_rev;
    uint8_t val, d[3];
    rotation = r & 3;           // just perform the operation ourselves on the protected variables
    _width = (rotation & 1) ? HEIGHT : WIDTH;
    _height = (rotation & 1) ? WIDTH : HEIGHT;
    switch (rotation) {
    case 0:                    //PORTRAIT:
        val = 0x48;             //MY=0, MX=1, MV=0, ML=0, BGR=1
        break;
    case 1:                    //LANDSCAPE: 90 degrees
        val = 0x28;             //MY=0, MX=0, MV=1, ML=0, BGR=1
        break;
    case 2:                    //PORTRAIT_REV: 180 degrees
        val = 0x98;             //MY=1, MX=0, MV=0, ML=1, BGR=1
        break;
    case 3:                    //LANDSCAPE_REV: 270 degrees
        val = 0xF8;             //MY=1, MX=1, MV=1, ML=1, BGR=1
        break;
    }
    if (_lcd_capable & INVERT_GS)
        val ^= 0x80;
    if (_lcd_capable & INVERT_SS)
        val ^= 0x40;
    if (_lcd_capable & INVERT_RGB)
        val ^= 0x08;
    if (_lcd_capable & MIPI_DCS_REV1) {
        if (_lcd_ID == 0x6814) {  //.kbv my weird 0x9486 might be 68140
            GS = (val & 0x80) ? (1 << 6) : 0;   //MY
            SS_v = (val & 0x40) ? (1 << 5) : 0;   //MX
            val &= 0x28;        //keep MV, BGR, MY=0, MX=0, ML=0
            d[0] = 0;
            d[1] = GS | SS_v | 0x02;      //MY, MX
            d[2] = 0x3B;
            WriteCmdParamN(0xB6, 3, d);
            goto common_MC;
        } else if (_lcd_ID == 0x1963 || _lcd_ID == 0x9481 || _lcd_ID == 0x1511) {
            if (val & 0x80)
                val |= 0x01;    //GS
            if ((val & 0x40))
                val |= 0x02;    //SS
            if (_lcd_ID == 0x1963) val &= ~0xC0;
            if (_lcd_ID == 0x9481) val &= ~0xD0;
            if (_lcd_ID == 0x1511) {
                val &= ~0x10;   //remove ML
                val |= 0xC0;    //force penguin 180 rotation
            }
//            val &= (_lcd_ID == 0x1963) ? ~0xC0 : ~0xD0; //MY=0, MX=0 with ML=0 for ILI9481
            goto common_MC;
        } else if (is8347) {
            _MC = 0x02, _MP = 0x06, _MW = 0x22, _SC = 0x02, _EC = 0x04, _SP = 0x06, _EP = 0x08;
            if (_lcd_ID == 0x0065) {             //HX8352-B
                val |= 0x01;    //GS=1
                if ((val & 0x10)) val ^= 0xD3;  //(ML) flip MY, MX, ML, SS, GS
                if (r & 1) _MC = 0x82, _MP = 0x80;
                else _MC = 0x80, _MP = 0x82;
            }
            if (_lcd_ID == 0x5252) {             //HX8352-A
                val |= 0x02;   //VERT_SCROLLON
                if ((val & 0x10)) val ^= 0xD4;  //(ML) flip MY, MX, SS. GS=1
            }
			goto common_BGR;
        }
      common_MC:
        _MC = 0x2A, _MP = 0x2B, _MW = 0x2C, _SC = 0x2A, _EC = 0x2A, _SP = 0x2B, _EP = 0x2B;
      common_BGR:
        WriteCmdParamN(is8347 ? 0x16 : 0x36, 1, &val);
        _lcd_madctl = val;
//	    if (_lcd_ID	== 0x1963) WriteCmdParamN(0x13, 0, NULL);   //NORMAL mode
    }
    // cope with 9320 variants
    else {
        switch (_lcd_ID) {
#if defined(SUPPORT_9225)
        case 0x9225:
            _SC = 0x37, _EC = 0x36, _SP = 0x39, _EP = 0x38;
            _MC = 0x20, _MP = 0x21, _MW = 0x22;
            GS = (val & 0x80) ? (1 << 9) : 0;
            SS_v = (val & 0x40) ? (1 << 8) : 0;
            WriteCmdData(0x01, GS | SS_v | 0x001C);       // set Driver Output Control
            goto common_ORG;
#endif
#if defined(SUPPORT_0139) || defined(SUPPORT_0154)
#ifdef SUPPORT_0139
        case 0x0139:
            _SC = 0x46, _EC = 0x46, _SP = 0x48, _EP = 0x47;
            goto common_S6D;
#endif
#ifdef SUPPORT_0154
        case 0x0154:
            _SC = 0x37, _EC = 0x36, _SP = 0x39, _EP = 0x38;
            goto common_S6D;
#endif
          common_S6D:
            _MC = 0x20, _MP = 0x21, _MW = 0x22;
            GS = (val & 0x80) ? (1 << 9) : 0;
            SS_v = (val & 0x40) ? (1 << 8) : 0;
            // S6D0139 requires NL = 0x27,  S6D0154 NL = 0x28
            WriteCmdData(0x01, GS | SS_v | ((_lcd_ID == 0x0139) ? 0x27 : 0x28));
            goto common_ORG;
#endif
        case 0x5420:
        case 0x7793:
        case 0x9326:
		case 0xB509:
            _MC = 0x200, _MP = 0x201, _MW = 0x202, _SC = 0x210, _EC = 0x211, _SP = 0x212, _EP = 0x213;
            GS = (val & 0x80) ? (1 << 15) : 0;
			uint16_t NL;
			NL = ((432 / 8) - 1) << 9;
            if (_lcd_ID == 0x9326 || _lcd_ID == 0x5420) NL >>= 1;
            WriteCmdData(0x400, GS | NL);
            goto common_SS;
        default:
            _MC = 0x20, _MP = 0x21, _MW = 0x22, _SC = 0x50, _EC = 0x51, _SP = 0x52, _EP = 0x53;
            GS = (val & 0x80) ? (1 << 15) : 0;
            WriteCmdData(0x60, GS | 0x2700);    // Gate Scan Line (0xA700)
          common_SS:
            SS_v = (val & 0x40) ? (1 << 8) : 0;
            WriteCmdData(0x01, SS_v);     // set Driver Output Control
          common_ORG:
            ORG = (val & 0x20) ? (1 << 3) : 0;
#ifdef SUPPORT_8230
            if (_lcd_ID == 0x8230) {    // UC8230 has strange BGR and READ_BGR behaviour
                if (rotation == 1 || rotation == 2) {
                    val ^= 0x08;        // change BGR bit for LANDSCAPE and PORTRAIT_REV
                }
            }               
#endif
            if (val & 0x08)
                ORG |= 0x1000;  //BGR
            _lcd_madctl = ORG | 0x0030;
            WriteCmdData(0x03, _lcd_madctl);    // set GRAM write direction and BGR=1.
            break;
#ifdef SUPPORT_1289
        case 0x1289:
            _MC = 0x4E, _MP = 0x4F, _MW = 0x22, _SC = 0x44, _EC = 0x44, _SP = 0x45, _EP = 0x46;
            if (rotation & 1)
                val ^= 0xD0;    // exchange Landscape modes
            GS = (val & 0x80) ? (1 << 14) : 0;    //called TB (top-bottom), CAD=0
            SS_v = (val & 0x40) ? (1 << 9) : 0;   //called RL (right-left)
            ORG = (val & 0x20) ? (1 << 3) : 0;  //called AM
            _lcd_drivOut = GS | SS_v | (REV << 13) | 0x013F;      //REV=0, BGR=0, MUX=319
            if (val & 0x08)
                _lcd_drivOut |= 0x0800; //BGR
            WriteCmdData(0x01, _lcd_drivOut);   // set Driver Output Control
            if (is9797) WriteCmdData(0x11, ORG | 0x4C30); else  // DFM=2, DEN=1, WM=1, TY=0
            WriteCmdData(0x11, ORG | 0x6070);   // DFM=3, EN=0, TY=1
            break;
#endif
		}
    }
    if ((rotation & 1) && ((_lcd_capable & MV_AXIS) == 0)) {
        uint16_t x;
        x = _MC, _MC = _MP, _MP = x;
        x = _SC, _SC = _SP, _SP = x;    //.kbv check 0139
        x = _EC, _EC = _EP, _EP = x;    //.kbv check 0139
    }
    setAddrWindow(0, 0, width() - 1, height() - 1);
    vertScroll(0, HEIGHT, 0);   //reset scrolling after a rotation
}

void MCUFRIEND_kbv::drawPixel(int16_t x, int16_t y, uint16_t color)
{
    // MCUFRIEND just plots at edge if you try to write outside of the box:
    if (x < 0 || y < 0 || x >= width() || y >= height())
        return;
#if defined(SUPPORT_9488_555)
    if (is555) color = color565_to_555(color);
#endif
    setAddrWindow(x, y, x, y);
//    CS_ACTIVE; WriteCmd(_MW); write16(color); CS_IDLE; //-0.01s +98B
    if (is9797) { CS_ACTIVE; WriteCmd(_MW); write24(color); CS_IDLE;} else
    WriteCmdData(_MW, color);
}

void MCUFRIEND_kbv::setAddrWindow(int16_t x, int16_t y, int16_t x1, int16_t y1)
{
#if defined(OFFSET_9327)
	if (_lcd_ID == 0x9327) {
	    if (rotation == 2) y += OFFSET_9327, y1 += OFFSET_9327;
	    if (rotation == 3) x += OFFSET_9327, x1 += OFFSET_9327;
    }
#endif
#if 1
    if (_lcd_ID == 0x1526 && (rotation & 1)) {
		int16_t dx = x1 - x, dy = y1 - y;
		if (dy == 0) { y1++; }
		else if (dx == 0) { x1 += dy; y1 -= dy; }
    }
#endif
    if (_lcd_capable & MIPI_DCS_REV1) {
        WriteCmdParam4(_SC, x >> 8, x, x1 >> 8, x1);   //Start column instead of _MC
        WriteCmdParam4(_SP, y >> 8, y, y1 >> 8, y1);   //
        if (is8347 && _lcd_ID == 0x0065) {             //HX8352-B has separate _MC, _SC
            uint8_t d[2];
            d[0] = x >> 8; d[1] = x;
            WriteCmdParamN(_MC, 2, d);                 //allows !MV_AXIS to work
            d[0] = y >> 8; d[1] = y;
            WriteCmdParamN(_MP, 2, d);
        }
    } else {
        WriteCmdData(_MC, x);
        WriteCmdData(_MP, y);
        if (!(x == x1 && y == y1)) {  //only need MC,MP for drawPixel
            if (_lcd_capable & XSA_XEA_16BIT) {
                if (rotation & 1)
                    y1 = y = (y1 << 8) | y;
                else
                    x1 = x = (x1 << 8) | x;
            }
            WriteCmdData(_SC, x);
            WriteCmdData(_SP, y);
            WriteCmdData(_EC, x1);
            WriteCmdData(_EP, y1);
        }
    }
}

void MCUFRIEND_kbv::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
{
    int16_t end;
#if defined(SUPPORT_9488_555)
    if (is555) color = color565_to_555(color);
#endif
    if (w < 0) {
        w = -w;
        x -= w;
    }                           //+ve w
    end = x + w;
    if (x < 0)
        x = 0;
    if (end > width())
        end = width();
    w = end - x;
    if (h < 0) {
        h = -h;
        y -= h;
    }                           //+ve h
    end = y + h;
    if (y < 0)
        y = 0;
    if (end > height())
        end = height();
    h = end - y;
    setAddrWindow(x, y, x + w - 1, y + h - 1);
    CS_ACTIVE;
    WriteCmd(_MW);
    if (h > w) {
        end = h;
        h = w;
        w = end;
    }
    uint8_t hi = color >> 8, lo = color & 0xFF;
    while (h-- > 0) {
        end = w;
#if USING_16BIT_BUS
#if defined(__MK66FX1M0__)      //180MHz M4
#define STROBE_16BIT {WR_ACTIVE4;WR_ACTIVE;WR_IDLE4;WR_IDLE;}   //56ns
#elif defined(__SAM3X8E__)      //84MHz M3
#define STROBE_16BIT {WR_ACTIVE4;WR_ACTIVE2;WR_IDLE4;WR_IDLE2;} //286ns ?ILI9486
//#define STROBE_16BIT {WR_ACTIVE4;WR_ACTIVE;WR_IDLE4;WR_IDLE;} //238ns SSD1289
//#define STROBE_16BIT {WR_ACTIVE2;WR_ACTIVE;WR_IDLE2;}      //119ns RM68140
#else                           //16MHz AVR
#define STROBE_16BIT {WR_ACTIVE;WR_ACTIVE;WR_IDLE; }            //375ns ?ILI9486
#endif
        write_16(color);        //we could just do the strobe
        lo = end & 7;
        hi = end >> 3;
        if (hi)
            do {
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
                STROBE_16BIT;
            } while (--hi > 0);
        while (lo-- > 0) {
            STROBE_16BIT;
        }
#else
#if defined(SUPPORT_1289)
        if (is9797) {
             uint8_t r = color565_to_r(color);
             uint8_t g = color565_to_g(color);
             uint8_t b = color565_to_b(color);
             do {
                 write8(r);
                 write8(g);
                 write8(b);
             } while (--end != 0);
        } else
#endif
        do {
            write8(hi);
            write8(lo);
        } while (--end != 0);
#endif
    }
    CS_IDLE;
    if (!(_lcd_capable & MIPI_DCS_REV1) || ((_lcd_ID == 0x1526) && (rotation & 1)))
        setAddrWindow(0, 0, width() - 1, height() - 1);
}

static void pushColors_any(uint16_t cmd, uint8_t * block, int16_t n, bool first, uint8_t flags)
{
    uint16_t color;
    uint8_t h, l;
	bool isconst = flags & 1;
	bool isbigend = (flags & 2) != 0;
    CS_ACTIVE;
    if (first) {
        WriteCmd(cmd);
    }

    if (!isconst && !isbigend) {
        uint16_t *block16 = (uint16_t*)block;
        while (n-- > 0) {
            color = *block16++;
            write16(color);
        }
    } else

    while (n-- > 0) {
        if (isconst) {
            h = pgm_read_byte(block++);
            l = pgm_read_byte(block++);
        } else {
		    h = (*block++);
            l = (*block++);
		}
        color = (isbigend) ? (h << 8 | l) :  (l << 8 | h);
#if defined(SUPPORT_9488_555)
        if (is555) color = color565_to_555(color);
#endif
        if (is9797) write24(color); else
        write16(color);
    }
    CS_IDLE;
}

void MCUFRIEND_kbv::pushColors(uint16_t * block, int16_t n, bool first)
{
    pushColors_any(_MW, (uint8_t *)block, n, first, 0);
}
void MCUFRIEND_kbv::pushColors(uint8_t * block, int16_t n, bool first)
{
    pushColors_any(_MW, (uint8_t *)block, n, first, 2);   //regular bigend
}
void MCUFRIEND_kbv::pushColors(const uint8_t * block, int16_t n, bool first, bool bigend)
{
    pushColors_any(_MW, (uint8_t *)block, n, first, bigend ? 3 : 1);
}

void MCUFRIEND_kbv::vertScroll(int16_t top, int16_t scrollines, int16_t offset)
{
#if defined(OFFSET_9327)
	if (_lcd_ID == 0x9327) {
	    if (rotation == 2 || rotation == 3) top += OFFSET_9327;
    }
#endif
    int16_t bfa = HEIGHT - top - scrollines;  // bottom fixed area
    int16_t vsp;
    int16_t sea = top;
	if (_lcd_ID == 0x9327) bfa += 32;
    if (offset <= -scrollines || offset >= scrollines) offset = 0; //valid scroll
	vsp = top + offset; // vertical start position
    if (offset < 0)
        vsp += scrollines;          //keep in unsigned range
    sea = top + scrollines - 1;
    if (_lcd_capable & MIPI_DCS_REV1) {
        uint8_t d[6];           // for multi-byte parameters
/*
        if (_lcd_ID == 0x9327) {        //panel is wired for 240x432 
            if (rotation == 2 || rotation == 3) { //180 or 270 degrees
                if (scrollines == HEIGHT) {
                    scrollines = 432;   // we get a glitch but hey-ho
                    vsp -= 432 - HEIGHT;
                }
                if (vsp < 0)
                    vsp += 432;
            }
            bfa = 432 - top - scrollines;
        }
*/
        d[0] = top >> 8;        //TFA
        d[1] = top;
        d[2] = scrollines >> 8; //VSA
        d[3] = scrollines;
        d[4] = bfa >> 8;        //BFA
        d[5] = bfa;
        WriteCmdParamN(is8347 ? 0x0E : 0x33, 6, d);
//        if (offset == 0 && rotation > 1) vsp = top + scrollines;   //make non-valid
		d[0] = vsp >> 8;        //VSP
        d[1] = vsp;
        WriteCmdParamN(is8347 ? 0x14 : 0x37, 2, d);
		if (is8347) { 
		    d[0] = (offset != 0) ? (_lcd_ID == 0x8347 ? 0x02 : 0x08) : 0;
			WriteCmdParamN(_lcd_ID == 0x8347 ? 0x18 : 0x01, 1, d);  //HX8347-D
		} else if (offset == 0 && (_lcd_capable & MIPI_DCS_REV1)) {
			WriteCmdParamN(0x13, 0, NULL);    //NORMAL i.e. disable scroll
		}
		return;
    }
    // cope with 9320 style variants:
    switch (_lcd_ID) {
    case 0x7783:
        WriteCmdData(0x61, _lcd_rev);   //!NDL, !VLE, REV
        WriteCmdData(0x6A, vsp);        //VL#
        break;
#ifdef SUPPORT_0139 
    case 0x0139:
        WriteCmdData(0x07, 0x0213 | (_lcd_rev << 2));  //VLE1=1, GON=1, REV=x, D=3
        WriteCmdData(0x41, vsp);  //VL# check vsp
        break;
#endif
#if defined(SUPPORT_0154) || defined(SUPPORT_9225)  //thanks tongbajiel
    case 0x9225:
	case 0x0154:
        WriteCmdData(0x31, sea);        //SEA
        WriteCmdData(0x32, top);        //SSA
        WriteCmdData(0x33, vsp - top);  //SST
        break;
#endif
#ifdef SUPPORT_1289
    case 0x1289:
        WriteCmdData(0x41, vsp);        //VL#
        break;
#endif
	case 0x5420:
    case 0x7793:
	case 0x9326:
	case 0xB509:
        WriteCmdData(0x401, (1 << 1) | _lcd_rev);       //VLE, REV 
        WriteCmdData(0x404, vsp);       //VL# 
        break;
    default:
        // 0x6809, 0x9320, 0x9325, 0x9335, 0xB505 can only scroll whole screen
        WriteCmdData(0x61, (1 << 1) | _lcd_rev);        //!NDL, VLE, REV
        WriteCmdData(0x6A, vsp);        //VL#
        break;
    }
}

void MCUFRIEND_kbv::invertDisplay(boolean i)
{
    uint8_t val;
    _lcd_rev = ((_lcd_capable & REV_SCREEN) != 0) ^ i;
    if (_lcd_capable & MIPI_DCS_REV1) {
        if (is8347) {
            // HX8347D: 0x36 Panel Characteristic. REV_Panel
            // HX8347A: 0x36 is Display Control 10
            if (_lcd_ID == 0x8347 || _lcd_ID == 0x5252) // HX8347-A, HX5352-A
			    val = _lcd_rev ? 6 : 2;       //INVON id bit#2,  NORON=bit#1
            else val = _lcd_rev ? 8 : 10;     //HX8347-D, G, I: SCROLLON=bit3, INVON=bit1
            // HX8347: 0x01 Display Mode has diff bit mapping for A, D 
            WriteCmdParamN(0x01, 1, &val);
        } else
            WriteCmdParamN(_lcd_rev ? 0x21 : 0x20, 0, NULL);
        return;
    }
    // cope with 9320 style variants:
    switch (_lcd_ID) {
#ifdef SUPPORT_0139
    case 0x0139:
#endif
    case 0x9225:                                        //REV is in reg(0x07) like Samsung
    case 0x0154:
        WriteCmdData(0x07, 0x13 | (_lcd_rev << 2));     //.kbv kludge
        break;
#ifdef SUPPORT_1289
    case 0x1289:
        _lcd_drivOut &= ~(1 << 13);
        if (_lcd_rev)
            _lcd_drivOut |= (1 << 13);
        WriteCmdData(0x01, _lcd_drivOut);
        break;
#endif
	case 0x5420:
    case 0x7793:
    case 0x9326:
	case 0xB509:
        WriteCmdData(0x401, (1 << 1) | _lcd_rev);       //.kbv kludge VLE 
        break;
    default:
        WriteCmdData(0x61, _lcd_rev);
        break;
    }
}

#define TFTLCD_DELAY 0xFFFF
#define TFTLCD_DELAY8 0x7F
static void init_table(const void *table, int16_t size)
{
#ifdef SUPPORT_8357D_GAMMA
    uint8_t *p = (uint8_t *) table, dat[36];            //HX8357_99 has GAMMA[34] 
#else
    uint8_t *p = (uint8_t *) table, dat[24];            //R61526 has GAMMA[22] 
#endif
    while (size > 0) {
        uint8_t cmd = pgm_read_byte(p++);
        uint8_t len = pgm_read_byte(p++);
        if (cmd == TFTLCD_DELAY8) {
            delay(len);
            len = 0;
        } else {
            for (uint8_t i = 0; i < len; i++)
                dat[i] = pgm_read_byte(p++);
            WriteCmdParamN(cmd, len, dat);
        }
        size -= len + 2;
    }
}

static void init_table16(const void *table, int16_t size)
{
    uint16_t *p = (uint16_t *) table;
    while (size > 0) {
        uint16_t cmd = pgm_read_word(p++);
        uint16_t d = pgm_read_word(p++);
        if (cmd == TFTLCD_DELAY)
            delay(d);
        else {
			writecmddata(cmd, d);                      //static function
        }
        size -= 2 * sizeof(int16_t);
    }
}

void MCUFRIEND_kbv::begin(uint16_t ID)
{
    int16_t *p16;               //so we can "write" to a const protected variable.
    const uint8_t *table8_ads = NULL;
    int16_t table_size;
    reset();
    _lcd_xor = 0;
    switch (_lcd_ID = ID) {
/*
	static const uint16_t _regValues[] PROGMEM = {
    0x0000, 0x0001, // start oscillation
    0x0007, 0x0000, //  source output control 0 D0 
    0x0013, 0x0000, // power control 3 off
    0x0011, 0x2604, //    
    0x0014, 0x0015, //   
    0x0010, 0x3C00, //  
 //    0x0013, 0x0040, // 
 //    0x0013, 0x0060, //     
 //    0x0013, 0x0070, // 
    0x0013, 0x0070, // power control 3 PON PON1 AON
       
    0x0001, 0x0127, //      driver output control
 //    0x0002, 0x0700, //  field 0 b/c waveform xor waveform
    0x0003, 0x1030, //    
    0x0007, 0x0000, //    
    0x0008, 0x0404, //    
    0x000B, 0x0200, // 
    0x000C, 0x0000, //   
    0x00015,0x0000, //     
       
    //gamma setting    
    0x0030, 0x0000,      
    0x0031, 0x0606,    
    0x0032, 0x0006,    
    0x0033, 0x0403,  
    0x0034, 0x0107,  
    0x0035, 0x0101, 
    0x0036, 0x0707,   
    0x0037, 0x0304,   
    0x0038, 0x0A00,     
    0x0039, 0x0706,     
       
    0x0040, 0x0000,     
    0x0041, 0x0000,      
    0x0042, 0x013F,    
    0x0043, 0x0000,   
    0x0044, 0x0000,     
    0x0045, 0x0000,     
    0x0046, 0xEF00,    
    0x0047, 0x013F,     
    0x0048, 0x0000,     
    0x0007, 0x0011,  
    0x0007, 0x0017,     
};
*/
#ifdef SUPPORT_0139
    case 0x0139:
        _lcd_capable = REV_SCREEN | XSA_XEA_16BIT;    //remove AUTO_READINC
        static const uint16_t S6D0139_regValues[] PROGMEM = {
            0x0000, 0x0001,     //Start oscillator
            0x0011, 0x1a00,     //Power Control 2
            0x0014, 0x2020,     //Power Control 4
            0x0010, 0x0900,     //Power Control 1
            0x0013, 0x0040,     //Power Control 3
            0x0013, 0x0060,     //Power Control 3
            0x0013, 0x0070,     //Power Control 3
            0x0011, 0x1a04,     //Power Control 2
            0x0010, 0x2f00,     //Power Control 1
            0x0001, 0x0127,     //Driver Control: SM=0, GS=0, SS=1, 240x320
            0x0002, 0x0100,     //LCD Control:  (.kbv was 0700) FLD=0, BC= 0, EOR=1
            0x0003, 0x1030,     //Entry Mode:    TR1=0, DFM=0, BGR=1, I_D=3   
            0x0007, 0x0000,     //Display Control: everything off
            0x0008, 0x0303,     //Blank Period:  FP=3, BP=3
            0x0009, 0x0000,     //f.k.
            0x000b, 0x0000,     //Frame Control:
            0x000c, 0x0000,     //Interface Control: system i/f
            0x0040, 0x0000,     //Scan Line
            0x0041, 0x0000,     //Vertical Scroll Control
            0x0007, 0x0014,     //Display Control: VLE1=0, SPT=0, GON=1, REV=1, D=0 (halt)
            0x0007, 0x0016,     //Display Control: VLE1=0, SPT=0, GON=1, REV=1, D=2 (blank)
            0x0007, 0x0017,     //Display Control: VLE1=0, SPT=0, GON=1, REV=1, D=3 (normal)
//            0x0007, 0x0217,     //Display Control: VLE1=1, SPT=0, GON=1, REV=1, D=3
        };
        init_table16(S6D0139_regValues, sizeof(S6D0139_regValues));
        break;
#endif

#ifdef SUPPORT_0154
    case 0x0154:
        _lcd_capable = AUTO_READINC | REV_SCREEN;
        static const uint16_t S6D0154_regValues[] PROGMEM = {
            0x0011, 0x001A,
            0x0012, 0x3121,     //BT=3, DC1=1, DC2=2, DC3=1
            0x0013, 0x006C,     //GVD=108
            0x0014, 0x4249,     //VCM=66, VML=73

            0x0010, 0x0800,     //SAP=8
            TFTLCD_DELAY, 10,
            0x0011, 0x011A,     //APON=0, PON=1, AON=0, VCI1_EN=1, VC=10
            TFTLCD_DELAY, 10,
            0x0011, 0x031A,     //APON=0, PON=3, AON=0, VCI1_EN=1, VC=10
            TFTLCD_DELAY, 10,
            0x0011, 0x071A,     //APON=0, PON=7, AON=0, VCI1_EN=1, VC=10
            TFTLCD_DELAY, 10,
            0x0011, 0x0F1A,     //APON=0, PON=15, AON=0, VCI1_EN=1, VC=10
            TFTLCD_DELAY, 10,
            0x0011, 0x0F3A,     //APON=0, PON=15, AON=1, VCI1_EN=1, VC=10 
            TFTLCD_DELAY, 30,

            0x0001, 0x0128,
            0x0002, 0x0100,
            0x0003, 0x1030,
            0x0007, 0x1012,
            0x0008, 0x0303,
            0x000B, 0x1100,
            0x000C, 0x0000,
            0x000F, 0x1801,
            0x0015, 0x0020,
            
               0x0050,0x0101,
               0x0051,0x0603,
               0x0052,0x0408,
               0x0053,0x0000,
               0x0054,0x0605,
               0x0055,0x0406,
               0x0056,0x0303,
               0x0057,0x0303,
               0x0058,0x0010,
               0x0059,0x1000,
            
            0x0007, 0x0012,     //GON=1, REV=0, D=2
            TFTLCD_DELAY, 40,
            0x0007, 0x0013,     //GON=1, REV=0, D=3
            0x0007, 0x0017,     //GON=1, REV=1, D=3 DISPLAY ON 
        };
        init_table16(S6D0154_regValues, sizeof(S6D0154_regValues));

        break;
#endif

#ifdef SUPPORT_1289
    case 0x9797:
        is9797 = 1;
//        _lcd_capable = 0 | XSA_XEA_16BIT | REV_SCREEN | AUTO_READINC | READ_24BITS;
// deliberately set READ_BGR to disable Software Scroll in graphictest_kbv example
        _lcd_capable = 0 | XSA_XEA_16BIT | REV_SCREEN | AUTO_READINC | READ_24BITS | READ_BGR;
        _lcd_ID = 0x1289;
        goto common_1289;
    case 0x1289:
        _lcd_capable = 0 | XSA_XEA_16BIT | REV_SCREEN | AUTO_READINC;
      common_1289:
        // came from MikroElektronika library http://www.hmsprojects.com/tft_lcd.html
        static const uint16_t SSD1289_regValues[] PROGMEM = {
            0x0000, 0x0001,
            0x0003, 0xA8A4,
            0x000C, 0x0000,
            0x000D, 0x000A,     // VRH=10
            0x000E, 0x2B00,
            0x001E, 0x00B7,
            0x0001, 0x2B3F,     // setRotation() alters
            0x0002, 0x0600,     // B_C=1, EOR=1
            0x0010, 0x0000,
            0x0011, 0x6070,     // setRotation() alters 
            0x0005, 0x0000,
            0x0006, 0x0000,
            0x0016, 0xEF1C,
            0x0017, 0x0003,
            0x0007, 0x0233,
            0x000B, 0x0000,
            0x000F, 0x0000,
            0x0030, 0x0707,
            0x0031, 0x0204,
            0x0032, 0x0204,
            0x0033, 0x0502,
            0x0034, 0x0507,
            0x0035, 0x0204,
            0x0036, 0x0204,
            0x0037, 0x0502,
            0x003A, 0x0302,
            0x003B, 0x0302,
            0x0023, 0x0000,
            0x0024, 0x0000,
            0x0025, 0x8000,
        };
        init_table16(SSD1289_regValues, sizeof(SSD1289_regValues));
        break;
#endif

    case 0x1511:                // Unknown from Levy
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1;   //extra read_8(dummy)
        static const uint8_t R61511_regValues[] PROGMEM = {
			0xB0, 1, 0x00,       //Command Access Protect
        };
        table8_ads = R61511_regValues, table_size = sizeof(R61511_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;

    case 0x1520:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t R61520_regValues[] PROGMEM = {
            0xB0, 1, 0x00,      //Command Access Protect
            0xC0, 1, 0x0A,      //DM=1, BGR=1
        };
        table8_ads = R61520_regValues, table_size = sizeof(R61520_regValues);
        break;

	case 0x1526:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t R61526_regValues[] PROGMEM = {
            0xB0, 1, 0x03,      //Command Access 
            0xE2, 1, 0x3F,      //Command Write Access
            0xC0, 1, 0x22,      //REV=0, BGR=1, SS=0
            0xE2, 1, 0x00,      //Command Write Protect
        };
        table8_ads = R61526_regValues, table_size = sizeof(R61526_regValues);
        break;

#ifdef SUPPORT_1580
    case 0x1580:
        _lcd_capable = 0 | REV_SCREEN | READ_BGR | INVERT_GS | READ_NODUMMY; //thanks vanhan123
        static const uint16_t R61580_regValues[] PROGMEM = {  //from MCHIP Graphics Lib drvTFT001.c
            // Synchronization after reset
            TFTLCD_DELAY, 2,
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0000,

            // Setup display
            0x00A4, 0x0001,          // CALB=1
            TFTLCD_DELAY, 2,
            0x0060, 0xA700,          // Driver Output Control
            0x0008, 0x0808,          // Display Control BP=8, FP=8
            0x0030, 0x0111,          // y control
            0x0031, 0x2410,          // y control
            0x0032, 0x0501,          // y control
            0x0033, 0x050C,          // y control
            0x0034, 0x2211,          // y control
            0x0035, 0x0C05,          // y control
            0x0036, 0x2105,          // y control
            0x0037, 0x1004,          // y control
            0x0038, 0x1101,          // y control
            0x0039, 0x1122,          // y control
            0x0090, 0x0019,          // 80Hz
            0x0010, 0x0530,          // Power Control
            0x0011, 0x0237,          //DC1=2, DC0=3, VC=7
//            0x0011, 0x17B0,          //DC1=7, DC0=3, VC=0 ?b12 ?b7 vanhan123
            0x0012, 0x01BF,          //VCMR=1, PSON=1, PON=1, VRH=15 
//            0x0012, 0x013A,          //VCMR=1, PSON=1, PON=1, VRH=10 vanhan123
            0x0013, 0x1300,          //VDV=19
            TFTLCD_DELAY, 100,

            0x0001, 0x0100,
            0x0002, 0x0200,
            0x0003, 0x1030,
            0x0009, 0x0001,
            0x000A, 0x0008,
            0x000C, 0x0001,
            0x000D, 0xD000,
            0x000E, 0x0030,
            0x000F, 0x0000,
            0x0020, 0x0000,
            0x0021, 0x0000,
            0x0029, 0x0077,
            0x0050, 0x0000,
            0x0051, 0xD0EF,
            0x0052, 0x0000,
            0x0053, 0x013F,
            0x0061, 0x0001,
            0x006A, 0x0000,
            0x0080, 0x0000,
            0x0081, 0x0000,
            0x0082, 0x005F,
            0x0093, 0x0701,
            0x0007, 0x0100,
        };
        static const uint16_t R61580_DEM240320C[] PROGMEM = { //from DEM 240320C TMH-PW-N
            0x00, 0x0000,
            0x00, 0x0000,
            TFTLCD_DELAY, 100,
            0x00, 0x0000,
            0x00, 0x0000,
            0x00, 0x0000,
            0x00, 0x0000,
            0xA4, 0x0001,
            TFTLCD_DELAY, 100,
            0x60, 0xA700,
            0x08, 0x0808,
            /******************************************/
            //Gamma Setting:
            0x30, 0x0203,
            0x31, 0x080F,
            0x32, 0x0401,
            0x33, 0x050B,
            0x34, 0x3330,
            0x35, 0x0B05,
            0x36, 0x0005,
            0x37, 0x0F08,
            0x38, 0x0302,
            0x39, 0x3033,
            /******************************************/
            //Power Setting:
            0x90, 0x0018, //80Hz
            0x10, 0x0530, //BT,AP
            0x11, 0x0237, //DC1,DC0,VC
            0x12, 0x01BF,
            0x13, 0x1000, //VCOM
            TFTLCD_DELAY, 200,
            /******************************************/
            0x01, 0x0100,
            0x02, 0x0200,
            0x03, 0x1030,
            0x09, 0x0001,
            0x0A, 0x0008,
            0x0C, 0x0000,
            0x0D, 0xD000,

            0x0E, 0x0030,
            0x0F, 0x0000,
            0x20, 0x0000, //H Start
            0x21, 0x0000, //V Start
            0x29, 0x002E,
            0x50, 0x0000,
            0x51, 0x00EF,
            0x52, 0x0000,
            0x53, 0x013F,
            0x61, 0x0001,
            0x6A, 0x0000,
            0x80, 0x0000,
            0x81, 0x0000,
            0x82, 0x005F,
            0x93, 0x0701,
            /******************************************/
            0x07, 0x0100,
            TFTLCD_DELAY, 100,
        };
        init_table16(R61580_DEM240320C, sizeof(R61580_DEM240320C));
//        init_table16(R61580_regValues, sizeof(R61580_regValues));
        break;
#endif

#if defined(SUPPORT_1963) && USING_16BIT_BUS 
    case 0x1963:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | READ_NODUMMY | INVERT_SS | INVERT_RGB;
        // from NHD 5.0" 8-bit
        static const uint8_t SSD1963_NHD_50_regValues[] PROGMEM = {
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    // Lock PLL
            (0xB0), 7, 0x08, 0x80, 0x03, 0x1F, 0x01, 0xDF, 0x00,        //LCD SPECIFICATION
            (0xF0), 1, 0x03,    //was 00 pixel data interface
            //            (0x3A), 1, 0x60,        // SET R G B format = 6 6 6
            (0xE2), 3, 0x1D, 0x02, 0x54,        //PLL multiplier, set PLL clock to 120M
            (0xE6), 3, 0x02, 0xFF, 0xFF,        //PLL setting for PCLK, depends on resolution
            (0xB4), 8, 0x04, 0x20, 0x00, 0x58, 0x80, 0x00, 0x00, 0x00,  //HSYNC
            (0xB6), 7, 0x02, 0x0D, 0x00, 0x20, 0x01, 0x00, 0x00,        //VSYNC
            (0x13), 0,          //Enter Normal mode
            (0x38), 0,          //Exit Idle mode
        };
        // from NHD 7.0" 8-bit
        static const uint8_t SSD1963_NHD_70_regValues[] PROGMEM = {
            (0xE2), 3, 0x1D, 0x02, 0x04,        //PLL multiplier, set PLL clock to 120M
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    // Lock PLL
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 120,
            (0xB0), 7, 0x08, 0x80, 0x03, 0x1F, 0x01, 0xDF, 0x00,        //LCD SPECIFICATION
            (0xF0), 1, 0x03,    //was 00 pixel data interface
            //            (0x3A), 1, 0x60,        // SET R G B format = 6 6 6
            (0xE6), 3, 0x0F, 0xFF, 0xFF,        //PLL setting for PCLK, depends on resolution
            (0xB4), 8, 0x04, 0x20, 0x00, 0x58, 0x80, 0x00, 0x00, 0x00,  //HSYNC
            (0xB6), 7, 0x02, 0x0D, 0x00, 0x20, 0x01, 0x00, 0x00,        //VSYNC
            (0x13), 0,          //Enter Normal mode
            (0x38), 0,          //Exit Idle mode
        };
        // from UTFTv2.81 initlcd.h
        static const uint8_t SSD1963_800_regValues[] PROGMEM = {
            (0xE2), 3, 0x1E, 0x02, 0x54,        //PLL multiplier, set PLL clock to 120M
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    //
            TFTLCD_DELAY8, 10,
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 100,
            (0xE6), 3, 0x03, 0xFF, 0xFF,        //PLL setting for PCLK, depends on resolution
            (0xB0), 7, 0x24, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x00,        //LCD SPECIFICATION
            //            (0xB0), 7, 0x24, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x2D,        //LCD SPECIFICATION
            (0xB4), 8, 0x03, 0xA0, 0x00, 0x2E, 0x30, 0x00, 0x0F, 0x00,  //HSYNC
            (0xB6), 7, 0x02, 0x0D, 0x00, 0x10, 0x10, 0x00, 0x08,        //VSYNC
            (0xBA), 1, 0x0F,    //GPIO[3:0] out 1
            (0xB8), 2, 0x07, 0x01,      //GPIO3=input, GPIO[2:0]=output
            (0xF0), 1, 0x03,    //pixel data interface
            TFTLCD_DELAY8, 1,
            0x28, 0,            //Display Off
            0x11, 0,            //Sleep Out
            TFTLCD_DELAY8, 100,
            0x29, 0,            //Display On
            (0xBE), 6, 0x06, 0xF0, 0x01, 0xF0, 0x00, 0x00,      //set PWM for B/L
            (0xD0), 1, 0x0D,
        };
        // from UTFTv2.82 initlcd.h
        static const uint8_t SSD1963_800NEW_regValues[] PROGMEM = {
            (0xE2), 3, 0x1E, 0x02, 0x54,        //PLL multiplier, set PLL clock to 120M
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    //
            TFTLCD_DELAY8, 10,
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 100,
            (0xE6), 3, 0x03, 0xFF, 0xFF,        //PLL setting for PCLK, depends on resolution
            (0xB0), 7, 0x24, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x00,        //LCD SPECIFICATION
            (0xB4), 8, 0x03, 0xA0, 0x00, 0x2E, 0x30, 0x00, 0x0F, 0x00,  //HSYNC HT=928, HPS=46, HPW=48, LPS=15
            (0xB6), 7, 0x02, 0x0D, 0x00, 0x10, 0x10, 0x00, 0x08,        //VSYNC VT=525, VPS=16, VPW=16, FPS=8
            (0xBA), 1, 0x0F,    //GPIO[3:0] out 1
            (0xB8), 2, 0x07, 0x01,      //GPIO3=input, GPIO[2:0]=output
            (0xF0), 1, 0x03,    //pixel data interface
            TFTLCD_DELAY8, 1,
            0x28, 0,            //Display Off
            0x11, 0,            //Sleep Out
            TFTLCD_DELAY8, 100,
            0x29, 0,            //Display On
            (0xBE), 6, 0x06, 0xF0, 0x01, 0xF0, 0x00, 0x00,      //set PWM for B/L
            (0xD0), 1, 0x0D,
        };
        // from UTFTv2.82 initlcd.h
        static const uint8_t SSD1963_800ALT_regValues[] PROGMEM = {
            (0xE2), 3, 0x23, 0x02, 0x04,        //PLL multiplier, set PLL clock to 120M
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    //
            TFTLCD_DELAY8, 10,
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 100,
            (0xE6), 3, 0x04, 0x93, 0xE0,        //PLL setting for PCLK, depends on resolution
            (0xB0), 7, 0x00, 0x00, 0x03, 0x1F, 0x01, 0xDF, 0x00,        //LCD SPECIFICATION
            (0xB4), 8, 0x03, 0xA0, 0x00, 0x2E, 0x30, 0x00, 0x0F, 0x00,  //HSYNC HT=928, HPS=46, HPW=48, LPS=15
            (0xB6), 7, 0x02, 0x0D, 0x00, 0x10, 0x10, 0x00, 0x08,        //VSYNC VT=525, VPS=16, VPW=16, FPS=8
            (0xBA), 1, 0x0F,    //GPIO[3:0] out 1
            (0xB8), 2, 0x07, 0x01,      //GPIO3=input, GPIO[2:0]=output
            (0xF0), 1, 0x03,    //pixel data interface
            TFTLCD_DELAY8, 1,
            0x28, 0,            //Display Off
            0x11, 0,            //Sleep Out
            TFTLCD_DELAY8, 100,
            0x29, 0,            //Display On
            (0xBE), 6, 0x06, 0xF0, 0x01, 0xF0, 0x00, 0x00,      //set PWM for B/L
            (0xD0), 1, 0x0D,
        };
        // from UTFTv2.82 initlcd.h
        static const uint8_t SSD1963_480_regValues[] PROGMEM = {
            (0xE2), 3, 0x23, 0x02, 0x54,        //PLL multiplier, set PLL clock to 120M
            (0xE0), 1, 0x01,    // PLL enable
            TFTLCD_DELAY8, 10,
            (0xE0), 1, 0x03,    //
            TFTLCD_DELAY8, 10,
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 100,
            (0xE6), 3, 0x01, 0x1F, 0xFF,        //PLL setting for PCLK, depends on resolution
            (0xB0), 7, 0x20, 0x00, 0x01, 0xDF, 0x01, 0x0F, 0x00,        //LCD SPECIFICATION
            (0xB4), 8, 0x02, 0x13, 0x00, 0x08, 0x2B, 0x00, 0x02, 0x00,  //HSYNC
            (0xB6), 7, 0x01, 0x20, 0x00, 0x04, 0x0C, 0x00, 0x02,        //VSYNC
            (0xBA), 1, 0x0F,    //GPIO[3:0] out 1
            (0xB8), 2, 0x07, 0x01,      //GPIO3=input, GPIO[2:0]=output
            (0xF0), 1, 0x03,    //pixel data interface
            TFTLCD_DELAY8, 1,
            0x28, 0,            //Display Off
            0x11, 0,            //Sleep Out
            TFTLCD_DELAY8, 100,
            0x29, 0,            //Display On
            (0xBE), 6, 0x06, 0xF0, 0x01, 0xF0, 0x00, 0x00,      //set PWM for B/L
            (0xD0), 1, 0x0D,
        };
//        table8_ads = SSD1963_480_regValues, table_size = sizeof(SSD1963_480_regValues);
        table8_ads = SSD1963_800_regValues, table_size = sizeof(SSD1963_800_regValues);
//        table8_ads = SSD1963_NHD_50_regValues, table_size = sizeof(SSD1963_NHD_50_regValues);
//        table8_ads = SSD1963_NHD_70_regValues, table_size = sizeof(SSD1963_NHD_70_regValues);
//        table8_ads = SSD1963_800NEW_regValues, table_size = sizeof(SSD1963_800NEW_regValues);
//        table8_ads = SSD1963_800ALT_regValues, table_size = sizeof(SSD1963_800ALT_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 800;
        break;
#endif

#ifdef SUPPORT_4532
//Support for LG Electronics LGDP4532 (also 4531 i guess) by Leodino v1.0 2-Nov-2016
//based on data by waveshare and the datasheet of LG Electronics
//My approach to get it working: the parameters by waveshare did no make it function allright
//I started with remming lines to see if this helped. Basically the stuff in range 41-93
//gives problems.
//The other lines that are REMmed give no problems, but it seems default values are OK as well.
case 0x4532:    // thanks Leodino
	_lcd_capable = 0 | REV_SCREEN;  // | INVERT_GS;
	static const uint16_t LGDP4532_regValues[] PROGMEM = {
		0x0000,0x0001, //Device code read
		0x0010,0x0628, //Power control 1 SAP[2:0] BT[3:0] AP[2:0] DK DSTB SLP
		0x0012,0x0006, //Power control 3 PON VRH[3:0]
		//0x0013,0x0A32, //Power control 4 VCOMG VDV[4:0] VCM[6:0]
		0x0011,0x0040, //Power control 2; DC1[2:0] DC0[2:0] VC[2:0]
		//0x0015,0x0050, //Regulator control RSET RI[2:0] RV[2:0] RCONT[2:0]
		0x0012,0x0016, //Power control 3 PON VRH[3:0]
		TFTLCD_DELAY,50,
		0x0010,0x5660, //Power control 1 SAP[2:0] BT[3:0] AP[2:0] DK DSTB SLP
		TFTLCD_DELAY,50,
		//0x0013,0x2A4E, //Power control 4 VCOMG VDV[4:0] VCM[6:0]
		//0x0001,0x0100, //Driver output control SM SS
		//0x0002,0x0300, //LCD Driving Wave Control
		//0x0003,0x1030, //Entry mode TRI DFM  BGR  ORG I/D[1:0] AM
		//0x0007,0x0202, //Display Control 1 PTDE[1:0] BASEE GON DTE COL D[1:0]
		TFTLCD_DELAY,50,
		//0x0008,0x0202, //Display Control 2 FP[3:0] BP[3:0] front and back porch (blank period at begin and end..)
		//0x000A,0x0000, //Test Register 1 (RA0h)
		//Gamma adjustment
		0x0030,0x0000,
		0x0031,0x0402,
		0x0032,0x0106,
		0x0033,0x0700,
		0x0034,0x0104,
		0x0035,0x0301,
		0x0036,0x0707,
		0x0037,0x0305,
		0x0038,0x0208,
		0x0039,0x0F0B,
		TFTLCD_DELAY,50,
		//some of this stuff in range 41-93 really throws things off....
		//0x0041,0x0002,
		//0x0060,0x2700, //Driver Output Control (R60h)
		//0x0061,0x0001, //Base Image Display Control (R61h)
		//0x0090,0x0119,   //Panel Interface Control 1 (R90h) DIVI[1:0]  RTNI[4:0]
		//0x0092,0x010A,  //Panel Interface Control 2 (R92h)  NOWI[2:0] EQI2[1:0] EQI1[1:0]
		//0x0093,0x0004, //Panel Interface Control 3 (R93h) MCPI[2:0]
		//0x00A0,0x0100, //Test Register 1 (RA0h)
		TFTLCD_DELAY,50,
		0x0007,0x0133, //Display Control 1 PTDE[1:0] BASEE GON DTE COL D[1:0]
		TFTLCD_DELAY,50,
		//0x00A0,0x0000, //Test Register 1 (RA0h)
		};
	init_table16(LGDP4532_regValues, sizeof(LGDP4532_regValues));
	break;
#endif

#ifdef SUPPORT_4535
    case 0x4535:
        _lcd_capable = 0 | REV_SCREEN;  // | INVERT_GS;
        static const uint16_t LGDP4535_regValues[] PROGMEM = {
            0x0015, 0x0030,     // Set the internal vcore voltage                                               
            0x009A, 0x0010,     // Start internal OSC 
            0x0011, 0x0020,     // set SS and SM bit 
            0x0010, 0x3428,     // set 1 line inversion 
            0x0012, 0x0002,     // set GRAM write direction and BGR=1  
            0x0013, 0x1038,     // Resize register 
            TFTLCD_DELAY, 40,
            0x0012, 0x0012,     // set the back porch and front porch 
            TFTLCD_DELAY, 40,
            0x0010, 0x3420,     // set non-display area refresh cycle ISC[3:0] 
            0x0013, 0x3045,     // FMARK function 
            TFTLCD_DELAY, 70,
            0x0030, 0x0000,     // RGB interface setting 
            0x0031, 0x0402,     // Frame marker Position 
            0x0032, 0x0307,     // RGB interface polarity 
            0x0033, 0x0304,     // SAP, BT[3:0], AP, DSTB, SLP, STB 
            0x0034, 0x0004,     // DC1[2:0], DC0[2:0], VC[2:0] 
            0x0035, 0x0401,     // VREG1OUT voltage 
            0x0036, 0x0707,     // VDV[4:0] for VCOM amplitude 
            0x0037, 0x0305,     // SAP, BT[3:0], AP, DSTB, SLP, STB 
            0x0038, 0x0610,     // DC1[2:0], DC0[2:0], VC[2:0] 
            0x0039, 0x0610,     // VREG1OUT voltage 
            0x0001, 0x0100,     // VDV[4:0] for VCOM amplitude 
            0x0002, 0x0300,     // VCM[4:0] for VCOMH 
            0x0003, 0x1030,     // GRAM horizontal Address 
            0x0008, 0x0808,     // GRAM Vertical Address 
            0x000A, 0x0008,
            0x0060, 0x2700,     // Gate Scan Line 
            0x0061, 0x0001,     // NDL,VLE, REV 
            0x0090, 0x013E,
            0x0092, 0x0100,
            0x0093, 0x0100,
            0x00A0, 0x3000,
            0x00A3, 0x0010,
            0x0007, 0x0001,
            0x0007, 0x0021,
            0x0007, 0x0023,
            0x0007, 0x0033,
            0x0007, 0x0133,
        };
        init_table16(LGDP4535_regValues, sizeof(LGDP4535_regValues));
        break;
#endif

    case 0x5310:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | INVERT_RGB | READ_24BITS;
        static const uint8_t NT35310_regValues[] PROGMEM = {        //
            TFTLCD_DELAY8, 10,    //just some dummy
        };
        table8_ads = NT35310_regValues, table_size = sizeof(NT35310_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;

#ifdef SUPPORT_68140
    case 0x6814:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS;
		static const uint8_t RM68140_regValues_max[] PROGMEM = {        //
            0x3A, 1, 0x55,      //Pixel format .kbv my Mega Shield
        };
        table8_ads = RM68140_regValues_max, table_size = sizeof(RM68140_regValues_max);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;
#endif

#ifdef SUPPORT_7735
    case 0x7735:                //
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN | READ_24BITS;
        static const uint8_t PROGMEM table7735S[] = {
            //  (COMMAND_BYTE), n, data_bytes....
            0xB1, 3, 0x01, 0x2C, 0x2D,  // [05 3C 3C] FRMCTR1 if GM==11
            0xB2, 3, 0x01, 0x2C, 0x2D,  // [05 3C 3C]
            0xB3, 6, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, // [05 3C 3C 05 3C 3C]
            0xB4, 1, 0x07,              // [07] INVCTR Column inversion
            //ST7735XR Power Sequence
            0xC0, 3, 0xA2, 0x02, 0x84,  // [A8 08 84] PWCTR1
            0xC1, 1, 0xC5,              // [C0]
            0xC2, 2, 0x0A, 0x00,        // [0A 00]
            0xC3, 2, 0x8A, 0x2A,        // [8A 26]
            0xC4, 2, 0x8A, 0xEE,        // [8A EE]
            0xC5, 1, 0x0E,              // [05] VMCTR1 VCOM
        };
        table8_ads = table7735S, table_size = sizeof(table7735S);   //
        p16 = (int16_t *) & HEIGHT;
        *p16 = 160;
        p16 = (int16_t *) & WIDTH;
        *p16 = 128;
        break;
#endif

#ifdef SUPPORT_7781
    case 0x7783:
        _lcd_capable = AUTO_READINC | REV_SCREEN | INVERT_GS;
        static const uint16_t ST7781_regValues[] PROGMEM = {
            0x00FF, 0x0001,     //can we do 0xFF
            0x00F3, 0x0008,
            //  LCD_Write_COM(0x00F3,

            0x00, 0x0001,
            0x0001, 0x0100,     // Driver Output Control Register (R01h)
            0x0002, 0x0700,     // LCD Driving Waveform Control (R02h)
            0x0003, 0x1030,     // Entry Mode (R03h)
            0x0008, 0x0302,
            0x0009, 0x0000,
            0x0010, 0x0000,     // Power Control 1 (R10h)
            0x0011, 0x0007,     // Power Control 2 (R11h)
            0x0012, 0x0000,     // Power Control 3 (R12h)
            0x0013, 0x0000,     // Power Control 4 (R13h)
            TFTLCD_DELAY, 50,
            0x0010, 0x14B0,     // Power Control 1 SAP=1, BT=4, APE=1, AP=3
            TFTLCD_DELAY, 10,
            0x0011, 0x0007,     // Power Control 2 VC=7
            TFTLCD_DELAY, 10,
            0x0012, 0x008E,     // Power Control 3 VCIRE=1, VRH=14
            0x0013, 0x0C00,     // Power Control 4 VDV=12
            0x0029, 0x0015,     // NVM read data 2 VCM=21
            TFTLCD_DELAY, 10,
            0x0030, 0x0000,     // Gamma Control 1
            0x0031, 0x0107,     // Gamma Control 2
            0x0032, 0x0000,     // Gamma Control 3
            0x0035, 0x0203,     // Gamma Control 6
            0x0036, 0x0402,     // Gamma Control 7
            0x0037, 0x0000,     // Gamma Control 8
            0x0038, 0x0207,     // Gamma Control 9
            0x0039, 0x0000,     // Gamma Control 10
            0x003C, 0x0203,     // Gamma Control 13
            0x003D, 0x0403,     // Gamma Control 14
            0x0060, 0xA700,     // Driver Output Control (R60h) .kbv was 0xa700
            0x0061, 0x0001,     // Driver Output Control (R61h)
            0x0090, 0X0029,     // Panel Interface Control 1 (R90h)

            // Display On
            0x0007, 0x0133,     // Display Control (R07h)
            TFTLCD_DELAY, 50,
        };
        init_table16(ST7781_regValues, sizeof(ST7781_regValues));
        break;
#endif

    case 0x7789:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t ST7789_regValues[] PROGMEM = {
            (0xB2), 5, 0x0C, 0x0C, 0x00, 0x33, 0x33,    //PORCTRK: Porch setting [08 08 00 22 22] PSEN=0 anyway
            (0xB7), 1, 0x35,    //GCTRL: Gate Control [35]
            (0xBB), 1, 0x2B,    //VCOMS: VCOM setting VCOM=1.175 [20] VCOM=0.9
            (0xC0), 1, 0x04,    //LCMCTRL: LCM Control [2C]
            (0xC2), 2, 0x01, 0xFF,      //VDVVRHEN: VDV and VRH Command Enable [01 FF]
            (0xC3), 1, 0x11,    //VRHS: VRH Set VAP=4.4, VAN=-4.4 [0B]
            (0xC4), 1, 0x20,    //VDVS: VDV Set [20]
            (0xC6), 1, 0x0F,    //FRCTRL2: Frame Rate control in normal mode [0F]
            (0xD0), 2, 0xA4, 0xA1,      //PWCTRL1: Power Control 1 [A4 A1]
            (0xE0), 14, 0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19,     //PVGAMCTRL: Positive Voltage Gamma control        
            (0xE1), 14, 0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19,     //NVGAMCTRL: Negative Voltage Gamma control
        };
        static const uint8_t ST7789_regValues_arcain6[] PROGMEM = {
            (0xB2), 5, 0x0C, 0x0C, 0x00, 0x33, 0x33,    //PORCTRK: Porch setting [08 08 00 22 22] PSEN=0 anyway
            (0xB7), 1, 0x35,    //GCTRL: Gate Control [35]
            (0xBB), 1, 0x35,    //VCOMS: VCOM setting VCOM=??? [20] VCOM=0.9
            (0xC0), 1, 0x2C,    //LCMCTRL: LCM Control [2C]
            (0xC2), 2, 0x01, 0xFF,      //VDVVRHEN: VDV and VRH Command Enable [01 FF]
            (0xC3), 1, 0x13,    //VRHS: VRH Set VAP=???, VAN=-??? [0B]
            (0xC4), 1, 0x20,    //VDVS: VDV Set [20]
            (0xC6), 1, 0x0F,    //FRCTRL2: Frame Rate control in normal mode [0F]
            (0xCA), 1, 0x0F,    //REGSEL2 [0F]
            (0xC8), 1, 0x08,    //REGSEL1 [08]
            (0x55), 1, 0x90,    //WRCACE  [00]
            (0xD0), 2, 0xA4, 0xA1,      //PWCTRL1: Power Control 1 [A4 A1]
            (0xE0), 14, 0xD0, 0x00, 0x06, 0x09, 0x0B, 0x2A, 0x3C, 0x55, 0x4B, 0x08, 0x16, 0x14, 0x19, 0x20,     //PVGAMCTRL: Positive Voltage Gamma control        
            (0xE1), 14, 0xD0, 0x00, 0x06, 0x09, 0x0B, 0x29, 0x36, 0x54, 0x4B, 0x0D, 0x16, 0x14, 0x21, 0x20,     //NVGAMCTRL: Negative Voltage Gamma control
        };
        table8_ads = ST7789_regValues, table_size = sizeof(ST7789_regValues); //
        break;

    case 0x8031:      //Unknown BangGood thanks PrinceCharles
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | REV_SCREEN;
        static const uint8_t FK8031_regValues[] PROGMEM = {
            // 0xF2:8.2 = SM, 0xF2:8.0 = REV. invertDisplay(), vertScroll() do not work
            0xF2,11, 0x16, 0x16, 0x03, 0x08, 0x08, 0x08, 0x08, 0x10, 0x04, 0x16, 0x16, // f.k. 0xF2:8.2 SM=1
            0xFD, 3, 0x11, 0x02, 0x35,     //f.k 0xFD:1.1 creates contiguous scan lins
        };
        table8_ads = FK8031_regValues, table_size = sizeof(FK8031_regValues);
        break;

#ifdef SUPPORT_8347D
    case 0x4747:       //HX8347-D
        _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | AUTO_READINC | READ_24BITS;
		goto common_8347DGI;
    case 0x6767:       //HX8367-A
	case 0x7575:       //HX8347-G
	case 0x9595:       //HX8347-I
        _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS;
      common_8347DGI:  
		is8347 = 1;
        static const uint8_t HX8347G_2_regValues[] PROGMEM = {
            0xEA, 2, 0x00, 0x20,        //PTBA[15:0]
            0xEC, 2, 0x0C, 0xC4,        //STBA[15:0]
            0xE8, 1, 0x38,      //OPON[7:0]
            0xE9, 1, 0x10,      //OPON1[7:0]
            0xF1, 1, 0x01,      //OTPS1B
            0xF2, 1, 0x10,      //GEN
            //Gamma 2.2 Setting
            0x40, 13, 0x01, 0x00, 0x00, 0x10, 0x0E, 0x24, 0x04, 0x50, 0x02, 0x13, 0x19, 0x19, 0x16,
            0x50, 14, 0x1B, 0x31, 0x2F, 0x3F, 0x3F, 0x3E, 0x2F, 0x7B, 0x09, 0x06, 0x06, 0x0C, 0x1D, 0xCC,
            //Power Voltage Setting
            0x1B, 1, 0x1B,      //VRH=4.65V
            0x1A, 1, 0x01,      //BT (VGH~15V,VGL~-10V,DDVDH~5V)
            0x24, 1, 0x2F,      //VMH(VCOM High voltage ~3.2V)
            0x25, 1, 0x57,      //VML(VCOM Low voltage -1.2V)
            //****VCOM offset**///
            0x23, 1, 0x88,      //for Flicker adjust //can reload from OTP
            //Power on Setting
            0x18, 1, 0x34,      //I/P_RADJ,N/P_RADJ, Normal mode 60Hz
            0x19, 1, 0x01,      //OSC_EN='1', start Osc
            0x01, 1, 0x00,      //DP_STB='0', out deep sleep
            0x1F, 1, 0x88,      // GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0
            TFTLCD_DELAY8, 5,
            0x1F, 1, 0x80,      // GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0
            TFTLCD_DELAY8, 3,
            0x1F, 1, 0x90,      // GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0
            TFTLCD_DELAY8, 5,
            0x1F, 1, 0xD0,      // GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
            TFTLCD_DELAY8, 5,
            //262k/65k color selection
            0x17, 1, 0x05,      //default 0x06 262k color // 0x05 65k color
            //SET PANEL
            0x36, 1, 0x00,      //SS_P, GS_P,REV_P,BGR_P
            //Display ON Setting
            0x28, 1, 0x38,      //GON=1, DTE=1, D=1000
            TFTLCD_DELAY8, 40,
            0x28, 1, 0x3F,      //GON=1, DTE=1, D=1100

            0x16, 1, 0x18,
        };
        init_table(HX8347G_2_regValues, sizeof(HX8347G_2_regValues));
        break;
#endif
		
#ifdef SUPPORT_8352A
	case 0x5252:       //HX8352-A
        _lcd_capable = MIPI_DCS_REV1 | MV_AXIS;
        is8347 = 1;
        static const uint8_t HX8352A_regValues[] PROGMEM = {
            0x83, 1, 0x02,      //Test Mode: TESTM=1
            0x85, 1, 0x03,      //VDD ctl  : VDC_SEL=3 [05]
            0x8B, 1, 0x01,      //VGS_RES 1: RES_VGS1=1 
            0x8C, 1, 0x93,      //VGS_RES 2: RES_VGS2=1, anon=0x13 [93]
            0x91, 1, 0x01,      //PWM control: SYNC=1
            0x83, 1, 0x00,      //Test Mode: TESTM=0
            //Gamma  Setting
            0x3E, 12, 0xB0, 0x03, 0x10, 0x56, 0x13, 0x46, 0x23, 0x76, 0x00, 0x5E, 0x4F, 0x40,
            //Power Voltage Setting
            0x17, 1, 0x91,      //OSC   1: RADJ=9, OSC_EN=1 [F0]
            0x2B, 1, 0xF9,      //Cycle 1: N_DC=F9 [BE]
            TFTLCD_DELAY8, 10,
            0x1B, 1, 0x14,      //Power 3: BT=1, ??=1, AP=0 [42]  
            0x1A, 1, 0x11,      //Power 2: VC3=1, VC1=1 [05]
            0x1C, 1, 0x06,      //Power 4: VRH=6 [0D]
            0x1F, 1, 0x42,      //VCOM   : VCM=42 [55]
            TFTLCD_DELAY8, 20,
            0x19, 1, 0x0A,      //Power 1: DK=1, VL_TR1=1 [09]
            0x19, 1, 0x1A,      //Power 1: PON=1, DK=1, VL_TR1=1 [09]
            TFTLCD_DELAY8, 40,
            0x19, 1, 0x12,      //Power 1: PON=1, DK=1, STB=1 [09]
            TFTLCD_DELAY8, 40,
            0x1E, 1, 0x27,      //Power 6: VCOMG=1, VDV=7 [10]
            TFTLCD_DELAY8, 100,
            //Display ON Setting
            0x24, 1, 0x60,      //Display 2: PT=1, GON=1 [A0]
            0x3D, 1, 0x40,      //Source 1: N_SAP=40 [C0]
            0x34, 1, 0x38,      //Cycle 10: EQS=0x38 [38]
            0x35, 1, 0x38,      //Cycle 11: EQP=0x38 [38]
            0x24, 1, 0x38,      //Display 2: GON=1 D=2 [A0]
            TFTLCD_DELAY8, 40,
            0x24, 1, 0x3C,      //Display 2: GON=1 D=3 [A0]
            0x16, 1, 0x1C,      //Memaccess: GS=1, BGR=1, SS=1 
            0x01, 1, 0x06,      //Disp Mode: INVON=1, NORON=1 [02]
            0x55, 1, 0x06,      //SM_PANEL=0, SS_PANEL=0, GS_PANEL=1, REV_PANEL=1, BGR_PANEL=0
        };
        init_table(HX8352A_regValues, sizeof(HX8352A_regValues));
        p16 = (int16_t *) & HEIGHT;
        *p16 = 400;
        break;
#endif

#ifdef SUPPORT_8352B
    case 0x0065:       //HX8352-B
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | REV_SCREEN;
        is8347 = 1;
        static const uint8_t HX8352B_regValues[] PROGMEM = {
            // Register setting for EQ setting
            0xe5, 1, 0x10,      //
            0xe7, 1, 0x10,      //
            0xe8, 1, 0x48,      //
            0xec, 1, 0x09,      //
            0xed, 1, 0x6c,      //
            // Power on Setting
            0x23, 1, 0x6F,      //VMF
            0x24, 1, 0x57,      //VMH
            0x25, 1, 0x71,      //VML
            0xE2, 1, 0x18,      //
            0x1B, 1, 0x15,      //VRH
            0x01, 1, 0x00,      //
            0x1C, 1, 0x03,      //AP=3
            // Power on sequence
            0x19, 1, 0x01,      //OSCEN=1
            TFTLCD_DELAY8, 5,
            0x1F, 1, 0x8C,      //GASEN=1, DK=1, XDK=1
            0x1F, 1, 0x84,      //GASEN=1, XDK=1
            TFTLCD_DELAY8, 10,
            0x1F, 1, 0x94,      //GASEN=1, PON=1, XDK=1
            TFTLCD_DELAY8, 10,
            0x1F, 1, 0xD4,      //GASEN=1, VCOMG=1, PON=1, XDK=1
            TFTLCD_DELAY8, 5,
            // Gamma Setting
            0x40, 13, 0x00, 0x2B, 0x29, 0x3E, 0x3D, 0x3F, 0x24, 0x74, 0x08, 0x06, 0x07, 0x0D, 0x17,
            0x50, 13, 0x00, 0x02, 0x01, 0x16, 0x14, 0x3F, 0x0B, 0x5B, 0x08, 0x12, 0x18, 0x19, 0x17,
            0x5D, 1, 0xFF,      //

            0x16, 1, 0x08,      //MemoryAccess BGR=1
            0x28, 1, 0x20,      //GON=1
            TFTLCD_DELAY8, 40,
            0x28, 1, 0x38,      //GON=1, DTE=1, D=2
            TFTLCD_DELAY8, 40,
            0x28, 1, 0x3C,      //GON=1, DTE=1, D=3

            0x02, 2, 0x00, 0x00,     //SC
            0x04, 2, 0x00, 0xEF,     //EC
            0x06, 2, 0x00, 0x00,     //SP
            0x08, 2, 0x01, 0x8F,     //EP

            0x80, 2, 0x00, 0x00,     //CAC
            0x82, 2, 0x00, 0x00,     //RAC
            0x17, 1, 0x05,      //COLMOD = 565

        };
        init_table(HX8352B_regValues, sizeof(HX8352B_regValues));
        p16 = (int16_t *) & HEIGHT;
        *p16 = 400;
        break;
#endif

#ifdef SUPPORT_8347A
    case 0x8347:
        _lcd_capable = REV_SCREEN | MIPI_DCS_REV1 | MV_AXIS;
        // AN.01 The reference setting of CMO 3.2” Panel
        static const uint8_t HX8347A_CMO32_regValues[] PROGMEM = {
            //  VENDOR Gamma for 3.2"
            (0x46), 12, 0xA4, 0x53, 0x00, 0x44, 0x04, 0x67, 0x33, 0x77, 0x12, 0x4C, 0x46, 0x44,
            // Display Setting
            (0x01), 1, 0x06,    // IDMON=0, INVON=1, NORON=1, PTLON=0
            (0x16), 1, 0x48,    // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0
            (0x23), 3, 0x95, 0x95, 0xFF,        // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111

            (0x27), 4, 0x02, 0x02, 0x02, 0x02,  // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2
            (0x2C), 2, 0x02, 0x02,      // I_BP=2, I_FP=2

            (0x3a), 4, 0x01, 0x01, 0xF0, 0x00,  // N_RTN=0, N_NW=1, P_RTN=0, P_NW=1, I_RTN=15, I_NW=0, DIV=0
            TFTLCD_DELAY8, 5,
            (0x35), 2, 0x38, 0x78,      // EQS=38h, EQP=78h
            (0x3E), 1, 0x38,    // SON=38h
            (0x40), 2, 0x0F, 0xF0,      // GDON=0Fh, GDOFF 
            // Power Supply Setting
            (0x19), 1, 0x49,    // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz
            (0x93), 1, 0x0F,    // RADJ=1111, 100%
            TFTLCD_DELAY8, 5,
            (0x20), 1, 0x40,    // BT=0100
            (0x1D), 3, 0x07, 0x00, 0x04,        // VC1=7, VC3=0, VRH=??
            //VCOM SETTING for 3.2"
            (0x44), 2, 0x4D, 0x11,      // VCM=100 1101, VDV=1 0001   
            TFTLCD_DELAY8, 10,
            (0x1C), 1, 0x04,    // AP=100
            TFTLCD_DELAY8, 20,
            (0x1B), 1, 0x18,    // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 40,
            (0x1B), 1, 0x10,    // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 40,
            (0x43), 1, 0x80,    //set VCOMG=1
            TFTLCD_DELAY8, 100,
            // Display ON Setting
            (0x90), 1, 0x7F,    // SAP=0111 1111
            (0x26), 1, 0x04,    //GON=0, DTE=0, D=01
            TFTLCD_DELAY8, 40,
            (0x26), 1, 0x24,    //GON=1, DTE=0, D=01
            (0x26), 1, 0x2C,    //GON=1, DTE=0, D=11
            TFTLCD_DELAY8, 40,
            (0x26), 1, 0x3C,    //GON=1, DTE=1, D=11
            // INTERNAL REGISTER SETTING
            (0x57), 1, 0x02,    // TEST_Mode=1: into TEST mode
            (0x55), 1, 0x00,    // VDC_SEL=000, VDDD=1.95V
            (0xFE), 1, 0x5A,    // For ESD protection
            (0x57), 1, 0x00,    // TEST_Mode=0: exit TEST mode
        };
        // AN.01 The reference setting of CMO 2.4” Panel
        static const uint8_t HX8347A_CMO24_regValues[] PROGMEM = {
            //  VENDOR Gamma for 2.4"
            (0x46), 12, 0x94, 0x41, 0x00, 0x33, 0x23, 0x45, 0x44, 0x77, 0x12, 0xCC, 0x46, 0x82,
            // Display Setting
            (0x01), 1, 0x06,    // IDMON=0, INVON=1, NORON=1, PTLON=0
            (0x16), 1, 0x48,    // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0
            (0x23), 3, 0x95, 0x95, 0xFF,        // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111

            (0x27), 4, 0x02, 0x02, 0x02, 0x02,  // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2
            (0x2C), 2, 0x02, 0x02,      // I_BP=2, I_FP=2

            (0x3a), 4, 0x01, 0x01, 0xF0, 0x00,  // N_RTN=0, N_NW=1, P_RTN=0, P_NW=1, I_RTN=15, I_NW=0, DIV=0
            TFTLCD_DELAY8, 5,
            (0x35), 2, 0x38, 0x78,      // EQS=38h, EQP=78h
            (0x3E), 1, 0x38,    // SON=38h
            (0x40), 2, 0x0F, 0xF0,      // GDON=0Fh, GDOFF 
            // Power Supply Setting
            (0x19), 1, 0x49,    // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz
            (0x93), 1, 0x0F,    // RADJ=1111, 100%
            TFTLCD_DELAY8, 5,
            (0x20), 1, 0x40,    // BT=0100
            (0x1D), 3, 0x07, 0x00, 0x04,        // VC1=7, VC3=0, VRH=??
            //VCOM SETTING for 2.4"
            (0x44), 2, 0x40, 0x12,      // VCM=100 0000, VDV=1 0001   
            TFTLCD_DELAY8, 10,
            (0x1C), 1, 0x04,    // AP=100
            TFTLCD_DELAY8, 20,
            (0x1B), 1, 0x18,    // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 40,
            (0x1B), 1, 0x10,    // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 40,
            (0x43), 1, 0x80,    //set VCOMG=1
            TFTLCD_DELAY8, 100,
            // Display ON Setting
            (0x90), 1, 0x7F,    // SAP=0111 1111
            (0x26), 1, 0x04,    //GON=0, DTE=0, D=01
            TFTLCD_DELAY8, 40,
            (0x26), 1, 0x24,    //GON=1, DTE=0, D=01
            (0x26), 1, 0x2C,    //GON=1, DTE=0, D=11
            TFTLCD_DELAY8, 40,
            (0x26), 1, 0x3C,    //GON=1, DTE=1, D=11
            // INTERNAL REGISTER SETTING
            (0x57), 1, 0x02,    // TEST_Mode=1: into TEST mode
            (0x55), 1, 0x00,    // VDC_SEL=000, VDDD=1.95V
            (0xFE), 1, 0x5A,    // For ESD protection
            (0x57), 1, 0x00,    // TEST_Mode=0: exit TEST mode
        };
        static const uint8_t HX8347A_ITDB02_regValues[] PROGMEM = {
            //  VENDOR Gamma ITDB02 same as CMO32.   Delays are shorter than AN01
            (0x46), 12, 0xA4, 0x53, 0x00, 0x44, 0x04, 0x67, 0x33, 0x77, 0x12, 0x4C, 0x46, 0x44,
            // Display Setting
            (0x01), 1, 0x06,    // IDMON=0, INVON=1, NORON=1, PTLON=0
            (0x16), 1, 0xC8,    // MY=0, MX=0, MV=0, ML=1, BGR=0, TEON=0 .itead
            (0x23), 3, 0x95, 0x95, 0xFF,        // N_DC=1001 0101, PI_DC=1001 0101, I_DC=1111 1111

            (0x27), 4, 0x02, 0x02, 0x02, 0x02,  // N_BP=2, N_FP=2, PI_BP=2, PI_FP=2
            (0x2C), 2, 0x02, 0x02,      // I_BP=2, I_FP=2

            (0x3a), 4, 0x01, 0x00, 0xF0, 0x00,  // N_RTN=0, N_NW=1, P_RTN=0, ?? P_NW=1, I_RTN=15, I_NW=0, DIV=0 .itead
            TFTLCD_DELAY8, 5,
            (0x35), 2, 0x38, 0x78,      // EQS=38h, EQP=78h
            (0x3E), 1, 0x38,    // SON=38h
            (0x40), 2, 0x0F, 0xF0,      // GDON=0Fh, GDOFF 
            // Power Supply Setting 
            (0x19), 1, 0x49,    // CADJ=0100, CUADJ=100, OSD_EN=1 ,60Hz
            (0x93), 1, 0x0F,    // RADJ=1111, 100%
            TFTLCD_DELAY8, 5,
            (0x20), 1, 0x40,    // BT=0100
            (0x1D), 3, 0x07, 0x00, 0x04,        // VC1=7, VC3=0, VRH=??
            //VCOM SETTING for ITDB02
            (0x44), 2, 0x4D, 0x0E,      // VCM=101 0000  4D, VDV=1 0001 .itead
            TFTLCD_DELAY8, 5,
            (0x1C), 1, 0x04,    // AP=100
            TFTLCD_DELAY8, 5,
            (0x1B), 1, 0x18,    // GASENB=0, PON=0, DK=1, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 5,
            (0x1B), 1, 0x10,    // GASENB=0, PON=1, DK=0, XDK=0, VLCD_TRI=0, STB=0
            TFTLCD_DELAY8, 5,
            (0x43), 1, 0x80,    //set VCOMG=1
            TFTLCD_DELAY8, 5,
            // Display ON Setting
            (0x90), 1, 0x7F,    // SAP=0111 1111
            (0x26), 1, 0x04,    //GON=0, DTE=0, D=01
            TFTLCD_DELAY8, 5,
            (0x26), 1, 0x24,    //GON=1, DTE=0, D=01
            (0x26), 1, 0x2C,    //GON=1, DTE=0, D=11
            TFTLCD_DELAY8, 5,
            (0x26), 1, 0x3C,    //GON=1, DTE=1, D=11
            // INTERNAL REGISTER SETTING for ITDB02
            (0x57), 1, 0x02,    // TEST_Mode=1: into TEST mode
            (0x95), 1, 0x01,    // SET DISPLAY CLOCK AND PUMPING CLOCK TO SYNCHRONIZE .itead
            (0x57), 1, 0x00,    // TEST_Mode=0: exit TEST mode
        };
        static const uint8_t HX8347A_NHD_regValues[] PROGMEM = {
            //Gamma Setting NHD
            (0x46), 12, 0x94, 0x41, 0x00, 0x33, 0x23, 0x45, 0x44, 0x77, 0x12, 0xCC, 0x46, 0x82,
            (0x01), 1, 0x06,    //Display Mode [06]
            (0x16), 1, 0xC8,    //MADCTL [00] MY=1, MX=1, BGR=1
//            (0x70), 1, 0x05,    //Panel [06] 16-bit
            (0x23), 3, 0x95, 0x95, 0xFF,        //Cycle Control 1-3 [95 95 FF]
            (0x27), 4, 0x02, 0x02, 0x02, 0x02,  //Display Control 2-5 [02 02 02 02]
            (0x2C), 2, 0x02, 0x02,      //Display Control 6-7 [02 02]
            (0x3A), 4, 0x01, 0x01, 0xF0, 0x00,  //Cycle Control 1-4 [01 01 F0 00]
            TFTLCD_DELAY8, 80,
            (0x35), 2, 0x38, 0x78,      //Display Control 9-10 [09 09] EQS=56, EQP=120
            (0x3E), 1, 0x38,    //Cycle Control 5 [38]  
            (0x40), 1, 0x0F,    //Cycle Control 6 [03]  GDON=15
            (0x41), 1, 0xF0,    //Cycle Control 14 [F8] GDOF=248

            (0x19), 1, 0x2D,    //OSC Control 1 [86] CADJ=2, CUADJ=6, OSCEN=1
            (0x93), 1, 0x06,    //SAP Idle mode [00] ???  .nhd
            TFTLCD_DELAY8, 80,
            (0x20), 1, 0x40,    //Power Control 6 [40]
            (0x1D), 3, 0x07, 0x00, 0x04,        //Power Control 3-5 [04 00 06] VC=7
            (0x44), 2, 0x3C, 0x12,      //VCOM Control 2-3 [5A 11] VCM=60, VDV=18
            TFTLCD_DELAY8, 80,
            (0x1C), 1, 0x04,    //Power Control 2 [04]
            TFTLCD_DELAY8, 80,
            (0x43), 1, 0x80,    //VCOM Control 1 [80]
            TFTLCD_DELAY8, 80,
            (0x1B), 1, 0x08,    //Power Control 1 [00] DK=1
            TFTLCD_DELAY8, 80,
            (0x1B), 1, 0x10,    //Power Control 1 [00] PON=1
            TFTLCD_DELAY8, 80,
            (0x90), 1, 0x7F,    //Display Control 8 [0A]
            (0x26), 1, 0x04,    //Display Control 1 [A0] D=1
            TFTLCD_DELAY8, 80,
            (0x26), 1, 0x24,    //Display Control 1 [A0] GON=1, D=1
            (0x26), 1, 0x2C,    //Display Control 1 [A0] GON=1, D=3 
            TFTLCD_DELAY8, 80,
            (0x26), 1, 0x3C,    //Display Control 1 [A0] GON=1, DTE=1, D=3
            (0x57), 1, 0x02,    //?
            (0x55), 1, 0x00,    //?
            (0x57), 1, 0x00,    //? 
        };
        // Atmel ASF code uses VCOM2-3: 0x38, 0x12. 50ms delays and no TEST mode changes.
        init_table(HX8347A_NHD_regValues, sizeof(HX8347A_NHD_regValues));
        //        init_table(HX8347A_CMO32_regValues, sizeof(HX8347A_CMO32_regValues));
        //        init_table(HX8347A_CMO24_regValues, sizeof(HX8347A_CMO24_regValues));
        //        init_table(HX8347A_ITDB02_regValues, sizeof(HX8347A_ITDB02_regValues));
        //        init_table(HX8347G_2_regValues, sizeof(HX8347G_2_regValues));
        break;
#endif

    case 0x8357:                //BIG CHANGE: HX8357-B is now 0x8357
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN;
        goto common_8357;
    case 0x9090:                //BIG CHANGE: HX8357-D was 0x8357
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN | READ_24BITS;
      common_8357:
        static const uint8_t HX8357C_regValues[] PROGMEM = {
            TFTLCD_DELAY8, 1,  //dummy table
        };
        table8_ads = HX8357C_regValues, table_size = sizeof(HX8357C_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;

    case 0x0099:                //HX8357-D matches datasheet
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN | READ_24BITS;
        static const uint8_t HX8357_99_regValues[] PROGMEM = {
            (0xB9), 3, 0xFF, 0x83, 0x57,   // SETEXTC
            TFTLCD_DELAY8, 150,
            TFTLCD_DELAY8, 150,
            (0xB6), 1, 0x25,   // SETCOM [4B 00] -2.5V+37*0.02V=-1.76V [-1.00V]
            (0xC0), 6, 0x50, 0x50, 0x01, 0x3C, 0x1E, 0x08,  // SETSTBA [73 50 00 3C C4 08]
            (0xB4), 7, 0x02, 0x40, 0x00, 0x2A, 0x2A, 0x0D, 0x78, // SETCYC [02 40 00 2A 2A 0D 96]
#ifdef SUPPORT_8357D_GAMMA
            // HX8357D_SETGAMMA [0B 0C 11 1D 25 37 43 4B 4E 47 41 39 35 31 2E 21 1C 1D 1D 26 31 44 4E 56 44 3F 39 33 31 2E 28 1D E0 01]
            (0xE0),34, 0x02, 0x0A, 0x11, 0x1D, 0x23, 0x35, 0x41, 0x4B, 0x4B, 0x42, 0x3A, 0x27, 0x1B, 0x08, 0x09, 0x03, 0x02, 0x0A, 0x11, 0x1D, 0x23, 0x35, 0x41, 0x4B, 0x4B, 0x42, 0x3A, 0x27, 0x1B, 0x08, 0x09, 0x03, 0x00, 0x01,
#endif
        };
        table8_ads = HX8357_99_regValues, table_size = sizeof(HX8357_99_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;

#ifdef SUPPORT_8230
    case 0x8230:    //thanks Auzman
        _lcd_capable = 0 | REV_SCREEN | INVERT_GS | INVERT_RGB | READ_BGR;
        static const uint16_t UC8230_regValues[] PROGMEM = {
            //After pin Reset wait at least 100ms
            TFTLCD_DELAY, 100, //at least 100ms
            0x0046, 0x0002, //MTP Disable
            0x0010, 0x1590, //SAP=1, BT=5, APE=1, AP=1
            0x0011, 0x0227, //DC1=2, DC0=2, VC=7
            0x0012, 0x80ff, //P5VMD=1, PON=7, VRH=15
            0x0013, 0x9c31, //VDV=28, VCM=49
            TFTLCD_DELAY, 10, //at least 10ms
            0x0002, 0x0300, //set N-line = 1
            0x0003, 0x1030, //set GRAM writing direction & BGR=1
            0x0060, 0xa700, //GS; gate scan: start position & drive line Q'ty
            0x0061, 0x0001, //REV, NDL, VLE
            /*--------------------Gamma control------------------------*/
            0x0030, 0x0303,
            0x0031, 0x0303,
            0x0032, 0x0303,
            0x0033, 0x0300,
            0x0034, 0x0003,
            0x0035, 0x0303,
            0x0036, 0x1400,
            0x0037, 0x0303,
            0x0038, 0x0303,
            0x0039, 0x0303,
            0x003a, 0x0300,
            0x003b, 0x0003,
            0x003c, 0x0303,
            0x003d, 0x1400,
            //-----------------------------------------------------------//
            0x0020, 0x0000, //GRAM horizontal address
            0x0021, 0x0000, //GRAM vertical address
            //************** Partial Display control*********************//
            0x0080, 0x0000,
            0x0081, 0x0000,
            0x0082, 0x0000,
            0x0083, 0x0000,
            0x0084, 0x0000,
            0x0085, 0x0000,
            //-----------------------------------------------------------//
            0x0092, 0x0200,
            0x0093, 0x0303,
            0x0090, 0x0010, //set clocks/Line
            0x0000, 0x0001,
            TFTLCD_DELAY, 200, // Delay 200 ms
            0x0007, 0x0173, //Display on setting
        };
        init_table16(UC8230_regValues, sizeof(UC8230_regValues));
        break;
#endif

#ifdef SUPPORT_9163
    case 0x9163:                //
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t PROGMEM table9163C[] = {
            //  (COMMAND_BYTE), n, data_bytes....
            0x26, 1, 0x02,       // [01] GAMMASET use CURVE=1, 2, 4, 8
            0xB1, 2, 0x08, 0x02, // [0E 14] FRMCTR1 if GM==011 61.7Hz
            0xB4, 1, 0x07,       // [02] INVCTR
            0xB8, 1, 0x01,       // [00] GSCTRL
            0xC0, 2, 0x0A, 0x02, // [0A 05] PWCTR1 if LCM==10
            0xC1, 1, 0x02,       // [07] PWCTR2
            0xC5, 2, 0x50, 0x63, // [43 4D] VMCTR1
            0xC7, 1, 0,          // [40] VCOMOFFS
        };
        table8_ads = table9163C, table_size = sizeof(table9163C);   //
        p16 = (int16_t *) & HEIGHT;
        *p16 = 160;
        p16 = (int16_t *) & WIDTH;
        *p16 = 128;
        break;
#endif

#ifdef SUPPORT_9225
#define ILI9225_DRIVER_OUTPUT_CTRL      (0x01u)  // Driver Output Control
#define ILI9225_LCD_AC_DRIVING_CTRL     (0x02u)  // LCD AC Driving Control
#define ILI9225_ENTRY_MODE                (0x03u)  // Entry Mode
#define ILI9225_DISP_CTRL1              (0x07u)  // Display Control 1
#define ILI9225_BLANK_PERIOD_CTRL1      (0x08u)  // Blank Period Control
#define ILI9225_FRAME_CYCLE_CTRL        (0x0Bu)  // Frame Cycle Control
#define ILI9225_INTERFACE_CTRL          (0x0Cu)  // Interface Control
#define ILI9225_OSC_CTRL                (0x0Fu)  // Osc Control
#define ILI9225_POWER_CTRL1             (0x10u)  // Power Control 1
#define ILI9225_POWER_CTRL2             (0x11u)  // Power Control 2
#define ILI9225_POWER_CTRL3             (0x12u)  // Power Control 3
#define ILI9225_POWER_CTRL4             (0x13u)  // Power Control 4
#define ILI9225_POWER_CTRL5             (0x14u)  // Power Control 5
#define ILI9225_VCI_RECYCLING           (0x15u)  // VCI Recycling
#define ILI9225_RAM_ADDR_SET1           (0x20u)  // Horizontal GRAM Address Set
#define ILI9225_RAM_ADDR_SET2           (0x21u)  // Vertical GRAM Address Set
#define ILI9225_GRAM_DATA_REG           (0x22u)  // GRAM Data Register
#define ILI9225_GATE_SCAN_CTRL          (0x30u)  // Gate Scan Control Register
#define ILI9225_VERTICAL_SCROLL_CTRL1   (0x31u)  // Vertical Scroll Control 1 Register
#define ILI9225_VERTICAL_SCROLL_CTRL2   (0x32u)  // Vertical Scroll Control 2 Register
#define ILI9225_VERTICAL_SCROLL_CTRL3   (0x33u)  // Vertical Scroll Control 3 Register
#define ILI9225_PARTIAL_DRIVING_POS1    (0x34u)  // Partial Driving Position 1 Register
#define ILI9225_PARTIAL_DRIVING_POS2    (0x35u)  // Partial Driving Position 2 Register
#define ILI9225_HORIZONTAL_WINDOW_ADDR1 (0x36u)  // Horizontal Address END Position   HEA
#define ILI9225_HORIZONTAL_WINDOW_ADDR2 (0x37u)  // Horizontal Address START Position HSA
#define ILI9225_VERTICAL_WINDOW_ADDR1   (0x38u)  // Vertical Address END Position     VEA
#define ILI9225_VERTICAL_WINDOW_ADDR2   (0x39u)  // Vertical Address START Position   VSA
#define ILI9225_GAMMA_CTRL1             (0x50u)  // Gamma Control 1
#define ILI9225_GAMMA_CTRL2             (0x51u)  // Gamma Control 2
#define ILI9225_GAMMA_CTRL3             (0x52u)  // Gamma Control 3
#define ILI9225_GAMMA_CTRL4             (0x53u)  // Gamma Control 4
#define ILI9225_GAMMA_CTRL5             (0x54u)  // Gamma Control 5
#define ILI9225_GAMMA_CTRL6             (0x55u)  // Gamma Control 6
#define ILI9225_GAMMA_CTRL7             (0x56u)  // Gamma Control 7
#define ILI9225_GAMMA_CTRL8             (0x57u)  // Gamma Control 8
#define ILI9225_GAMMA_CTRL9             (0x58u)  // Gamma Control 9
#define ILI9225_GAMMA_CTRL10            (0x59u)  // Gamma Control 10

#define ILI9225C_INVOFF  0x20
#define ILI9225C_INVON   0x21

    case 0x6813:
    case 0x9226:
        _lcd_ID = 0x9225;                //fall through
    case 0x9225:
        _lcd_capable = REV_SCREEN | READ_BGR;     //thanks tongbajiel
        static const uint16_t ILI9225_regValues[] PROGMEM = {
            /* Start Initial Sequence */
            /* Set SS bit and direction output from S528 to S1 */
            ILI9225_POWER_CTRL1, 0x0000, // Set SAP,DSTB,STB
            ILI9225_POWER_CTRL2, 0x0000, // Set APON,PON,AON,VCI1EN,VC
            ILI9225_POWER_CTRL3, 0x0000, // Set BT,DC1,DC2,DC3
            ILI9225_POWER_CTRL4, 0x0000, // Set GVDD
            ILI9225_POWER_CTRL5, 0x0000, // Set VCOMH/VCOML voltage
            TFTLCD_DELAY, 40,

            // Power-on sequence
            ILI9225_POWER_CTRL2, 0x0018, // Set APON,PON,AON,VCI1EN,VC
            ILI9225_POWER_CTRL3, 0x6121, // Set BT,DC1,DC2,DC3
            ILI9225_POWER_CTRL4, 0x006F, // Set GVDD   /*007F 0088 */
            ILI9225_POWER_CTRL5, 0x495F, // Set VCOMH/VCOML voltage
            ILI9225_POWER_CTRL1, 0x0800, // Set SAP,DSTB,STB
            TFTLCD_DELAY, 10,
            ILI9225_POWER_CTRL2, 0x103B, // Set APON,PON,AON,VCI1EN,VC
            TFTLCD_DELAY, 50,

            ILI9225_DRIVER_OUTPUT_CTRL, 0x011C, // set the display line number and display direction
            ILI9225_LCD_AC_DRIVING_CTRL, 0x0100, // set 1 line inversion
            ILI9225_ENTRY_MODE, 0x1030, // set GRAM write direction and BGR=1.
            ILI9225_DISP_CTRL1, 0x0000, // Display off
            ILI9225_BLANK_PERIOD_CTRL1, 0x0808, // set the back porch and front porch
            ILI9225_FRAME_CYCLE_CTRL, 0x1100, // set the clocks number per line
            ILI9225_INTERFACE_CTRL, 0x0000, // CPU interface
            ILI9225_OSC_CTRL, 0x0D01, // Set Osc  /*0e01*/
            ILI9225_VCI_RECYCLING, 0x0020, // Set VCI recycling
            ILI9225_RAM_ADDR_SET1, 0x0000, // RAM Address
            ILI9225_RAM_ADDR_SET2, 0x0000, // RAM Address

            /* Set GRAM area */
            ILI9225_GATE_SCAN_CTRL, 0x0000,
            ILI9225_VERTICAL_SCROLL_CTRL1, 0x00DB,
            ILI9225_VERTICAL_SCROLL_CTRL2, 0x0000,
            ILI9225_VERTICAL_SCROLL_CTRL3, 0x0000,
            ILI9225_PARTIAL_DRIVING_POS1, 0x00DB,
            ILI9225_PARTIAL_DRIVING_POS2, 0x0000,
            ILI9225_HORIZONTAL_WINDOW_ADDR1, 0x00AF,
            ILI9225_HORIZONTAL_WINDOW_ADDR2, 0x0000,
            ILI9225_VERTICAL_WINDOW_ADDR1, 0x00DB,
            ILI9225_VERTICAL_WINDOW_ADDR2, 0x0000,

            /* Set GAMMA curve */
            ILI9225_GAMMA_CTRL1, 0x0000,
            ILI9225_GAMMA_CTRL2, 0x0808,
            ILI9225_GAMMA_CTRL3, 0x080A,
            ILI9225_GAMMA_CTRL4, 0x000A,
            ILI9225_GAMMA_CTRL5, 0x0A08,
            ILI9225_GAMMA_CTRL6, 0x0808,
            ILI9225_GAMMA_CTRL7, 0x0000,
            ILI9225_GAMMA_CTRL8, 0x0A00,
            ILI9225_GAMMA_CTRL9, 0x0710,
            ILI9225_GAMMA_CTRL10, 0x0710,

            ILI9225_DISP_CTRL1, 0x0012,
            TFTLCD_DELAY, 50,
            ILI9225_DISP_CTRL1, 0x1017,
        };
        init_table16(ILI9225_regValues, sizeof(ILI9225_regValues));
        p16 = (int16_t *) & HEIGHT;
        *p16 = 220;
        p16 = (int16_t *) & WIDTH;
        *p16 = 176;
        break;
#endif

    case 0x0001:
        _lcd_capable = 0 | REV_SCREEN | INVERT_GS; //no RGB bug. thanks Ivo_Deshev
        goto common_9320;
    case 0x5408:
        _lcd_capable = 0 | REV_SCREEN | READ_BGR; //Red 2.4" thanks jorgenv, Ardlab_Gent
//        _lcd_capable = 0 | REV_SCREEN | READ_BGR | INVERT_GS; //Blue 2.8" might be different
        goto common_9320;
    case 0x1505:                //R61505 thanks Ravi_kanchan2004. R61505V, R61505W different
    case 0x9320:
        _lcd_capable = 0 | REV_SCREEN | READ_BGR;
      common_9320:
        static const uint16_t ILI9320_regValues[] PROGMEM = {
            0x00e5, 0x8000,
            0x0000, 0x0001,
            0x0001, 0x100,
            0x0002, 0x0700,
            0x0003, 0x1030,
            0x0004, 0x0000,
            0x0008, 0x0202,
            0x0009, 0x0000,
            0x000A, 0x0000,
            0x000C, 0x0000,
            0x000D, 0x0000,
            0x000F, 0x0000,
            //-----Power On sequence-----------------------
            0x0010, 0x0000,
            0x0011, 0x0007,
            0x0012, 0x0000,
            0x0013, 0x0000,
            TFTLCD_DELAY, 50,
            0x0010, 0x17B0,  //SAP=1, BT=7, APE=1, AP=3
            0x0011, 0x0007,  //DC1=0, DC0=0, VC=7
            TFTLCD_DELAY, 10,
            0x0012, 0x013A,  //VCMR=1, PON=3, VRH=10
            TFTLCD_DELAY, 10,
            0x0013, 0x1A00,  //VDV=26
            0x0029, 0x000c,  //VCM=12
            TFTLCD_DELAY, 10,
            //-----Gamma control-----------------------
            0x0030, 0x0000,
            0x0031, 0x0505,
            0x0032, 0x0004,
            0x0035, 0x0006,
            0x0036, 0x0707,
            0x0037, 0x0105,
            0x0038, 0x0002,
            0x0039, 0x0707,
            0x003C, 0x0704,
            0x003D, 0x0807,
            //-----Set RAM area-----------------------
            0x0060, 0xA700,     //GS=1
            0x0061, 0x0001,
            0x006A, 0x0000,
            0x0021, 0x0000,
            0x0020, 0x0000,
            //-----Partial Display Control------------
            0x0080, 0x0000,
            0x0081, 0x0000,
            0x0082, 0x0000,
            0x0083, 0x0000,
            0x0084, 0x0000,
            0x0085, 0x0000,
            //-----Panel Control----------------------
            0x0090, 0x0010,
            0x0092, 0x0000,
            0x0093, 0x0003,
            0x0095, 0x0110,
            0x0097, 0x0000,
            0x0098, 0x0000,
            //-----Display on-----------------------
            0x0007, 0x0173,
            TFTLCD_DELAY, 50,
        };
        init_table16(ILI9320_regValues, sizeof(ILI9320_regValues));
        break;
    case 0x6809:
        _lcd_capable = 0 | REV_SCREEN | INVERT_GS | AUTO_READINC;
        goto common_93x5;
    case 0x9328:
    case 0x9325:
        _lcd_capable = 0 | REV_SCREEN | INVERT_GS;
        goto common_93x5;
    case 0x9331:
    case 0x9335:
        _lcd_capable = 0 | REV_SCREEN;
      common_93x5:
        static const uint16_t ILI9325_regValues[] PROGMEM = {
            0x00E5, 0x78F0,     // set SRAM internal timing
            0x0001, 0x0100,     // set Driver Output Control
            0x0002, 0x0200,     // set 1 line inversion
            0x0003, 0x1030,     // set GRAM write direction and BGR=1.
            0x0004, 0x0000,     // Resize register
            0x0005, 0x0000,     // .kbv 16bits Data Format Selection
            0x0008, 0x0207,     // set the back porch and front porch
            0x0009, 0x0000,     // set non-display area refresh cycle ISC[3:0]
            0x000A, 0x0000,     // FMARK function
            0x000C, 0x0000,     // RGB interface setting
            0x000D, 0x0000,     // Frame marker Position
            0x000F, 0x0000,     // RGB interface polarity
            // ----------- Power On sequence ----------- //
            0x0010, 0x0000,     // SAP, BT[3:0], AP, DSTB, SLP, STB
            0x0011, 0x0007,     // DC1[2:0], DC0[2:0], VC[2:0]
            0x0012, 0x0000,     // VREG1OUT voltage
            0x0013, 0x0000,     // VDV[4:0] for VCOM amplitude
            0x0007, 0x0001,
            TFTLCD_DELAY, 200,  // Dis-charge capacitor power voltage
            0x0010, 0x1690,     // SAP=1, BT=6, APE=1, AP=1, DSTB=0, SLP=0, STB=0
            0x0011, 0x0227,     // DC1=2, DC0=2, VC=7
            TFTLCD_DELAY, 50,   // wait_ms 50ms
            0x0012, 0x000D,     // VCIRE=1, PON=0, VRH=5
            TFTLCD_DELAY, 50,   // wait_ms 50ms
            0x0013, 0x1200,     // VDV=28 for VCOM amplitude
            0x0029, 0x000A,     // VCM=10 for VCOMH
            0x002B, 0x000D,     // Set Frame Rate
            TFTLCD_DELAY, 50,   // wait_ms 50ms
            0x0020, 0x0000,     // GRAM horizontal Address
            0x0021, 0x0000,     // GRAM Vertical Address
            // ----------- Adjust the Gamma Curve ----------//

            0x0030, 0x0000,
            0x0031, 0x0404,
            0x0032, 0x0003,
            0x0035, 0x0405,
            0x0036, 0x0808,
            0x0037, 0x0407,
            0x0038, 0x0303,
            0x0039, 0x0707,
            0x003C, 0x0504,
            0x003D, 0x0808,

            //------------------ Set GRAM area ---------------//
            0x0060, 0x2700,     // Gate Scan Line GS=0 [0xA700] 
            0x0061, 0x0001,     // NDL,VLE, REV .kbv
            0x006A, 0x0000,     // set scrolling line
            //-------------- Partial Display Control ---------//
            0x0080, 0x0000,
            0x0081, 0x0000,
            0x0082, 0x0000,
            0x0083, 0x0000,
            0x0084, 0x0000,
            0x0085, 0x0000,
            //-------------- Panel Control -------------------//
            0x0090, 0x0010,
            0x0092, 0x0000,
            0x0007, 0x0133,     // 262K color and display ON
        };
        init_table16(ILI9325_regValues, sizeof(ILI9325_regValues));
        break;

#if defined(SUPPORT_9326_5420)
	case 0x5420:
    case 0x9326:
        _lcd_capable = REV_SCREEN | READ_BGR;
        static const uint16_t ILI9326_CPT28_regValues[] PROGMEM = {
//************* Start Initial Sequence **********//
         0x0702, 0x3008,     //  Set internal timing, don’t change this value
         0x0705, 0x0036,     //  Set internal timing, don’t change this value
         0x070B, 0x1213,     //  Set internal timing, don’t change this value
         0x0001, 0x0100,     //  set SS and SM bit
         0x0002, 0x0100,     //  set 1 line inversion
         0x0003, 0x1030,     //  set GRAM write direction and BGR=1.
         0x0008, 0x0202,     //  set the back porch and front porch
         0x0009, 0x0000,     //  set non-display area refresh cycle ISC[3:0]
         0x000C, 0x0000,     //  RGB interface setting
         0x000F, 0x0000,     //  RGB interface polarity
//*************Power On sequence ****************//
         0x0100, 0x0000,     //  SAP, BT[3:0], AP, DSTB, SLP, STB
         0x0102, 0x0000,     //  VREG1OUT voltage
         0x0103, 0x0000,   // VDV[4:0] for VCOM amplitude
        TFTLCD_DELAY, 200,   // Dis-charge capacitor power voltage
         0x0100, 0x1190,   // SAP, BT[3:0], AP, DSTB, SLP, STB
         0x0101, 0x0227,   // DC1[2:0], DC0[2:0], VC[2:0]
        TFTLCD_DELAY, 50,   // Delay 50ms
         0x0102, 0x01BD,   // VREG1OUT voltage
        TFTLCD_DELAY, 50,   // Delay 50ms
         0x0103, 0x2D00,   // VDV[4:0] for VCOM amplitude
         0x0281, 0x000E,   // VCM[5:0] for VCOMH
        TFTLCD_DELAY, 50,   //
         0x0200, 0x0000,   // GRAM horizontal Address
         0x0201, 0x0000,   // GRAM Vertical Address
// ----------- Adjust the Gamma Curve ----------//
         0x0300, 0x0000,   //
         0x0301, 0x0707,   //
         0x0302, 0x0606,   //
         0x0305, 0x0000,   //
         0x0306, 0x0D00,   //
         0x0307, 0x0706,   //
         0x0308, 0x0005,   //
         0x0309, 0x0007,   //
         0x030C, 0x0000,   //
         0x030D, 0x000A,   //
//------------------ Set GRAM area ---------------//
         0x0400, 0x3100,     //  Gate Scan Line 400 lines
         0x0401, 0x0001,     //  NDL,VLE, REV
         0x0404, 0x0000,     //  set scrolling line
//-------------- Partial Display Control ---------//
         0x0500, 0x0000,     // Partial Image 1 Display Position
         0x0501, 0x0000,     // Partial Image 1 RAM Start/End Address
         0x0502, 0x0000,     // Partial Image 1 RAM Start/End Address
         0x0503, 0x0000,     // Partial Image 2 Display Position
         0x0504, 0x0000,     // Partial Image 2 RAM Start/End Address
         0x0505, 0x0000,     // Partial Image 2 RAM Start/End Address
//-------------- Panel Control -------------------//
         0x0010, 0x0010,     // DIVI[1:0];RTNI[4:0]
         0x0011, 0x0600,     // NOWI[2:0];SDTI[2:0]
         0x0020, 0x0002,     // DIVE[1:0];RTNE[5:0]
         0x0007, 0x0173,     //  262K color and display ON
		 };
        init_table16(ILI9326_CPT28_regValues, sizeof(ILI9326_CPT28_regValues));
        p16 = (int16_t *) & HEIGHT;
        *p16 = 400;
        p16 = (int16_t *) & WIDTH;
        *p16 = 240;
        break;
#endif

    case 0x9327:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS;
        static const uint8_t ILI9327_regValues[] PROGMEM = {
            0xB0, 1, 0x00,      //Disable Protect for cmds B1-DF, E0-EF, F0-FF 
            //            0xE0, 1, 0x20,      //NV Memory Write [00]
            //            0xD1, 3, 0x00, 0x71, 0x19,  //VCOM control [00 40 0F]
            //            0xD0, 3, 0x07, 0x01, 0x08,  //Power Setting [07 04 8C]
            0xC1, 4, 0x10, 0x10, 0x02, 0x02,    //Display Timing [10 10 02 02]
            0xC0, 6, 0x00, 0x35, 0x00, 0x00, 0x01, 0x02,        //Panel Drive [00 35 00 00 01 02 REV=0,GS=0,SS=0
            0xC5, 1, 0x04,      //Frame Rate [04]
            0xD2, 2, 0x01, 0x04,        //Power Setting [01 44]
            //            0xC8, 15, 0x04, 0x67, 0x35, 0x04, 0x08, 0x06, 0x24, 0x01, 0x37, 0x40, 0x03, 0x10, 0x08, 0x80, 0x00,
            //            0xC8, 15, 0x00, 0x77, 0x77, 0x04, 0x04, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
            0xCA, 1, 0x00,      //DGC LUT ???
            0xEA, 1, 0x80,      //3-Gamma Function Enable
            //                     0xB0, 1, 0x03,      //Enable Protect
        };
        table8_ads = ILI9327_regValues, table_size = sizeof(ILI9327_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 400;
        p16 = (int16_t *) & WIDTH;
        *p16 = 240;
        break;
    case 0x1602:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS; //does not readGRAM
        static const uint8_t XX1602_regValues[] PROGMEM = {
            0xB8, 1, 0x01,      //GS [00]
            0xC0, 1, 0x0E,      //??Power [0A]
        };
        table8_ads = XX1602_regValues, table_size = sizeof(XX1602_regValues);
        break;

    case 0x2053:    //weird from BangGood
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | REV_SCREEN | READ_BGR;
		goto common_9329;
    case 0xAC11:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | REV_SCREEN; //thanks viliam
		goto common_9329;
    case 0x9302:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS;
		goto common_9329;
    case 0x9338:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
		goto common_9329;
    case 0x9329:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | REV_SCREEN;
	  common_9329:
        static const uint8_t ILI9329_regValues[] PROGMEM = {
//            0xF6, 3, 0x01, 0x01, 0x00,  //Interface Control needs EXTC=1 MX_EOR=1, TM=0, RIM=0
//            0xB6, 3, 0x0A, 0x82, 0x27,  //Display Function [0A 82 27]
//            0xB7, 1, 0x06,      //Entry Mode Set [06]
            0x36, 1, 0x00,      //Memory Access [00] pointless but stops an empty array
        };
        table8_ads = ILI9329_regValues, table_size = sizeof(ILI9329_regValues);
        break;

    case 0x9340:                //ILI9340 thanks Ravi_kanchan2004.
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | REV_SCREEN;
        goto common_9341;
    case 0x9341:
      common_9341:	
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        static const uint8_t ILI9341_regValues_2_4[] PROGMEM = {        // BOE 2.4"
            0xF6, 3, 0x01, 0x01, 0x00,  //Interface Control needs EXTC=1 MV_EOR=0, TM=0, RIM=0
            0xCF, 3, 0x00, 0x81, 0x30,  //Power Control B [00 81 30]
            0xED, 4, 0x64, 0x03, 0x12, 0x81,    //Power On Seq [55 01 23 01]
            0xE8, 3, 0x85, 0x10, 0x78,  //Driver Timing A [04 11 7A]
            0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,      //Power Control A [39 2C 00 34 02]
            0xF7, 1, 0x20,      //Pump Ratio [10]
            0xEA, 2, 0x00, 0x00,        //Driver Timing B [66 00]
            0xB0, 1, 0x00,      //RGB Signal [00] 
            0xB1, 2, 0x00, 0x1B,        //Frame Control [00 1B]
            //            0xB6, 2, 0x0A, 0xA2, 0x27, //Display Function [0A 82 27 XX]    .kbv SS=1  
            0xB4, 1, 0x00,      //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1
            0xC0, 1, 0x21,      //Power Control 1 [26]
            0xC1, 1, 0x11,      //Power Control 2 [00]
            0xC5, 2, 0x3F, 0x3C,        //VCOM 1 [31 3C]
            0xC7, 1, 0xB5,      //VCOM 2 [C0]
            0x36, 1, 0x48,      //Memory Access [00]
            0xF2, 1, 0x00,      //Enable 3G [02]
            0x26, 1, 0x01,      //Gamma Set [01]
            0xE0, 15, 0x0f, 0x26, 0x24, 0x0b, 0x0e, 0x09, 0x54, 0xa8, 0x46, 0x0c, 0x17, 0x09, 0x0f, 0x07, 0x00,
            0xE1, 15, 0x00, 0x19, 0x1b, 0x04, 0x10, 0x07, 0x2a, 0x47, 0x39, 0x03, 0x06, 0x06, 0x30, 0x38, 0x0f,
        };
        static const uint8_t ILI9341_regValues_ada[] PROGMEM = {        // Adafruit_TFTLCD only works with EXTC=0
            //                     0xF6, 3, 0x00, 0x01, 0x00,  //Interface Control needs EXTC=1 TM=0, RIM=0
            //            0xF6, 3, 0x01, 0x01, 0x03,  //Interface Control needs EXTC=1 RM=1, RIM=1
            0xF6, 3, 0x09, 0x01, 0x03,  //Interface Control needs EXTC=1 RM=0, RIM=1
            0xB0, 1, 0x40,      //RGB Signal [40] RCM=2
            0xB4, 1, 0x00,      //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1
            0xC0, 1, 0x23,      //Power Control 1 [26]
            0xC1, 1, 0x10,      //Power Control 2 [00]
            0xC5, 2, 0x2B, 0x2B,        //VCOM 1 [31 3C]
            0xC7, 1, 0xC0,      //VCOM 2 [C0]
            0x36, 1, 0x88,      //Memory Access [00]
            0xB1, 2, 0x00, 0x1B,        //Frame Control [00 1B]
            0xB7, 1, 0x07,      //Entry Mode [00]
        };
        table8_ads = ILI9341_regValues_2_4, table_size = sizeof(ILI9341_regValues_2_4);   //
        break;
#if defined(SUPPORT_9342)
    case 0x9342:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS | INVERT_GS | REV_SCREEN;
        static const uint8_t ILI9342_regValues_CPT24[] PROGMEM = {     //CPT 2.4"
            (0xB9), 3, 0xFF, 0x93, 0x42, //[00 00 00]
            (0xC0), 2, 0x1D, 0x0A,    //[26 09]
            (0xC1), 1, 0x02,          //[10]
            (0xC5), 2, 0x2F, 0x2F,    //[31 3C]
            (0xC7), 1, 0xC3,          //[C0]
            (0xB8), 1, 0x0B,          //[07]
            (0xE0), 15, 0x0F, 0x33, 0x30, 0x0C, 0x0F, 0x08, 0x5D, 0x66, 0x4A, 0x07, 0x13, 0x05, 0x1B, 0x0E, 0x08,
            (0xE1), 15, 0x08, 0x0E, 0x11, 0x02, 0x0E, 0x02, 0x24, 0x33, 0x37, 0x03, 0x0A, 0x09, 0x26, 0x33, 0x0F,
        };
        static const uint8_t ILI9342_regValues_Tianma23[] PROGMEM = {     //Tianma 2.3"
            (0xB9), 3, 0xFF, 0x93, 0x42,
            (0xC0), 2, 0x1D, 0x0A,
            (0xC1), 1, 0x01,
            (0xC5), 2, 0x2C, 0x2C,
            (0xC7), 1, 0xC6,
            (0xB8), 1, 0x09,
            (0xE0), 15, 0x0F, 0x26, 0x21, 0x07, 0x0A, 0x03, 0x4E, 0x62, 0x3E, 0x0B, 0x11, 0x00, 0x08, 0x02, 0x00,
            (0xE1), 15, 0x00, 0x19, 0x1E, 0x03, 0x0E, 0x03, 0x30, 0x23, 0x41, 0x03, 0x0B, 0x07, 0x2F, 0x36, 0x0F,
        };
        static const uint8_t ILI9342_regValues_HSD23[] PROGMEM = {     //HSD 2.3"
            (0xB9), 3, 0xFF, 0x93, 0x42,
            (0xC0), 2, 0x1D, 0x0A,
            (0xC1), 1, 0x02,
            (0xC5), 2, 0x2F, 0x27,
            (0xC7), 1, 0xA4,
            (0xB8), 1, 0x0B,
            (0xE0), 15, 0x0F, 0x24, 0x21, 0x0C, 0x0F, 0x06, 0x50, 0x75, 0x3F, 0x07, 0x12, 0x05, 0x11, 0x0B, 0x08,
            (0xE1), 15, 0x08, 0x1D, 0x20, 0x02, 0x0E, 0x04, 0x31, 0x24, 0x42, 0x03, 0x0B, 0x09, 0x30, 0x36, 0x0F,
        };
        table8_ads = ILI9342_regValues_CPT24, table_size = sizeof(ILI9342_regValues_CPT24);   //
        //        table8_ads = ILI9342_regValues_Tianma23, table_size = sizeof(ILI9342_regValues_Tianma23);   //
        //        table8_ads = ILI9342_regValues_HSD23, table_size = sizeof(ILI9342_regValues_HSD23);   //
        p16 = (int16_t *) & HEIGHT;
        *p16 = 240;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;
#endif
    case 0x1581:                        //no BGR in MADCTL.  set BGR in Panel Control
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS; //thanks zdravke
		goto common_9481;
    case 0x9481:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_BGR;
	  common_9481:
        static const uint8_t ILI9481_regValues[] PROGMEM = {    // Atmel MaxTouch
            0xB0, 1, 0x00,              // unlocks E0, F0
            0xB3, 4, 0x02, 0x00, 0x00, 0x00, //Frame Memory, interface [02 00 00 00]
			0xB4, 1, 0x00,              // Frame mode [00]
			0xD0, 3, 0x07, 0x42, 0x18,  // Set Power [00 43 18] x1.00, x6, x3
            0xD1, 3, 0x00, 0x07, 0x10,  // Set VCOM  [00 00 00] x0.72, x1.02
            0xD2, 2, 0x01, 0x02,        // Set Power for Normal Mode [01 22]
            0xD3, 2, 0x01, 0x02,        // Set Power for Partial Mode [01 22]
            0xD4, 2, 0x01, 0x02,        // Set Power for Idle Mode [01 22]
            0xC0, 5, 0x12, 0x3B, 0x00, 0x02, 0x11, //Panel Driving BGR for 1581 [10 3B 00 02 11]
            0xC1, 3, 0x10, 0x10, 0x88,  // Display Timing Normal [10 10 88]
			0xC5, 1, 0x03,      //Frame Rate [03]
			0xC6, 1, 0x02,      //Interface Control [02]
            0xC8, 12, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00,
			0xCC, 1, 0x00,      //Panel Control [00]
        };
        static const uint8_t ILI9481_CPT29_regValues[] PROGMEM = {    // 320x430
            0xB0, 1, 0x00,
            0xD0, 3, 0x07, 0x42, 0x1C,  // Set Power [00 43 18]
            0xD1, 3, 0x00, 0x02, 0x0F,  // Set VCOM  [00 00 00] x0.695, x1.00
            0xD2, 2, 0x01, 0x11,        // Set Power for Normal Mode [01 22]
            0xC0, 5, 0x10, 0x35, 0x00, 0x02, 0x11,      //Set Panel Driving [10 3B 00 02 11]
            0xC5, 1, 0x03,      //Frame Rate [03]
            0xC8, 12, 0x00, 0x30, 0x36, 0x45, 0x04, 0x16, 0x37, 0x75, 0x77, 0x54, 0x0F, 0x00,
            0xE4, 1, 0xA0,
            0xF0, 1, 0x01,
            0xF3, 2, 0x02, 0x1A,			
        };
        static const uint8_t ILI9481_PVI35_regValues[] PROGMEM = {    // 320x480
            0xB0, 1, 0x00,
            0xD0, 3, 0x07, 0x41, 0x1D,  // Set Power [00 43 18]
            0xD1, 3, 0x00, 0x2B, 0x1F,  // Set VCOM  [00 00 00] x0.900, x1.32
            0xD2, 2, 0x01, 0x11,        // Set Power for Normal Mode [01 22]
            0xC0, 5, 0x10, 0x3B, 0x00, 0x02, 0x11,      //Set Panel Driving [10 3B 00 02 11]
            0xC5, 1, 0x03,      //Frame Rate [03]
            0xC8, 12, 0x00, 0x14, 0x33, 0x10, 0x00, 0x16, 0x44, 0x36, 0x77, 0x00, 0x0F, 0x00,
            0xE4, 1, 0xA0,
            0xF0, 1, 0x01,
            0xF3, 2, 0x40, 0x0A,			
        };
        static const uint8_t ILI9481_AUO317_regValues[] PROGMEM = {    // 320x480
            0xB0, 1, 0x00,
            0xD0, 3, 0x07, 0x40, 0x1D,  // Set Power [00 43 18]
            0xD1, 3, 0x00, 0x18, 0x13,  // Set VCOM  [00 00 00] x0.805, x1.08
            0xD2, 2, 0x01, 0x11,        // Set Power for Normal Mode [01 22]
            0xC0, 5, 0x10, 0x3B, 0x00, 0x02, 0x11,      //Set Panel Driving [10 3B 00 02 11]
            0xC5, 1, 0x03,      //Frame Rate [03]
            0xC8, 12, 0x00, 0x44, 0x06, 0x44, 0x0A, 0x08, 0x17, 0x33, 0x77, 0x44, 0x08, 0x0C,
            0xE4, 1, 0xA0,
            0xF0, 1, 0x01,			
        };
        static const uint8_t ILI9481_CMO35_regValues[] PROGMEM = {    // 320480
            0xB0, 1, 0x00,
            0xD0, 3, 0x07, 0x41, 0x1D,  // Set Power [00 43 18] 07,41,1D
            0xD1, 3, 0x00, 0x1C, 0x1F,  // Set VCOM  [00 00 00] x0.825, x1.32 1C,1F
            0xD2, 2, 0x01, 0x11,        // Set Power for Normal Mode [01 22]
            0xC0, 5, 0x10, 0x3B, 0x00, 0x02, 0x11,      //Set Panel Driving [10 3B 00 02 11]
            0xC5, 1, 0x03,      //Frame Rate [03]
			0xC6, 1, 0x83, 
            0xC8, 12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00,
            0xF0, 1, 0x01,		//?
            0xE4, 1, 0xA0,      //?SETCABC on Himax
            0x36, 1, 0x48,      //Memory Access [00]
            0xB4, 1, 0x11,			
        };
        static const uint8_t ILI9481_RGB_regValues[] PROGMEM = {    // 320x480
            0xB0, 1, 0x00,
            0xD0, 3, 0x07, 0x41, 0x1D,  // SETPOWER [00 43 18]
            0xD1, 3, 0x00, 0x2B, 0x1F,  // SETVCOM  [00 00 00] x0.900, x1.32
            0xD2, 2, 0x01, 0x11,        // SETNORPOW for Normal Mode [01 22]
            0xC0, 6, 0x10, 0x3B, 0x00, 0x02, 0x11, 0x00,     //SETPANEL [10 3B 00 02 11]
            0xC5, 1, 0x03,      //SETOSC Frame Rate [03]
            0xC6, 1, 0x80,      //SETRGB interface control
			0xC8, 12, 0x00, 0x14, 0x33, 0x10, 0x00, 0x16, 0x44, 0x36, 0x77, 0x00, 0x0F, 0x00,
            0xF3, 2, 0x40, 0x0A,			
            0xF0, 1, 0x08,
            0xF6, 1, 0x84,
            0xF7, 1, 0x80,
            0x0C, 2, 0x00, 0x55, //RDCOLMOD
			0xB4, 1, 0x00,      //SETDISPLAY
//			0xB3, 4, 0x00, 0x01, 0x06, 0x01,  //SETGRAM simple example
			0xB3, 4, 0x00, 0x01, 0x06, 0x30,  //jpegs example
        };
        table8_ads = ILI9481_regValues, table_size = sizeof(ILI9481_regValues);
//        table8_ads = ILI9481_CPT29_regValues, table_size = sizeof(ILI9481_CPT29_regValues);
//        table8_ads = ILI9481_PVI35_regValues, table_size = sizeof(ILI9481_PVI35_regValues);
//        table8_ads = ILI9481_AUO317_regValues, table_size = sizeof(ILI9481_AUO317_regValues);
//        table8_ads = ILI9481_CMO35_regValues, table_size = sizeof(ILI9481_CMO35_regValues);
//        table8_ads = ILI9481_RGB_regValues, table_size = sizeof(ILI9481_RGB_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;
    case 0x9486:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS; //Red 3.5", Blue 3.5"
//        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | REV_SCREEN; //old Red 3.5"
        static const uint8_t ILI9486_regValues[] PROGMEM = {
/*
            0xF2, 9, 0x1C, 0xA3, 0x32, 0x02, 0xB2, 0x12, 0xFF, 0x12, 0x00,        //f.k
            0xF1, 2, 0x36, 0xA4,        //
            0xF8, 2, 0x21, 0x04,        //
            0xF9, 2, 0x00, 0x08,        //
*/
            0xC0, 2, 0x0d, 0x0d,        //Power Control 1 [0E 0E]
            0xC1, 2, 0x43, 0x00,        //Power Control 2 [43 00]
            0xC2, 1, 0x00,      //Power Control 3 [33]
            0xC5, 4, 0x00, 0x48, 0x00, 0x48,    //VCOM  Control 1 [00 40 00 40]
            0xB4, 1, 0x00,      //Inversion Control [00]
            0xB6, 3, 0x02, 0x02, 0x3B,  // Display Function Control [02 02 3B]
#define GAMMA9486 4
#if GAMMA9486 == 0
            // default GAMMA terrible
#elif GAMMA9486 == 1
            // GAMMA f.k.	bad		
            0xE0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00,
            0xE1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f,
#elif GAMMA9486 == 2
            // 1.2 CPT 3.5 Inch Initial Code not bad
			0xE0, 15, 0x0F, 0x1B, 0x18, 0x0B, 0x0E, 0x09, 0x47, 0x94, 0x35, 0x0A, 0x13, 0x05, 0x08, 0x03, 0x00, 
			0xE1, 15, 0x0F, 0x3A, 0x37, 0x0B, 0x0C, 0x05, 0x4A, 0x24, 0x39, 0x07, 0x10, 0x04, 0x27, 0x25, 0x00, 
#elif GAMMA9486 == 3
            // 2.2 HSD 3.5 Inch Initial Code not bad
			0xE0, 15, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00, 
			0xE1, 15, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, 
#elif GAMMA9486 == 4
            // 3.2 TM  3.2 Inch Initial Code not bad
			0xE0, 15, 0x0F, 0x21, 0x1C, 0x0B, 0x0E, 0x08, 0x49, 0x98, 0x38, 0x09, 0x11, 0x03, 0x14, 0x10, 0x00, 
			0xE1, 15, 0x0F, 0x2F, 0x2B, 0x0C, 0x0E, 0x06, 0x47, 0x76, 0x37, 0x07, 0x11, 0x04, 0x23, 0x1E, 0x00, 
#elif GAMMA9486 == 5
            // 4.2 WTK 3.5 Inch Initial Code too white
			0xE0, 15, 0x0F, 0x10, 0x08, 0x05, 0x09, 0x05, 0x37, 0x98, 0x26, 0x07, 0x0F, 0x02, 0x09, 0x07, 0x00, 
			0xE1, 15, 0x0F, 0x38, 0x36, 0x0D, 0x10, 0x08, 0x59, 0x76, 0x48, 0x0A, 0x16, 0x0A, 0x37, 0x2F, 0x00, 
#endif
        };
        table8_ads = ILI9486_regValues, table_size = sizeof(ILI9486_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;
    case 0x7796:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS;   //thanks to safari1
        goto common_9488;
    case 0x9487:                //with thanks to Charlyf
    case 0x9488:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
      common_9488:
        static const uint8_t ILI9488_regValues_max[] PROGMEM = {        // Atmel MaxTouch
            0xC0, 2, 0x10, 0x10,        //Power Control 1 [0E 0E]
            0xC1, 1, 0x41,      //Power Control 2 [43]
            0xC5, 4, 0x00, 0x22, 0x80, 0x40,    //VCOM  Control 1 [00 40 00 40]
            0x36, 1, 0x68,      //Memory Access [00]
            0xB0, 1, 0x00,      //Interface     [00]
            0xB1, 2, 0xB0, 0x11,        //Frame Rate Control [B0 11]
            0xB4, 1, 0x02,      //Inversion Control [02]
            0xB6, 3, 0x02, 0x02, 0x3B,  // Display Function Control [02 02 3B] .kbv NL=480
            0xB7, 1, 0xC6,      //Entry Mode      [06]
            0x3A, 1, 0x55,      //Interlace Pixel Format [XX]
            0xF7, 4, 0xA9, 0x51, 0x2C, 0x82,    //Adjustment Control 3 [A9 51 2C 82]
        };
        table8_ads = ILI9488_regValues_max, table_size = sizeof(ILI9488_regValues_max);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;
    case 0xB505:                //R61505V
    case 0xC505:                //R61505W
        _lcd_capable = 0 | REV_SCREEN | READ_LOWHIGH;
        static const uint16_t R61505V_regValues[] PROGMEM = {
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0001,
            0x00A4, 0x0001,     //CALB=1
            TFTLCD_DELAY, 10,
            0x0060, 0x2700,     //NL
            0x0008, 0x0808,     //FP & BP
            0x0030, 0x0214,     //Gamma settings
            0x0031, 0x3715,
            0x0032, 0x0604,
            0x0033, 0x0E16,
            0x0034, 0x2211,
            0x0035, 0x1500,
            0x0036, 0x8507,
            0x0037, 0x1407,
            0x0038, 0x1403,
            0x0039, 0x0020,
            0x0090, 0x0015,     //DIVI & RTNI
            0x0010, 0x0410,     //BT=4,AP=1
            0x0011, 0x0237,     //DC1=2,DC0=3, VC=7
            0x0029, 0x0046,     //VCM1=70
            0x002A, 0x0046,     //VCMSEL=0,VCM2=70
            // Sleep mode IN sequence
            0x0007, 0x0000,
            //0x0012, 0x0000,   //PSON=0,PON=0
            // Sleep mode EXIT sequence 
            0x0012, 0x0189,     //VCMR=1,PSON=0,PON=0,VRH=9
            0x0013, 0x1100,     //VDV=17
            TFTLCD_DELAY, 150,
            0x0012, 0x01B9,     //VCMR=1,PSON=1,PON=1,VRH=9 [018F]
            0x0001, 0x0100,     //SS=1 Other mode settings
            0x0002, 0x0200,     //BC0=1--Line inversion
            0x0003, 0x1030,
            0x0009, 0x0001,     //ISC=1 [0000]
            0x000A, 0x0000,     // [0000]
            //            0x000C, 0x0001,   //RIM=1 [0000]
            0x000D, 0x0000,     // [0000]
            0x000E, 0x0030,     //VEM=3 VCOM equalize [0000]
            0x0061, 0x0001,
            0x006A, 0x0000,
            0x0080, 0x0000,
            0x0081, 0x0000,
            0x0082, 0x005F,
            0x0092, 0x0100,
            0x0093, 0x0701,
            TFTLCD_DELAY, 80,
            0x0007, 0x0100,     //BASEE=1--Display On
        };
        init_table16(R61505V_regValues, sizeof(R61505V_regValues));
        break;

#if defined(SUPPORT_B509_7793)
    case 0x7793:
    case 0xB509:
        _lcd_capable = REV_SCREEN;
        static const uint16_t R61509V_regValues[] PROGMEM = {
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0000,
            0x0000, 0x0000,
            TFTLCD_DELAY, 15,
            0x0400, 0x6200,     //NL=0x31 (49) i.e. 400 rows
            0x0008, 0x0808,
            //gamma
            0x0300, 0x0C00,
            0x0301, 0x5A0B,
            0x0302, 0x0906,
            0x0303, 0x1017,
            0x0304, 0x2300,
            0x0305, 0x1700,
            0x0306, 0x6309,
            0x0307, 0x0C09,
            0x0308, 0x100C,
            0x0309, 0x2232,

            0x0010, 0x0016,     //69.5Hz         0016
            0x0011, 0x0101,
            0x0012, 0x0000,
            0x0013, 0x0001,

            0x0100, 0x0330,     //BT,AP
            0x0101, 0x0237,     //DC0,DC1,VC
            0x0103, 0x0D00,     //VDV
            0x0280, 0x6100,     //VCM
            0x0102, 0xC1B0,     //VRH,VCMR,PSON,PON
            TFTLCD_DELAY, 50,

            0x0001, 0x0100,
            0x0002, 0x0100,
            0x0003, 0x1030,     //1030
            0x0009, 0x0001,
            0x000C, 0x0000,
            0x0090, 0x8000,
            0x000F, 0x0000,

            0x0210, 0x0000,
            0x0211, 0x00EF,
            0x0212, 0x0000,
            0x0213, 0x018F,     //432=01AF,400=018F
            0x0500, 0x0000,
            0x0501, 0x0000,
            0x0502, 0x005F,     //???
            0x0401, 0x0001,     //REV=1
            0x0404, 0x0000,
            TFTLCD_DELAY, 50,

            0x0007, 0x0100,     //BASEE
            TFTLCD_DELAY, 50,

            0x0200, 0x0000,
            0x0201, 0x0000,
        };
        init_table16(R61509V_regValues, sizeof(R61509V_regValues));
        p16 = (int16_t *) & HEIGHT;
        *p16 = 400;
        break;
#endif

#ifdef SUPPORT_9806
    case 0x9806:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | READ_24BITS;
        // from ZinggJM
        static const uint8_t ILI9806_regValues[] PROGMEM = {
            (0xFF), 3, /* EXTC Command Set enable register*/ 0xFF, 0x98, 0x06,
            (0xBA), 1, /* SPI Interface Setting*/0xE0,
            (0xBC), 21, /* GIP 1*/0x03, 0x0F, 0x63, 0x69, 0x01, 0x01, 0x1B, 0x11, 0x70, 0x73, 0xFF, 0xFF, 0x08, 0x09, 0x05, 0x00, 0xEE, 0xE2, 0x01, 0x00, 0xC1,
            (0xBD), 8, /* GIP 2*/0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
            (0xBE), 9, /* GIP 3*/0x00, 0x22, 0x27, 0x6A, 0xBC, 0xD8, 0x92, 0x22, 0x22,
            (0xC7), 1, /* Vcom*/0x1E,
            (0xED), 3, /* EN_volt_reg*/0x7F, 0x0F, 0x00,
            (0xC0), 3, /* Power Control 1*/0xE3, 0x0B, 0x00,
            (0xFC), 1, 0x08,
            (0xDF), 6, /* Engineering Setting*/0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
            (0xF3), 1, /* DVDD Voltage Setting*/0x74,
            (0xB4), 3, /* Display Inversion Control*/0x00, 0x00, 0x00,
            (0xF7), 1, /* 480x854*/0x81,
            (0xB1), 3, /* Frame Rate*/0x00, 0x10, 0x14,
            (0xF1), 3, /* Panel Timing Control*/0x29, 0x8A, 0x07,
            (0xF2), 4, /*Panel Timing Control*/0x40, 0xD2, 0x50, 0x28,
            (0xC1), 4, /* Power Control 2*/0x17, 0x85, 0x85, 0x20,
            (0xE0), 16, 0x00, 0x0C, 0x15, 0x0D, 0x0F, 0x0C, 0x07, 0x05, 0x07, 0x0B, 0x10, 0x10, 0x0D, 0x17, 0x0F, 0x00,
            (0xE1), 16, 0x00, 0x0D, 0x15, 0x0E, 0x10, 0x0D, 0x08, 0x06, 0x07, 0x0C, 0x11, 0x11, 0x0E, 0x17, 0x0F, 0x00,
            (0x35), 1, /*Tearing Effect ON*/0x00,
        };
        table8_ads = ILI9806_regValues, table_size = sizeof(ILI9806_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 854;
        break;
#endif
    default:
        p16 = (int16_t *) & WIDTH;
        *p16 = 0;       //error value for WIDTH
        break;
    }
    _lcd_rev = ((_lcd_capable & REV_SCREEN) != 0);
    if (table8_ads != NULL) {
        static const uint8_t reset_off[] PROGMEM = {
            0x01, 0,            //Soft Reset
            TFTLCD_DELAY8, 150,  // .kbv will power up with ONLY reset, sleep out, display on
            0x28, 0,            //Display Off
            0x3A, 1, 0x55,      //Pixel read=565, write=565.
        };
        static const uint8_t wake_on[] PROGMEM = {
			0x11, 0,            //Sleep Out
            TFTLCD_DELAY8, 150,
            0x29, 0,            //Display On
        };
		init_table(&reset_off, sizeof(reset_off));
	    init_table(table8_ads, table_size);   //can change PIXFMT
		init_table(&wake_on, sizeof(wake_on));
    }
    setRotation(0);             //PORTRAIT
    invertDisplay(false);
#if defined(SUPPORT_9488_555)
    if (_lcd_ID == 0x9488) {
		is555 = 0;
		drawPixel(0, 0, 0xFFE0);
		if (readPixel(0, 0) == 0xFF1F) {
			uint8_t pixfmt = 0x06;
			pushCommand(0x3A, &pixfmt, 1);
			_lcd_capable &= ~READ_24BITS;
			is555 = 1;
		}
	}
#endif
}

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Adafruit_GFX.cpp

viki13viki
Offline
Зарегистрирован: 14.11.2016

лови

/*
This is the core graphics library for all our displays, providing a common
set of graphics primitives (points, lines, circles, etc.).  It needs to be
paired with a hardware-specific library for each display device we carry
(to handle the lower-level functions).

Adafruit invests time and resources providing this open source code, please
support Adafruit & open-source hardware by purchasing products from Adafruit!

Copyright (c) 2013 Adafruit Industries.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
 */

#include "Adafruit_GFX.h"
#include "glcdfont.c"
#ifdef __AVR__
  #include <avr/pgmspace.h>
#elif defined(ESP8266) || defined(ESP32)
  #include <pgmspace.h>
#endif

// Many (but maybe not all) non-AVR board installs define macros
// for compatibility with existing PROGMEM-reading AVR code.
// Do our own checks and defines here for good measure...

#ifndef pgm_read_byte
 #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
 #define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
 #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif

// Pointers are a peculiar case...typically 16-bit on AVR boards,
// 32 bits elsewhere.  Try to accommodate both...

#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
 #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
#else
 #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif

inline GFXglyph * pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c)
{
#ifdef __AVR__
    return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
#else
    // expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning
    // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
    // So expression may be simplified
    return gfxFont->glyph + c;
#endif //__AVR__
}

inline uint8_t * pgm_read_bitmap_ptr(const GFXfont *gfxFont)
{
#ifdef __AVR__
    return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
#else
    // expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning
    // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
    // So expression may be simplified
    return gfxFont->bitmap;
#endif //__AVR__
}

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif

/**************************************************************************/
/*!
   @brief    Instatiate a GFX context for graphics! Can only be done by a superclass
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
WIDTH(w), HEIGHT(h)
{
    _width    = WIDTH;
    _height   = HEIGHT;
    rotation  = 0;
    cursor_y  = cursor_x    = 0;
    textsize_x = textsize_y  = 1;
    textcolor = textbgcolor = 0xFFFF;
    wrap      = true;
    _cp437    = false;
    gfxFont   = NULL;
}

/**************************************************************************/
/*!
   @brief    Write a line.  Bresenham's algorithm - thx wikpedia
    @param    x0  Start point x coordinate
    @param    y0  Start point y coordinate
    @param    x1  End point x coordinate
    @param    y1  End point y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
        uint16_t color) {
#if defined(ESP8266)
    yield();
#endif
    int16_t steep = abs(y1 - y0) > abs(x1 - x0);
    if (steep) {
        _swap_int16_t(x0, y0);
        _swap_int16_t(x1, y1);
    }

    if (x0 > x1) {
        _swap_int16_t(x0, x1);
        _swap_int16_t(y0, y1);
    }

    int16_t dx, dy;
    dx = x1 - x0;
    dy = abs(y1 - y0);

    int16_t err = dx / 2;
    int16_t ystep;

    if (y0 < y1) {
        ystep = 1;
    } else {
        ystep = -1;
    }

    for (; x0<=x1; x0++) {
        if (steep) {
            writePixel(y0, x0, color);
        } else {
            writePixel(x0, y0, color);
        }
        err -= dy;
        if (err < 0) {
            y0 += ystep;
            err += dx;
        }
    }
}

/**************************************************************************/
/*!
   @brief    Start a display-writing routine, overwrite in subclasses.
*/
/**************************************************************************/
void Adafruit_GFX::startWrite(){
}

/**************************************************************************/
/*!
   @brief    Write a pixel, overwrite in subclasses if startWrite is defined!
    @param   x   x coordinate
    @param   y   y coordinate
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color){
    drawPixel(x, y, color);
}

/**************************************************************************/
/*!
   @brief    Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
    @param    x   Top-most x coordinate
    @param    y   Top-most y coordinate
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y,
        int16_t h, uint16_t color) {
    // Overwrite in subclasses if startWrite is defined!
    // Can be just writeLine(x, y, x, y+h-1, color);
    // or writeFillRect(x, y, 1, h, color);
    drawFastVLine(x, y, h, color);
}

/**************************************************************************/
/*!
   @brief    Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
    @param    x   Left-most x coordinate
    @param    y   Left-most y coordinate
    @param    w   Width in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y,
        int16_t w, uint16_t color) {
    // Overwrite in subclasses if startWrite is defined!
    // Example: writeLine(x, y, x+w-1, y, color);
    // or writeFillRect(x, y, w, 1, color);
    drawFastHLine(x, y, w, color);
}

/**************************************************************************/
/*!
   @brief    Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    // Overwrite in subclasses if desired!
    fillRect(x,y,w,h,color);
}

/**************************************************************************/
/*!
   @brief    End a display-writing routine, overwrite in subclasses if startWrite is defined!
*/
/**************************************************************************/
void Adafruit_GFX::endWrite(){
}

/**************************************************************************/
/*!
   @brief    Draw a perfectly vertical line (this is often optimized in a subclass!)
    @param    x   Top-most x coordinate
    @param    y   Top-most y coordinate
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
        int16_t h, uint16_t color) {
    startWrite();
    writeLine(x, y, x, y+h-1, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Draw a perfectly horizontal line (this is often optimized in a subclass!)
    @param    x   Left-most x coordinate
    @param    y   Left-most y coordinate
    @param    w   Width in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
        int16_t w, uint16_t color) {
    startWrite();
    writeLine(x, y, x+w-1, y, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Fill a rectangle completely with one color. Update in subclasses if desired!
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    startWrite();
    for (int16_t i=x; i<x+w; i++) {
        writeFastVLine(i, y, h, color);
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Fill the screen completely with one color. Update in subclasses if desired!
    @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillScreen(uint16_t color) {
    fillRect(0, 0, _width, _height, color);
}

/**************************************************************************/
/*!
   @brief    Draw a line
    @param    x0  Start point x coordinate
    @param    y0  Start point y coordinate
    @param    x1  End point x coordinate
    @param    y1  End point y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
        uint16_t color) {
    // Update in subclasses if desired!
    if(x0 == x1){
        if(y0 > y1) _swap_int16_t(y0, y1);
        drawFastVLine(x0, y0, y1 - y0 + 1, color);
    } else if(y0 == y1){
        if(x0 > x1) _swap_int16_t(x0, x1);
        drawFastHLine(x0, y0, x1 - x0 + 1, color);
    } else {
        startWrite();
        writeLine(x0, y0, x1, y1, color);
        endWrite();
    }
}

/**************************************************************************/
/*!
   @brief    Draw a circle outline
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
        uint16_t color) {
#if defined(ESP8266)
    yield();
#endif
    int16_t f = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x = 0;
    int16_t y = r;

    startWrite();
    writePixel(x0  , y0+r, color);
    writePixel(x0  , y0-r, color);
    writePixel(x0+r, y0  , color);
    writePixel(x0-r, y0  , color);

    while (x<y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        writePixel(x0 + x, y0 + y, color);
        writePixel(x0 - x, y0 + y, color);
        writePixel(x0 + x, y0 - y, color);
        writePixel(x0 - x, y0 - y, color);
        writePixel(x0 + y, y0 + x, color);
        writePixel(x0 - y, y0 + x, color);
        writePixel(x0 + y, y0 - x, color);
        writePixel(x0 - y, y0 - x, color);
    }
    endWrite();
}

/**************************************************************************/
/*!
    @brief    Quarter-circle drawer, used to do circles and roundrects
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    cornername  Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
        int16_t r, uint8_t cornername, uint16_t color) {
    int16_t f     = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x     = 0;
    int16_t y     = r;

    while (x<y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f     += ddF_y;
        }
        x++;
        ddF_x += 2;
        f     += ddF_x;
        if (cornername & 0x4) {
            writePixel(x0 + x, y0 + y, color);
            writePixel(x0 + y, y0 + x, color);
        }
        if (cornername & 0x2) {
            writePixel(x0 + x, y0 - y, color);
            writePixel(x0 + y, y0 - x, color);
        }
        if (cornername & 0x8) {
            writePixel(x0 - y, y0 + x, color);
            writePixel(x0 - x, y0 + y, color);
        }
        if (cornername & 0x1) {
            writePixel(x0 - y, y0 - x, color);
            writePixel(x0 - x, y0 - y, color);
        }
    }
}

/**************************************************************************/
/*!
   @brief    Draw a circle with filled color
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
        uint16_t color) {
    startWrite();
    writeFastVLine(x0, y0-r, 2*r+1, color);
    fillCircleHelper(x0, y0, r, 3, 0, color);
    endWrite();
}


/**************************************************************************/
/*!
    @brief  Quarter-circle drawer with fill, used for circles and roundrects
    @param  x0       Center-point x coordinate
    @param  y0       Center-point y coordinate
    @param  r        Radius of circle
    @param  corners  Mask bits indicating which quarters we're doing
    @param  delta    Offset from center-point, used for round-rects
    @param  color    16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
  uint8_t corners, int16_t delta, uint16_t color) {

    int16_t f     = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x     = 0;
    int16_t y     = r;
    int16_t px    = x;
    int16_t py    = y;

    delta++; // Avoid some +1's in the loop

    while(x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f     += ddF_y;
        }
        x++;
        ddF_x += 2;
        f     += ddF_x;
        // These checks avoid double-drawing certain lines, important
        // for the SSD1306 library which has an INVERT drawing mode.
        if(x < (y + 1)) {
            if(corners & 1) writeFastVLine(x0+x, y0-y, 2*y+delta, color);
            if(corners & 2) writeFastVLine(x0-x, y0-y, 2*y+delta, color);
        }
        if(y != py) {
            if(corners & 1) writeFastVLine(x0+py, y0-px, 2*px+delta, color);
            if(corners & 2) writeFastVLine(x0-py, y0-px, 2*px+delta, color);
            py = y;
        }
        px = x;
    }
}

/**************************************************************************/
/*!
   @brief   Draw a rectangle with no fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    startWrite();
    writeFastHLine(x, y, w, color);
    writeFastHLine(x, y+h-1, w, color);
    writeFastVLine(x, y, h, color);
    writeFastVLine(x+w-1, y, h, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a rounded rectangle with no fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    r   Radius of corner rounding
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
  int16_t h, int16_t r, uint16_t color) {
    int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    if(r > max_radius) r = max_radius;
    // smarter version
    startWrite();
    writeFastHLine(x+r  , y    , w-2*r, color); // Top
    writeFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
    writeFastVLine(x    , y+r  , h-2*r, color); // Left
    writeFastVLine(x+w-1, y+r  , h-2*r, color); // Right
    // draw four corners
    drawCircleHelper(x+r    , y+r    , r, 1, color);
    drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
    drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
    drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a rounded rectangle with fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    r   Radius of corner rounding
    @param    color 16-bit 5-6-5 Color to draw/fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
  int16_t h, int16_t r, uint16_t color) {
    int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    if(r > max_radius) r = max_radius;
    // smarter version
    startWrite();
    writeFillRect(x+r, y, w-2*r, h, color);
    // draw four corners
    fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
    fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a triangle with no fill color
    @param    x0  Vertex #0 x coordinate
    @param    y0  Vertex #0 y coordinate
    @param    x1  Vertex #1 x coordinate
    @param    y1  Vertex #1 y coordinate
    @param    x2  Vertex #2 x coordinate
    @param    y2  Vertex #2 y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
        int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
    drawLine(x0, y0, x1, y1, color);
    drawLine(x1, y1, x2, y2, color);
    drawLine(x2, y2, x0, y0, color);
}

/**************************************************************************/
/*!
   @brief     Draw a triangle with color-fill
    @param    x0  Vertex #0 x coordinate
    @param    y0  Vertex #0 y coordinate
    @param    x1  Vertex #1 x coordinate
    @param    y1  Vertex #1 y coordinate
    @param    x2  Vertex #2 x coordinate
    @param    y2  Vertex #2 y coordinate
    @param    color 16-bit 5-6-5 Color to fill/draw with
*/
/**************************************************************************/
void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
        int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {

    int16_t a, b, y, last;

    // Sort coordinates by Y order (y2 >= y1 >= y0)
    if (y0 > y1) {
        _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
    }
    if (y1 > y2) {
        _swap_int16_t(y2, y1); _swap_int16_t(x2, x1);
    }
    if (y0 > y1) {
        _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
    }

    startWrite();
    if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
        a = b = x0;
        if(x1 < a)      a = x1;
        else if(x1 > b) b = x1;
        if(x2 < a)      a = x2;
        else if(x2 > b) b = x2;
        writeFastHLine(a, y0, b-a+1, color);
        endWrite();
        return;
    }

    int16_t
    dx01 = x1 - x0,
    dy01 = y1 - y0,
    dx02 = x2 - x0,
    dy02 = y2 - y0,
    dx12 = x2 - x1,
    dy12 = y2 - y1;
    int32_t
    sa   = 0,
    sb   = 0;

    // For upper part of triangle, find scanline crossings for segments
    // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
    // is included here (and second loop will be skipped, avoiding a /0
    // error there), otherwise scanline y1 is skipped here and handled
    // in the second loop...which also avoids a /0 error here if y0=y1
    // (flat-topped triangle).
    if(y1 == y2) last = y1;   // Include y1 scanline
    else         last = y1-1; // Skip it

    for(y=y0; y<=last; y++) {
        a   = x0 + sa / dy01;
        b   = x0 + sb / dy02;
        sa += dx01;
        sb += dx02;
        /* longhand:
        a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
        b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
        */
        if(a > b) _swap_int16_t(a,b);
        writeFastHLine(a, y, b-a+1, color);
    }

    // For lower part of triangle, find scanline crossings for segments
    // 0-2 and 1-2.  This loop is skipped if y1=y2.
    sa = (int32_t)dx12 * (y - y1);
    sb = (int32_t)dx02 * (y - y0);
    for(; y<=y2; y++) {
        a   = x1 + sa / dy12;
        b   = x0 + sb / dy02;
        sa += dx12;
        sb += dx02;
        /* longhand:
        a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
        b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
        */
        if(a > b) _swap_int16_t(a,b);
        writeFastHLine(a, y, b-a+1, color);
    }
    endWrite();
}

// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------

/**************************************************************************/
/*!
   @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            if(byte & 0x80) writePixel(x+i, y, color);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
    @param    bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h,
  uint16_t color, uint16_t bg) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            writePixel(x+i, y, (byte & 0x80) ? color : bg);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = bitmap[j * byteWidth + i / 8];
            if(byte & 0x80) writePixel(x+i, y, color);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
    @param    bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = bitmap[j * byteWidth + i / 8];
            writePixel(x+i, y, (byte & 0x80) ? color : bg);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
   Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
   C Array can be directly used with this function.
   There is no RAM-resident version of this function; if generating bitmaps
   in RAM, use the format defined by drawBitmap() and call that instead.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
*/
/**************************************************************************/
void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte >>= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            // Nearly identical to drawBitmap(), only the bit order
            // is reversed here (left-to-right = LSB to MSB):
            if(byte & 0x01) writePixel(x+i, y, color);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, bitmap[j * w + i]);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
   (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   BOTH buffers (grayscale and mask) must be PROGMEM-resident.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    mask  byte array with mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], const uint8_t mask[],
  int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&mask[j * bw + i / 8]);
            if(byte & 0x80) {
                writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
            }
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
   (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    mask  byte array with mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = mask[j * bw + i / 8];
            if(byte & 0x80) {
                writePixel(x+i, y, bitmap[j * w + i]);
            }
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  const uint16_t bitmap[], int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  uint16_t *bitmap, int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, bitmap[j * w + i]);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be PROGMEM-resident. For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    mask  byte array with monochrome mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  const uint16_t bitmap[], const uint8_t mask[],
  int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&mask[j * bw + i / 8]);
            if(byte & 0x80) {
                writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
            }
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be RAM-resident. For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    mask  byte array with monochrome mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = mask[j * bw + i / 8];
            if(byte & 0x80) {
                writePixel(x+i, y, bitmap[j * w + i]);
            }
        }
    }
    endWrite();
}

// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------

// Draw a character
/**************************************************************************/
/*!
   @brief   Draw a single character
    @param    x   Bottom left corner x coordinate
    @param    y   Bottom left corner y coordinate
    @param    c   The 8-bit font-indexed character (likely ascii)
    @param    color 16-bit 5-6-5 Color to draw chraracter with
    @param    bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
    @param    size  Font magnification level, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
  uint16_t color, uint16_t bg, uint8_t size) {
    drawChar(x, y, c, color, bg, size, size);
}

// Draw a character
/**************************************************************************/
/*!
   @brief   Draw a single character
    @param    x   Bottom left corner x coordinate
    @param    y   Bottom left corner y coordinate
    @param    c   The 8-bit font-indexed character (likely ascii)
    @param    color 16-bit 5-6-5 Color to draw chraracter with
    @param    bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
    @param    size_x  Font magnification level in X-axis, 1 is 'original' size
    @param    size_y  Font magnification level in Y-axis, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
  uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) {

    if(!gfxFont) { // 'Classic' built-in font

        if((x >= _width)            || // Clip right
           (y >= _height)           || // Clip bottom
           ((x + 6 * size_x - 1) < 0) || // Clip left
           ((y + 8 * size_y - 1) < 0))   // Clip top
            return;

        if(!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior

        startWrite();
        for(int8_t i=0; i<5; i++ ) { // Char bitmap = 5 columns
            uint8_t line = pgm_read_byte(&font[c * 5 + i]);
            for(int8_t j=0; j<8; j++, line >>= 1) {
                if(line & 1) {
                    if(size_x == 1 && size_y == 1)
                        writePixel(x+i, y+j, color);
                    else
                        writeFillRect(x+i*size_x, y+j*size_y, size_x, size_y, color);
                } else if(bg != color) {
                    if(size_x == 1 && size_y == 1)
                        writePixel(x+i, y+j, bg);
                    else
                        writeFillRect(x+i*size_x, y+j*size_y, size_x, size_y, bg);
                }
            }
        }
        if(bg != color) { // If opaque, draw vertical line for last column
            if(size_x == 1 && size_y == 1) writeFastVLine(x+5, y, 8, bg);
            else          writeFillRect(x+5*size_x, y, size_x, 8*size_y, bg);
        }
        endWrite();

    } else { // Custom font

        // Character is assumed previously filtered by write() to eliminate
        // newlines, returns, non-printable characters, etc.  Calling
        // drawChar() directly with 'bad' characters of font may cause mayhem!

        c -= (uint8_t)pgm_read_byte(&gfxFont->first);
        GFXglyph *glyph  = pgm_read_glyph_ptr(gfxFont, c);
        uint8_t  *bitmap = pgm_read_bitmap_ptr(gfxFont);

        uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
        uint8_t  w  = pgm_read_byte(&glyph->width),
                 h  = pgm_read_byte(&glyph->height);
        int8_t   xo = pgm_read_byte(&glyph->xOffset),
                 yo = pgm_read_byte(&glyph->yOffset);
        uint8_t  xx, yy, bits = 0, bit = 0;
        int16_t  xo16 = 0, yo16 = 0;

        if(size_x > 1 || size_y > 1) {
            xo16 = xo;
            yo16 = yo;
        }

        // Todo: Add character clipping here

        // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
        // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
        // has typically been used with the 'classic' font to overwrite old
        // screen contents with new data.  This ONLY works because the
        // characters are a uniform size; it's not a sensible thing to do with
        // proportionally-spaced fonts with glyphs of varying sizes (and that
        // may overlap).  To replace previously-drawn text when using a custom
        // font, use the getTextBounds() function to determine the smallest
        // rectangle encompassing a string, erase the area with fillRect(),
        // then draw new text.  This WILL infortunately 'blink' the text, but
        // is unavoidable.  Drawing 'background' pixels will NOT fix this,
        // only creates a new set of problems.  Have an idea to work around
        // this (a canvas object type for MCUs that can afford the RAM and
        // displays supporting setAddrWindow() and pushColors()), but haven't
        // implemented this yet.

        startWrite();
        for(yy=0; yy<h; yy++) {
            for(xx=0; xx<w; xx++) {
                if(!(bit++ & 7)) {
                    bits = pgm_read_byte(&bitmap[bo++]);
                }
                if(bits & 0x80) {
                    if(size_x == 1 && size_y == 1) {
                        writePixel(x+xo+xx, y+yo+yy, color);
                    } else {
                        writeFillRect(x+(xo16+xx)*size_x, y+(yo16+yy)*size_y,
                          size_x, size_y, color);
                    }
                }
                bits <<= 1;
            }
        }
        endWrite();

    } // End classic vs custom font
}
/**************************************************************************/
/*!
    @brief  Print one byte/character of data, used to support print()
    @param  c  The 8-bit ascii character to write
*/
/**************************************************************************/
size_t Adafruit_GFX::write(uint8_t c) {
    if(!gfxFont) { // 'Classic' built-in font

        if(c == '\n') {                        // Newline?
            cursor_x  = 0;                     // Reset x to zero,
            cursor_y += textsize_y * 8;        // advance y one line
        } else if(c != '\r') {                 // Ignore carriage returns
            if(wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right?
                cursor_x  = 0;                 // Reset x to zero,
                cursor_y += textsize_y * 8;    // advance y one line
            }
            drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y);
            cursor_x += textsize_x * 6;          // Advance x one char
        }

    } else { // Custom font

        if(c == '\n') {
            cursor_x  = 0;
            cursor_y += (int16_t)textsize_y *
                        (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
        } else if(c != '\r') {
            uint8_t first = pgm_read_byte(&gfxFont->first);
            if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
                GFXglyph *glyph  = pgm_read_glyph_ptr(gfxFont, c - first);
                uint8_t   w     = pgm_read_byte(&glyph->width),
                          h     = pgm_read_byte(&glyph->height);
                if((w > 0) && (h > 0)) { // Is there an associated bitmap?
                    int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
                    if(wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
                        cursor_x  = 0;
                        cursor_y += (int16_t)textsize_y *
                          (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
                    }
                    drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y);
                }
                cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x;
            }
        }

    }
    return 1;
}

/**************************************************************************/
/*!
    @brief   Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
    @param  s  Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
*/
/**************************************************************************/
void Adafruit_GFX::setTextSize(uint8_t s) {
    setTextSize(s, s);
}

/**************************************************************************/
/*!
    @brief   Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
    @param  s_x  Desired text width magnification level in X-axis. 1 is default
    @param  s_y  Desired text width magnification level in Y-axis. 1 is default
*/
/**************************************************************************/
void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
    textsize_x = (s_x > 0) ? s_x : 1;
    textsize_y = (s_y > 0) ? s_y : 1;
}

/**************************************************************************/
/*!
    @brief      Set rotation setting for display
    @param  x   0 thru 3 corresponding to 4 cardinal rotations
*/
/**************************************************************************/
void Adafruit_GFX::setRotation(uint8_t x) {
    rotation = (x & 3);
    switch(rotation) {
        case 0:
        case 2:
            _width  = WIDTH;
            _height = HEIGHT;
            break;
        case 1:
        case 3:
            _width  = HEIGHT;
            _height = WIDTH;
            break;
    }
}

/**************************************************************************/
/*!
    @brief Set the font to display when print()ing, either custom or default
    @param  f  The GFXfont object, if NULL use built in 6x8 font
*/
/**************************************************************************/
void Adafruit_GFX::setFont(const GFXfont *f) {
    if(f) {            // Font struct pointer passed in?
        if(!gfxFont) { // And no current font struct?
            // Switching from classic to new font behavior.
            // Move cursor pos down 6 pixels so it's on baseline.
            cursor_y += 6;
        }
    } else if(gfxFont) { // NULL passed.  Current font struct defined?
        // Switching from new to classic font behavior.
        // Move cursor pos up 6 pixels so it's at top-left of char.
        cursor_y -= 6;
    }
    gfxFont = (GFXfont *)f;
}


/**************************************************************************/
/*!
    @brief    Helper to determine size of a character with current font/size.
       Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
    @param    c     The ascii character in question
    @param    x     Pointer to x location of character
    @param    y     Pointer to y location of character
    @param    minx  Minimum clipping value for X
    @param    miny  Minimum clipping value for Y
    @param    maxx  Maximum clipping value for X
    @param    maxy  Maximum clipping value for Y
*/
/**************************************************************************/
void Adafruit_GFX::charBounds(char c, int16_t *x, int16_t *y,
  int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) {

    if(gfxFont) {

        if(c == '\n') { // Newline?
            *x  = 0;    // Reset x to zero, advance y by one line
            *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
        } else if(c != '\r') { // Not a carriage return; is normal char
            uint8_t first = pgm_read_byte(&gfxFont->first),
                    last  = pgm_read_byte(&gfxFont->last);
            if((c >= first) && (c <= last)) { // Char present in this font?
                GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
                uint8_t gw = pgm_read_byte(&glyph->width),
                        gh = pgm_read_byte(&glyph->height),
                        xa = pgm_read_byte(&glyph->xAdvance);
                int8_t  xo = pgm_read_byte(&glyph->xOffset),
                        yo = pgm_read_byte(&glyph->yOffset);
                if(wrap && ((*x+(((int16_t)xo+gw)*textsize_x)) > _width)) {
                    *x  = 0; // Reset x to zero, advance y by one line
                    *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
                }
                int16_t tsx = (int16_t)textsize_x,
                        tsy = (int16_t)textsize_y,
                        x1 = *x + xo * tsx,
                        y1 = *y + yo * tsy,
                        x2 = x1 + gw * tsx - 1,
                        y2 = y1 + gh * tsy - 1;
                if(x1 < *minx) *minx = x1;
                if(y1 < *miny) *miny = y1;
                if(x2 > *maxx) *maxx = x2;
                if(y2 > *maxy) *maxy = y2;
                *x += xa * tsx;
            }
        }

    } else { // Default font

        if(c == '\n') {                     // Newline?
            *x  = 0;                        // Reset x to zero,
            *y += textsize_y * 8;           // advance y one line
            // min/max x/y unchaged -- that waits for next 'normal' character
        } else if(c != '\r') {  // Normal char; ignore carriage returns
            if(wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
                *x  = 0;                    // Reset x to zero,
                *y += textsize_y * 8;       // advance y one line
            }
            int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
                y2 = *y + textsize_y * 8 - 1;
            if(x2 > *maxx) *maxx = x2;      // Track max x, y
            if(y2 > *maxy) *maxy = y2;
            if(*x < *minx) *minx = *x;      // Track min x, y
            if(*y < *miny) *miny = *y;
            *x += textsize_x * 6;             // Advance x one char
        }
    }
}

/**************************************************************************/
/*!
    @brief    Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str     The ascii string to measure
    @param    x       The current cursor X
    @param    y       The current cursor Y
    @param    x1      The boundary X coordinate, set by function
    @param    y1      The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
        int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    uint8_t c; // Current character

    *x1 = x;
    *y1 = y;
    *w  = *h = 0;

    int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;

    while((c = *str++))
        charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);

    if(maxx >= minx) {
        *x1 = minx;
        *w  = maxx - minx + 1;
    }
    if(maxy >= miny) {
        *y1 = miny;
        *h  = maxy - miny + 1;
    }
}

/**************************************************************************/
/*!
    @brief    Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str    The ascii string to measure (as an arduino String() class)
    @param    x      The current cursor X
    @param    y      The current cursor Y
    @param    x1     The boundary X coordinate, set by function
    @param    y1     The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
        int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    if (str.length() != 0) {
        getTextBounds(const_cast<char*>(str.c_str()), x, y, x1, y1, w, h);
    }
}


/**************************************************************************/
/*!
    @brief    Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str     The flash-memory ascii string to measure
    @param    x       The current cursor X
    @param    y       The current cursor Y
    @param    x1      The boundary X coordinate, set by function
    @param    y1      The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str,
        int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    uint8_t *s = (uint8_t *)str, c;

    *x1 = x;
    *y1 = y;
    *w  = *h = 0;

    int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;

    while((c = pgm_read_byte(s++)))
        charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);

    if(maxx >= minx) {
        *x1 = minx;
        *w  = maxx - minx + 1;
    }
    if(maxy >= miny) {
        *y1 = miny;
        *h  = maxy - miny + 1;
    }
}

/**************************************************************************/
/*!
    @brief      Invert the display (ideally using built-in hardware command)
    @param   i  True if you want to invert, false to make 'normal'
*/
/**************************************************************************/
void Adafruit_GFX::invertDisplay(boolean i) {
    // Do nothing, must be subclassed if supported by hardware
}

/***************************************************************************/

/**************************************************************************/
/*!
   @brief    Create a simple drawn button UI element
*/
/**************************************************************************/
Adafruit_GFX_Button::Adafruit_GFX_Button(void) {
  _gfx = 0;
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x       The X coordinate of the center of the button
   @param    y       The Y coordinate of the center of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize The font magnification of the label text
*/
/**************************************************************************/
// Classic initButton() function: pass center & size
void Adafruit_GFX_Button::initButton(
 Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize)
{
  // Tweak arguments and pass to the newer initButtonUL() function...
  initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
    textcolor, label, textsize);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x       The X coordinate of the center of the button
   @param    y       The Y coordinate of the center of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize_x The font magnification in X-axis of the label text
   @param    textsize_y The font magnification in Y-axis of the label text
*/
/**************************************************************************/
// Classic initButton() function: pass center & size
void Adafruit_GFX_Button::initButton(
 Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize_x, uint8_t textsize_y)
{
  // Tweak arguments and pass to the newer initButtonUL() function...
  initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
    textcolor, label, textsize_x, textsize_y);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings, with upper-left coordinates
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x1       The X coordinate of the Upper-Left corner of the button
   @param    y1       The Y coordinate of the Upper-Left corner of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize The font magnification of the label text
*/
/**************************************************************************/
void Adafruit_GFX_Button::initButtonUL(
 Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize)
{
  initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize, textsize);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings, with upper-left coordinates
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x1       The X coordinate of the Upper-Left corner of the button
   @param    y1       The Y coordinate of the Upper-Left corner of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize_x The font magnification in X-axis of the label text
   @param    textsize_y The font magnification in Y-axis of the label text
*/
/**************************************************************************/
void Adafruit_GFX_Button::initButtonUL(
 Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize_x, uint8_t textsize_y)
{
  _x1           = x1;
  _y1           = y1;
  _w            = w;
  _h            = h;
  _outlinecolor = outline;
  _fillcolor    = fill;
  _textcolor    = textcolor;
  _textsize_x   = textsize_x;
  _textsize_y   = textsize_y;
  _gfx          = gfx;
  strncpy(_label, label, 9);
}

/**************************************************************************/
/*!
   @brief    Draw the button on the screen
   @param    inverted Whether to draw with fill/text swapped to indicate 'pressed'
*/
/**************************************************************************/
void Adafruit_GFX_Button::drawButton(boolean inverted) {
  uint16_t fill, outline, text;

  if(!inverted) {
    fill    = _fillcolor;
    outline = _outlinecolor;
    text    = _textcolor;
  } else {
    fill    = _textcolor;
    outline = _outlinecolor;
    text    = _fillcolor;
  }

  uint8_t r = min(_w, _h) / 4; // Corner radius
  _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
  _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);

  _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize_x),
    _y1 + (_h/2) - (4 * _textsize_y));
  _gfx->setTextColor(text);
  _gfx->setTextSize(_textsize_x, _textsize_y);
  _gfx->print(_label);
}

/**************************************************************************/
/*!
    @brief    Helper to let us know if a coordinate is within the bounds of the button
    @param    x       The X coordinate to check
    @param    y       The Y coordinate to check
    @returns  True if within button graphics outline
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
  return ((x >= _x1) && (x < (int16_t) (_x1 + _w)) &&
          (y >= _y1) && (y < (int16_t) (_y1 + _h)));
}

/**************************************************************************/
/*!
   @brief    Query whether the button was pressed since we last checked state
   @returns  True if was not-pressed before, now is.
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }

/**************************************************************************/
/*!
   @brief    Query whether the button was released since we last checked state
   @returns  True if was pressed before, now is not.
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }

// -------------------------------------------------------------------------

// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
// comfy with the implementation) provide 1-, 8- and 16-bit offscreen
// canvases, the address of which can be passed to drawBitmap() or
// pushColors() (the latter appears only in a couple of GFX-subclassed TFT
// libraries at this time).  This is here mostly to help with the recently-
// added proportionally-spaced fonts; adds a way to refresh a section of the
// screen without a massive flickering clear-and-redraw...but maybe you'll
// find other uses too.  VERY RAM-intensive, since the buffer is in MCU
// memory and not the display driver...GXFcanvas1 might be minimally useful
// on an Uno-class board, but this and the others are much more likely to
// require at least a Mega or various recent ARM-type boards (recommended,
// as the text+bitmap draw can be pokey).  GFXcanvas1 requires 1 bit per
// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
// scanline pad).
// NOT EXTENSIVELY TESTED YET.  MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 1-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint16_t bytes = ((w + 7) / 8) * h;
    if((buffer = (uint8_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas1::~GFXcanvas1(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x     x coordinate
    @param  y     y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
#ifdef __AVR__
    // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
    static const uint8_t PROGMEM
        GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
        GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
#endif

    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        uint8_t   *ptr  = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
        if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
        else      *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
#else
        if(color) *ptr |=   0x80 >> (x & 7);
        else      *ptr &= ~(0x80 >> (x & 7));
#endif
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas1::fillScreen(uint16_t color) {
    if(buffer) {
        uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
        memset(buffer, color ? 0xFF : 0x00, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 8-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint32_t bytes = w * h;
    if((buffer = (uint8_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas8::~GFXcanvas8(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x   x coordinate
    @param  y   y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        buffer[x + y * WIDTH] = color;
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas8::fillScreen(uint16_t color) {
    if(buffer) {
        memset(buffer, color, WIDTH * HEIGHT);
    }
}

void GFXcanvas8::writeFastHLine(int16_t x, int16_t y,
  int16_t w, uint16_t color) {

    if((x >= _width) || (y < 0) || (y >= _height)) return;
    int16_t x2 = x + w - 1;
    if(x2 < 0) return;

    // Clip left/right
    if(x < 0) {
        x = 0;
        w = x2 + 1;
    }
    if(x2 >= _width) w = _width - x;

    int16_t t;
    switch(rotation) {
        case 1:
            t = x;
            x = WIDTH  - 1 - y;
            y = t;
            break;
        case 2:
            x = WIDTH  - 1 - x;
            y = HEIGHT - 1 - y;
            break;
        case 3:
            t = x;
            x = y;
            y = HEIGHT - 1 - t;
            break;
    }

    memset(buffer + y * WIDTH + x, color, w);
}

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 16-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint32_t bytes = w * h * 2;
    if((buffer = (uint16_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas16::~GFXcanvas16(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x   x coordinate
    @param  y   y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        buffer[x + y * WIDTH] = color;
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas16::fillScreen(uint16_t color) {
    if(buffer) {
        uint8_t hi = color >> 8, lo = color & 0xFF;
        if(hi == lo) {
            memset(buffer, lo, WIDTH * HEIGHT * 2);
        } else {
            uint32_t i, pixels = WIDTH * HEIGHT;
            for(i=0; i<pixels; i++) buffer[i] = color;
        }
    }
}

/**************************************************************************/
/*!
    @brief  Reverses the "endian-ness" of each 16-bit pixel within the
            canvas; little-endian to big-endian, or big-endian to little.
            Most microcontrollers (such as SAMD) are little-endian, while
            most displays tend toward big-endianness. All the drawing
            functions (including RGB bitmap drawing) take care of this
            automatically, but some specialized code (usually involving
            DMA) can benefit from having pixel data already in the
            display-native order. Note that this does NOT convert to a
            SPECIFIC endian-ness, it just flips the bytes within each word.
*/
/**************************************************************************/
void GFXcanvas16::byteSwap(void) {
    if(buffer) {
        uint32_t i, pixels = WIDTH * HEIGHT;
        for(i=0; i<pixels; i++) buffer[i] = __builtin_bswap16(buffer[i]);
    }
}

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Пробуй:

/*
This is the core graphics library for all our displays, providing a common
set of graphics primitives (points, lines, circles, etc.).  It needs to be
paired with a hardware-specific library for each display device we carry
(to handle the lower-level functions).

Adafruit invests time and resources providing this open source code, please
support Adafruit & open-source hardware by purchasing products from Adafruit!

Copyright (c) 2013 Adafruit Industries.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
 */

#include "Adafruit_GFX.h"
#include "glcdfont.c"
#ifdef __AVR__
  #include <avr/pgmspace.h>
#elif defined(ESP8266) || defined(ESP32)
  #include <pgmspace.h>
#endif

// Many (but maybe not all) non-AVR board installs define macros
// for compatibility with existing PROGMEM-reading AVR code.
// Do our own checks and defines here for good measure...

#ifndef pgm_read_byte
 #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
 #define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
 #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif

// Pointers are a peculiar case...typically 16-bit on AVR boards,
// 32 bits elsewhere.  Try to accommodate both...

#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
 #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
#else
 #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif

inline GFXglyph * pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c)
{
#ifdef __AVR__
    return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
#else
    // expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning
    // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
    // So expression may be simplified
    return gfxFont->glyph + c;
#endif //__AVR__
}

inline uint8_t * pgm_read_bitmap_ptr(const GFXfont *gfxFont)
{
#ifdef __AVR__
    return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
#else
    // expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning
    // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
    // So expression may be simplified
    return gfxFont->bitmap;
#endif //__AVR__
}

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

#ifndef _swap_int16_t
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#endif

/**************************************************************************/
/*!
   @brief    Instatiate a GFX context for graphics! Can only be done by a superclass
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
WIDTH(w), HEIGHT(h)
{
    _width    = WIDTH;
    _height   = HEIGHT;
    rotation  = 0;
    cursor_y  = cursor_x    = 0;
    textsize_x = textsize_y  = 1;
    textcolor = textbgcolor = 0xFFFF;
    wrap      = true;
    _cp437    = false;
    gfxFont   = NULL;
}

/**************************************************************************/
/*!
   @brief    Write a line.  Bresenham's algorithm - thx wikpedia
    @param    x0  Start point x coordinate
    @param    y0  Start point y coordinate
    @param    x1  End point x coordinate
    @param    y1  End point y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
        uint16_t color) {
#if defined(ESP8266)
    yield();
#endif
    int16_t steep = abs(y1 - y0) > abs(x1 - x0);
    if (steep) {
        _swap_int16_t(x0, y0);
        _swap_int16_t(x1, y1);
    }

    if (x0 > x1) {
        _swap_int16_t(x0, x1);
        _swap_int16_t(y0, y1);
    }

    int16_t dx, dy;
    dx = x1 - x0;
    dy = abs(y1 - y0);

    int16_t err = dx / 2;
    int16_t ystep;

    if (y0 < y1) {
        ystep = 1;
    } else {
        ystep = -1;
    }

    for (; x0<=x1; x0++) {
        if (steep) {
            writePixel(y0, x0, color);
        } else {
            writePixel(x0, y0, color);
        }
        err -= dy;
        if (err < 0) {
            y0 += ystep;
            err += dx;
        }
    }
}

/**************************************************************************/
/*!
   @brief    Start a display-writing routine, overwrite in subclasses.
*/
/**************************************************************************/
void Adafruit_GFX::startWrite(){
}

/**************************************************************************/
/*!
   @brief    Write a pixel, overwrite in subclasses if startWrite is defined!
    @param   x   x coordinate
    @param   y   y coordinate
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color){
    drawPixel(x, y, color);
}

/**************************************************************************/
/*!
   @brief    Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
    @param    x   Top-most x coordinate
    @param    y   Top-most y coordinate
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y,
        int16_t h, uint16_t color) {
    // Overwrite in subclasses if startWrite is defined!
    // Can be just writeLine(x, y, x, y+h-1, color);
    // or writeFillRect(x, y, 1, h, color);
    drawFastVLine(x, y, h, color);
}

/**************************************************************************/
/*!
   @brief    Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
    @param    x   Left-most x coordinate
    @param    y   Left-most y coordinate
    @param    w   Width in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y,
        int16_t w, uint16_t color) {
    // Overwrite in subclasses if startWrite is defined!
    // Example: writeLine(x, y, x+w-1, y, color);
    // or writeFillRect(x, y, w, 1, color);
    drawFastHLine(x, y, w, color);
}

/**************************************************************************/
/*!
   @brief    Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    // Overwrite in subclasses if desired!
    fillRect(x,y,w,h,color);
}

/**************************************************************************/
/*!
   @brief    End a display-writing routine, overwrite in subclasses if startWrite is defined!
*/
/**************************************************************************/
void Adafruit_GFX::endWrite(){
}

/**************************************************************************/
/*!
   @brief    Draw a perfectly vertical line (this is often optimized in a subclass!)
    @param    x   Top-most x coordinate
    @param    y   Top-most y coordinate
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
        int16_t h, uint16_t color) {
    startWrite();
    writeLine(x, y, x, y+h-1, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Draw a perfectly horizontal line (this is often optimized in a subclass!)
    @param    x   Left-most x coordinate
    @param    y   Left-most y coordinate
    @param    w   Width in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
        int16_t w, uint16_t color) {
    startWrite();
    writeLine(x, y, x+w-1, y, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Fill a rectangle completely with one color. Update in subclasses if desired!
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
   @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    startWrite();
    for (int16_t i=x; i<x+w; i++) {
        writeFastVLine(i, y, h, color);
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief    Fill the screen completely with one color. Update in subclasses if desired!
    @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillScreen(uint16_t color) {
    fillRect(0, 0, _width, _height, color);
}

/**************************************************************************/
/*!
   @brief    Draw a line
    @param    x0  Start point x coordinate
    @param    y0  Start point y coordinate
    @param    x1  End point x coordinate
    @param    y1  End point y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
        uint16_t color) {
    // Update in subclasses if desired!
    if(x0 == x1){
        if(y0 > y1) _swap_int16_t(y0, y1);
        drawFastVLine(x0, y0, y1 - y0 + 1, color);
    } else if(y0 == y1){
        if(x0 > x1) _swap_int16_t(x0, x1);
        drawFastHLine(x0, y0, x1 - x0 + 1, color);
    } else {
        startWrite();
        writeLine(x0, y0, x1, y1, color);
        endWrite();
    }
}

/**************************************************************************/
/*!
   @brief    Draw a circle outline
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
        uint16_t color) {
#if defined(ESP8266)
    yield();
#endif
    int16_t f = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x = 0;
    int16_t y = r;

    startWrite();
    writePixel(x0  , y0+r, color);
    writePixel(x0  , y0-r, color);
    writePixel(x0+r, y0  , color);
    writePixel(x0-r, y0  , color);

    while (x<y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        writePixel(x0 + x, y0 + y, color);
        writePixel(x0 - x, y0 + y, color);
        writePixel(x0 + x, y0 - y, color);
        writePixel(x0 - x, y0 - y, color);
        writePixel(x0 + y, y0 + x, color);
        writePixel(x0 - y, y0 + x, color);
        writePixel(x0 + y, y0 - x, color);
        writePixel(x0 - y, y0 - x, color);
    }
    endWrite();
}

/**************************************************************************/
/*!
    @brief    Quarter-circle drawer, used to do circles and roundrects
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    cornername  Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
        int16_t r, uint8_t cornername, uint16_t color) {
    int16_t f     = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x     = 0;
    int16_t y     = r;

    while (x<y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f     += ddF_y;
        }
        x++;
        ddF_x += 2;
        f     += ddF_x;
        if (cornername & 0x4) {
            writePixel(x0 + x, y0 + y, color);
            writePixel(x0 + y, y0 + x, color);
        }
        if (cornername & 0x2) {
            writePixel(x0 + x, y0 - y, color);
            writePixel(x0 + y, y0 - x, color);
        }
        if (cornername & 0x8) {
            writePixel(x0 - y, y0 + x, color);
            writePixel(x0 - x, y0 + y, color);
        }
        if (cornername & 0x1) {
            writePixel(x0 - y, y0 - x, color);
            writePixel(x0 - x, y0 - y, color);
        }
    }
}

/**************************************************************************/
/*!
   @brief    Draw a circle with filled color
    @param    x0   Center-point x coordinate
    @param    y0   Center-point y coordinate
    @param    r   Radius of circle
    @param    color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
        uint16_t color) {
    startWrite();
    writeFastVLine(x0, y0-r, 2*r+1, color);
    fillCircleHelper(x0, y0, r, 3, 0, color);
    endWrite();
}


/**************************************************************************/
/*!
    @brief  Quarter-circle drawer with fill, used for circles and roundrects
    @param  x0       Center-point x coordinate
    @param  y0       Center-point y coordinate
    @param  r        Radius of circle
    @param  corners  Mask bits indicating which quarters we're doing
    @param  delta    Offset from center-point, used for round-rects
    @param  color    16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
  uint8_t corners, int16_t delta, uint16_t color) {

    int16_t f     = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x     = 0;
    int16_t y     = r;
    int16_t px    = x;
    int16_t py    = y;

    delta++; // Avoid some +1's in the loop

    while(x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f     += ddF_y;
        }
        x++;
        ddF_x += 2;
        f     += ddF_x;
        // These checks avoid double-drawing certain lines, important
        // for the SSD1306 library which has an INVERT drawing mode.
        if(x < (y + 1)) {
            if(corners & 1) writeFastVLine(x0+x, y0-y, 2*y+delta, color);
            if(corners & 2) writeFastVLine(x0-x, y0-y, 2*y+delta, color);
        }
        if(y != py) {
            if(corners & 1) writeFastVLine(x0+py, y0-px, 2*px+delta, color);
            if(corners & 2) writeFastVLine(x0-py, y0-px, 2*px+delta, color);
            py = y;
        }
        px = x;
    }
}

/**************************************************************************/
/*!
   @brief   Draw a rectangle with no fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
        uint16_t color) {
    startWrite();
    writeFastHLine(x, y, w, color);
    writeFastHLine(x, y+h-1, w, color);
    writeFastVLine(x, y, h, color);
    writeFastVLine(x+w-1, y, h, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a rounded rectangle with no fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    r   Radius of corner rounding
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
  int16_t h, int16_t r, uint16_t color) {
    int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    if(r > max_radius) r = max_radius;
    // smarter version
    startWrite();
    writeFastHLine(x+r  , y    , w-2*r, color); // Top
    writeFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
    writeFastVLine(x    , y+r  , h-2*r, color); // Left
    writeFastVLine(x+w-1, y+r  , h-2*r, color); // Right
    // draw four corners
    drawCircleHelper(x+r    , y+r    , r, 1, color);
    drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
    drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
    drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a rounded rectangle with fill color
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    w   Width in pixels
    @param    h   Height in pixels
    @param    r   Radius of corner rounding
    @param    color 16-bit 5-6-5 Color to draw/fill with
*/
/**************************************************************************/
void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
  int16_t h, int16_t r, uint16_t color) {
    int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    if(r > max_radius) r = max_radius;
    // smarter version
    startWrite();
    writeFillRect(x+r, y, w-2*r, h, color);
    // draw four corners
    fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
    fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a triangle with no fill color
    @param    x0  Vertex #0 x coordinate
    @param    y0  Vertex #0 y coordinate
    @param    x1  Vertex #1 x coordinate
    @param    y1  Vertex #1 y coordinate
    @param    x2  Vertex #2 x coordinate
    @param    y2  Vertex #2 y coordinate
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
        int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
    drawLine(x0, y0, x1, y1, color);
    drawLine(x1, y1, x2, y2, color);
    drawLine(x2, y2, x0, y0, color);
}

/**************************************************************************/
/*!
   @brief     Draw a triangle with color-fill
    @param    x0  Vertex #0 x coordinate
    @param    y0  Vertex #0 y coordinate
    @param    x1  Vertex #1 x coordinate
    @param    y1  Vertex #1 y coordinate
    @param    x2  Vertex #2 x coordinate
    @param    y2  Vertex #2 y coordinate
    @param    color 16-bit 5-6-5 Color to fill/draw with
*/
/**************************************************************************/
void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
        int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {

    int16_t a, b, y, last;

    // Sort coordinates by Y order (y2 >= y1 >= y0)
    if (y0 > y1) {
        _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
    }
    if (y1 > y2) {
        _swap_int16_t(y2, y1); _swap_int16_t(x2, x1);
    }
    if (y0 > y1) {
        _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
    }

    startWrite();
    if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
        a = b = x0;
        if(x1 < a)      a = x1;
        else if(x1 > b) b = x1;
        if(x2 < a)      a = x2;
        else if(x2 > b) b = x2;
        writeFastHLine(a, y0, b-a+1, color);
        endWrite();
        return;
    }

    int16_t
    dx01 = x1 - x0,
    dy01 = y1 - y0,
    dx02 = x2 - x0,
    dy02 = y2 - y0,
    dx12 = x2 - x1,
    dy12 = y2 - y1;
    int32_t
    sa   = 0,
    sb   = 0;

    // For upper part of triangle, find scanline crossings for segments
    // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
    // is included here (and second loop will be skipped, avoiding a /0
    // error there), otherwise scanline y1 is skipped here and handled
    // in the second loop...which also avoids a /0 error here if y0=y1
    // (flat-topped triangle).
    if(y1 == y2) last = y1;   // Include y1 scanline
    else         last = y1-1; // Skip it

    for(y=y0; y<=last; y++) {
        a   = x0 + sa / dy01;
        b   = x0 + sb / dy02;
        sa += dx01;
        sb += dx02;
        /* longhand:
        a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
        b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
        */
        if(a > b) _swap_int16_t(a,b);
        writeFastHLine(a, y, b-a+1, color);
    }

    // For lower part of triangle, find scanline crossings for segments
    // 0-2 and 1-2.  This loop is skipped if y1=y2.
    sa = (int32_t)dx12 * (y - y1);
    sb = (int32_t)dx02 * (y - y0);
    for(; y<=y2; y++) {
        a   = x1 + sa / dy12;
        b   = x0 + sb / dy02;
        sa += dx12;
        sb += dx02;
        /* longhand:
        a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
        b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
        */
        if(a > b) _swap_int16_t(a,b);
        writeFastHLine(a, y, b-a+1, color);
    }
    endWrite();
}

// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------

/**************************************************************************/
/*!
   @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            if(byte & 0x80) writePixel(x+i, y, color);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
    @param    bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h,
  uint16_t color, uint16_t bg) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            writePixel(x+i, y, (byte & 0x80) ? color : bg);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = bitmap[j * byteWidth + i / 8];
            if(byte & 0x80) writePixel(x+i, y, color);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
    @param    bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = bitmap[j * byteWidth + i / 8];
            writePixel(x+i, y, (byte & 0x80) ? color : bg);
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief      Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
   Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
   C Array can be directly used with this function.
   There is no RAM-resident version of this function; if generating bitmaps
   in RAM, use the format defined by drawBitmap() and call that instead.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with monochrome bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
    @param    color 16-bit 5-6-5 Color to draw pixels with
*/
/**************************************************************************/
void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {

    int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    uint8_t byte = 0;

    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte >>= 1;
            else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
            // Nearly identical to drawBitmap(), only the bit order
            // is reversed here (left-to-right = LSB to MSB):
            if(byte & 0x01) writePixel(x+i, y, color);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, bitmap[j * w + i]);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
   (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   BOTH buffers (grayscale and mask) must be PROGMEM-resident.
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    mask  byte array with mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  const uint8_t bitmap[], const uint8_t mask[],
  int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&mask[j * bw + i / 8]);
            if(byte & 0x80) {
                writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
            }
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
   (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
   Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with grayscale bitmap
    @param    mask  byte array with mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = mask[j * bw + i / 8];
            if(byte & 0x80) {
                writePixel(x+i, y, bitmap[j * w + i]);
            }
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  const uint16_t bitmap[], int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  uint16_t *bitmap, int16_t w, int16_t h) {
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            writePixel(x+i, y, bitmap[j * w + i]);
        }
    }
    endWrite();
}


/**************************************************************************/
/*!
   @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be PROGMEM-resident. For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    mask  byte array with monochrome mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  const uint16_t bitmap[], const uint8_t mask[],
  int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = pgm_read_byte(&mask[j * bw + i / 8]);
            if(byte & 0x80) {
                writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
            }
        }
    }
    endWrite();
}

/**************************************************************************/
/*!
   @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be RAM-resident. For 16-bit display devices; no color reduction performed.
    @param    x   Top left corner x coordinate
    @param    y   Top left corner y coordinate
    @param    bitmap  byte array with 16-bit color bitmap
    @param    mask  byte array with monochrome mask bitmap
    @param    w   Width of bitmap in pixels
    @param    h   Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
    int16_t bw   = (w + 7) / 8; // Bitmask scanline pad = whole byte
    uint8_t byte = 0;
    startWrite();
    for(int16_t j=0; j<h; j++, y++) {
        for(int16_t i=0; i<w; i++ ) {
            if(i & 7) byte <<= 1;
            else      byte   = mask[j * bw + i / 8];
            if(byte & 0x80) {
                writePixel(x+i, y, bitmap[j * w + i]);
            }
        }
    }
    endWrite();
}

// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------

// Draw a character
/**************************************************************************/
/*!
   @brief   Draw a single character
    @param    x   Bottom left corner x coordinate
    @param    y   Bottom left corner y coordinate
    @param    c   The 8-bit font-indexed character (likely ascii)
    @param    color 16-bit 5-6-5 Color to draw chraracter with
    @param    bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
    @param    size  Font magnification level, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
  uint16_t color, uint16_t bg, uint8_t size) {
    drawChar(x, y, c, color, bg, size, size);
}

// Draw a character
/**************************************************************************/
/*!
   @brief   Draw a single character
    @param    x   Bottom left corner x coordinate
    @param    y   Bottom left corner y coordinate
    @param    c   The 8-bit font-indexed character (likely ascii)
    @param    color 16-bit 5-6-5 Color to draw chraracter with
    @param    bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
    @param    size_x  Font magnification level in X-axis, 1 is 'original' size
    @param    size_y  Font magnification level in Y-axis, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
  uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) {

    if(!gfxFont) { // 'Classic' built-in font

        if((x >= _width)            || // Clip right
           (y >= _height)           || // Clip bottom
           ((x + 6 * size_x - 1) < 0) || // Clip left
           ((y + 8 * size_y - 1) < 0))   // Clip top
            return;

        if(!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior

        startWrite();
        for(int8_t i=0; i<5; i++ ) { // Char bitmap = 5 columns
            uint8_t line = pgm_read_byte(&font[c * 5 + i]);
            for(int8_t j=0; j<8; j++, line >>= 1) {
                if(line & 1) {
                    if(size_x == 1 && size_y == 1)
                        writePixel(x+i, y+j, color);
                    else
                        writeFillRect(x+i*size_x, y+j*size_y, size_x, size_y, color);
                } else if(bg != color) {
                    if(size_x == 1 && size_y == 1)
                        writePixel(x+i, y+j, bg);
                    else
                        writeFillRect(x+i*size_x, y+j*size_y, size_x, size_y, bg);
                }
            }
        }
        if(bg != color) { // If opaque, draw vertical line for last column
            if(size_x == 1 && size_y == 1) writeFastVLine(x+5, y, 8, bg);
            else          writeFillRect(x+5*size_x, y, size_x, 8*size_y, bg);
        }
        endWrite();

    } else { // Custom font

        // Character is assumed previously filtered by write() to eliminate
        // newlines, returns, non-printable characters, etc.  Calling
        // drawChar() directly with 'bad' characters of font may cause mayhem!

        c -= (uint8_t)pgm_read_byte(&gfxFont->first);
        GFXglyph *glyph  = pgm_read_glyph_ptr(gfxFont, c);
        uint8_t  *bitmap = pgm_read_bitmap_ptr(gfxFont);

        uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
        uint8_t  w  = pgm_read_byte(&glyph->width),
                 h  = pgm_read_byte(&glyph->height);
        int8_t   xo = pgm_read_byte(&glyph->xOffset),
                 yo = pgm_read_byte(&glyph->yOffset);
        uint8_t  xx, yy, bits = 0, bit = 0;
        int16_t  xo16 = 0, yo16 = 0;

        if(size_x > 1 || size_y > 1) {
            xo16 = xo;
            yo16 = yo;
        }

        // Todo: Add character clipping here

        // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
        // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
        // has typically been used with the 'classic' font to overwrite old
        // screen contents with new data.  This ONLY works because the
        // characters are a uniform size; it's not a sensible thing to do with
        // proportionally-spaced fonts with glyphs of varying sizes (and that
        // may overlap).  To replace previously-drawn text when using a custom
        // font, use the getTextBounds() function to determine the smallest
        // rectangle encompassing a string, erase the area with fillRect(),
        // then draw new text.  This WILL infortunately 'blink' the text, but
        // is unavoidable.  Drawing 'background' pixels will NOT fix this,
        // only creates a new set of problems.  Have an idea to work around
        // this (a canvas object type for MCUs that can afford the RAM and
        // displays supporting setAddrWindow() and pushColors()), but haven't
        // implemented this yet.

        startWrite();
        for(yy=0; yy<h; yy++) {
            for(xx=0; xx<w; xx++) {
                if(!(bit++ & 7)) {
                    bits = pgm_read_byte(&bitmap[bo++]);
                }
                if(bits & 0x80) {
                    if(size_x == 1 && size_y == 1) {
                        writePixel(x+xo+xx, y+yo+yy, 0xF800);//color);
                    } else {
                        writeFillRect(x+(xo16+xx)*size_x, y+(yo16+yy)*size_y,
                          size_x, size_y, 0xF800);//color);
                    }
                } else {
                    if(size_x == 1 && size_y == 1) {
                        writePixel(x+xo+xx, y+yo+yy, 0x0000);//color);
                    } else {
                        writeFillRect(x+(xo16+xx)*size_x, y+(yo16+yy)*size_y,
                          size_x, size_y, 0x0000);//color);
                    }
                 }
                bits <<= 1;
            }
        }
        endWrite();

    } // End classic vs custom font
}
/**************************************************************************/
/*!
    @brief  Print one byte/character of data, used to support print()
    @param  c  The 8-bit ascii character to write
*/
/**************************************************************************/
size_t Adafruit_GFX::write(uint8_t c) {
    if(!gfxFont) { // 'Classic' built-in font

        if(c == '\n') {                        // Newline?
            cursor_x  = 0;                     // Reset x to zero,
            cursor_y += textsize_y * 8;        // advance y one line
        } else if(c != '\r') {                 // Ignore carriage returns
            if(wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right?
                cursor_x  = 0;                 // Reset x to zero,
                cursor_y += textsize_y * 8;    // advance y one line
            }
            drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y);
            cursor_x += textsize_x * 6;          // Advance x one char
        }

    } else { // Custom font

        if(c == '\n') {
            cursor_x  = 0;
            cursor_y += (int16_t)textsize_y *
                        (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
        } else if(c != '\r') {
            uint8_t first = pgm_read_byte(&gfxFont->first);
            if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
                GFXglyph *glyph  = pgm_read_glyph_ptr(gfxFont, c - first);
                uint8_t   w     = pgm_read_byte(&glyph->width),
                          h     = pgm_read_byte(&glyph->height);
                if((w > 0) && (h > 0)) { // Is there an associated bitmap?
                    int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
                    if(wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
                        cursor_x  = 0;
                        cursor_y += (int16_t)textsize_y *
                          (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
                    }
                    drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y);
                }
                cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x;
            }
        }

    }
    return 1;
}

/**************************************************************************/
/*!
    @brief   Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
    @param  s  Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
*/
/**************************************************************************/
void Adafruit_GFX::setTextSize(uint8_t s) {
    setTextSize(s, s);
}

/**************************************************************************/
/*!
    @brief   Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
    @param  s_x  Desired text width magnification level in X-axis. 1 is default
    @param  s_y  Desired text width magnification level in Y-axis. 1 is default
*/
/**************************************************************************/
void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
    textsize_x = (s_x > 0) ? s_x : 1;
    textsize_y = (s_y > 0) ? s_y : 1;
}

/**************************************************************************/
/*!
    @brief      Set rotation setting for display
    @param  x   0 thru 3 corresponding to 4 cardinal rotations
*/
/**************************************************************************/
void Adafruit_GFX::setRotation(uint8_t x) {
    rotation = (x & 3);
    switch(rotation) {
        case 0:
        case 2:
            _width  = WIDTH;
            _height = HEIGHT;
            break;
        case 1:
        case 3:
            _width  = HEIGHT;
            _height = WIDTH;
            break;
    }
}

/**************************************************************************/
/*!
    @brief Set the font to display when print()ing, either custom or default
    @param  f  The GFXfont object, if NULL use built in 6x8 font
*/
/**************************************************************************/
void Adafruit_GFX::setFont(const GFXfont *f) {
    if(f) {            // Font struct pointer passed in?
        if(!gfxFont) { // And no current font struct?
            // Switching from classic to new font behavior.
            // Move cursor pos down 6 pixels so it's on baseline.
            cursor_y += 6;
        }
    } else if(gfxFont) { // NULL passed.  Current font struct defined?
        // Switching from new to classic font behavior.
        // Move cursor pos up 6 pixels so it's at top-left of char.
        cursor_y -= 6;
    }
    gfxFont = (GFXfont *)f;
}


/**************************************************************************/
/*!
    @brief    Helper to determine size of a character with current font/size.
       Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
    @param    c     The ascii character in question
    @param    x     Pointer to x location of character
    @param    y     Pointer to y location of character
    @param    minx  Minimum clipping value for X
    @param    miny  Minimum clipping value for Y
    @param    maxx  Maximum clipping value for X
    @param    maxy  Maximum clipping value for Y
*/
/**************************************************************************/
void Adafruit_GFX::charBounds(char c, int16_t *x, int16_t *y,
  int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) {

    if(gfxFont) {

        if(c == '\n') { // Newline?
            *x  = 0;    // Reset x to zero, advance y by one line
            *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
        } else if(c != '\r') { // Not a carriage return; is normal char
            uint8_t first = pgm_read_byte(&gfxFont->first),
                    last  = pgm_read_byte(&gfxFont->last);
            if((c >= first) && (c <= last)) { // Char present in this font?
                GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
                uint8_t gw = pgm_read_byte(&glyph->width),
                        gh = pgm_read_byte(&glyph->height),
                        xa = pgm_read_byte(&glyph->xAdvance);
                int8_t  xo = pgm_read_byte(&glyph->xOffset),
                        yo = pgm_read_byte(&glyph->yOffset);
                if(wrap && ((*x+(((int16_t)xo+gw)*textsize_x)) > _width)) {
                    *x  = 0; // Reset x to zero, advance y by one line
                    *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
                }
                int16_t tsx = (int16_t)textsize_x,
                        tsy = (int16_t)textsize_y,
                        x1 = *x + xo * tsx,
                        y1 = *y + yo * tsy,
                        x2 = x1 + gw * tsx - 1,
                        y2 = y1 + gh * tsy - 1;
                if(x1 < *minx) *minx = x1;
                if(y1 < *miny) *miny = y1;
                if(x2 > *maxx) *maxx = x2;
                if(y2 > *maxy) *maxy = y2;
                *x += xa * tsx;
            }
        }

    } else { // Default font

        if(c == '\n') {                     // Newline?
            *x  = 0;                        // Reset x to zero,
            *y += textsize_y * 8;           // advance y one line
            // min/max x/y unchaged -- that waits for next 'normal' character
        } else if(c != '\r') {  // Normal char; ignore carriage returns
            if(wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
                *x  = 0;                    // Reset x to zero,
                *y += textsize_y * 8;       // advance y one line
            }
            int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
                y2 = *y + textsize_y * 8 - 1;
            if(x2 > *maxx) *maxx = x2;      // Track max x, y
            if(y2 > *maxy) *maxy = y2;
            if(*x < *minx) *minx = *x;      // Track min x, y
            if(*y < *miny) *miny = *y;
            *x += textsize_x * 6;             // Advance x one char
        }
    }
}

/**************************************************************************/
/*!
    @brief    Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str     The ascii string to measure
    @param    x       The current cursor X
    @param    y       The current cursor Y
    @param    x1      The boundary X coordinate, set by function
    @param    y1      The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
        int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    uint8_t c; // Current character

    *x1 = x;
    *y1 = y;
    *w  = *h = 0;

    int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;

    while((c = *str++))
        charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);

    if(maxx >= minx) {
        *x1 = minx;
        *w  = maxx - minx + 1;
    }
    if(maxy >= miny) {
        *y1 = miny;
        *h  = maxy - miny + 1;
    }
}

/**************************************************************************/
/*!
    @brief    Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str    The ascii string to measure (as an arduino String() class)
    @param    x      The current cursor X
    @param    y      The current cursor Y
    @param    x1     The boundary X coordinate, set by function
    @param    y1     The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
        int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    if (str.length() != 0) {
        getTextBounds(const_cast<char*>(str.c_str()), x, y, x1, y1, w, h);
    }
}


/**************************************************************************/
/*!
    @brief    Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
    @param    str     The flash-memory ascii string to measure
    @param    x       The current cursor X
    @param    y       The current cursor Y
    @param    x1      The boundary X coordinate, set by function
    @param    y1      The boundary Y coordinate, set by function
    @param    w      The boundary width, set by function
    @param    h      The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str,
        int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
    uint8_t *s = (uint8_t *)str, c;

    *x1 = x;
    *y1 = y;
    *w  = *h = 0;

    int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;

    while((c = pgm_read_byte(s++)))
        charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);

    if(maxx >= minx) {
        *x1 = minx;
        *w  = maxx - minx + 1;
    }
    if(maxy >= miny) {
        *y1 = miny;
        *h  = maxy - miny + 1;
    }
}

/**************************************************************************/
/*!
    @brief      Invert the display (ideally using built-in hardware command)
    @param   i  True if you want to invert, false to make 'normal'
*/
/**************************************************************************/
void Adafruit_GFX::invertDisplay(boolean i) {
    // Do nothing, must be subclassed if supported by hardware
}

/***************************************************************************/

/**************************************************************************/
/*!
   @brief    Create a simple drawn button UI element
*/
/**************************************************************************/
Adafruit_GFX_Button::Adafruit_GFX_Button(void) {
  _gfx = 0;
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x       The X coordinate of the center of the button
   @param    y       The Y coordinate of the center of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize The font magnification of the label text
*/
/**************************************************************************/
// Classic initButton() function: pass center & size
void Adafruit_GFX_Button::initButton(
 Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize)
{
  // Tweak arguments and pass to the newer initButtonUL() function...
  initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
    textcolor, label, textsize);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x       The X coordinate of the center of the button
   @param    y       The Y coordinate of the center of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize_x The font magnification in X-axis of the label text
   @param    textsize_y The font magnification in Y-axis of the label text
*/
/**************************************************************************/
// Classic initButton() function: pass center & size
void Adafruit_GFX_Button::initButton(
 Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize_x, uint8_t textsize_y)
{
  // Tweak arguments and pass to the newer initButtonUL() function...
  initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
    textcolor, label, textsize_x, textsize_y);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings, with upper-left coordinates
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x1       The X coordinate of the Upper-Left corner of the button
   @param    y1       The Y coordinate of the Upper-Left corner of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize The font magnification of the label text
*/
/**************************************************************************/
void Adafruit_GFX_Button::initButtonUL(
 Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize)
{
  initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize, textsize);
}

/**************************************************************************/
/*!
   @brief    Initialize button with our desired color/size/settings, with upper-left coordinates
   @param    gfx     Pointer to our display so we can draw to it!
   @param    x1       The X coordinate of the Upper-Left corner of the button
   @param    y1       The Y coordinate of the Upper-Left corner of the button
   @param    w       Width of the buttton
   @param    h       Height of the buttton
   @param    outline  Color of the outline (16-bit 5-6-5 standard)
   @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   @param    label  Ascii string of the text inside the button
   @param    textsize_x The font magnification in X-axis of the label text
   @param    textsize_y The font magnification in Y-axis of the label text
*/
/**************************************************************************/
void Adafruit_GFX_Button::initButtonUL(
 Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
 uint16_t outline, uint16_t fill, uint16_t textcolor,
 char *label, uint8_t textsize_x, uint8_t textsize_y)
{
  _x1           = x1;
  _y1           = y1;
  _w            = w;
  _h            = h;
  _outlinecolor = outline;
  _fillcolor    = fill;
  _textcolor    = textcolor;
  _textsize_x   = textsize_x;
  _textsize_y   = textsize_y;
  _gfx          = gfx;
  strncpy(_label, label, 9);
}

/**************************************************************************/
/*!
   @brief    Draw the button on the screen
   @param    inverted Whether to draw with fill/text swapped to indicate 'pressed'
*/
/**************************************************************************/
void Adafruit_GFX_Button::drawButton(boolean inverted) {
  uint16_t fill, outline, text;

  if(!inverted) {
    fill    = _fillcolor;
    outline = _outlinecolor;
    text    = _textcolor;
  } else {
    fill    = _textcolor;
    outline = _outlinecolor;
    text    = _fillcolor;
  }

  uint8_t r = min(_w, _h) / 4; // Corner radius
  _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
  _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);

  _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize_x),
    _y1 + (_h/2) - (4 * _textsize_y));
  _gfx->setTextColor(text);
  _gfx->setTextSize(_textsize_x, _textsize_y);
  _gfx->print(_label);
}

/**************************************************************************/
/*!
    @brief    Helper to let us know if a coordinate is within the bounds of the button
    @param    x       The X coordinate to check
    @param    y       The Y coordinate to check
    @returns  True if within button graphics outline
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
  return ((x >= _x1) && (x < (int16_t) (_x1 + _w)) &&
          (y >= _y1) && (y < (int16_t) (_y1 + _h)));
}

/**************************************************************************/
/*!
   @brief    Query whether the button was pressed since we last checked state
   @returns  True if was not-pressed before, now is.
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }

/**************************************************************************/
/*!
   @brief    Query whether the button was released since we last checked state
   @returns  True if was pressed before, now is not.
*/
/**************************************************************************/
boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }

// -------------------------------------------------------------------------

// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
// comfy with the implementation) provide 1-, 8- and 16-bit offscreen
// canvases, the address of which can be passed to drawBitmap() or
// pushColors() (the latter appears only in a couple of GFX-subclassed TFT
// libraries at this time).  This is here mostly to help with the recently-
// added proportionally-spaced fonts; adds a way to refresh a section of the
// screen without a massive flickering clear-and-redraw...but maybe you'll
// find other uses too.  VERY RAM-intensive, since the buffer is in MCU
// memory and not the display driver...GXFcanvas1 might be minimally useful
// on an Uno-class board, but this and the others are much more likely to
// require at least a Mega or various recent ARM-type boards (recommended,
// as the text+bitmap draw can be pokey).  GFXcanvas1 requires 1 bit per
// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
// scanline pad).
// NOT EXTENSIVELY TESTED YET.  MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 1-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint16_t bytes = ((w + 7) / 8) * h;
    if((buffer = (uint8_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas1::~GFXcanvas1(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x     x coordinate
    @param  y     y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
#ifdef __AVR__
    // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
    static const uint8_t PROGMEM
        GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
        GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
#endif

    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        uint8_t   *ptr  = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
        if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
        else      *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
#else
        if(color) *ptr |=   0x80 >> (x & 7);
        else      *ptr &= ~(0x80 >> (x & 7));
#endif
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas1::fillScreen(uint16_t color) {
    if(buffer) {
        uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
        memset(buffer, color ? 0xFF : 0x00, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 8-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint32_t bytes = w * h;
    if((buffer = (uint8_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas8::~GFXcanvas8(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x   x coordinate
    @param  y   y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        buffer[x + y * WIDTH] = color;
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas8::fillScreen(uint16_t color) {
    if(buffer) {
        memset(buffer, color, WIDTH * HEIGHT);
    }
}

void GFXcanvas8::writeFastHLine(int16_t x, int16_t y,
  int16_t w, uint16_t color) {

    if((x >= _width) || (y < 0) || (y >= _height)) return;
    int16_t x2 = x + w - 1;
    if(x2 < 0) return;

    // Clip left/right
    if(x < 0) {
        x = 0;
        w = x2 + 1;
    }
    if(x2 >= _width) w = _width - x;

    int16_t t;
    switch(rotation) {
        case 1:
            t = x;
            x = WIDTH  - 1 - y;
            y = t;
            break;
        case 2:
            x = WIDTH  - 1 - x;
            y = HEIGHT - 1 - y;
            break;
        case 3:
            t = x;
            x = y;
            y = HEIGHT - 1 - t;
            break;
    }

    memset(buffer + y * WIDTH + x, color, w);
}

/**************************************************************************/
/*!
   @brief    Instatiate a GFX 16-bit canvas context for graphics
   @param    w   Display width, in pixels
   @param    h   Display height, in pixels
*/
/**************************************************************************/
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
    uint32_t bytes = w * h * 2;
    if((buffer = (uint16_t *)malloc(bytes))) {
        memset(buffer, 0, bytes);
    }
}

/**************************************************************************/
/*!
   @brief    Delete the canvas, free memory
*/
/**************************************************************************/
GFXcanvas16::~GFXcanvas16(void) {
    if(buffer) free(buffer);
}

/**************************************************************************/
/*!
    @brief  Draw a pixel to the canvas framebuffer
    @param  x   x coordinate
    @param  y   y coordinate
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
    if(buffer) {
        if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;

        int16_t t;
        switch(rotation) {
            case 1:
                t = x;
                x = WIDTH  - 1 - y;
                y = t;
                break;
            case 2:
                x = WIDTH  - 1 - x;
                y = HEIGHT - 1 - y;
                break;
            case 3:
                t = x;
                x = y;
                y = HEIGHT - 1 - t;
                break;
        }

        buffer[x + y * WIDTH] = color;
    }
}

/**************************************************************************/
/*!
    @brief  Fill the framebuffer completely with one color
    @param  color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFXcanvas16::fillScreen(uint16_t color) {
    if(buffer) {
        uint8_t hi = color >> 8, lo = color & 0xFF;
        if(hi == lo) {
            memset(buffer, lo, WIDTH * HEIGHT * 2);
        } else {
            uint32_t i, pixels = WIDTH * HEIGHT;
            for(i=0; i<pixels; i++) buffer[i] = color;
        }
    }
}

/**************************************************************************/
/*!
    @brief  Reverses the "endian-ness" of each 16-bit pixel within the
            canvas; little-endian to big-endian, or big-endian to little.
            Most microcontrollers (such as SAMD) are little-endian, while
            most displays tend toward big-endianness. All the drawing
            functions (including RGB bitmap drawing) take care of this
            automatically, but some specialized code (usually involving
            DMA) can benefit from having pixel data already in the
            display-native order. Note that this does NOT convert to a
            SPECIFIC endian-ness, it just flips the bytes within each word.
*/
/**************************************************************************/
void GFXcanvas16::byteSwap(void) {
    if(buffer) {
        uint32_t i, pixels = WIDTH * HEIGHT;
        for(i=0; i<pixels; i++) buffer[i] = __builtin_bswap16(buffer[i]);
    }
}

 

viki13viki
Offline
Зарегистрирован: 14.11.2016

сверни текс а то огромный . Не помогло

MaksVV
Offline
Зарегистрирован: 06.08.2015

а если против налипания сделать  setbackcolor ?

viki13viki
Offline
Зарегистрирован: 14.11.2016

делал , если поставить после цвета, то данные не отображаются закрашены. если перед цветом эфекта нет, если в конце после выводных данных тоже нет эфекта. может я не там вставлял......

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

viki13viki пишет:

Не помогло

Вообще ничего не изменилось ?

viki13viki
Offline
Зарегистрирован: 14.11.2016

неа накладываются как и раньше. раскажу интересное. ставлю такую пару

myGLCD.setBackColor(BLACK);

myGLCD.setTextColor(WHITE); не затриает накладываются

меняю ченый на красный. на фоне красный квадратик на нем цифры типа прозрачные черный фона за ними и прекрасно затираются. любой цвет кроме ченого такая же картинка. с ченым не хочет. но это фигня из за бека венулось моргание. замкнутый круг какой то

MaksVV
Offline
Зарегистрирован: 06.08.2015

может ввести переменные клоны (старые значения), и перед распечаткой нового значения, сначала распечатывать старое чёрным цветом, тогда не будет накладываться

MaksVV
Offline
Зарегистрирован: 06.08.2015

типа как с двоеточием порешали

viki13viki
Offline
Зарегистрирован: 14.11.2016

блин но почему с черным так не работает, и почему при других цветах цифры становятся png а при черном белые остаются, фигня какя то, ведь должно по идеи работать, странно. каким образом клонов организовать? это не сильно затормозит вывод? он и так не очень быстрый

MaksVV
Offline
Зарегистрирован: 06.08.2015

не знаю, но когда мигает он вобщееее  не быстрый , когда не мигает может будет и нормально. как каким образом, объявляешь все распечатываемые переменные (ещё одни) с префиксом last_ например. после распечатки этих чёрных last приравниваешь их к текущим. и далее распечатываешь текущее уже белым. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

и это людям помогает myGLCD.setTextColor(WHITE, BLACK); мне нет. да он сейчас быстрее чем был с миганием тут и говорить не чего. ландно про lastы буду завтра думать. на сегодня все, всем спасибо.

MaksVV
Offline
Зарегистрирован: 06.08.2015

попробовал , так тоже будет мигать, конечно гораздо менее заметно. Но глаз успевает увидеть эти черные цифры на мгновение. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

Макс ты имеешь в виду затирание колоном? лан все башка лопает, я домой.

MaksVV
Offline
Зарегистрирован: 06.08.2015

может тут что полезное увидишь 

MaksVV
Offline
Зарегистрирован: 06.08.2015

viki13viki пишет:

Макс ты имеешь в виду затирание колоном? лан все башка лопает, я домой.

имел ввиду затирание ластами

viki13viki
Offline
Зарегистрирован: 14.11.2016

А понял. Завтра сылку гляну твою.

viki13viki
Offline
Зарегистрирован: 14.11.2016

Ехал домой и думал. Settextcolor только даёт цвет тексту и не затирает, потому что даже разделители и рамки кнопок на неё не ведутся . А вот SetColor он универсальный он даёт цвет всему что после него, не толко тексту, по сути он мигал потому-что делал очистку. Но эта функция тормозит сильно все, вот её недостаток. Примерно так.

MaksVV
Offline
Зарегистрирован: 06.08.2015

кинь мне файл своего шрифта 

viki13viki
Offline
Зарегистрирован: 14.11.2016

Завтра кину, я уже дома.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Моргает из-за 165 строки utftglue.h

viki13viki
Offline
Зарегистрирован: 14.11.2016

 эта if (_fcolor != _bcolor) MCUFRIEND_kbv::fillRect(x, y, len + pad + 1, h, _bcolor); ?

че с ней можно сделать?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Если тут исправить (закомментировать 163-167), то будет наслоение символов, моргать должно перестать совсем - в любом раскладе. Я вроде вчера исправил фруктовую библиотеку - должно было как то измениться наслоение или уменьшится или пропасть.