// IMPORTANT: LIBRARY MUST BE SPECIFICALLY CONFIGURED FOR EITHER TFT SHIELD
// OR BREAKOUT BOARD USAGE.

// Lcdwiki GUI library
// MIT license

#if defined(__SAM3X8E__)
	#include <include/pio.h>
    #define PROGMEM
    #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
    #define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif

#include "pins_arduino.h"
#include "wiring_private.h"
#include "LCDWIKI_KBV.h"
#include "lcd_registers.h"
#include "lcd_mode.h"
#if (CONFIG_USE_8BIT_BUS==1)
#include "mcu_8bit_magic.h"
#elif (CONFIG_USE_8BIT_BUS==0)
#include "mcu_16bit_magic.h"
#endif

#define TFTLCD_DELAY16  0xFFFF
#define TFTLCD_DELAY8   0x7F
#define MAX_REG_NUM     24

//static uint8_t have_reset;

//#define LEFT_SHIFT(x) (1<<x) //x value 0:mipi dcs rev1
                             //        1:auto readinc
                             //        2:read bgr
                             //        3:read low and high
                             //        4:read 24 bits
                             //        5:xsa and xea 16 bit
                             //        6:read no dummy
                             //        8:invert gs
                             //        9:invert ss
                             //       10:mv axis
                             //       11:invert rgb
                             //       12:rev screen
                             //       13:filp vert	
			                 //       14:flip horiz

//The mode,width and heigth of supported LCD modules
lcd_info current_lcd_info[] = 
						 { 
							 0x9325,240,320,			
							 0x9328,240,320,
							 0x9341,240,320,
							 0x9090,320,480,
							 0x7575,240,320,
							 0x9595,240,320,
							 0x9486,320,480,
							 0x7735,128,160,
							 0x9488,320,480,
							 0x9481,320,480,
							 0x7796,320,480,
							 0x7789,240,320,
						 };

// Constructor for breakout board (configurable LCD control lines).
// Can still use this w/shield, but parameters are ignored.
// if modules is unreadable or you don't know the width and height of modules,you can use this constructor.
LCDWIKI_KBV::LCDWIKI_KBV(uint16_t model,uint8_t cs, uint8_t cd, uint8_t wr, uint8_t rd, uint8_t reset)
{	
  #ifndef USE_ADAFRUIT_SHIELD_PIN
	  // Convert pin numbers to registers and bitmasks
	  _reset	 = reset;
  #ifdef __AVR__
		csPort	   = portOutputRegister(digitalPinToPort(cs));
		cdPort	   = portOutputRegister(digitalPinToPort(cd));
		wrPort	   = portOutputRegister(digitalPinToPort(wr));
		rdPort	   = portOutputRegister(digitalPinToPort(rd));
  #endif
  #if defined(__SAM3X8E__)
		csPort	   = digitalPinToPort(cs);
		cdPort	   = digitalPinToPort(cd);
		wrPort	   = digitalPinToPort(wr);
		rdPort	   = digitalPinToPort(rd);
  #endif
	  csPinSet	 = digitalPinToBitMask(cs);
	  cdPinSet	 = digitalPinToBitMask(cd);
	  wrPinSet	 = digitalPinToBitMask(wr);
	  rdPinSet	 = digitalPinToBitMask(rd);
	  csPinUnset = ~csPinSet;
	  cdPinUnset = ~cdPinSet;
	  wrPinUnset = ~wrPinSet;
	  rdPinUnset = ~rdPinSet;
  #ifdef __AVR__
		*csPort   |=  csPinSet; // Set all control bits to HIGH (idle)
		*cdPort   |=  cdPinSet; // Signals are ACTIVE LOW
		*wrPort   |=  wrPinSet;
		*rdPort   |=  rdPinSet;
  #endif
  #if defined(__SAM3X8E__)
		csPort->PIO_SODR  |=  csPinSet; // Set all control bits to HIGH (idle)
		cdPort->PIO_SODR  |=  cdPinSet; // Signals are ACTIVE LOW
		wrPort->PIO_SODR  |=  wrPinSet;
		rdPort->PIO_SODR  |=  rdPinSet;
  #endif
	  pinMode(cs, OUTPUT);	  // Enable outputs
	  pinMode(cd, OUTPUT);
	  pinMode(wr, OUTPUT);
	  pinMode(rd, OUTPUT);
	  if(reset) 
	  {
		 digitalWrite(reset, HIGH);
		 pinMode(reset, OUTPUT);
	  }
  #endif
  #ifdef USE_ADAFRUIT_SHIELD_PIN 
  	 CS_IDLE; // Set all control bits to idle state
 	 WR_IDLE;
  	 RD_IDLE;
  	 CD_DATA;
 	 digitalWrite(5, HIGH); // Reset line
 	 pinMode(A3, OUTPUT);   // Enable outputs
 	 pinMode(A2, OUTPUT);
 	 pinMode(A1, OUTPUT);
 	 pinMode(A0, OUTPUT);
  	 pinMode( 5, OUTPUT);
 #endif
 	rotation = 0;
 	lcd_model = current_lcd_info[model].lcd_id;
	WIDTH = current_lcd_info[model].lcd_wid;
	HEIGHT = current_lcd_info[model].lcd_heg;
/*
	switch(lcd_model)
	{
		case 0x7735:
			WIDTH = 128;
			HEIGHT = 160;
		    break;
		case 0x9325:
		case 0x9328:
		case 0x9341:
		case 0x7575:
		case 0x9595:
			WIDTH = 240;
			HEIGHT = 320;
		    break;
		case 0x9486:
			WIDTH = 320;
			HEIGHT = 480;
            break;
		default:
			WIDTH = 0;
			HEIGHT = 0;
			break;
	}
*/
    setWriteDir();
 	width = WIDTH;
	height = HEIGHT;		
}

