Basically i glued Peter Drescher and Simon Ford libs in a GraphicsDisplay class, then derived TFT or LCD class (which inherits Protocols class), then the most derived ones (Inits), which are per-display and are the only part needed to be adapted to diff hw.

Dependents:   testUniGraphic_150217 maze_TFT_MMA8451Q TFT_test_frdm-kl25z TFT_test_NUCLEO-F411RE ... more

Files at this revision

API Documentation at this revision

Comitter:
Geremia
Date:
Tue Feb 17 11:02:06 2015 +0000
Parent:
6:8356d48a07db
Child:
8:26757296c79d
Commit message:
TFT: added get deviceID, scroll functions

Changed in this revision

Display/LCD.cpp Show annotated file Show diff for this revision Revisions of this file
Display/LCD.h Show annotated file Show diff for this revision Revisions of this file
Display/TFT.cpp Show annotated file Show diff for this revision Revisions of this file
Display/TFT.h Show annotated file Show diff for this revision Revisions of this file
Inits/ILI9341.cpp Show annotated file Show diff for this revision Revisions of this file
Inits/ILI9486.cpp Show annotated file Show diff for this revision Revisions of this file
Inits/TFT_MIPI.cpp Show annotated file Show diff for this revision Revisions of this file
Protocols/PAR16.cpp Show annotated file Show diff for this revision Revisions of this file
Protocols/PAR16.h Show annotated file Show diff for this revision Revisions of this file
Protocols/PAR8.cpp Show annotated file Show diff for this revision Revisions of this file
Protocols/PAR8.h Show annotated file Show diff for this revision Revisions of this file
Protocols/Protocols.h Show annotated file Show diff for this revision Revisions of this file
Protocols/SPI16.cpp Show annotated file Show diff for this revision Revisions of this file
Protocols/SPI16.h Show annotated file Show diff for this revision Revisions of this file
Protocols/SPI8.cpp Show annotated file Show diff for this revision Revisions of this file
Protocols/SPI8.h Show annotated file Show diff for this revision Revisions of this file
--- a/Display/LCD.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Display/LCD.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -21,40 +21,29 @@
 #include "LCD.h"
 
 //#include "mbed_debug.h"
-//#define LCDPAGES        (LCDSIZE_Y>>3) // 8raws per page
-//#define IC_PAGES        (IC_Y_COMS>>3) // max pages in IC ddram, 8raws per page
+
 #define SWAP(a, b)  { a ^= b; b ^= a; a ^= b; }
-//#define USEFRAMEBUFFER
-
-//#define FRAMEBUFSIZE    (LCDSIZE_X*LCDPAGES)
 
 
 LCD::LCD(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const int ic_x_segs, const int ic_y_coms, const char *name)
-    : /*PAR8(port, CS, reset, DC, WR, RD),*/ GraphicsDisplay(name), LCDSIZE_X(lcdsize_x), LCDSIZE_Y(lcdsize_y), LCDPAGES(lcdsize_y>>3), IC_X_SEGS(ic_x_segs), IC_Y_COMS(ic_y_coms), IC_PAGES(ic_y_coms>>3)
+    : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y), _LCDPAGES(lcdsize_y>>3), _IC_X_SEGS(ic_x_segs), _IC_Y_COMS(ic_y_coms), _IC_PAGES(ic_y_coms>>3)
 {
- //   LCDPAGES = LCDSIZE_Y>>3;
- //   IC_PAGES = IC_Y_COMS>>3;
-  //  buffer = new unsigned char [LCDSIZE_X*LCDPAGES];
-  //  PAR8 par8proto(port, CS, reset, DC, WR, RD);
     if(displayproto==PAR_8) proto = new PAR8(port, CS, reset, DC, WR, RD);
     useNOP=false;
-    buffer = (unsigned char*) malloc (LCDSIZE_X*LCDPAGES);
+    buffer = (unsigned char*) malloc (screensize_X*_LCDPAGES);
     buffer16 = (unsigned short*)buffer;
     draw_mode = NORMAL;
     set_orientation(1);
     foreground(White);
     background(Black);
     set_auto_up(true);
+    tftID=0;
   //  cls();
   //  locate(0,0);
 }
 LCD::LCD(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC, const int lcdsize_x, const int lcdsize_y, const int ic_x_segs, const int ic_y_coms, const char *name)
