Added methods and features

Fork of SPI_TFT_ILI9341 by Peter Drescher

SPI_TFT_ILI9341.cpp

Committer:
wim
Date:
2014-04-22
Revision:
11:7aabc3810093
Parent:
10:2d505d14b7eb

File content as of revision 11:7aabc3810093:

/* mbed library for 240*320 pixel display TFT based on ILI9341 LCD Controller
 * Copyright (c) 2013 Peter Drescher - DC2PD
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 
// 12.06.13 fork from SPI_TFT code because controller is different ...
// 14.07.13 Test with real display and bugfix 
// 18.10.13 Better Circle function from Michael Ammann
// 22.10.13 Fixes for Kinetis Board - 8 bit spi
// 26.01.14 Change interface for BMP_16 to also use SD-cards
// 30.03.14 WH Added some methods & defines, Fixed typos & warnings, General define for SPI_16 selection

#include "mbed.h"
#include "SPI_TFT_ILI9341.h"

//extern Serial pc;
//extern DigitalOut xx;     // debug !!

SPI_TFT_ILI9341::SPI_TFT_ILI9341(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset, PinName dc, const char *name)
    : GraphicsDisplay(name), _spi(mosi, miso, sclk), _cs(cs), _dc(dc) 
{

  // The hardware Reset pin is optional. Test and make sure whether it exists or not to prevent illegal access.
  if (reset != NC) {
    _reset = new DigitalOut(reset, 1);   //Construct new pin, Deactivated 
//    _reset->write(1);                 //Deactivate    
  }
  else {
    // No Hardware Reset pin       
    _reset = NULL;                 //Construct dummy pin     
  }  

//WH    clk = sclk;
//WH    orientation = 0;
    _origin = Origin_LeftTop;  
    _char_x = 0;
    _char_y = 0;
    _transparancy = false;    
//    set_font(Arial12x12); //Default font    
//    set_font(FONT8x8); //Default font, shame it doesnt fit format.. waste of flash space at moment
  
    tft_reset();
}


/** Destruct a SPI_TFT LCD object
  *
  * @param  none
  * @return none
  */ 
SPI_TFT_ILI9341::~SPI_TFT_ILI9341() {
  if (_reset != NULL) {delete _reset;}  // HW Reset pin
}



int SPI_TFT_ILI9341::width()
{
//    if (orientation == 0 || orientation == 2) return 240;
//    else return 320;

    if (_origin == Origin_LeftTop || _origin == Origin_RightBot) return TFT_WIDTH;
    else return TFT_HEIGHT;
}


int SPI_TFT_ILI9341::height()
{
//    if (orientation == 0 || orientation == 2) return 320;
//    else return 240;

    if (_origin == Origin_LeftTop || _origin == Origin_RightBot) return TFT_HEIGHT;
    else return TFT_WIDTH;
}

//WH
#if(0)
void SPI_TFT_ILI9341::set_orientation(unsigned int o)
{
    orientation = o;
    wr_cmd(0x36);                     // MEMORY_ACCESS_CONTROL
    switch (orientation) {
        case 0:
            _spi.write(0x48);
            break;
        case 1:
            _spi.write(0x28);
            break;
        case 2:
            _spi.write(0x88);
            break;
        case 3:
            _spi.write(0xE8);
            break;
    }
    _cs = 1; 
    window_max();
} 
#else
void SPI_TFT_ILI9341::set_origin(Origin origin) {
    _origin = origin;
    wr_cmd(ILI9341_MAC);             // MEMORY_ACCESS_CONTROL
    switch (_origin) {
        case Origin_LeftTop:         /* Left Top of panel is origin */    
            _spi.write(0x48);
            break;
        case Origin_RightTop:        /* ok */ 
            _spi.write(0x28);
            break;
        case Origin_RightBot:        /* ok */ 
            _spi.write(0x88);
            break;
        case Origin_LeftBot:        /* ok */ 
            _spi.write(0xE8);
            break;
    }
    _cs = 1; 
    window_max();
} 
#endif


// background transparancy for characters 
void SPI_TFT_ILI9341::set_transparancy(bool state) {
  _transparancy = state;  
}

// HW Reset to tft
void SPI_TFT_ILI9341::_hwreset()
{
  // _reset is an optional pin which defaults to NC. Make sure it does not hang mbed lib
  if (_reset != NULL) {_reset->write(0);}  //Clear _reset pin
  wait_us(50);
  if (_reset != NULL) {_reset->write(1);}  //Set _reset pin  
  wait_ms(5);
}


// write command to tft register
void SPI_TFT_ILI9341::wr_cmd(unsigned char cmd)
{
    _dc = 0;
    _cs = 0;
    _spi.write(cmd);      // mbed lib
    _dc = 1;
}


// write data to tft
void SPI_TFT_ILI9341::wr_dat(unsigned char dat)
{
   _spi.write(dat);      // mbed lib
}

//WH
// The ILI9341 can be read 
// Read not supported in M24SR