// Constructor for breakout board (configurable LCD control lines).
// Can still use this w/shield, but parameters are ignored.
// if modules is readable or you know the width and height of modules,you can use this constructor.
LCDWIKI_KBV::LCDWIKI_KBV(int16_t wid,int16_t heg,uint8_t cs, uint8_t cd, uint8_t wr, uint8_t rd, uint8_t reset)
{	
  #ifndef USE_ADAFRUIT_SHIELD_PIN
	  // Convert pin numbers to registers and bitmasks
	  _reset	 = reset;
  #ifdef __AVR__
		csPort	   = portOutputRegister(digitalPinToPort(cs));
		cdPort	   = portOutputRegister(digitalPinToPort(cd));
		wrPort	   = portOutputRegister(digitalPinToPort(wr));
		rdPort	   = portOutputRegister(digitalPinToPort(rd));
  #endif
  #if defined(__SAM3X8E__)
		csPort	   = digitalPinToPort(cs);
		cdPort	   = digitalPinToPort(cd);
		wrPort	   = digitalPinToPort(wr);
		rdPort	   = digitalPinToPort(rd);
  #endif
	  csPinSet	 = digitalPinToBitMask(cs);
	  cdPinSet	 = digitalPinToBitMask(cd);
	  wrPinSet	 = digitalPinToBitMask(wr);
	  rdPinSet	 = digitalPinToBitMask(rd);
	  csPinUnset = ~csPinSet;
	  cdPinUnset = ~cdPinSet;
	  wrPinUnset = ~wrPinSet;
	  rdPinUnset = ~rdPinSet;
  #ifdef __AVR__
		*csPort   |=  csPinSet; // Set all control bits to HIGH (idle)
		*cdPort   |=  cdPinSet; // Signals are ACTIVE LOW
		*wrPort   |=  wrPinSet;
		*rdPort   |=  rdPinSet;
  #endif
  #if defined(__SAM3X8E__)
		csPort->PIO_SODR  |=  csPinSet; // Set all control bits to HIGH (idle)
		cdPort->PIO_SODR  |=  cdPinSet; // Signals are ACTIVE LOW
		wrPort->PIO_SODR  |=  wrPinSet;
		rdPort->PIO_SODR  |=  rdPinSet;
  #endif
	  pinMode(cs, OUTPUT);	  // Enable outputs
	  pinMode(cd, OUTPUT);
	  pinMode(wr, OUTPUT);
	  pinMode(rd, OUTPUT);
	  if(reset) 
	  {
		 digitalWrite(reset, HIGH);
		 pinMode(reset, OUTPUT);
	  }
  #endif
  #ifdef USE_ADAFRUIT_SHIELD_PIN 
  	 CS_IDLE; // Set all control bits to idle state
 	 WR_IDLE;
  	 RD_IDLE;
  	 CD_DATA;
 	 digitalWrite(5, HIGH); // Reset line
 	 pinMode(A3, OUTPUT);   // Enable outputs
 	 pinMode(A2, OUTPUT);
 	 pinMode(A1, OUTPUT);
 	 pinMode(A0, OUTPUT);
  	 pinMode( 5, OUTPUT);
 #endif
 	rotation = 0;
 	lcd_model = 0xFFFF;
    setWriteDir();
	WIDTH = wid;
	HEIGHT = heg;
 	width = WIDTH;
	height = HEIGHT;		
}

// Initialization lcd modules
void LCDWIKI_KBV::Init_LCD(void)
{
	reset();
	if(lcd_model == 0xFFFF)
	{
		lcd_model = Read_ID(); 
	}
//	uint16_t ID = Read_ID(); 
	start(lcd_model);
//	Set_Rotation(0);
}

// Initialization common to both shield & breakout configs
void LCDWIKI_KBV::reset(void)
{
//	have_reset = 1;
//    setWriteDir();
//Set all control bits to idle state
    CS_IDLE;
    RD_IDLE;
    WR_IDLE;

#ifdef USE_ADAFRUIT_SHIELD_PIN
  digitalWrite(5, LOW);
  delay(2);
  digitalWrite(5, HIGH);
//  delay(100);
  //digitalWrite(5, LOW);
 // delay(100);
#else
  if(_reset) 
  {
    digitalWrite(_reset, LOW);
    delay(2);
    digitalWrite(_reset, HIGH);
//	delay(100);
	//digitalWrite(_reset, LOW);
	//delay(100);
  }
#endif
  CS_ACTIVE;
  CD_COMMAND;
  write8(0x00);
  for(uint8_t i=0; i<3; i++)
  {
  	WR_STROBE; // Three extra 0x00s
  }
  CS_IDLE;
}

void LCDWIKI_KBV::Write_Cmd(uint16_t cmd)
{
	CS_ACTIVE;
	writeCmd16(cmd);
	CS_IDLE;
}

void LCDWIKI_KBV::Write_Data(uint16_t data)
{
	CS_ACTIVE;
	writeData16(data);
	CS_IDLE;
}

void LCDWIKI_KBV::Write_Cmd_Data(uint16_t cmd, uint16_t data)
{
	CS_ACTIVE;
	writeCmdData16(cmd,data);
	CS_IDLE;
}

//Write a command and N datas
void LCDWIKI_KBV::Push_Command(uint16_t cmd, uint8_t *block, int8_t N)
{
  	CS_ACTIVE;
    writeCmd16(cmd);
    while (N-- > 0) 
	{
        uint8_t u8 = *block++;
        writeData8(u8); 
		if(N && (lcd_driver == ID_7575))
		{
			cmd++;
			writeCmd16(cmd);
		}
    }
    CS_IDLE;
}