-    : GraphicsDisplay(name), LCDSIZE_X(lcdsize_x), LCDSIZE_Y(lcdsize_y), LCDPAGES(lcdsize_y>>3), IC_X_SEGS(ic_x_segs), IC_Y_COMS(ic_y_coms), IC_PAGES(ic_y_coms>>3)
+    : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y), _LCDPAGES(lcdsize_y>>3), _IC_X_SEGS(ic_x_segs), _IC_Y_COMS(ic_y_coms), _IC_PAGES(ic_y_coms>>3)
 {
- //   LCDPAGES = LCDSIZE_Y>>3;
- //   IC_PAGES = IC_Y_COMS>>3;
-  //  buffer = new unsigned char [LCDSIZE_X*LCDPAGES];
-  //  PAR8 par8proto(port, CS, reset, DC, WR, RD);
     if(displayproto==SPI_8)
     {
         proto = new SPI8(Hz, mosi, miso, sclk, CS, reset, DC);
@@ -65,7 +54,7 @@
         proto = new SPI16(Hz, mosi, miso, sclk, CS, reset, DC);
         useNOP=true;
     }
-    buffer = (unsigned char*) malloc (LCDSIZE_X*LCDPAGES);
+    buffer = (unsigned char*) malloc (screensize_X*_LCDPAGES);
     buffer16 = (unsigned short*)buffer;
     draw_mode = NORMAL;
   //  cls();
@@ -73,6 +62,7 @@
     foreground(White);
     background(Black);
     set_auto_up(true);
+    tftID=0;
   //  locate(0,0);
 
 }
@@ -122,33 +112,33 @@
         case (0):// portrait view -90°
             mirrorXY(Y);
             col_offset = 0;
-            page_offset = IC_PAGES-LCDPAGES;
-            set_width(LCDSIZE_Y);
-            set_height(LCDSIZE_X);
+            page_offset = _IC_PAGES-_LCDPAGES;
+            set_width(screensize_Y);
+            set_height(screensize_X);
         //    portrait = true;
             break;
         case (1): // default, landscape view 0°
             mirrorXY(NONE);
             col_offset = 0;
             page_offset = 0;
-            set_width(LCDSIZE_X);
-            set_height(LCDSIZE_Y);
+            set_width(screensize_X);
+            set_height(screensize_Y);
        //     portrait = false;
             break;
         case (2):// portrait view +90°
             mirrorXY(X);
-            col_offset = IC_X_SEGS-LCDSIZE_X; // some displays have less pixels than IC ram
+            col_offset = _IC_X_SEGS-screensize_X; // some displays have less pixels than IC ram
             page_offset = 0;
-            set_width(LCDSIZE_Y);
-            set_height(LCDSIZE_X);
+            set_width(screensize_Y);
+            set_height(screensize_X);
        //     portrait = true;
             break;
         case (3):// landscape view +180°
             mirrorXY(XY);
-            col_offset = IC_X_SEGS-LCDSIZE_X;
-            page_offset = IC_PAGES-LCDPAGES;
-            set_width(LCDSIZE_X);
-            set_height(LCDSIZE_Y);
+            col_offset = _IC_X_SEGS-screensize_X;
+            page_offset = _IC_PAGES-_LCDPAGES;
+            set_width(screensize_X);
+            set_height(screensize_Y);
        //     portrait = false;
             break;
     }
@@ -251,43 +241,51 @@
 {
     if(!(orientation&1)) SWAP(x,y);
     // first check parameter
-    if((x >= LCDSIZE_X) || (y >= LCDSIZE_Y)) return;
+    if((x >= screensize_X) || (y >= screensize_Y)) return;
 
 //    if(draw_mode == NORMAL)
 //    {
-        if(color) buffer[(x + ((y>>3)*LCDSIZE_X))^1] &= ~(1 << (y&7));  // erase pixel
-        else buffer[(x + ((y>>3)*LCDSIZE_X))^1] |= (1 << (y&7));   //Black=0000, set pixel
+        if(color) buffer[(x + ((y>>3)*screensize_X))^1] &= ~(1 << (y&7));  // erase pixel
+        else buffer[(x + ((y>>3)*screensize_X))^1] |= (1 << (y&7));   //Black=0000, set pixel
 //    }
 //    else
 //    { // XOR mode
-//        if(color == 1) buffer[x + ((y>>3) * LCDSIZE_X)] ^= (1 << (y&7));   // xor pixel
+//        if(color == 1) buffer[x + ((y>>3) * screensize_X)] ^= (1 << (y&7));   // xor pixel
 //    }
 }
 void LCD::copy_to_lcd(void)
 {
     unsigned short i=0;
     unsigned short setcolcmd = 0x0010 | ((col_offset&0xF)<<8) | (col_offset>>4);
-    for(int page=0; page<LCDPAGES; page++)
+    for(int page=0; page<_LCDPAGES; page++)
     {
       //  wr_cmd8(col_offset&0xF);              // set column low nibble
       //  wr_cmd8(0x10|(col_offset>>4));      // set column hi  nibble
         wr_cmd16(setcolcmd);
         wr_cmd8(0xB0|(page+page_offset));      // set page
-        wr_grambuf(buffer16+i, LCDSIZE_X>>1);   // send whole page pixels
-        i+=LCDSIZE_X>>1;
+        wr_grambuf(buffer16+i, screensize_X>>1);   // send whole page pixels
+        i+=screensize_X>>1;
     }
 }
 void LCD::cls(void)
 {
     unsigned short tmp = _background^0xFFFF;
-    memset(buffer,tmp,LCDSIZE_X*LCDPAGES);  // clear display buffer
+    memset(buffer,tmp,screensize_X*_LCDPAGES);  // clear display buffer
     unsigned short setcolcmd = 0x0010 | ((col_offset&0xF)<<8) | (col_offset>>4);
-    for(int page=0; page<LCDPAGES; page++)
+    for(int page=0; page<_LCDPAGES; page++)
     {
      //   wr_cmd8((unsigned char)col_offset&0xF);              // set column low nibble
      //   wr_cmd8(0x10|(col_offset>>4));      // set column hi  nibble
         wr_cmd16(setcolcmd);
         wr_cmd8(0xB0|(page+page_offset));      // set page
-        wr_gram(tmp, LCDSIZE_X>>1);   // send whole page pixels =0
+        wr_gram(tmp, screensize_X>>1);   // send whole page pixels =0
     }
+}
+int LCD::sizeX()
+{
+    return screensize_X;
+}
+int LCD::sizeY()
+{
+    return screensize_Y;
 }