// Read byte
char SPI_TFT_ILI9341::rd_byte(unsigned char cmd)
{
    char r;
    _dc = 0;
    _cs = 0;
    _spi.write(cmd);      // mbed lib
    _cs = 1;
    r = _spi.write(0xff);
    _cs = 1;    
    return(r);
}

// Read 32 bit
int SPI_TFT_ILI9341::rd_32(unsigned char cmd)
{
    int d;
    char r;
    _dc = 0;
    _cs = 0;
    d = cmd;
    d = d << 1;

//Note WH: the 9bit format is not supported for most mbed devices...This wont work.
    _spi.format(9,0);    // we have to add a dummy clock cycle
     
    _spi.write(d);
    _spi.format(8,0);   
    _dc = 1;
    r = _spi.write(0xff);
    d = r;
    r = _spi.write(0xff);
    d = (d << 8) | r;
    r = _spi.write(0xff);
    d = (d << 8) | r;
    r = _spi.write(0xff);
    d = (d << 8) | r;
    _cs = 1;    
    return(d);
}

//This may be not supported on some revisions of IL9341
int  SPI_TFT_ILI9341::Read_ID(void){
    int r;
    r = rd_byte(0x0A);
    r = rd_byte(0x0A);
    r = rd_byte(0x0A);
    r = rd_byte(0x0A);
    return(r);
}


// Init code based on MI0283QT datasheet
void SPI_TFT_ILI9341::tft_reset()
{
//WH    _spi.format(8,3);                  // 8 bit spi Mode 3
    _spi.format(8,0);                  // 8 bit spi, mode 0    
    
//    _spi.frequency(4000000);          // 4 Mhz SPI clock
//    _spi.frequency(8000000);          // 8 Mhz SPI clock
    _spi.frequency(10000000);           // 10 Mhz SPI ... works on current version of mbed F103 lib after fix for HSI/HSE...
        
    _cs = 1;                           // cs high
    _dc = 1;                           // dc high 

    _hwreset();                        // HW reset 
         
    wr_cmd(ILI9341_DISPLAY_RST);      // SW reset      
    wait_ms(5);

    wr_cmd(ILI9341_DISPLAY_OFF);      // display off      

    /* Start Initial Sequence ----------------------------------------------------*/
     wr_cmd(ILI9341_POWERB);    /* Power control B register */
     _spi.write(0x00);
     _spi.write(0x83);
     _spi.write(0x30);
     _cs = 1;
     
     wr_cmd(ILI9341_POWER_SEQ); /* Power on sequence register */
     _spi.write(0x64);
     _spi.write(0x03);
     _spi.write(0x12);
     _spi.write(0x81);
     _cs = 1;
     
     wr_cmd(ILI9341_DTCA);      /* Driver timing control A */                      
     _spi.write(0x85);
     _spi.write(0x01);
     _spi.write(0x79);
     _cs = 1;
     
     wr_cmd(ILI9341_POWERA);    /* Power control A register */                     
     _spi.write(0x39);
     _spi.write(0x2C);
     _spi.write(0x00);
     _spi.write(0x34);
     _spi.write(0x02);
     _cs = 1;
           
     wr_cmd(ILI9341_PRC);       /* Pump ratio control register */                   
     _spi.write(0x20);
     _cs = 1;
           
     wr_cmd(ILI9341_DTCB);      /* Driver timing control B */                          
     _spi.write(0x00);
     _spi.write(0x00);
     _cs = 1;
     
     wr_cmd(ILI9341_POWER1);    // POWER_CONTROL_1   
     _spi.write(0x26);
     _cs = 1;
 
     wr_cmd(ILI9341_POWER2);    // POWER_CONTROL_2
     _spi.write(0x11);
     _cs = 1;
     
     wr_cmd(ILI9341_VCOM1);     // VCOM_CONTROL_1     
     _spi.write(0x35);
     _spi.write(0x3E);
     _cs = 1;
     
     wr_cmd(ILI9341_VCOM2);     // VCOM_CONTROL_2     
     _spi.write(0xBE);
     _cs = 1; 
     
     wr_cmd(ILI9341_MAC);       // MEMORY_ACCESS_CONTROL     
     _spi.write(0x48);            // my,mx,mv,ml,BGR,mh,0,0
     _cs = 1; 
     
     wr_cmd(ILI9341_PIXEL_FORMAT); /* Pixel Format register */
     _spi.write(0x55);                 // 16 bit pixel 
     _cs = 1;
     
     wr_cmd(ILI9341_FRC);          /* Frame Rate Control register */
     _spi.write(0x00);
     _spi.write(0x1B);               
     _cs = 1;
     
     wr_cmd(ILI9341_3GAMMA_EN);    /* 3 Gamma enable register */     
     _spi.write(0x08);             // Gamma Function Disable
     _cs = 1; 
     
     wr_cmd(ILI9341_GAMMA);        /* Gamma register */
     _spi.write(0x01);                 // gamma set for curve 01/2/04/08
     _cs = 1; 
     
     wr_cmd(ILI9341_PGAMMA);       /* Positive Gamma Correction register*/     
     _spi.write(0x1F); 
     _spi.write(0x1A); 
     _spi.write(0x18); 
     _spi.write(0x0A); 
     _spi.write(0x0F); 
     _spi.write(0x06); 
     _spi.write(0x45); 
     _spi.write(0x87); 
     _spi.write(0x32); 
     _spi.write(0x0A); 
     _spi.write(0x07); 
     _spi.write(0x02); 
     _spi.write(0x07);
     _spi.write(0x05); 
     _spi.write(0x00);
     _cs = 1;
     
     wr_cmd(ILI9341_NGAMMA);       /* Negative Gamma Correction register*/
     _spi.write(0x00); 
     _spi.write(0x25); 
     _spi.write(0x27); 
     _spi.write(0x05); 
     _spi.write(0x10); 
     _spi.write(0x09); 
     _spi.write(0x3A); 
     _spi.write(0x78); 
     _spi.write(0x4D); 
     _spi.write(0x05); 
     _spi.write(0x18); 
     _spi.write(0x0D); 
     _spi.write(0x38);
     _spi.write(0x3A); 
     _spi.write(0x1F);
     _cs = 1;
     
     window_max();

     //wr_cmd(ILI9341_TEAR_OFF);           // tearing effect off
     //_cs = 1;
     
     //wr_cmd(ILI9341_TEAR_ON);            // tearing effect on
     //_cs = 1;
      
     wr_cmd(ILI9341_ENTRY_MODE);          // entry mode         
     _spi.write(0x07);
     _cs = 1;
     
     wr_cmd(ILI9341_DFC);                /* Display Function Control register*/     
     _spi.write(0x0A);
     _spi.write(0x82);
     _spi.write(0x27);
     _spi.write(0x00);
     _cs = 1;
     
     wr_cmd(ILI9341_SLEEP_OUT);          // sleep out     
     _cs = 1;
     
     wait_ms(100);
     
     wr_cmd(ILI9341_DISPLAY_ON); 
     _cs = 1;
     
     wait_ms(100);
     
 }