// Sets the LCD address window 
void LCDWIKI_KBV::Set_Addr_Window(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{
	CS_ACTIVE;
	if(lcd_driver == ID_932X) 
	{

	    // Values passed are in current (possibly rotated) coordinate
	    // system.  932X requires hardware-native coords regardless of
	    // MADCTL, so rotate inputs as needed.  The address counter is
	    // set to the top-left corner -- although fill operations can be
	    // done in any direction, the current screen rotation is applied
	    // because some users find it disconcerting when a fill does not
	    // occur top-to-bottom.
	    int x, y, t;
	    switch(rotation) 
		{
		     default:
			      x  = x1;
			      y  = y1;
			      break;
		     case 1:
			      t  = y1;
			      y1 = x1;
			      x1 = WIDTH  - 1 - y2;
			      y2 = x2;
			      x2 = WIDTH  - 1 - t;
			      x  = x2;
			      y  = y1;
		      	  break;
		     case 2:
			      t  = x1;
			      x1 = WIDTH  - 1 - x2;
			      x2 = WIDTH  - 1 - t;
			      t  = y1;
			      y1 = HEIGHT - 1 - y2;
			      y2 = HEIGHT - 1 - t;
			      x  = x2;
			      y  = y2;
			      break;
		     case 3:
			      t  = x1;
			      x1 = y1;
			      y1 = HEIGHT - 1 - x2;
			      x2 = y2;
			      y2 = HEIGHT - 1 - t;
			      x  = x1;
			      y  = y2;
			      break;
    	}
    writeCmdData16(ILI932X_HOR_START_AD, x1); // Set address window
    writeCmdData16(ILI932X_HOR_END_AD, x2);
    writeCmdData16(ILI932X_VER_START_AD, y1);
    writeCmdData16(ILI932X_VER_END_AD, y2);
    writeCmdData16(ILI932X_GRAM_HOR_AD, x ); // Set address counter to top left
    writeCmdData16(ILI932X_GRAM_VER_AD, y );
 	} 
	else if(lcd_driver == ID_7575)
	{
		writeCmdData8(HX8347G_COLADDRSTART_HI,x1>>8);
		writeCmdData8(HX8347G_COLADDRSTART_LO,x1);
		writeCmdData8(HX8347G_ROWADDRSTART_HI,y1>>8);
		writeCmdData8(HX8347G_ROWADDRSTART_LO,y1);
		writeCmdData8(HX8347G_COLADDREND_HI,x2>>8);
		writeCmdData8(HX8347G_COLADDREND_LO,x2);
		writeCmdData8(HX8347G_ROWADDREND_HI,y2>>8);
		writeCmdData8(HX8347G_ROWADDREND_LO,y2);
	}
	else
	{
		uint8_t x_buf[] = {x1>>8,x1&0xFF,x2>>8,x2&0xFF}; 
		uint8_t y_buf[] = {y1>>8,y1&0xFF,y2>>8,y2&0xFF}; 
	
		Push_Command(XC, x_buf, 4); //set x address
		Push_Command(YC, y_buf, 4); //set y address
	}
	CS_IDLE;		
}

// Unlike the 932X drivers that set the address window to the full screen
// by default (using the address counter for drawPixel operations), the
// 7575 needs the address window set on all graphics operations.  In order
// to save a few register writes on each pixel drawn, the lower-right
// corner of the address window is reset after most fill operations, so
// that drawPixel only needs to change the upper left each time.
void LCDWIKI_KBV::Set_LR(void)
{
	CS_ACTIVE;
	writeCmdData8(HX8347G_COLADDREND_HI,(width -1)>>8);
	writeCmdData8(HX8347G_COLADDREND_LO,width -1);
	writeCmdData8(HX8347G_ROWADDREND_HI,(height -1)>>8);
	writeCmdData8(HX8347G_ROWADDREND_LO,height -1);
	CS_IDLE;
}

//push color table for 16bits
void LCDWIKI_KBV::Push_Any_Color(uint16_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) 
	{  
		if(lcd_driver == ID_932X)
		{
			writeCmd8(ILI932X_START_OSC);
			
		}
		writeCmd8(CC);			
    }
    while (n-- > 0) 
	{
        if (isconst) 
		{
			color = pgm_read_word(block++);		
        } 
		else 
		{
			color = (*block++);			

		}		
        writeData16(color);
    }
    CS_IDLE;
}

//push color table for 8bits
void LCDWIKI_KBV::Push_Any_Color(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) 
	{
		if(lcd_driver == ID_932X)
		{
			writeCmd8(ILI932X_START_OSC);
			
		}
		writeCmd8(CC);		
	}
    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);
        writeData16(color);
    }
    CS_IDLE;
}

//Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t LCDWIKI_KBV::Color_To_565(uint8_t r, uint8_t g, uint8_t b)
{
	return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}

//read value from lcd register 
uint16_t LCDWIKI_KBV::Read_Reg(uint16_t reg, int8_t index)
{
	uint16_t ret,high;
    uint8_t low;
//  if (!have_reset)
 // {
 //     reset();
//  }
	CS_ACTIVE;
    writeCmd16(reg);
    setReadDir();
    delay(1); 
	do 
	{ 
	//ead8(high);
	//ead8(low);
	//et = (high << 8) | lowc
		read16(ret);  //read 16bits
	}while (--index >= 0);   
//    RD_IDLE;
    CS_IDLE;
    setWriteDir();
    return ret;
}

//read graph RAM data
int16_t LCDWIKI_KBV::Read_GRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h)
{
	uint16_t ret, dummy;
    int16_t n = w * h;
    uint8_t r, g, b, tmp;
    Set_Addr_Window(x, y, x + w - 1, y + h - 1);
    while (n > 0) 
	{
        CS_ACTIVE;
		writeCmd16(RC);
        setReadDir();
		if(lcd_driver == ID_932X)
		{
			while(n)
			{
				for(int i =0; i< 2; i++)
				{
					read8(r);
					read8(r);
					read8(r);
					read8(g);
				}
				*block++ = (r<<8 | g);
				n--;
			}
			Set_Addr_Window(0, 0, width - 1, height - 1);
		}
		else 
		{
			read8(r);
        	while (n) 
			{
				if(R24BIT == 1)
				{
        			read8(r);
         			read8(g);
        			read8(b);
            		ret = Color_To_565(r, g, b);
				}
				else if(R24BIT == 0)
				{
					read16(ret);
				}
            	*block++ = ret;
            	n--;
        	}
        }
//        RD_IDLE;
        CS_IDLE;
        setWriteDir();
    }
	return 0;
}

//read LCD controller chip ID 
uint16_t LCDWIKI_KBV::Read_ID(void)
{
	uint16_t ret;
	if ((Read_Reg(0x04,0) == 0x00)&&(Read_Reg(0x04,1) == 0x8000))
	{
		uint8_t buf[] = {0xFF, 0x83, 0x57};
		Push_Command(HX8357D_SETC, buf, sizeof(buf));
		ret = (Read_Reg(0xD0,0) << 16) | Read_Reg(0xD0,1);
		if((ret == 0x990000) || (ret == 0x900000))
		{
			return 0x9090;
		}
	}
	if((Read_Reg(0x04,1) == 0x8552)||(((Read_Reg(0x04,0)<<8)|(Read_Reg(0x04,1)>>8)) == 0x7789))
	{
		return 0x7789;
	}
	ret = Read_Reg(0xD3,1); //0x9341 0x9486
	if(ret == 0x9341)
	{
		return 0x9341;
	}
	else if(ret == 0x9486)
	{
		return 0x9486;
	}
	else if(ret == 0x9488)
	{
		return 0x9488;
	}
	else if(ret == 0x7796)
	{
		return 0x7796;
	}
	else
	{
		return Read_Reg(0, 0); //others
	}
}