\ No newline at end of file
--- a/Display/LCD.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Display/LCD.h	Tue Feb 17 11:02:06 2015 +0000
@@ -53,9 +53,6 @@
     */
     virtual void pixel(int x, int y, unsigned short color);
 
-    
-        
-    
     /** Set the window, which controls where items are written to the screen.
     * When something hits the window width, it wraps back to the left side
     * and down a row. If the initial write is outside the window, it will
@@ -66,6 +63,8 @@
     * @param h is the window height in pixels.
     */
     virtual void window(int x, int y, int w, int h);
+    
+    
 
     /** Push a single pixel into the window and increment position.
     * You must first call window() then push pixels in loop.
@@ -102,7 +101,7 @@
       */
     int get_contrast(void);
 
-    /** invert the screen
+    /** display inverted colors
       *
       * @param o = 0 normal, 1 invert
       */
@@ -114,10 +113,6 @@
     */
     virtual void cls();
     
-    
-    
-    
-    
     /** Set the orientation of the screen
     *  x,y: 0,0 is always top left 
     *
@@ -135,6 +130,29 @@
     */
     virtual void BusEnable(bool enable);
     
+    /** get display X size in pixels (native, orientation independent)
+    * @returns X size in pixels
+    */
+    int sizeX();
+
+    /** get display X size in pixels (native, orientation independent)
+    * @returns screen height in pixels.
+    */
+    int sizeY();
+    
+////////////////////////////////////////////////////////////////////////////////    
+    // not implemented yet
+//////////////////////////////////////////////////////////////////
+    virtual unsigned short pixelread(int x, int y){return 0;};
+    virtual void window4read(int x, int y, int w, int h){};
+    void setscrollarea (int startY, int areasize){};
+    void scroll (int lines){};
+    void scrollreset(){};
+    
+    unsigned int tftID;
+    
+    
+    
     
 protected:
 
@@ -196,12 +214,12 @@
     Protocols* proto;
     unsigned char *buffer;
     unsigned short *buffer16;
-    const int LCDSIZE_X;
-    const int LCDSIZE_Y;
-    const int LCDPAGES;
-    const int IC_X_SEGS;
-    const int IC_Y_COMS;
-    const int IC_PAGES;
+    const int screensize_X;
+    const int screensize_Y;
+    const int _LCDPAGES;
+    const int _IC_X_SEGS;
+    const int _IC_Y_COMS;
+    const int _IC_PAGES;
     
     int page_offset;
     int col_offset;
--- a/Display/TFT.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Display/TFT.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -23,7 +23,7 @@
 #define SWAP(a, b)  { a ^= b; b ^= a; a ^= b; }
 
 TFT::TFT(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const char *name)
-    : GraphicsDisplay(name), LCDSIZE_X(lcdsize_x), LCDSIZE_Y(lcdsize_y)
+    : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y)
 {
     if(displayproto==PAR_8) proto = new PAR8(port, CS, reset, DC, WR, RD);
     else if(displayproto==PAR_16) proto = new PAR16(port, CS, reset, DC, WR, RD);
@@ -34,11 +34,13 @@
     foreground(White);
     background(Black);
     set_auto_up(false); //we don't have framebuffer
+    topfixedareasize=0;
+    scrollareasize=0;
   //  cls();
   //  locate(0,0);
 }
 TFT::TFT(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC, const int lcdsize_x, const int lcdsize_y, const char *name)