void SPI_TFT_ILI9341::tft_on(bool on)
{
  if (on) {
    wr_cmd(ILI9341_DISPLAY_ON); 
  }  
  else {
    wr_cmd(ILI9341_DISPLAY_OFF); 
  }  
  _cs = 1;
}

void SPI_TFT_ILI9341::pixel(int x, int y, int color)
{
    wr_cmd(ILI9341_COLUMN_ADDR);
    _spi.write(x >> 8);
    _spi.write(x);
    _spi.write((x+1) >> 8);  //WH
    _spi.write(x+1);   
    
    _cs = 1;
    
    wr_cmd(ILI9341_PAGE_ADDR);
    _spi.write(y >> 8);
    _spi.write(y);
    _spi.write((y+1) >> 8); //WH
    _spi.write(y+1);
    
    _cs = 1;

    wr_cmd(ILI9341_GRAM);  // send pixel     

//    #if (SPI_16 == 1)
    #if(0)   // dont bother switching for only one pixel
    // 16 Bit SPI
    _spi.format(16,0);                            // switch to 16 bit Mode 0
    _spi.write(color);                            // Write D0..D15
    _spi.format(8,0);                             // switch back to 8 bit Mode 0
    #else 
    // 8 Bit SPI
    _spi.write(color >> 8);
    _spi.write(color & 0xff);   
    #endif

    _cs = 1;
}


void SPI_TFT_ILI9341::window (unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{

    wr_cmd(ILI9341_COLUMN_ADDR);
    _spi.write(x >> 8);
    _spi.write(x);
    _spi.write((x+w-1) >> 8);
    _spi.write(x+w-1);   
    _cs = 1;

    wr_cmd(ILI9341_PAGE_ADDR);  
    _spi.write(y >> 8);
    _spi.write(y);
    _spi.write((y+h-1) >> 8);
    _spi.write(y+h-1);
    _cs = 1;
}


void SPI_TFT_ILI9341::window_max (void)
{
  window (0, 0, width(),  height());
}



/** Fill the screen with _background color
  *  @param none
  *  @return none
  */  
void SPI_TFT_ILI9341::cls()
{  
  fillrect(0, 0, width()-1, height()-1, _background);
}    


//WH test
void SPI_TFT_ILI9341::newcls (void)
{  
    int pixels = height() * width();
    int i;
    int color = _background;
#if (SPI_16 != 1)    
    int msb, lsb;        
#endif    
 
    window(0,0,width(),height());

    wr_cmd(ILI9341_GRAM);  // send pixel         

#if (SPI_16 == 1)    
    // 16 Bit SPI
    _spi.format(16,0);   // switch to 16 bit Mode 0

    //unroll loop in chunks of 8 pixels
    for (i = 0; i < (pixels>>3); i++) {
      _spi.write(color);
      _spi.write(color);
      _spi.write(color);
      _spi.write(color); 
      
      _spi.write(color);
      _spi.write(color);
      _spi.write(color);
      _spi.write(color);                                          
    }  

    //remainder
    for (i = 0; i < (pixels & 0x07); i++)
      _spi.write(color);

    _spi.format(8,0);    // switch back to 8 bit Mode 0 
#else
    // 8 Bit SPI
    msb = color >> 8;
    lsb = color & 0xff;

    for (i = 0; i < (pixels>>3); i+=8) {
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);
      
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);
      _spi.write(msb); _spi.write(lsb);                                          
    }
    
    for (i = 0; i < (pixels & 0x07); i++) {
      _spi.write(msb); _spi.write(lsb);
    }    