//set x,y  coordinate and color to draw a pixel point 
void LCDWIKI_KBV::Draw_Pixe(int16_t x, int16_t y, uint16_t color)
{
	if((x < 0) || (y < 0) || (x > Get_Width()) || (y > Get_Height()))
	{
		return;
	}
	Set_Addr_Window(x, y, x, y);
	CS_ACTIVE;
	writeCmdData16(CC, color);
	CS_IDLE;
}

//fill area from x to x+w,y to y+h
void LCDWIKI_KBV::Fill_Rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
{
	int16_t end;
	if (w < 0) 
	{
        w = -w;
        x -= w;
    }                           //+ve w
    end = x + w;
    if (x < 0)
    {
        x = 0;
    }
    if (end > Get_Width())
    {
        end = Get_Width();
    }
    w = end - x;
    if (h < 0) 
	{
        h = -h;
        y -= h;
    }                           //+ve h
    end = y + h;
    if (y < 0)
    {
        y = 0;
    }
    if (end > Get_Height())
    {
        end = Get_Height();
    }
    h = end - y;
    Set_Addr_Window(x, y, x + w - 1, y + h - 1);//set area
	CS_ACTIVE;
    if(lcd_driver == ID_932X)
	{
		writeCmd8(ILI932X_START_OSC);
			
	}
	writeCmd8(CC);	
	if (h > w) 
	{
        end = h;
        h = w;
        w = end;
    }
	while (h-- > 0) 
	{
		end = w;
		do 
		{
   			writeData16(color);//set color data
        } while (--end != 0);
	}
	if(lcd_driver == ID_932X)
	{
		Set_Addr_Window(0, 0, width - 1, height - 1);
	}
	else if(lcd_driver == ID_7575)
	{
		Set_LR();
	}
	CS_IDLE;
}

//Scroll display 
void LCDWIKI_KBV::Vert_Scroll(int16_t top, int16_t scrollines, int16_t offset)
{
    int16_t bfa = HEIGHT - top - scrollines; 
    int16_t vsp;
    int16_t sea = top;
    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_driver == ID_932X)
	{
		writeCmdData8(SC1, (1 << 1) | 0x1);        //!NDL, VLE, REV
        writeCmdData8(SC2, vsp);        //VL#
	}
	else
	{
  		uint8_t d[6];           // for multi-byte parameters
  		d[0] = top >> 8;        //TFA
  		d[1] = top;
  		d[2] = scrollines >> 8; //VSA
  		d[3] = scrollines;
  		d[4] = bfa >> 8;        //BFA
  		d[5] = bfa;
		Push_Command(SC1, d, 6);
		d[0] = vsp >> 8;        //VSP
  		d[1] = vsp;
		Push_Command(SC2, d, 2);
		if(lcd_driver == ID_7575)
		{
			d[0] = (offset != 0) ? 0x08:0;
			Push_Command(0x01, d, 1);
		}
		else if (offset == 0) 
		{
			Push_Command(0x13, NULL, 0);
		}
	}
}

//get lcd width
int16_t LCDWIKI_KBV::Get_Width(void) const
{
	return width;
}

//get lcd height
int16_t LCDWIKI_KBV::Get_Height(void) const
{
	return height;
}

//set clockwise rotation
void LCDWIKI_KBV::Set_Rotation(uint8_t r)
{
    rotation = r & 3;           // just perform the operation ourselves on the protected variables
    width = (rotation & 1) ? HEIGHT : WIDTH;
    height = (rotation & 1) ? WIDTH : HEIGHT;
	CS_ACTIVE;
	if(lcd_driver == ID_932X)
	{
		uint16_t val;
		switch(rotation) 
		{
			default: 
				val = 0x1030;  //0 degree 
				break;
		 	case 1 : 
				val = 0x1028;  //90 degree 
				break;
		 	case 2 : 
				val = 0x1000;  //180 degree 
				break;
		 	case 3 : 
				val = 0x1018;  //270 degree 
				break;
		}
		writeCmdData16(MD, val); 
	}
	else if(lcd_driver == ID_7735)
	{
		uint8_t val;
		switch(rotation)
		{
			case 0: 
				val = 0xD0; //0 degree 
				break;
		 	case 1: 
				val = 0xA0; //90 degree 
				break;
		 	case 2: 
				val = 0x00; //180 degree 
				break;
		 	case 3: 
				val = 0x60; //270 degree
				break;			
		}
		writeCmdData8(MD, val);
	}
	else if(lcd_driver == ID_9481)
	{
		uint8_t val;
		switch (rotation) 
		{
		   	case 0:
		     	val = 0x09; //0 degree PAO=0,CAO=0,P/CO=0,VO=0,RGBO=1,DO=0,HF=0,VF=1
		     	break;
		   	case 1:
		     	val = 0x2B; //90 degree PAO=0,CAO=0,P/CO=1,VO=0,RGBO=1,DO=0,HF=1,VF=1
		     	break;
		 	case 2:
		    	val = 0x0A; //180 degree PAO=0,CAO=0,P/CO=0,VO=0,RGBO=1,DO=0,HF=1,VF=0
		    	break;
		   	case 3:
		     	val = 0x28; //270 degree PAO=0,CAO=0,P/CO=1,VO=0,RGBO=1,DO=0,HF=0,VF=0
		     	break;
		 }
		 writeCmdData8(MD, val); 

	}
	else if(lcd_driver == ID_9486)
	{
		uint8_t val;
		switch (rotation) 
		{
		   	case 0:
		     	val = ILI9341_MADCTL_BGR; //0 degree 
		     	break;
		   	case 1:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_MV | ILI9341_MADCTL_ML | ILI9341_MADCTL_BGR ; //90 degree 
		     	break;
		 	case 2:
		    	val = ILI9341_MADCTL_MY | ILI9341_MADCTL_MX |ILI9341_MADCTL_BGR; //180 degree 
		    	break;
		   	case 3:
		     	val = ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR; //270 degree
		     	break;
		 }
		 writeCmdData8(MD, val); 
	}
	else if(lcd_driver == ID_9488)
	{
		uint8_t val;
		switch (rotation) 
		{			
			case 0:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR ; //0 degree 
		     	break;
		   	case 1:
		     	val = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR ; //90 degree 
		     	break;
		 	case 2:
		    	val = ILI9341_MADCTL_ML | ILI9341_MADCTL_BGR; //180 degree 
		    	break;
		   	case 3:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_ML | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR; //270 degree
		     	break;
		 }
		 writeCmdData8(MD, val); 
	}
	else if(lcd_driver == ID_7789)
	{
		uint8_t val;
		switch (rotation) 
		{
		   	case 0:
		     	val = 0; //0 degree 
		     	break;
		   	case 1:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_MV; //90 degree 
		     	break;
		 	case 2:
		    	val = ILI9341_MADCTL_MY | ILI9341_MADCTL_MX; //180 degree 
		    	break;
		   	case 3:
		     	val = ILI9341_MADCTL_MY | ILI9341_MADCTL_MV; //270 degree
		     	break;
		 }
		 writeCmdData8(MD, val); 
	}
	else
	{
		uint8_t val;
		switch (rotation) 
		{
		   	case 0:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR; //0 degree 
		     	break;
		   	case 1:
		     	val = ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR; //90 degree 
		     	break;
		 	case 2:
		    	val = ILI9341_MADCTL_MY | ILI9341_MADCTL_ML |ILI9341_MADCTL_BGR; //180 degree 
		    	break;
		   	case 3:
		     	val = ILI9341_MADCTL_MX | ILI9341_MADCTL_MY| ILI9341_MADCTL_ML | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR; //270 degree
		     	break;
		 }
		 writeCmdData8(MD, val); 
	}
 	Set_Addr_Window(0, 0, width - 1, height - 1);
	Vert_Scroll(0, HEIGHT, 0);
	CS_IDLE;
}