-    : GraphicsDisplay(name), LCDSIZE_X(lcdsize_x), LCDSIZE_Y(lcdsize_y)
+    : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y)
 {
     if(displayproto==SPI_8)
     {
@@ -56,6 +58,8 @@
     foreground(White);
     background(Black);
     set_auto_up(false);
+    topfixedareasize=0;
+    scrollareasize=0;
   //  locate(0,0);
 }
 void TFT::wr_cmd8(unsigned char cmd)
@@ -83,13 +87,17 @@
     {
         proto->wr_grambuf(data, lenght);
     }
-unsigned int TFT::rd_data32_wdummy()
-    {
-        return proto->rd_data32_wdummy();
-    }
 unsigned short TFT::rd_gram()
     {
-        return (proto->rd_gram());
+        return proto->rd_gram();
+    }
+unsigned int TFT::rd_reg_data32(unsigned char reg)
+    {
+        return proto->rd_reg_data32(reg);
+    }
+unsigned int TFT::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd)
+    {
+        return proto->rd_extcreg_data32(reg, SPIreadenablecmd);
     }
 //for TFT, just send data, position counters are in hw
 void TFT::window_pushpixel(unsigned short color)
@@ -121,29 +129,34 @@
         case 0:// default, portrait view 0°
             if(mipistd) wr_data8(0x0A); // this is in real a vertical flip enabled, seems most displays are vertical flipped
             else wr_data8(0x48); //for some other ILIxxxx
-            set_width(LCDSIZE_X);
-            set_height(LCDSIZE_Y);
+            set_width(screensize_X);
+            set_height(screensize_Y);
             break;
         case 1:// landscape view +90°
             if(mipistd) wr_data8(0x28); 
             else wr_data8(0x29);//for some other ILIxxxx
-            set_width(LCDSIZE_Y);
-            set_height(LCDSIZE_X);
+            set_width(screensize_Y);
+            set_height(screensize_X);
             break;
         case 2:// portrait view +180°
             if(mipistd) wr_data8(0x09); 
             else wr_data8(0x99);//for some other ILIxxxx
-            set_width(LCDSIZE_X);
-            set_height(LCDSIZE_Y);
+            set_width(screensize_X);
+            set_height(screensize_Y);
             break;
         case 3:// landscape view -90°
             if(mipistd) wr_data8(0x2B); 
             else wr_data8(0xF8);//for some other ILIxxxx
-            set_width(LCDSIZE_Y);
-            set_height(LCDSIZE_X);
+            set_width(screensize_Y);
+            set_height(screensize_X);
             break;
     }
 }
+void TFT::invert(unsigned char o)
+{
+    if(o == 0) wr_cmd8(0x20);
+    else wr_cmd8(0x21);
+}
 // TFT have both column and raw autoincrement inside a window, with internal counters
 void TFT::window(int x, int y, int w, int h)
 {
@@ -186,10 +199,70 @@
     if(mipistd) color = BGR2RGB(color); // in case, convert BGR to RGB (should depend on cmd36 bit3) but maybe is device specific
     return color;
 }
+void TFT::setscrollarea (int startY, int areasize) // ie 0,480 for whole screen
+{
+    unsigned int bfa;
+    topfixedareasize=startY;
+    scrollareasize=areasize;
+    wr_cmd8(0x33);
+    wr_data16(topfixedareasize); //num lines of top fixed area
+    wr_data16(scrollareasize+scrollbugfix); //num lines of vertical scroll area, +1 for ILI9481 fix
+    if((areasize+startY)>height()) bfa=0;
+    else bfa = height()-(areasize+startY);
+    wr_data16(bfa); //num lines of bottom fixed area
+}
+void TFT::scroll (int lines) // ie 1= scrollup 1, 479= scrolldown 1
+{
+    wr_cmd8(0x37);
+    wr_data16((topfixedareasize+lines)%scrollareasize); //num lines of top fixed area
+}
+void TFT::scrollreset()
+{
+    wr_cmd8(0x13);  //normal display mode
+}
 void TFT::cls (void)
 {
     WindowMax();
-  //  proto->wr_gram(_background,LCDSIZE_X*LCDSIZE_Y);
-  //  proto->wr_gram(0,LCDSIZE_X*LCDSIZE_Y);
-    wr_gram(_background,LCDSIZE_X*LCDSIZE_Y);
+  //  proto->wr_gram(_background,screensize_X*screensize_Y);
+  //  proto->wr_gram(0,screensize_X*screensize_Y);
+    wr_gram(_background,screensize_X*screensize_Y);
+}
+// try to identify display controller
+void TFT::identify()
+{
+    // MIPI std read ID cmd
+    tftID=rd_reg_data32(0xBF);
+    mipistd=true;
+ //   debug("ID MIPI : 0x%8X\r\n",tftID);
+    if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF)))
+    {
+        mipistd=false;
+        // ILI specfic read ID cmd
+        tftID=rd_reg_data32(0xD3)>>8; 
+    //    debug("ID ILI : 0x%8X\r\n",tftID);
+    }
+    if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF)))
+    {
+        // ILI specfic read ID cmd with ili9341 specific spi read-in enable 0xD9 cmd
+        tftID=rd_extcreg_data32(0xD3, 0xD9);
+    //    debug("ID D9 extc ILI : 0x%8X\r\n",tftID);
+    }
+    if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF)))
+    {
+        // ILI specfic read ID cmd with ili9486/88 specific spi read-in enable 0xFB cmd
+        tftID=rd_extcreg_data32(0xD3, 0xFB);
+    //    debug("ID D9 extc ILI : 0x%8X\r\n",tftID);
+    }
+    if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF))) tftID=0xDEAD;
+    if ((tftID&0xFFFF)==0x9481) scrollbugfix=1;
+    else scrollbugfix=0;
+    hw_reset(); // in case wrong cmds messed up important settings
+}
+int TFT::sizeX()
+{
+    return screensize_X;
+}
+int TFT::sizeY()
+{
+    return screensize_Y;
 }