#endif        

    _cs = 1; 
}




void SPI_TFT_ILI9341::circle(int x0, int y0, int r, int color)
{

    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        pixel(x0-x, y0+y,color);
        pixel(x0+x, y0+y,color);
        pixel(x0+x, y0-y,color);
        pixel(x0-x, y0-y,color);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);

}

void SPI_TFT_ILI9341::fillcircle(int x0, int y0, int r, int color)
{
    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        vline(x0-x, y0-y, y0+y, color);
        vline(x0+x, y0-y, y0+y, color);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);
}


void SPI_TFT_ILI9341::oval ( int x, int y, int b, int color, float aspect )
{  
  /* local variables */
  int   col;               /* Column. */
  int   row;               /* Row. */
  float aspect_square;
  int   a_square;
  int   b_square;
  int   two_a_square;
  int   two_b_square;
  int   four_a_square;
  int   four_b_square;
  int   d; 

  aspect_square = aspect * aspect;  
  
  b_square = b * b;
  a_square = b_square / aspect_square; 
  row = b;
  col = 0;
  two_a_square = a_square << 1;
  four_a_square = a_square << 2;
  four_b_square = b_square << 2;
  two_b_square = b_square << 1;
  d = two_a_square * ((row - 1) * (row)) + a_square + two_b_square * (1 - a_square);
      
  while (a_square * (row) > b_square * col ) {
    pixel( x + col, y + row, color );    
    pixel( x + col, y - row, color );    
    pixel( x - col, y + row, color );    
    pixel( x - col, y - row, color );    
    if ( d >= 0 ) {
      row--;
      d -= four_a_square * row;
    }
    d += two_b_square * (3 + (col << 1));
    col++;
  }
  
  d = two_b_square * (col + 1) * col + two_a_square * (row * (row - 2) + 1) + (1 - two_a_square) * b_square;    
  
  while ( row + 1 ) {
    pixel( x + col, y + row, color );    
    pixel( x + col, y - row, color );    
    pixel( x - col, y + row, color );    
    pixel( x - col, y - row, color );    
    if ( d <= 0 ) {
      col++;
      d += four_b_square * col;
    }
    row--;
    d += two_a_square * (3 - (row << 1));
  }

} /* End oval */


void SPI_TFT_ILI9341::filloval ( int x, int y, int b, int color, float aspect )
{  
  /* local variables */
  int   col;               /* Column. */
  int   row;               /* Row. */
  float aspect_square;
  int   a_square;
  int   b_square;
  int   two_a_square;
  int   two_b_square;
  int   four_a_square;
  int   four_b_square;
  int   d; 

  aspect_square = aspect * aspect;  
  
  b_square = b * b;
  a_square = b_square / aspect_square; 
  row = b;
  col = 0;
  two_a_square = a_square << 1;
  four_a_square = a_square << 2;
  four_b_square = b_square << 2;
  two_b_square = b_square << 1;
  d = two_a_square * ((row - 1) * (row)) + a_square + two_b_square * (1 - a_square);
      
  while (a_square * (row) > b_square * col ) {
    vline(x - col, y - row, y + row, color);    
    vline(x + col, y - row, y + row, color);           

    if ( d >= 0 ) {
      row--;
      d -= four_a_square * row;
    }
    d += two_b_square * (3 + (col << 1));
    col++;
  }
  
  d = two_b_square * (col + 1) * col + two_a_square * (row * (row - 2) + 1) + (1 - two_a_square) * b_square;    
  
  while ( row + 1 ) {
    vline(x - col, y - row, y + row, color);    
    vline(x + col, y - row, y + row, color);           
   
    if ( d <= 0 ) {
      col++;
      d += four_b_square * col;
    }
    row--;
    d += two_a_square * (3 - (row << 1));
  }

} /* End filloval */


void SPI_TFT_ILI9341::hline(int x0, int x1, int y, int color)
{
    int i, w;
#if (SPI_16 != 1)    
    int msb, lsb;
#endif    
    w = x1 - x0 + 1;
    window(x0,y,w,1);
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel         
    
#if (SPI_16 == 1)
    // 16 Bit SPI
    _spi.format(16,0);   // switch to 16 bit Mode 0
    for (i = 0; i < w; i++)
      _spi.write(color);
    _spi.format(8,0);    // switch back to 8 bit Mode 0 
#else
    // 8 Bit SPI
    msb = color >> 8;
    lsb = color & 0xff;
    for (i = 0; i < w; i++){
      _spi.write(msb);
      _spi.write(lsb);
    }
#endif        

    _cs = 1;
    window_max();
}