//get current rotation
//0  :  0 degree 
//1  :  90 degree
//2  :  180 degree
//3  :  270 degree
uint8_t LCDWIKI_KBV::Get_Rotation(void) const
{
	return rotation;
}

//Anti color display 
void LCDWIKI_KBV::Invert_Display(boolean i)
{
	CS_ACTIVE;
	uint8_t val = VL^i;
	if(lcd_driver == ID_932X)
	{
		writeCmdData8(0x61, val);
	}
	else if(lcd_driver == ID_7575)
	{
		writeCmdData8(0x01, val ? 8 : 10);
	}
	else
	{
		writeCmd8(val ? 0x21 : 0x20);
	}
	CS_IDLE;
}

void LCDWIKI_KBV:: init_table8(const void *table, int16_t size)
{
	uint8_t i;
    uint8_t *p = (uint8_t *) table, dat[MAX_REG_NUM];            //R61526 has GAMMA[22] 
    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 (i = 0; i < len; i++)
            {
                dat[i] = pgm_read_byte(p++);
            }
			Push_Command(cmd,dat,len);
        }
        size -= len + 2;
    }
}

void LCDWIKI_KBV:: 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_DELAY16)
        {
            delay(d);
        }
        else 
		{
			Write_Cmd_Data(cmd, d);                      //static function
        }
        size -= 2 * sizeof(int16_t);
    }
}