\ No newline at end of file
--- a/Display/TFT.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Display/TFT.h	Tue Feb 17 11:02:06 2015 +0000
@@ -85,7 +85,7 @@
     */
     virtual void copy_to_lcd(){ };
 
-    /** invert the screen
+    /** display inverted colors
       *
       * @param o = 0 normal, 1 invert
       */
@@ -114,6 +114,40 @@
     */
     virtual void BusEnable(bool enable);
     
+    /** Set scroll area boundaries
+    * scroll is done in hw but only on the native vertical axis
+    * TFTs are mainly native protrait view, so horizontal scroll if rotated in landscape view
+    *
+    * @param startY boundary offset from top (or left if rotated), 0 for fullscreen scroll
+    * @param areasize size of the scroll area, 480 for fullscreen scroll of a 320x480 display
+    */
+    void setscrollarea (int startY, int areasize);
+    
+    /** Scroll up(or left) the scrollarea
+    * 
+    * @param lines number of lines to scroll, 1= scrollup 1, areasize-1= scrolldown 1
+    */
+    void scroll (int lines);
+    
+    /** Reset the scrollarea and display un-scrolled screen
+    *  
+    */
+    void scrollreset();
+    
+    /** get display X size in pixels (native, orientation independent)
+    * @returns X size in pixels
+    */
+    int sizeX();
+
+    /** get display X size in pixels (native, orientation independent)
+    * @returns screen height in pixels.
+    */
+    int sizeY();
+    
+    unsigned int tftID;
+    
+    
+    
     
 protected:
 
@@ -165,38 +199,44 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght);
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy();
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram();
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg);
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @param SPIreadenablecmd vendor/device specific cmd to read EXTC registers
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers but needs special cmd to be read in SPI mode
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd);
+    
     /** HW reset sequence (without display init commands)   
     */
     void hw_reset();
     
+    /** Try to identify display ID
+    * @note support ILI9341,94xx, MIPI standard. May be be overridden in Init class for other specific IC
+    */
+    virtual void identify();
+    
     unsigned int scrollbugfix;
     bool mipistd;
     
 private:
 
     Protocols* proto;
-    const int LCDSIZE_X;
-    const int LCDSIZE_Y;
- //   const int LCDPAGES;
- //   const int IC_X_SEGS;
- //   const int IC_Y_COMS;
- //   const int IC_PAGES;
-    
- //   int page_offset;
- //   int col_offset;
+    const int screensize_X;
+    const int screensize_Y;
     // pixel location
     int cur_x;
     int cur_y;
@@ -206,7 +246,8 @@
     int win_y1;
     int win_y2;
     int orientation;
-    unsigned int tftID;
+    int topfixedareasize;
+    int scrollareasize;
     bool useNOP;
 };
 