void SPI_TFT_ILI9341::vline(int x, int y0, int y1, int color)
{
    int i, h;
#if (SPI_16 != 1)    
    int msb, lsb;
#endif    
    
    h = y1 - y0 + 1;
    window(x,y0,1,h);
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel         

#if (SPI_16 == 1)
    // 16 Bit SPI
    _spi.format(16,0);   // switch to 16 bit Mode 0
    for (i = 0; i < h; i++)
      _spi.write(color);
    _spi.format(8,0);    // switch back to 8 bit Mode 0 
#else
    // 8 Bit SPI
    msb = color >> 8;
    lsb = color & 0xff;
    for (i = 0; i < h; i++){
      _spi.write(msb);
      _spi.write(lsb);
    }
#endif        
  
    _cs = 1;
    window_max();
}

void SPI_TFT_ILI9341::line(int x0, int y0, int x1, int y1, int color)
{
    //window_max();
    int   dx = 0, dy = 0;
    int   dx_sym = 0, dy_sym = 0;
    int   dx_x2 = 0, dy_x2 = 0;
    int   di = 0;

    dx = x1-x0;
    dy = y1-y0;

    if (dx == 0) {        /* vertical line */
        if (y1 > y0) vline(x0,y0,y1,color);
        else vline(x0,y1,y0,color);
        return;
    }

    if (dx > 0) {
        dx_sym = 1;
    } else {
        dx_sym = -1;
    }
    if (dy == 0) {        /* horizontal line */
        if (x1 > x0) hline(x0,x1,y0,color);
        else  hline(x1,x0,y0,color);
        return;
    }

    if (dy > 0) {
        dy_sym = 1;
    } else {
        dy_sym = -1;
    }

    dx = dx_sym*dx;
    dy = dy_sym*dy;

    dx_x2 = dx*2;
    dy_x2 = dy*2;

    if (dx >= dy) {
        di = dy_x2 - dx;
        while (x0 != x1) {

            pixel(x0, y0, color);
            x0 += dx_sym;
            if (di<0) {
                di += dy_x2;
            } else {
                di += dy_x2 - dx_x2;
                y0 += dy_sym;
            }
        }
        pixel(x0, y0, color);
    } else {
        di = dx_x2 - dy;
        while (y0 != y1) {
            pixel(x0, y0, color);
            y0 += dy_sym;
            if (di < 0) {
                di += dx_x2;
            } else {
                di += dx_x2 - dy_x2;
                x0 += dx_sym;
            }
        }
        pixel(x0, y0, color);
    }
//WH    return;
}


void SPI_TFT_ILI9341::rect(int x0, int y0, int x1, int y1, int color)
{

    if (x1 > x0) hline(x0,x1,y0,color);
    else  hline(x1,x0,y0,color);

    if (y1 > y0) vline(x0,y0,y1,color);
    else vline(x0,y1,y0,color);

    if (x1 > x0) hline(x0,x1,y1,color);
    else  hline(x1,x0,y1,color);

    if (y1 > y0) vline(x1,y0,y1,color);
    else vline(x1,y1,y0,color);

//WH    return;
}


void SPI_TFT_ILI9341::fillrect(int x0, int y0, int x1, int y1, int color)
{  
    //sanity check
    if ( x0 > x1 ) swap( int, x0, x1 )
    if ( y0 > y1 ) swap( int, y0, y1 )

    int h = y1 - y0 + 1; 
    int w = x1 - x0 + 1; 
    int pixels = h * w;
    int i;
#if (SPI_16 != 1)    
    int msb, lsb;        
#endif    
 
    window(x0,y0,w,h);
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel         

#if (SPI_16 == 1)    
    // 16 Bit SPI
    _spi.format(16,0);   // switch to 16 bit Mode 0

    for (i = 0; i < pixels; i++)
      _spi.write(color);

    _spi.format(8,0);    // switch back to 8 bit Mode 0 
#else
    // 8 Bit SPI
    msb = color >> 8;
    lsb = color & 0xff;
    for (i = 0; i < pixels; i++){
      _spi.write(msb);
      _spi.write(lsb);
    }
#endif        

    _cs = 1; 
}