void LCDWIKI_KBV::start(uint16_t ID)
{
	reset();
	delay(200);
	switch(ID)
	{
		case 0x9325:
		case 0x9328:
			lcd_driver = ID_932X;
			//WIDTH = 240,HEIGHT = 320;
			//width = WIDTH, height = HEIGHT;
			XC=0,YC=0,CC=ILI932X_RW_GRAM,RC=ILI932X_RW_GRAM,SC1=ILI932X_GATE_SCAN_CTRL2,SC2=ILI932X_GATE_SCAN_CTRL3,MD=0x0003,VL=1,R24BIT=0;
			static const uint16_t ILI932x_regValues[] PROGMEM = 
			{			
		  		ILI932X_START_OSC 	   , 0x0001, // Start oscillator
		  		TFTLCD_DELAY16			   , 50,	 // 50 millisecond delay
		  		ILI932X_DRIV_OUT_CTRL    , 0x0100,
		  		ILI932X_DRIV_WAV_CTRL    , 0x0700,
		  		ILI932X_ENTRY_MOD 	   , 0x1030,
		  		ILI932X_RESIZE_CTRL	   , 0x0000,
		  		ILI932X_DISP_CTRL2	   , 0x0202,
		  		ILI932X_DISP_CTRL3	   , 0x0000,
		  		ILI932X_DISP_CTRL4	   , 0x0000,
		  		ILI932X_RGB_DISP_IF_CTRL1, 0x0,
		  		ILI932X_FRM_MARKER_POS   , 0x0,
		  		ILI932X_RGB_DISP_IF_CTRL2, 0x0,
		  		ILI932X_POW_CTRL1 	   , 0x0000,
		  		ILI932X_POW_CTRL2 	   , 0x0007,
		  		ILI932X_POW_CTRL3 	   , 0x0000,
		  		ILI932X_POW_CTRL4 	   , 0x0000,
		  		TFTLCD_DELAY16			   , 200,
		  		ILI932X_POW_CTRL1 	   , 0x1690,
		  		ILI932X_POW_CTRL2 	   , 0x0227,
		  		TFTLCD_DELAY16			   , 50,
		  		ILI932X_POW_CTRL3 	   , 0x001A,
		  		TFTLCD_DELAY16			   , 50,
		  		ILI932X_POW_CTRL4 	   , 0x1800,
		  		ILI932X_POW_CTRL7 	   , 0x002A,
		  		TFTLCD_DELAY16			   , 50,
		  		ILI932X_GAMMA_CTRL1	   , 0x0000,
		  		ILI932X_GAMMA_CTRL2	   , 0x0000,
		  		ILI932X_GAMMA_CTRL3	   , 0x0000,
		  		ILI932X_GAMMA_CTRL4	   , 0x0206,
		  		ILI932X_GAMMA_CTRL5	   , 0x0808,
		  		ILI932X_GAMMA_CTRL6	   , 0x0007,
		  		ILI932X_GAMMA_CTRL7	   , 0x0201,
		  		ILI932X_GAMMA_CTRL8	   , 0x0000,
		  		ILI932X_GAMMA_CTRL9	   , 0x0000,
		 		ILI932X_GAMMA_CTRL10	   , 0x0000,
		  		ILI932X_GRAM_HOR_AD	   , 0x0000,
		  		ILI932X_GRAM_VER_AD	   , 0x0000,
		  		ILI932X_HOR_START_AD	   , 0x0000,
		  		ILI932X_HOR_END_AD	   , 0x00EF,
		  		ILI932X_VER_START_AD	   , 0X0000,
		  		ILI932X_VER_END_AD	   , 0x013F,
		  		ILI932X_GATE_SCAN_CTRL1  , 0xA700, // Driver Output Control (R60h)
		  		ILI932X_GATE_SCAN_CTRL2  , 0x0003, // Driver Output Control (R61h)
		  		ILI932X_GATE_SCAN_CTRL3  , 0x0000, // Driver Output Control (R62h)
		  		ILI932X_PANEL_IF_CTRL1   , 0X0010, // Panel Interface Control 1 (R90h)
		  		ILI932X_PANEL_IF_CTRL2   , 0X0000,
		  		ILI932X_PANEL_IF_CTRL3   , 0X0003,
		  		ILI932X_PANEL_IF_CTRL4   , 0X1100,
		  		ILI932X_PANEL_IF_CTRL5   , 0X0000,
		  		ILI932X_PANEL_IF_CTRL6   , 0X0000,
		  		ILI932X_DISP_CTRL1	   , 0x0133 // Main screen turn on		
			};
			init_table16(ILI932x_regValues, sizeof(ILI932x_regValues));
			break;
		case 0x9341:
			lcd_driver = ID_9341;
			//WIDTH = 240,HEIGHT = 320;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=1;
			static const uint8_t ILI9341_regValues[] PROGMEM = 
			{        // BOE 2.4"
				ILI9341_SOFTRESET,0,                 //Soft Reset
				TFTLCD_DELAY8, 50, 
				ILI9341_DISPLAYOFF, 0,            //Display Off
            //	ILI9341_PIXELFORMAT, 1, 0x55,      //Pixel read=565, write=565.
            	ILI9341_INTERFACECONTROL, 3, 0x01, 0x01, 0x00,  //Interface Control needs EXTC=1 MV_EOR=0, TM=0, RIM=0
            	ILI9341_POWERCONTROLB, 3, 0x00, 0x81, 0x30,  //Power Control B [00 81 30]
            	ILI9341_POWERONSEQ, 4, 0x64, 0x03, 0x12, 0x81,    //Power On Seq [55 01 23 01]
            	ILI9341_DRIVERTIMINGA, 3, 0x85, 0x10, 0x78,  //Driver Timing A [04 11 7A]
            	ILI9341_POWERCONTROLA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,      //Power Control A [39 2C 00 34 02]
            	ILI9341_RUMPRATIO, 1, 0x20,      //Pump Ratio [10]
            	ILI9341_DRIVERTIMINGB, 2, 0x00, 0x00,        //Driver Timing B [66 00]
            	ILI9341_RGBSIGNAL, 1, 0x00,      //RGB Signal [00] 
            //	ILI9341_FRAMECONTROL, 2, 0x00, 0x1B,        //Frame Control [00 1B]
            	//            0xB6, 2, 0x0A, 0xA2, 0x27, //Display Function [0A 82 27 XX]    .kbv SS=1  
            	ILI9341_INVERSIONCONRTOL, 1, 0x00,      //Inversion Control [02] .kbv NLA=1, NLB=1, NLC=1
            	ILI9341_POWERCONTROL1, 1, 0x21,      //Power Control 1 [26]
            	ILI9341_POWERCONTROL2, 1, 0x11,      //Power Control 2 [00]
            	ILI9341_VCOMCONTROL1, 2, 0x3F, 0x3C,        //VCOM 1 [31 3C]
            	ILI9341_VCOMCONTROL2, 1, 0xB5,      //VCOM 2 [C0]
            	ILI9341_MEMCONTROL, 1, ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR,
            	ILI9341_PIXELFORMAT, 1, 0x55,      //Pixel read=565, write=565.
            	ILI9341_FRAMECONTROL, 2, 0x00, 0x1B,        //Frame Control [00 1B]
            	ILI9341_MEMORYACCESS, 1, 0x48,      //Memory Access [00]
            	ILI9341_ENABLE3G, 1, 0x00,      //Enable 3G [02]
            	ILI9341_GAMMASET, 1, 0x01,      //Gamma Set [01]
            	ILI9341_UNDEFINE0, 15, 0x0f, 0x26, 0x24, 0x0b, 0x0e, 0x09, 0x54, 0xa8, 0x46, 0x0c, 0x17, 0x09, 0x0f, 0x07, 0x00,
            	ILI9341_UNDEFINE1, 15, 0x00, 0x19, 0x1b, 0x04, 0x10, 0x07, 0x2a, 0x47, 0x39, 0x03, 0x06, 0x06, 0x30, 0x38, 0x0f,
				ILI9341_ENTRYMODE, 1,0x07,
            	ILI9341_SLEEPOUT, 0,            //Sleep Out
            	TFTLCD_DELAY8, 150,
            	ILI9341_DISPLAYON, 0          //Display On
            };
			init_table8(ILI9341_regValues, sizeof(ILI9341_regValues));    
			break;
		case 0x9090:
			lcd_driver = ID_HX8357D;
			//WIDTH = 320,HEIGHT = 480;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=HX8357_RAMWR,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=HX8357_MADCTL,VL=1,R24BIT=1;
			static const uint8_t HX8357D_regValues[] PROGMEM = 
			{
  				HX8357_SWRESET, 0,
  				HX8357D_SETC, 3, 0xFF, 0x83, 0x57,
  				TFTLCD_DELAY8, 250,
				HX8357_SETRGB, 4, 0x00, 0x00, 0x06, 0x06,
				HX8357D_SETCOM, 1, 0x25,  // -1.52V
  				HX8357_SETOSC, 1, 0x68,  // Normal mode 70Hz, Idle mode 55 Hz
  				HX8357_SETPANEL, 1, 0x05,  // BGR, Gate direction swapped
  				HX8357_SETPWR1, 6, 0x00, 0x15, 0x1C, 0x1C, 0x83, 0xAA,
  				HX8357D_SETSTBA, 6, 0x50, 0x50, 0x01, 0x3C, 0x1E, 0x08,
  				// MEME GAMMA HERE
  				HX8357D_SETCYC, 7, 0x02, 0x40, 0x00, 0x2A, 0x2A, 0x0D, 0x78,
  				HX8357_COLMOD, 1, 0x55,
  				HX8357_MADCTL, 1, 0xC0,
  				HX8357_TEON, 1, 0x00,
  				HX8357_TEARLINE, 2, 0x00, 0x02,
  				HX8357_SLPOUT, 0,
  				TFTLCD_DELAY8, 150,
  				HX8357_DISPON, 0, 
  				TFTLCD_DELAY8, 50
			};
			init_table8(HX8357D_regValues, sizeof(HX8357D_regValues));
			break;
		case 0x7575:
		case 0x9595:
			lcd_driver = ID_7575;
			//WIDTH = 240,HEIGHT = 320;
			//width = WIDTH, height = HEIGHT;
			XC=0,YC=0,CC=0x22,RC=ILI932X_RW_GRAM,SC1=0x0E,SC2=0x14,MD=HX8347G_MEMACCESS,VL=1,R24BIT=1;
			static const uint8_t HX8347G_regValues[] PROGMEM = 
			{
				//  0xEA, 2, 0x00, 0x20,        //PTBA[15:0]
               //   0xEC, 2, 0x0C, 0xC4,   //
				  0x2E , 1 , 0x89,
        		  0x29 , 1 , 0x8F,
        		  0x2B , 1 , 0x02,
        		  0xE2 , 1 , 0x00,
        		  0xE4 , 1 , 0x01,
        		  0xE5 , 1 , 0x10,
        		  0xE6 , 1 , 0x01,
        		  0xE7 , 1 , 0x10,
        		  0xE8 , 1 , 0x70,   //0x70
        		  0xF2 , 1 , 0x00,   //0x00
        		  0xEA , 1 , 0x00,
        		  0xEB , 1 , 0x20,
        		  0xEC , 1 , 0x3C,
        		  0xED , 1 , 0xC8,
        		  0xE9 , 1 , 0x38, //0x38
        		  0xF1 , 1 , 0x01,

				 // 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,  //
        
        		  // skip gamma, do later
        
        		  0x1B , 1 , 0x1A,  //0x1A
        		  0x1A , 1 , 0x01,  //0x01
        		  0x24 , 1 , 0x61,  //0x61
        		  0x25 , 1 , 0x5C,  //0x5C
        		  0x23 , 1 , 0x88,
        		  0x18 , 1 , 0x36,  //0x36
        		  0x19 , 1 , 0x01,
        		  0x1F , 1 , 0x88,
        		  TFTLCD_DELAY8 , 5   , // delay 5 ms
        		  0x1F , 1 , 0x80,
        		  TFTLCD_DELAY8   , 5   ,
        		  0x1F , 1 , 0x90,
        		  TFTLCD_DELAY8   , 5   ,
        		  0x1F , 1 , 0xD4,  //0xD4
        		  TFTLCD_DELAY8   , 5   ,
        		  0x17 , 1 , 0x05,
        
        		  0x36 , 1 , 0x00, //0x09
        		  0x28 , 1 , 0x38,
        		  TFTLCD_DELAY8   , 40  ,
        		  0x28 , 1 , 0x3C,  //0x3C
        		  0x02 , 1 , 0x00,
        		  0x03 , 1 , 0x00,
        		  0x04 , 1 , 0x00,
        		  0x05 , 1 , 0xEF,
        		  0x06 , 1 , 0x00,
        		  0x07 , 1 , 0x00,
        		  0x08 , 1 , 0x01,
        		  0x09 , 1 , 0x3F
			};
		    init_table8(HX8347G_regValues, sizeof(HX8347G_regValues));
			break;
		case 0x9486:
			lcd_driver = ID_9486;
			//WIDTH = 320,HEIGHT = 480;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=0;
			static const uint8_t ILI9486_regValues[] PROGMEM = 
			{
				0xF9, 2, 0x00, 0x08,
				0xC0, 2, 0x19, 0x1A,
				0xC1, 2, 0x45, 0x00,
				0xC2, 1, 0x33,
				0xC5, 2, 0x00, 0x28,
				0xB1, 2, 0x90, 0x11,
				0xB4, 1, 0x02,
				0xB6, 3, 0x00, 0x42, 0x3B,
				0xB7, 1, 0x07,
				0xE0, 15, 0x1F, 0x25, 0x22, 0x0B, 0x06, 0x0A, 0x4E, 0xC6, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0xE1, 15, 0x1F, 0x3F, 0x3F, 0x0F, 0x1F, 0x0F, 0x46, 0x49, 0x31, 0x05, 0x09 ,0x03, 0x1C, 0x1A, 0x00,
				0xF1, 8, 0x36, 0x04, 0x00, 0x3C, 0x0F, 0x0F, 0xA4, 0x02,
				0xF2, 9, 0x18, 0xA3, 0x12, 0x02, 0x32, 0x12, 0xFF, 0x32, 0x00,
				0xF4, 5, 0x40, 0x00, 0x08, 0x91, 0x04, 
				0xF8, 2, 0x21, 0x04,
				0x36, 1, 0x48,
				0x3A, 1, 0x55,
				0x11,0,
				TFTLCD_DELAY8, 120,
				0x29,0
/*
				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.
            	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] 
            	0xE0, 15,0x0F, 0x24, 0x1C, 0x0A, 0x0F, 0x08, 0x43, 0x88, 0x32, 0x0F, 0x10, 0x06, 0x0F, 0x07, 0x00,
            	0xE1, 15,0x0F, 0x38, 0x30, 0x09, 0x0F, 0x0F, 0x4E, 0x77, 0x3C, 0x07, 0x10, 0x05, 0x23, 0x1B, 0x00,
            	0x11, 0,            //Sleep Out
            	TFTLCD_DELAY8, 150,
            	0x29, 0         //Display On
*/
			};
			init_table8(ILI9486_regValues, sizeof(ILI9486_regValues));
			break;
		case 0x9488:
			lcd_driver = ID_9488;
			//WIDTH = 320,HEIGHT = 480;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=1;
			static const uint8_t ILI9488_regValues[] PROGMEM = 
			{
				0xF7, 4, 0xA9, 0x51, 0x2C, 0x82,
				0xC0, 2, 0x11, 0x09,
				0xC1, 1, 0x41,
				0xC5, 3, 0x00, 0x0A, 0x80,
				0xB1, 2, 0xB0, 0x11,
				0xB4, 1, 0x02,
				0xB6, 2, 0x02, 0x42,
				0xB7, 1, 0xC6,
				0xBE, 2, 0x00, 0x04,
				0xE9, 1, 0x00,
				0x36, 1, 0x08,
				0x3A, 1, 0x55,
				0xE0, 15, 0x00, 0x07, 0x10, 0x09, 0x17, 0x0B, 0x41, 0x89, 0x4B, 0x0A, 0x0C, 0x0E, 0x18, 0x1B, 0x0F,
				0xE1, 15, 0x00, 0x17, 0x1A, 0x04, 0x0E, 0x06, 0x2F, 0x45, 0x43, 0x02, 0x0A, 0x09, 0x32, 0x36, 0x0F,
				0x11, 0,
				TFTLCD_DELAY8, 120,
				0x29, 0
			};
			init_table8(ILI9488_regValues, sizeof(ILI9488_regValues));
			break;
		case 0x9481:
			lcd_driver = ID_9481;
			//WIDTH = 320,HEIGHT = 480;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=0;
			static const uint8_t ILI9481_regValues[] PROGMEM = 
			{
				0x11, 0,
				TFTLCD_DELAY8, 20,
				0xD0, 3, 0x07, 0x42, 0x18,
				0xD1, 3, 0x00, 0x07, 0x10,
				0xD2, 2, 0x01, 0x02,
				0xC0, 5, 0x10, 0x3B, 0x00, 0x02, 0x11,
				0xC5, 1, 0x03,
				0xC8, 12, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00,
				0x36, 1, 0x0A,
				0x3A, 1, 0x55,
				0x2A, 4, 0x00, 0x00, 0x01, 0x3F,
				0x2B, 4, 0x00, 0x00, 0x01, 0xE0,
				TFTLCD_DELAY8, 120,
				0x29, 0
			};
			init_table8(ILI9481_regValues, sizeof(ILI9481_regValues));
			break;
		case 0x7735:
			lcd_driver = ID_7735;
			//WIDTH = 128,HEIGHT = 160;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=0;
			static const uint8_t ST7735S_regValues[] PROGMEM = 
			{
				0x011, 0,            //Soft Reset
            	TFTLCD_DELAY8, 120,  // .kbv will power up with ONLY reset, sleep out, display on
            	0xB1, 3, 0x05, 0x3C, 0x3C,           //Display Off
            	0xB2, 3, 0x05, 0x3C, 0x3C,      //Pixel read=565, write=565.
            	0xB3, 6, 0x05, 0x3C, 0x3C, 0x05, 0x3C, 0x3C,        //Power Control 1 [0E 0E]
            	0xB4, 1, 0x03,         //Power Control 2 [43 00]
            	0xC0, 3, 0x28, 0x08, 0x04,      //Power Control 3 [33]
            	0xC1, 1, 0xC0,     //VCOM  Control 1 [00 40 00 40]
            	0xC2, 2, 0x0D, 0x00,      //Inversion Control [00]
            	0xC3, 2, 0x8D, 0x2A,   // Display Function Control [02 02 3B]
            	0xC4, 2, 0x8D, 0xEE,
            	0xC5, 1, 0x1A,
            	//0x36, 1, 0xC0,
            	0xE0, 16,0x03, 0x22, 0x07, 0x0A, 0x2E, 0x30, 0x25, 0x2A, 0x28, 0x26, 0x2E, 0x3A, 0x00, 0x01, 0x03, 0x13,
            	0xE1, 16,0x04, 0x16, 0x06, 0x0D, 0x2D, 0x26, 0x23, 0x27, 0x27, 0x25, 0x2D, 0x3B, 0x00, 0x01, 0x04, 0x13,
            	0x3A, 1, 0x05,            //Sleep Out
            	TFTLCD_DELAY8, 150,
            	0x29, 0         //Display On
			};
			init_table8(ST7735S_regValues, sizeof(ST7735S_regValues));
			break;
		case 0x7796:
			lcd_driver = ID_7796;
			//WIDTH = 128,HEIGHT = 160;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=0;
			static const uint8_t ST7796S_regValues[] PROGMEM = 
			{
				0xF0, 1, 0xC3,           
            	0xF0, 1, 0x96, 
            	0x36, 1, 0x68, 
            	0x3A, 1, 0x05, 
            	0xB0, 1, 0x80,         
            	0xB6, 2, 0x20, 0x02,
            	0xB5, 4, 0x02, 0x03, 0x00, 0x04, 
            	0xB1, 2, 0x80, 0x10,      
            	0xB4, 1, 0x00, 
            	0xB7, 1, 0xC6, 
            	0xC5, 1, 0x24,
                0xE4, 1, 0x31,
                0xE8, 8, 0x40, 0x8A, 0x00, 0x00, 0x29, 0x19, 0xA5, 0x33,
                0xC2, 0,
                0xA7, 0,
            	0xE0, 14,0xF0, 0x09, 0x13, 0x12, 0x12, 0x2B, 0x3C, 0x44, 0x4B, 0x1B, 0x18, 0x17, 0x1D, 0x21,
            	0xE1, 14,0xF0, 0x09, 0x13, 0x0C, 0x0D, 0x27, 0x3B, 0x44, 0x4D, 0x0B, 0x17, 0x17, 0x1D, 0x21,
            	0x36, 1, 0xEC,
            	0xF0, 1, 0xC3, 
            	0xF0, 1, 0x69,
            	0x13, 0,
            	0x11, 0,
            	0x29, 0 
			};
			init_table8(ST7796S_regValues, sizeof(ST7796S_regValues));
			break;
		case 0x7789:
			lcd_driver = ID_7789;
			//WIDTH = 128,HEIGHT = 160;
			//width = WIDTH, height = HEIGHT;
			XC=ILI9341_COLADDRSET,YC=ILI9341_PAGEADDRSET,CC=ILI9341_MEMORYWRITE,RC=HX8357_RAMRD,SC1=0x33,SC2=0x37,MD=ILI9341_MADCTL,VL=0,R24BIT=0;
			static const uint8_t ST7789V_regValues[] PROGMEM = 
			{	
				0x11, 0,
				TFTLCD_DELAY8, 50, 
            	0x36, 1, 0x00, 
            	0x3A, 1, 0x55, 
            	0xB2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33,   	
            	0xB7, 1, 0x72,   	
            	0xBB, 1, 0x3D,  
				0xC0, 1, 0x2C,				
            	0xC2, 1, 0x01, 
            	0xC3, 1, 0x19, 
				0xC4, 1, 0x20,
                0xC6, 1, 0x0F,  
                0xD0, 2, 0xA4, 0xA1,

            	0xE0, 14,0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23,
            	0xE1, 14,0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23,
            	0x20, 0,
            	TFTLCD_DELAY8, 50,
            	0x29, 0,
     			TFTLCD_DELAY8, 100,
			};
			init_table8(ST7789V_regValues, sizeof(ST7789V_regValues));
			break;
		default:
			lcd_driver = ID_UNKNOWN;
			break;		
	}
	Set_Rotation(rotation); 
	Invert_Display(false);
}