--- a/Inits/ILI9341.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Inits/ILI9341.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -20,8 +20,8 @@
 {
     hw_reset();
     BusEnable(true);
+    identify(); // will collect tftID and set mipistd flag
     init();
-    mipistd=false;
     set_orientation(0);
     cls();
     locate(0,0); 
@@ -31,8 +31,8 @@
 {
     hw_reset(); //TFT class forwards to Protocol class
     BusEnable(true); //TFT class forwards to Protocol class
+    identify(); // will collect tftID and set mipistd flag
     init(); // per display custom init cmd sequence, implemented here
-    mipistd=false;
     set_orientation(0); //TFT class does for MIPI standard and some ILIxxx
     cls();
     locate(0,0); 
--- a/Inits/ILI9486.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Inits/ILI9486.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -19,9 +19,8 @@
 {
     hw_reset();
     BusEnable(true);
+    identify(); // will collect tftID and set mipistd flag
     init();
-    mipistd=false;
-    scrollbugfix=1; // when scrolling 1 line, the last line disappears, set to 1 to fix it
     set_orientation(0);
     cls();
     locate(0,0); 
@@ -31,9 +30,8 @@
 {
     hw_reset(); //TFT class forwards to Protocol class
     BusEnable(true); //TFT class forwards to Protocol class
+    identify(); // will collect tftID and set mipistd flag
     init(); // per display custom init cmd sequence, implemented here
-    mipistd=false;
-    scrollbugfix=1; // when scrolling 1 line, the last line disappears, set to 1 to fix it
     set_orientation(0); //TFT class does for MIPI standard and some ILIxxx
     cls();
     locate(0,0); 
--- a/Inits/TFT_MIPI.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Inits/TFT_MIPI.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -19,8 +19,9 @@
 {
     hw_reset();
     BusEnable(true);
+    identify(); // will collect tftID, set mipistd flag
     init();
-    mipistd=true;
+//    scrollbugfix=1; // when scrolling 1 line, the last line disappears, set to 1 to fix it, for ili9481 is set automatically in identify()
     set_orientation(0);
     cls();
     locate(0,0); 
@@ -30,8 +31,9 @@
 {
     hw_reset(); //TFT class forwards to Protocol class
     BusEnable(true); //TFT class forwards to Protocol class
+    identify(); // will collect tftID and set mipistd flag
     init(); // per display custom init cmd sequence, implemented here
-    mipistd=true;
+ //   scrollbugfix=1; // when scrolling 1 line, the last line disappears, set to 1 to fix it, for ili9481 is set automatically in identify()
     set_orientation(0); //TFT class does for MIPI standard and some ILIxxx
     cls();
     locate(0,0); 
--- a/Protocols/PAR16.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/PAR16.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -150,11 +150,36 @@
     _CS = 1;
 #endif
 }
-unsigned int PAR16::rd_data32_wdummy()
+unsigned short PAR16::rd_gram()
 {
 #ifdef USE_CS
     _CS = 0;
 #endif
+    unsigned short r=0;
+    _DC = 1; // 1=data
+   _port.input();
+   
+    _RD = 0;
+    _port.read(); //dummy read
+    _RD = 1;
+    
+    _RD = 0;
+//    _RD = 0; // add wait
+    r |= _port.read();
+    _RD = 1;
+    
+#ifdef USE_CS
+    _CS = 1;
+#endif
+    _port.output();
+    return r;
+}
+unsigned int PAR16::rd_reg_data32(unsigned char reg)
+{
+#ifdef USE_CS
+    _CS = 0;
+#endif
+    wr_cmd8(reg);
     unsigned int r=0;
     _DC = 1; // 1=data
    _port.input();
@@ -193,29 +218,10 @@
     _port.output();
     return r;
 }
-unsigned short PAR16::rd_gram()
+// in Par mode EXTC regs (0xB0-0xFF) can be directly read
+unsigned int PAR16::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd)
 {
-#ifdef USE_CS
-    _CS = 0;
-#endif
-    unsigned short r=0;
-    _DC = 1; // 1=data
-   _port.input();
-   
-    _RD = 0;
-    _port.read(); //dummy read
-    _RD = 1;
-    
-    _RD = 0;
-//    _RD = 0; // add wait
-    r |= _port.read();
-    _RD = 1;
-    
-#ifdef USE_CS
-    _CS = 1;
-#endif
-    _port.output();
-    return r;
+    return rd_reg_data32(reg);
 }
 void PAR16::hw_reset()
 {
--- a/Protocols/PAR16.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/PAR16.h	Tue Feb 17 11:02:06 2015 +0000
@@ -75,19 +75,26 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght);
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy();
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram();
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg);
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers, for Parallel mode directly accessible in both directions
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd);
+    
     /** HW reset sequence (without display init commands)   
     */
     virtual void hw_reset();
--- a/Protocols/PAR8.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/PAR8.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -174,11 +174,42 @@
     _CS = 1;
 #endif
 }
-unsigned int PAR8::rd_data32_wdummy()
+unsigned short PAR8::rd_gram()
 {
 #ifdef USE_CS
     _CS = 0;
 #endif
+    unsigned short r=0;
+    _DC = 1; // 1=data
+   _port.input();
+   
+    _RD = 0;
+    _port.read(); //dummy read
+    _RD = 1;
+    
+    _RD = 0;
+//    _RD = 0; // add wait
+    r |= (_port.read()&0xFF);
+    r <<= 8;
+    _RD = 1;
+    
+    _RD = 0;
+//    _RD = 0; // add wait
+    r |= (_port.read()&0xFF);
+    _RD = 1;
+    
+#ifdef USE_CS
+    _CS = 1;
+#endif
+    _port.output();
+    return r;
+}
+unsigned int PAR8::rd_reg_data32(unsigned char reg)
+{
+#ifdef USE_CS
+    _CS = 0;
+#endif
+    wr_cmd8(reg);
     unsigned int r=0;
     _DC = 1; // 1=data
    _port.input();
@@ -217,35 +248,10 @@
     _port.output();
     return r;
 }
-unsigned short PAR8::rd_gram()
+// in Par mode EXTC regs (0xB0-0xFF) can be directly read
+unsigned int PAR8::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd)
 {
-#ifdef USE_CS
-    _CS = 0;
-#endif
-    unsigned short r=0;
-    _DC = 1; // 1=data
-   _port.input();
-   
-    _RD = 0;
-    _port.read(); //dummy read
-    _RD = 1;
-    
-    _RD = 0;
-//    _RD = 0; // add wait
-    r |= (_port.read()&0xFF);
-    r <<= 8;
-    _RD = 1;
-    
-    _RD = 0;
-//    _RD = 0; // add wait
-    r |= (_port.read()&0xFF);
-    _RD = 1;
-    
-#ifdef USE_CS
-    _CS = 1;
-#endif
-    _port.output();
-    return r;
+    return rd_reg_data32(reg);
 }
 void PAR8::hw_reset()
 {
--- a/Protocols/PAR8.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/PAR8.h	Tue Feb 17 11:02:06 2015 +0000
@@ -75,19 +75,26 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght);
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy();
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram();
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg);
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers, for Parallel mode directly accessible in both directions
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd);
+    
     /** HW reset sequence (without display init commands)   
     */
     virtual void hw_reset();