void SPI_TFT_ILI9341::roundrect( int x1, int y1, int x2, int y2, int color )
{
    //sanity check      
    if ( x1 > x2 ) swap( int, x1, x2 )
    if ( y1 > y2 ) swap( int, y1, y2 )
 
    if ( ( x2 - x1 ) > 4 && ( y2 - y1 ) > 4 )
    {
        pixel( x1 + 1, y1 + 1, color );
        pixel( x2 - 1, y1 + 1, color );
        pixel( x1 + 1, y2 - 1, color );
        pixel( x2 - 1, y2 - 1, color );
//x0, x1, y
        hline( x1 + 2, x2 - 2 ,y1, color );
        hline( x1 + 2, x2 - 2, y2, color );     
//y0, y1, x        
        vline( y1 + 2, y2 - 2, x1, color );
        vline( y1 + 2, y2 - 2, x2, color );
    }
}

 
void SPI_TFT_ILI9341::fillroundrect( int x1, int y1, int x2, int y2, int color )
{
    //sanity check
    if ( x1 > x2 ) swap( int, x1, x2 )
    if ( y1 > y2 ) swap( int, y1, y2 )
 
    if ( ( x2 - x1 ) > 4 && ( y2 - y1 ) > 4 )
    {
        for ( int i = 0; i < ( ( y2 - y1 ) / 2 ) + 1; i++ )
        {
            switch ( i )
            {
                case 0:
                    hline( x1 + 2, x2 - 2, y1 + i, color );
                    hline( x1 + 2, x2 - 2, y2 - i, color );
                    break;
 
                case 1:
                    hline( x1 + 1, x2 - 1, y1 + i, color );
                    hline( x1 + 1, x2 - 1, y2 - i, color );
                    break;
 
                default:
                    hline( x1, x2, y1 + i, color );
                    hline( x1, x2, y2 - i, color );
                    break;
            }
        }
    }
}



void SPI_TFT_ILI9341::locate(int x, int y)
{
    _char_x = x;
    _char_y = y;
}



int SPI_TFT_ILI9341::columns()
{
    return width() / _font[1];
}



int SPI_TFT_ILI9341::rows()
{
    return height() / _font[2];
}



int SPI_TFT_ILI9341::_putc(int value)
{
    if (value == '\n') {    // new line
        _char_x = 0;
        _char_y = _char_y + _font[2];
        if (_char_y >= height() - _font[2]) {
            _char_y = 0;
        }
    } else {
        character(_char_x, _char_y, value);
    }
    return value;
}

//WH
#if(0)
void SPI_TFT_ILI9341::character(int x, int y, int c)
{
    unsigned int hor,vert,offset,bpl,j,i,b;
    unsigned char* zeichen;
    unsigned char z,w;

    if ((c < 31) || (c > 127)) return;   // test char range

    // read font parameter from start of array
    offset = _font[0];                   // bytes / char
    hor    = _font[1];                   // get hor size of font
    vert   = _font[2];                   // get vert size of font
    bpl    = _font[3];                   // bytes per line

    if (_char_x + hor > width()) {
        _char_x = 0;
        _char_y = _char_y + vert;
        if (_char_y >= height() - _font[2]) {
            _char_y = 0;
        }
    }
    window(_char_x, _char_y,hor,vert); // char box
    wr_cmd(0x2C);  // send pixel
    #ifndef TARGET_KL25Z  // 16 Bit SPI 
    _spi.format(16,0);   
    #endif                         // switch to 16 bit Mode 0
    zeichen = &_font[((c -32) * offset) + 4]; // start of char bitmap
    w = zeichen[0];                          // width of actual char
     for (j=0; j<vert; j++) {  //  vert line
        for (i=0; i<hor; i++) {   //  horz line
            z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
            b = 1 << (j & 0x07);
            if (( z & b ) == 0x00) {
               #ifndef TARGET_KL25Z  // 16 Bit SPI 
                _spi.write(_background);
               #else
                _spi.write(_background >> 8);
                _spi.write(_background & 0xff);
                #endif
            } else {
                #ifndef TARGET_KL25Z  // 16 Bit SPI
                _spi.write(_foreground);
                #else
                _spi.write(_foreground >> 8);
                _spi.write(_foreground & 0xff);
                #endif
            }
        }
    }
    _cs = 1;
    #ifndef TARGET_KL25Z  // 16 Bit SPI
    _spi.format(8,0);
    #endif
    window_max();
    if ((w + 2) < hor) {                   // x offset to next char
        __char_x += w + 2;
    } else __char_x += hor;
}
#else

#if (TRANSPARANCY == 1)
//WH write foreground, write background only when not transparant mode
void SPI_TFT_ILI9341::character(int x, int y, int c)
{
    unsigned int hor,vert,offset,bpl,j,i,b;
    unsigned char* symbol;
    unsigned char z,w;

    if ((c < 31) || (c > 127)) return;   // test char range

    // read font parameter from start of array
    offset = _font[0];                   // bytes / char
    hor    = _font[1];                   // get hor size of font
    vert   = _font[2];                   // get vert size of font
    bpl    = _font[3];                   // bytes per line

    if (_char_x + hor > width()) {
        _char_x = 0;
        _char_y = _char_y + vert;
        if (_char_y >= height() - vert) {
            _char_y = 0;
        }
    }
  
    symbol = &_font[((c - 32) * offset) + 4]; // start of char bitmap
    w = symbol[0];                            // width of actual char (proportional font)
    for (j=0; j<vert; j++) {  //  vert line
      for (i=0; i<hor; i++) {   //  horz line
        z =  symbol[bpl * i + ((j & 0xF8) >> 3) + 1];
        b = 1 << (j & 0x07);
        
        // Test bit in character bitmap to write either _foreground or _background color
        if (( z & b ) == 0x00) {
          // bit is 0, write _background color
          if (!_transparancy) { // write background color only when transparancy is 'off'  
            pixel(_char_x+i, _char_y+j, _background);
          }  
        }
        else {
          // bit is 1, write _foreground color          
          pixel(_char_x+i, _char_y+j, _foreground);
        } // if bit
      } // for i
    } // for j

    window_max();

    if ((w + 2) < hor) {                   // x offset to next char
        _char_x += w + 2;
    } else _char_x += hor;
}