--- a/Protocols/Protocols.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/Protocols.h	Tue Feb 17 11:02:06 2015 +0000
@@ -82,19 +82,27 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght) = 0;
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy() = 0;
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram() = 0;
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg) = 0;
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @param SPIreadenablecmd vendor/device specific cmd to read EXTC registers
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers but needs special cmd to be read in SPI mode
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd) = 0;
+    
     /** HW reset sequence (without display init commands)   
     */
     virtual void hw_reset() = 0;
--- a/Protocols/SPI16.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/SPI16.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -121,26 +121,6 @@
     _CS = 1;
 #endif
 }
-unsigned int SPI16::rd_data32_wdummy()
-{
-#ifdef USE_CS
-    _CS = 0;
-#endif
-    unsigned int r=0;
-    _DC.write(1);; // 1=data
-   
-    r |= _spi.write(0); // we get only 15bit valid, first bit was the dummy cycle
-    r <<= 16;
-    r |= _spi.write(0);
-    r <<= 1; // 32bits are aligned, now collecting bit_0
-    r |= (_spi.write(0) >> 15);
-    // we clocked 15 more bit so ILI waiting for 16th, we need to reset spi bus
-    _CS = 1; // force CS HIG to interupt the cmd
-#ifndef USE_CS //if CS is not used, force fixed LOW again
-    _CS = 0;
-#endif
-    return r;
-}
 unsigned short SPI16::rd_gram()
 {
 #ifdef USE_CS
@@ -160,6 +140,45 @@
     r = RGB18to16((r&0xFC0000)>>16, (r&0xFC00)>>8, r&0xFC);// 18bit pixel, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit
     return (unsigned short)r;
 }
+unsigned int SPI16::rd_reg_data32(unsigned char reg)
+{
+#ifdef USE_CS
+    _CS = 0;
+#endif
+    wr_cmd8(reg);
+    unsigned int r=0;
+    _DC.write(1);; // 1=data
+   
+    r |= _spi.write(0); // we get only 15bit valid, first bit was the dummy cycle
+    r <<= 16;
+    r |= _spi.write(0);
+    r <<= 1; // 32bits are aligned, now collecting bit_0
+    r |= (_spi.write(0) >> 15);
+    // we clocked 15 more bit so ILI waiting for 16th, we need to reset spi bus
+    _CS = 1; // force CS HIG to interupt the cmd
+#ifndef USE_CS //if CS is not used, force fixed LOW again
+    _CS = 0;
+#endif
+    return r;
+}
+unsigned int SPI16::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd)
+{
+    unsigned int r=0;
+    for(int regparam=1; regparam<4; regparam++) // when reading EXTC regs, first parameter is always dummy, so start with 1
+    {
+        wr_cmd8(SPIreadenablecmd);  // spi-in enable cmd, 0xD9 (ili9341) or 0xFB (ili9488) or don't know
+        wr_data8(0xF0|regparam);    // in low nibble specify which reg parameter we want
+        wr_cmd8(reg);               // now send cmd (select register we want to read)
+        _DC.write(1); // 1=data
+        r <<= 8;
+        r |= (_spi.write(0) >> 8);
+    }
+_CS = 1; // force CS HIG to interupt the cmd
+#ifndef USE_CS //if CS is not used, force fixed LOW again
+    _CS = 0;
+#endif
+    return r;
+}
 void SPI16::hw_reset()
 {
     wait_ms(15);
--- a/Protocols/SPI16.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/SPI16.h	Tue Feb 17 11:02:06 2015 +0000
@@ -77,19 +77,27 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght);
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy();
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram();
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg);
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @param SPIreadenablecmd vendor/device specific cmd to read EXTC registers
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers but needs special cmd to be read in SPI mode
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd);
+    
     /** HW reset sequence (without display init commands)   
     */
     virtual void hw_reset();