#else

//WH write foreground and background
void SPI_TFT_ILI9341::character(int x, int y, int c)
{
    unsigned int hor,vert,offset,bpl,j,i,b;
    unsigned char* symbol;
    unsigned char z,w;

    if ((c < 31) || (c > 127)) return;   // test char range

    // read font parameter from start of array
    offset = _font[0];                   // bytes / char
    hor    = _font[1];                   // get hor size of font
    vert   = _font[2];                   // get vert size of font
    bpl    = _font[3];                   // bytes per line

    if (_char_x + hor > width()) {
        _char_x = 0;
        _char_y = _char_y + vert;
        if (_char_y >= height() - vert) {
            _char_y = 0;
        }
    }
    window(_char_x, _char_y, hor, vert); // char box
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel         
    
    #if (SPI_16 == 1)
    // 16 Bit SPI 
    _spi.format(16,0);   // switch to 16 bit Mode 0
    #endif                         
    symbol = &_font[((c - 32) * offset) + 4]; // start of char bitmap
    w = symbol[0];                            // width of actual char (proportional font)
    for (j=0; j<vert; j++) {  //  vert line
      for (i=0; i<hor; i++) {   //  horz line
        z =  symbol[bpl * i + ((j & 0xF8) >> 3) + 1];
        b = 1 << (j & 0x07);
        
        // Test bit in character bitmap to write either _foreground or _background color
        if (( z & b ) == 0x00) {
          // bit is 0, write _background color
          #if (SPI_16 == 1)
          // 16 Bit SPI 
          _spi.write(_background);
          #else
          // 8 Bit SPI           
          _spi.write(_background >> 8);
          _spi.write(_background & 0xff);
          #endif
        }
        else {
          // bit is 1, write _foreground color          
          #if (SPI_16 == 1)
          // 16 Bit SPI
          _spi.write(_foreground);
          #else
          // 8 Bit SPI                     
          _spi.write(_foreground >> 8);
          _spi.write(_foreground & 0xff);
          #endif
        } // if bit
      } // for i
    } // for j

    _cs = 1;
    #if (SPI_16 == 1)  // 16 Bit SPI
    _spi.format(8,0);  // switch back to 8 bit Mode 0
    #endif
    window_max();

    if ((w + 2) < hor) {                   // x offset to next char
        _char_x += w + 2;
    } else _char_x += hor;
}
#endif

#endif


void SPI_TFT_ILI9341::set_font(unsigned char* f)
{
  _font = f;
}



void SPI_TFT_ILI9341::Bitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h,unsigned char *bitmap)
{
    unsigned int  j;
    int padd;
    unsigned short *bitmap_ptr = (unsigned short *)bitmap;
    #if (SPI_16 != 1)  // 16 Bit SPI    
    unsigned short pix_temp;
    #endif
    
    unsigned int i;
    
    // the lines are padded to multiple of 4 bytes in a bitmap
    padd = -1;
    do {
        padd ++;
    } while (2*(w + padd)%4 != 0);
    window(x, y, w, h);
    bitmap_ptr += ((h - 1)* (w + padd));
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel     
        
    #if (SPI_16 == 1)  // 16 Bit SPI
    _spi.format(16,0); // switch to 16 bit Mode 0
    #endif                            
    for (j = 0; j < h; j++) {         //Lines
        for (i = 0; i < w; i++) {     // one line
            #if (SPI_16 == 1)
                // 16 Bit SPI            
                _spi.write(*bitmap_ptr);    // one line
                bitmap_ptr++;
            #else                
               // 8 Bit SPI
                pix_temp = *bitmap_ptr;
                _spi.write(pix_temp >> 8);
                _spi.write(pix_temp);
                bitmap_ptr++;
            #endif
        }
        bitmap_ptr -= 2*w;
        bitmap_ptr -= padd;
    }
    _cs = 1;

    #if (SPI_16 == 1)    
    _spi.format(8,0); // switch back to 8 bit Mode 0
    #endif
    window_max();
}


// local filesystem is not implemented in kinetis board, but you can add an SD card