--- a/Protocols/SPI8.cpp	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/SPI8.cpp	Tue Feb 17 11:02:06 2015 +0000
@@ -135,30 +135,6 @@
     _CS = 1;
 #endif
 }
-unsigned int SPI8::rd_data32_wdummy()
-{
-#ifdef USE_CS
-    _CS = 0;
-#endif
-    unsigned int r=0;
-    _DC.write(1); // 1=data
-   
-    r |= _spi.write(0); // we get only 7bit valid, first bit was the dummy cycle
-    r <<= 8;
-    r |= _spi.write(0);
-    r <<= 8;
-    r |= _spi.write(0);
-    r <<= 8;
-    r |= _spi.write(0);
-    r <<= 1; // 32bits are aligned, now collecting bit_0
-    r |= (_spi.write(0) >> 7);
-    // we clocked 7 more bit so ILI waiting for 8th, we need to reset spi bus
-    _CS = 1; // force CS HIG to interupt the cmd
-#ifndef USE_CS //if CS is not used, force fixed LOW again
-    _CS = 0;
-#endif
-    return r;
-}
 unsigned short SPI8::rd_gram()
 {
 #ifdef USE_CS
@@ -181,6 +157,50 @@
     r = RGB18to16((r&0xFC0000)>>16, (r&0xFC00)>>8, r&0xFC);// 18bit pixel, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit
     return (unsigned short)r;
 }
+unsigned int SPI8::rd_reg_data32(unsigned char reg)
+{
+#ifdef USE_CS
+    _CS = 0;
+#endif
+    wr_cmd8(reg);
+    unsigned int r=0;
+    _DC.write(1); // 1=data
+   
+    r |= _spi.write(0); // we get only 7bit valid, first bit was the dummy cycle
+    r <<= 8;
+    r |= _spi.write(0);
+    r <<= 8;
+    r |= _spi.write(0);
+    r <<= 8;
+    r |= _spi.write(0);
+    r <<= 1; // 32bits are aligned, now collecting bit_0
+    r |= (_spi.write(0) >> 7);
+    // we clocked 7 more bit so ILI waiting for 8th, we need to reset spi bus
+    _CS = 1; // force CS HIG to interupt the cmd
+#ifndef USE_CS //if CS is not used, force fixed LOW again
+    _CS = 0;
+#endif
+    return r;
+}
+unsigned int SPI8::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd)
+{
+    unsigned int r=0;
+    for(int regparam=1; regparam<4; regparam++) // when reading EXTC regs, first parameter is always dummy, so start with 1
+    {
+        wr_cmd8(SPIreadenablecmd);  // spi-in enable cmd, 0xD9 (ili9341) or 0xFB (ili9488) or don't know
+        wr_data8(0xF0|regparam);    // in low nibble specify which reg parameter we want
+        wr_cmd8(reg);               // now send cmd (select register we want to read)
+        _DC.write(1); // 1=data
+        r <<= 8;
+        r |= _spi.write(0);
+        // r = _spi.write(0) >> 8; for 16bit
+    }
+_CS = 1; // force CS HIG to interupt the cmd
+#ifndef USE_CS //if CS is not used, force fixed LOW again
+    _CS = 0;
+#endif
+    return r;
+}
 void SPI8::hw_reset()
 {
     wait_ms(15);
--- a/Protocols/SPI8.h	Mon Feb 16 01:18:29 2015 +0000
+++ b/Protocols/SPI8.h	Tue Feb 17 11:02:06 2015 +0000
@@ -74,19 +74,27 @@
     */   
     virtual void wr_grambuf(unsigned short* data, unsigned int lenght);
     
-    /** Read 4x8bit data from display controller (with dummy cycle)
-    *
-    * @returns data as uint
-    *
-    */ 
-    virtual unsigned int rd_data32_wdummy();
-    
     /** Read 16bit pixeldata from display controller (with dummy cycle)
     *
     * @returns 16bit color
     */ 
     virtual unsigned short rd_gram();
     
+    /** Read 4x8bit register data (with dummy cycle)
+    * @param reg the register to read
+    * @returns data as uint
+    * 
+    */ 
+    virtual unsigned int rd_reg_data32(unsigned char reg);
+    
+    /** Read 3x8bit ExtendedCommands register data
+    * @param reg the register to read
+    * @param SPIreadenablecmd vendor/device specific cmd to read EXTC registers
+    * @returns data as uint
+    * @note EXTC regs (0xB0 to 0xFF) are read/write registers but needs special cmd to be read in SPI mode
+    */ 
+    virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd);
+    
     /** HW reset sequence (without display init commands)   
     */
     virtual void hw_reset();