int SPI_TFT_ILI9341::BMP_16(unsigned int x, unsigned int y, const char *Name_BMP)
{

#define OffsetPixelWidth    18
#define OffsetPixelHeigh    22
#define OffsetFileSize      34
#define OffsetPixData       10
#define OffsetBPP           28

    char filename[50];
    unsigned char BMP_Header[54];
    unsigned short BPP_t;
    unsigned int PixelWidth,PixelHeigh,start_data;
    unsigned int    i,off;
    int padd,j;
    unsigned short *line;

    // get the filename
    i=0;
    while (*Name_BMP!='\0') {
        filename[i++]=*Name_BMP++;
    }
    filename[i] = 0;  
    
    FILE *Image = fopen((const char *)&filename[0], "rb");  // open the bmp file
    if (!Image) {
        return(0);      // error file not found !
    }

    fread(&BMP_Header[0],1,54,Image);      // get the BMP Header

    if (BMP_Header[0] != 0x42 || BMP_Header[1] != 0x4D) {  // check magic byte
        fclose(Image);
        return(-1);     // error no BMP file
    }

    BPP_t = BMP_Header[OffsetBPP] + (BMP_Header[OffsetBPP + 1] << 8);
    if (BPP_t != 0x0010) {
        fclose(Image);
        return(-2);     // error no 16 bit BMP
    }

    PixelHeigh = BMP_Header[OffsetPixelHeigh] + (BMP_Header[OffsetPixelHeigh + 1] << 8) + (BMP_Header[OffsetPixelHeigh + 2] << 16) + (BMP_Header[OffsetPixelHeigh + 3] << 24);
    PixelWidth = BMP_Header[OffsetPixelWidth] + (BMP_Header[OffsetPixelWidth + 1] << 8) + (BMP_Header[OffsetPixelWidth + 2] << 16) + (BMP_Header[OffsetPixelWidth + 3] << 24);
    if (PixelHeigh > height() + y || PixelWidth > width() + x) {
        fclose(Image);
        return(-3);      // to big
    }

    start_data = BMP_Header[OffsetPixData] + (BMP_Header[OffsetPixData + 1] << 8) + (BMP_Header[OffsetPixData + 2] << 16) + (BMP_Header[OffsetPixData + 3] << 24);

    line = (unsigned short *) malloc (2 * PixelWidth); // we need a buffer for a line
    if (line == NULL) {
        return(-4);         // error no memory
    }

    // the bmp lines are padded to multiple of 4 bytes
    padd = -1;
    do {
        padd ++;
    } while ((PixelWidth * 2 + padd)%4 != 0);

    window(x, y,PixelWidth ,PixelHeigh);
//    wr_cmd(0x2C);  // send pixel
    wr_cmd(ILI9341_GRAM);  // send pixel         
    
    #if (SPI_16 == 1)        
    _spi.format(16,0);   // switch to 16 bit Mode 0
    #endif                          
    for (j = PixelHeigh - 1; j >= 0; j--) {               //Lines bottom up
        off = j * (PixelWidth  * 2 + padd) + start_data;   // start of line
        fseek(Image, off ,SEEK_SET);
        fread(line,1,PixelWidth * 2,Image);       // read a line - slow 
        for (i = 0; i < PixelWidth; i++) {        // copy pixel data to TFT
        #if (SPI_16 == 1)
        // one 16 bit pixel                                                   
        _spi.write(line[i]);
        #else              
        // only 8 Bit SPI
        _spi.write(line[i] >> 8);
        _spi.write(line[i]);
        #endif    
        } 
     }
    _cs = 1;
    
    #if (SPI_16 == 1)            
    _spi.format(8,0);    // switch back to 8 bit Mode 0
    #endif
    
    free (line);
    fclose(Image);
    window_max();
    return(1);
}


/*******************************************************************************
* Function Name  : WriteBMP_FAT
* @brief Displays a bitmap picture loaded in Flash.
* @param Xpos: specifies the X position.
* @param Ypos: specifies the Y position.
* @param BmpAddress: Bmp picture address in Flash.
* @return None
*******************************************************************************/
void SPI_TFT_ILI9341::WriteBMP_FAT(uint16_t Xpos, uint16_t Ypos, const char* BmpName)
{
  uint32_t index = 0, size = 0, width=0, height=0;
  uint16_t *pBmpWord=0;
//  uint16_t data;
 
  /* Read bitmap width*/
  width = BmpName[0]+1; 
  /* Read bitmap height*/
  height = BmpName[1]+1; 
  /* Read bitmap size */
  size   = width * height;  /* nb of 16 bits */
    
  window(Xpos, Ypos, width , height);    

//  wr_cmd(0x2C);  // send pixel
  wr_cmd(ILI9341_GRAM);  // send pixel       

  /* Set WRX to send data */
//WH  _dc = 1;

  #if (SPI_16 == 1)        
  _spi.format(16,0);   // switch to 16 bit Mode 0
  #endif                          

  pBmpWord = (uint16_t *) (&BmpName[5]);
  /* Send to the screen */
  for(index = 0; index < size; index++)
  {
    #if (SPI_16 == 1)
    // one 16 bit pixel                                                   
    _spi.write(*pBmpWord);    
    #else              
    // only 8 Bit SPI
    _spi.write(*pBmpWord & 0xFF);
    _spi.write((*pBmpWord>>8) & 0xFF);   
    #endif       
                  
    pBmpWord++;
  } 

  /* Set LCD control line(/CS) */
  _cs = 1;  

  #if (SPI_16 == 1)            
  _spi.format(8,0);    // switch back to 8 bit Mode 0
  #endif
        
  window_max();
}