Library for MI0283QT-2 LCD

MI0283QTlib.cpp

Committer:
clemente
Date:
2012-05-23
Revision:
0:7ad454fed160

File content as of revision 0:7ad454fed160:

/* mbed Graphics LCD library. Library for MI0283QT-2 screen.

    Copyright (c) 2011 NXP 3803 
 
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
 
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
 
    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.
*/

#include "MI0283QTlib.h"
#include "mbed.h"
#include "Terminal24x12.h"
#include "Terminal12x6.h"

#ifdef _USE_FILE
#include "SDFileSystem.h"
#endif

/* GLCD definition and functions. */
#define LCD_MODE_262K        5          // 5=65K, 6=262K colors.

/* */
#define LCD_FAST_SPEED      40000000
#define LCD_SLOW_SPEED       3000000
//
#define LCD_ID               (0)
#define LCD_DATA             ((0x72)|(LCD_ID<<2))
#define LCD_REGISTER         ((0x70)|(LCD_ID<<2))
//
#define LCD_WIDTH            (320)
#define LCD_HEIGHT           (240)

#if ( LCD_MODE_262K==6 )
    #define RGB(r,g,b)           (((r&0xFC)<<16)|((g&0xFC)<<8)|((b&0xFC))) //6 red | 6 green | 6 blue
#else
    #define RGB(r,g,b)           (((r&0xF8)<<8)|((g&0xFC)<<3)|((b&0xF8)>>3)) //5 red | 6 green | 5 blue
 #endif

#define LCD_RST_DISABLE()    _rst = 1;
#define LCD_RST_ENABLE()     _rst = 0;
#define LCD_CS_DISABLE()     _cs = 1;
#define LCD_CS_ENABLE()      _cs = 0;

//MODDMA dma;

GLCD::GLCD(  PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName bklgh) : _spi( mosi, miso, sclk), _cs( cs), _rst( rst), _bklgh( bklgh) {
    // deselect the device
    LCD_CS_DISABLE();
    LCD_RST_ENABLE();
    // defaults params
    SPIClkSpeed=LCD_FAST_SPEED;
    SPISlowClkSpeed=LCD_SLOW_SPEED;
    SPIMode=3;
    LCDBkLight=0.5;
    //
    BackGroundColor=LCD_BLACK;
    //
#if 0
struct _FONTINFO {
    unsigned char *pText;
    unsigned int h_size;
    unsigned int v_size;
    unsigned int h_line;
};
#endif
  
    FontInfo[0].pText=(unsigned char*)&Text12x6[0];
    FontInfo[0].h_size=6;
    FontInfo[0].v_size=12;
    FontInfo[0].h_line=1;
    
    FontInfo[1].pText=(unsigned char*)&Text24x12[0];
    FontInfo[1].h_size=12;
    FontInfo[1].v_size=24;
    FontInfo[1].h_line=2;
    
    FontIdx=0;
}

void GLCD::backlighton( void)
{
    backlightset( 1);
}

void GLCD::backlightoff( void)
{
    backlightset( 0);
}

void GLCD::backlightset( double val)
{
    LCDBkLight=val;
    _bklgh = LCDBkLight;    
}

void GLCD::lcd_init( void)
{
    _spi.format(8,SPIMode);
    _spi.frequency( SPIClkSpeed);
    _bklgh = LCDBkLight;
    
    lcd_reset();

}

void GLCD::lcd_init( unsigned int speedf)
{
    _spi.format(8,SPIMode);
    _spi.frequency( speedf);
    SPIClkSpeed=speedf;
    _bklgh = LCDBkLight;
    
    lcd_reset();

}

void GLCD::lcd_init( unsigned int speedf, unsigned int speeds)
{
    _spi.format(8,SPIMode);
    _spi.frequency( speedf);
    SPIClkSpeed=speedf;
    SPISlowClkSpeed=speeds;
    _bklgh = LCDBkLight;
    
    lcd_reset();

}

void GLCD::lcd_setfontsmall(  void)
{
    FontIdx=0;
}

void GLCD::lcd_setfontbig(  void)
{
    FontIdx=1;
}

void GLCD::lcd_setbackgroundcolor( unsigned int color) {
    BackGroundColor=color;
}

void GLCD::lcd_drawstr(char *__putstr, unsigned int xpos, unsigned int ypos, unsigned int color)
{
    char __ps;
    unsigned int xp,yp;
    
    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
    
    xp=xpos; yp=ypos;
    
    while((__ps = *__putstr))
    {
        __putstr++;
        if (__ps== 0) break;
        lcd_drawch(__ps,xp,yp, color);
        xp+=FontInfo[FontIdx].h_size;           // la dimensione del font per adesso è impostata manualmente.
    }
    /* Reset to slow speed. */
    _spi.frequency( SPISlowClkSpeed);
}
    
void GLCD::lcd_drawch( unsigned ch, unsigned int xpos, unsigned int ypos, unsigned int color)
{
    unsigned int H_Line, H_Size, V_Size, SrcInc;
    unsigned char *pSrc;
    unsigned int i, j, txtcolor;
    
    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
    
    // per adesso imposto i valori di queste grandezze manualmente
    H_Line=FontInfo[FontIdx].h_line;
    H_Size=FontInfo[FontIdx].h_size;
    V_Size=FontInfo[FontIdx].v_size;
    
    //
    lcd_area(xpos, ypos, (H_Size-1)+xpos, (V_Size-1)+ypos);
    // printf("Programmo area: xpos=%d, ypos=%d, Hs=%d, Vs=%d\r\n", xpos,ypos,(H_Size-1)+xpos, (V_Size-1)+ypos);
    // wait( 1);
    //
    pSrc=(unsigned char*)&FontInfo[FontIdx].pText[0]+(H_Line*V_Size*ch);
    // printf("Carico il puntatore @ Text[%d]\r\n", (H_Line*V_Size*ch));
    // wait( 1);

    lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif 

    //
    for ( i=0; i<V_Size; i++) {
        SrcInc=H_Line;
        for ( j=0; j<H_Size; j++) {
            txtcolor=(*pSrc & (1UL<<(j&0x07)))?color:BackGroundColor;
#if (LCD_MODE_262K==6 )    
            _spi.write( (txtcolor&0x00FC0000)>>18 );
            _spi.write( (txtcolor&0x0000FC00)>>10 );
            _spi.write( (txtcolor&0x000000FC)>>2);
#else  
            lcd_draw( txtcolor);
#endif            //
            if ((j&0x07) == 7) {
                ++pSrc;
                --SrcInc;
            }
        }
        pSrc += SrcInc;
    }
    //
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif   
    lcd_drawstop();
   /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);
}

void GLCD::lcd_draw(unsigned int color)
{
  _spi.write(color>>8);
  _spi.write(color);

  return;
}


void GLCD::lcd_drawstop(void)
{
  LCD_CS_DISABLE();

  return;
}


void GLCD::lcd_drawstart(void)
{
  LCD_CS_ENABLE();
  _spi.write(LCD_REGISTER);
  _spi.write(0x22);
  LCD_CS_DISABLE();

  LCD_CS_ENABLE();
  _spi.write(LCD_DATA);

  return;
}

inline void GLCD::lcd_cmd(unsigned int reg, unsigned int param)
{
  LCD_CS_ENABLE();
  _spi.write( LCD_REGISTER);
  _spi.write( reg);
  LCD_CS_DISABLE();

  LCD_CS_ENABLE();
  _spi.write( LCD_DATA);
  _spi.write( param);
  LCD_CS_DISABLE();

  return;
}


void GLCD::lcd_data(unsigned int c)
{
  LCD_CS_ENABLE();
  _spi.write(LCD_DATA);
  _spi.write(c>>8);
  _spi.write(c);
  LCD_CS_DISABLE();

  return;
}

void GLCD::lcd_area(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1)
{
  lcd_cmd(0x03, (x0>>0)); //set x0
  lcd_cmd(0x02, (x0>>8)); //set x0
  lcd_cmd(0x05, (x1>>0)); //set x1
  lcd_cmd(0x04, (x1>>8)); //set x1
  lcd_cmd(0x07, (y0>>0)); //set y0
  lcd_cmd(0x06, (y0>>8)); //set y0
  lcd_cmd(0x09, (y1>>0)); //set y1
  lcd_cmd(0x08, (y1>>8)); //set y1

  return;
}

void GLCD::lcd_setverticalarea( unsigned int topf, unsigned int height, unsigned int butf)
{
    if ( (topf+height+butf) > 320)
        return;
        
    lcd_cmd( 0x0F, (topf>>0));
    lcd_cmd( 0x0E, (topf>>8));
    lcd_cmd( 0x11, (height>>0));
    lcd_cmd( 0x10, (height>>8));
    lcd_cmd( 0x13, (butf>>0));
    lcd_cmd( 0x12, (butf>>8));
}

void GLCD::lcd_scrollstartadd( unsigned int ssa)
{
    lcd_cmd( 0x15, (ssa>>0));
    lcd_cmd( 0x14, (ssa>>8));
}

void GLCD::lcd_scrollstart( void)
{
    lcd_cmd( 0x01, 0x0008);
}

void GLCD::lcd_scrollstop( void)
{
    lcd_cmd( 0x01, 0x0000);
}

unsigned int GLCD::lcd_RGB( unsigned int color)
{

     return ( RGB( (( color&0x00FF0000)>>16), ( ( color&0x0000FF00)>>8), ( color&0x000000FF)) );

}

unsigned int GLCD::lcd_RGB( unsigned int r, unsigned int g, unsigned int b)
{
    return ( RGB( r, g, b));
}


void GLCD::lcd_clear(unsigned int color)
{
  unsigned int i;

  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));

  lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
    _spi.frequency( SPIClkSpeed);
#endif 
  
  for(i=(LCD_WIDTH*LCD_HEIGHT); i!=0; i--)
  {
#if (LCD_MODE_262K==6 )    
    _spi.write( (color&0x00FC0000)>>18 );
    _spi.write( (color&0x0000FC00)>>10 );
    _spi.write( (color&0x000000FC)>>2);
#else  
    lcd_draw( color);
#endif    
  }
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
    _spi.frequency( SPIClkSpeed);
#endif   
  lcd_drawstop();

  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
  return;
}

void GLCD::lcd_clear(unsigned int x0, unsigned int y0, unsigned int w, unsigned int h, unsigned int color)
{
  unsigned int i;

  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area(x0, y0, (w-1)+x0, (h-1)+y0);

  lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
    _spi.frequency( SPIClkSpeed);
#endif 
  
  for(i=(w*h); i!=0; i--)
  {
#if (LCD_MODE_262K==6 )    
    _spi.write( (color&0x00FC0000)>>18 );
    _spi.write( (color&0x0000FC00)>>10 );
    _spi.write( (color&0x000000FC)>>2);
#else  
    lcd_draw( color);
#endif    
  }
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
    _spi.frequency( SPIClkSpeed);
#endif   
  lcd_drawstop();

  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
  return;
}


#ifdef _USE_FILE
unsigned int GLCD::lcd_drawimage(char *fname)
{
    unsigned int i;
    unsigned char  r, g, b;
    
    FILE *fp;
    
    if ( (fp=fopen( fname, "r")) == NULL ) {
        return 0;
    }

    lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));
    
    lcd_drawstart();
    
#if ( LCD_MODE_262K==6 )
    _spi.format(6,3);
#endif   

    for(i=(LCD_WIDTH*LCD_HEIGHT); i!=0; i--)
    {
        //
        r=fgetc( fp);
        g=fgetc( fp);
        b=fgetc( fp);
        //    
#if ( LCD_MODE_262K==6 )        
        _spi.write( (r&0xFC)>>2 );
        _spi.write( (g&0xFC)>>2 );
        _spi.write( (b&0xFC)>>2 );        
#else
        lcd_draw( RGB( r, g, b));
#endif        
        //
        if ( feof( fp)) {
            fclose( fp);
            break;
        }
    }
    //
    if ( fp)
        fclose( fp);
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,3);
#endif      
    lcd_drawstop();

    return 1;
}
#endif


#ifdef _USE_FILE

unsigned int GLCD::lcd_drawimagebuff(char *fname)
{
    unsigned int i;
    unsigned char  r, g, b;
    unsigned char buffer[320*BUFFER_LINE*3];
    unsigned int size, idx, y=0;
    
    FILE *fp;
    
    if ( (fp=fopen( fname, "r")) == NULL ) {
        return 0;
    }

    size=fread( &buffer[0], sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);

    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
        
    lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));
    
    lcd_drawstart();
    
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif   
    
    idx=0;
    for(i=(LCD_WIDTH*LCD_HEIGHT); i!=0; i--)
    {
        //
        r=buffer[idx++];
        g=buffer[idx++];
        b=buffer[idx++];
        //    
#if ( LCD_MODE_262K==6 )  
        _spi.write( (r&0xFC)>>2 );
        _spi.write( (g&0xFC)>>2 );
        _spi.write( (b&0xFC)>>2 );        
#else
        lcd_draw( RGB( r, g, b));
#endif        
        //
        if ( idx>=size){
#if ( LCD_MODE_262K==6 )
            _spi.format(8,SPIMode);
#endif             
            lcd_drawstop();
            //
            if ( feof( fp)) {
                fclose( fp);
                break;
            }
            //
            size=fread( &buffer[0], sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);
            idx=0;
            y+=BUFFER_LINE;
            lcd_area(0, y, (LCD_WIDTH-1), (LCD_HEIGHT-1));
            lcd_drawstart();
#if ( LCD_MODE_262K==6 )
            _spi.format(6,SPIMode);
#endif                 
        }            
    }
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif          
    //
    lcd_drawstop();
    /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);    
    //
    if ( fp)
        fclose( fp);

    return 1;
}
#endif

#ifdef _USE_FILE
unsigned int GLCD::lcd_drawimagebyline(unsigned char *buffer, unsigned int lnum, unsigned int xstart, unsigned int ystart, unsigned int scale)
{
    unsigned int i, idx;
    unsigned char  r, g, b;

    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
        
    lcd_area(xstart, lnum+ystart, ((LCD_WIDTH/scale)-1)+xstart, lnum+ystart);
    
    lcd_drawstart();
    
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif   
    
    idx=0;
    for(i=LCD_WIDTH/scale; i!=0; i--)
    {
        //
        r=buffer[idx];
        g=buffer[idx+1];
        b=buffer[idx+2];
        //
        idx+=(scale*3);
        //    
#if ( LCD_MODE_262K==6 )  
        _spi.write( (r&0xFC)>>2 );
        _spi.write( (g&0xFC)>>2 );
        _spi.write( (b&0xFC)>>2 );        
#else
        lcd_draw( RGB( r, g, b));
#endif        
    }
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif          
    //
    lcd_drawstop();
    /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);    
    
    return 1;
}
#endif

#ifdef _USE_FILE
unsigned int GLCD::lcd_drawimagebyline(unsigned char *buffer, unsigned int lnum)
{
    unsigned int i, idx;
    unsigned char  r, g, b;

    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
        
    lcd_area(0, lnum, (LCD_WIDTH-1), lnum);
    
    lcd_drawstart();
    
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif   
    
    idx=0;
    for(i=LCD_WIDTH; i!=0; i--)
    {
        //
        r=buffer[idx++];
        g=buffer[idx++];
        b=buffer[idx++];
        //    
#if ( LCD_MODE_262K==6 )  
        _spi.write( (r&0xFC)>>2 );
        _spi.write( (g&0xFC)>>2 );
        _spi.write( (b&0xFC)>>2 );        
#else
        lcd_draw( RGB( r, g, b));
#endif        
    }
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif          
    //
    lcd_drawstop();
    /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);    
    
    return 1;
}
#endif

#ifdef _USE_FILE

unsigned int GLCD::lcd_drawmovie(char *fname, unsigned int x_start, unsigned int y_start)
{
    unsigned int i;
    unsigned char  r, g, b;
    
    FILE *fp;
    
    if ( (fp=fopen( fname, "r")) == NULL ) {
        return 0;
    }

    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);

    lcd_drawstop();
    // lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));
    lcd_area(x_start, y_start, (80-1)+x_start, (60-1)+y_start);
    
    lcd_drawstart();
    
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif   

    while( 1)
    {
        //
        r=fgetc( fp);
        g=fgetc( fp);
        b=fgetc( fp);
        //    
#if ( LCD_MODE_262K==6 )        
        _spi.write( (r&0xFC)>>2 );
        _spi.write( (g&0xFC)>>2 );
        _spi.write( (b&0xFC)>>2 );        
#else
        lcd_draw( RGB( r, g, b));
#endif        
        //
        if ( feof( fp)) {
            fclose( fp);
            break;
        }
    }
    //
    if ( fp)
        fclose( fp);
    //   
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif      
    lcd_drawstop();

    /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);    

    return 1;
}
#endif

#ifdef _USE_FILE
#if ( LCD_MODE_262K==5 )

// I will use a portion of memory proportional to a defined number of rows.
#define cLINE_NUMBER    40

// Ping-pong buffer. The buffer are proportional to the number of pixel per row (160), to the
// numeber of line I want to read and to the number of byte for each pixel. In this case I have
// a ready-made file with each pixel defined with 16bit (RGB==565bit)
unsigned char buffer[160*cLINE_NUMBER*2] __attribute((section("AHBSRAM1"),aligned));
unsigned char buffer1[160*cLINE_NUMBER*2] __attribute((section("AHBSRAM0"),aligned));

/** DMA_IRQHandler Called by DMA.
 *  Please to learn more read: http://mbed.org/users/AjK/programs/SOWB/lg489e/docs/flash__read_8c_source.html
 */
volatile int DMA_flag;
extern "C" void DMA_IRQHandler(void) __irq {
    if (LPC_GPDMA->DMACIntStat & 1) {
        if (LPC_GPDMA->DMACIntTCStat & 1) {
            DMA_flag=1;
            LPC_GPDMA->DMACIntTCClear = 1;
        }
        if (LPC_GPDMA->DMACIntErrStat & 1) {
            LPC_GPDMA->DMACIntErrClr = 1;
        }
    }
}

/** Linked List structure. I use this structure to send with one shot 3x3200 byte to the GLCD.
 */
typedef struct {
    uint32_t SrcAddr;    /* Source Address */
    uint32_t DstAddr;    /* Destination address  */
    uint32_t NextLLI;    /* Next LLI address, otherwise set to '0'  */
    uint32_t Control;    /* GPDMA Control Register of this LLI. Reflect the content of LPC_GPDMACH0->DMACCControl */
} GPDMA_LLI;

/* Let declare the 3 linked list. The first LLI address will be programmed inside the DMA registers. */
GPDMA_LLI LLI0, LLI1, LLI2;

#define DMA_CHANNEL_ENABLE      1
#define DMA_TRANSFER_TYPE_M2P   (1UL << 11)   
#define DMA_CHANNEL_TCIE        (1UL << 31)
#define DMA_CHANNEL_SRC_INC     (1UL << 26)
#define DMA_MASK_IE             (1UL << 14)
#define DMA_MASK_ITC            (1UL << 15)
#define DMA_CHANNEL_SRC_PERIPHERAL_SSP0_RX  (1UL << 1)
#define DMA_CHANNEL_SRC_PERIPHERAL_SSP0_TX  (0UL << 1)
#define DMA_CHANNEL_DST_PERIPHERAL_SSP0_RX  (1UL << 6)
#define DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX  (0UL << 6)

/** Display a movie file. The file is ready made to speed up the entire process.
 *
 * @param the name file.
 *
 */
unsigned int GLCD::lcd_drawmoviebuff(char *fname, unsigned int x_start, unsigned int y_start)
{
    unsigned int i;
    unsigned char  r, g, b;
    unsigned int size, idx, y=0;
    unsigned char *pframe;
    FILE *fp;
    
    LPC_SSP0->DMACR=2;

    /* Load the content to the LLI */    
    /* The LLI are chained, so I load the address to the corrispondent LLI*/
    LLI0.NextLLI=(uint32_t)&LLI1;
    LLI1.NextLLI=(uint32_t)&LLI2;
    LLI2.NextLLI=0;                 // The last is NULL to stop the chain.
    
    /* The dimension of the buffer are fixed. So each LLI have a fixed pointer to the owned block of memory */
    /* Each buffer is 16KB long but I use fixed chunk following this rule: */
    /* The image is 160x120x2 = 38400 byte big. I have divided this amount by three so that it can */
    /* use the two memory buffer. Each chunk is now 12800 byte. But the DMA can only transfer 4KB of RAM, */ 
    /* so I divided this amount of memory by four, 3200 byte, and use three LLI to let the DMA to send the entire buffer all at once. */
    /* The LLI are three because the DMA is programmed with the first chund of buffer. At the end of this operation, the DMA load the LLI */
    /* and sends the remaining buffers. */
    LLI0.SrcAddr=(uint32_t)&buffer[3200];
    LLI1.SrcAddr=(uint32_t)&buffer[3200+3200];
    LLI2.SrcAddr=(uint32_t)&buffer[3200+3200+3200];
    /* OK, the destination address is the same for all LLI. Please change if you use a different SPI. */
    LLI0.DstAddr=(uint32_t)&LPC_SSP0->DR;
    LLI1.DstAddr=(uint32_t)&LPC_SSP0->DR;
    LLI2.DstAddr=(uint32_t)&LPC_SSP0->DR;
    /* This is the control register. */
    LLI0.Control= DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
    LLI1.Control= DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
    LLI2.Control= DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
    /* ****************************************************** */
    
    /* Power up the GPDMA. */
    LPC_SC->PCONP |= (1UL << 29);
    LPC_GPDMA->DMACConfig = 1;
    LPC_GPDMA->DMACIntTCClear = 0x1;
    // LPC_GPDMA->DMACSoftSReq   = 0xC;
    LPC_GPDMA->DMACSoftSReq   = 0x3;
    
    /* Enable the IRQ */
    NVIC_EnableIRQ(DMA_IRQn);
    
    /* Open the file */
    if ( (fp=fopen( fname, "rb")) == NULL ) {
        return 0;
    }
        
    /* Set the fast SPI speed. */
    _spi.frequency( SPIClkSpeed);
    _spi.format(8,SPIMode);
    /* Define a fixed area to display the movie. */
    lcd_area(x_start, y_start, (160-1)+x_start, (120-1)+y_start);
    lcd_drawstart();

    /* read the first buffer... */
    size=fread( &buffer[0], sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);
    
    /* Loop untile the whole file is read. */
    while( 1) {
        pframe=&buffer[0];
        /* set the source buffer... */
        LLI0.SrcAddr=(uint32_t)&pframe[3200];
        LLI1.SrcAddr=(uint32_t)&pframe[3200+3200];
        LLI2.SrcAddr=(uint32_t)&pframe[3200+3200+3200];

        /* configure the DMA channell... */
        LPC_GPDMACH0->DMACCSrcAddr  = (uint32_t)pframe;
        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
        LPC_GPDMACH0->DMACCLLI      = (uint32_t)&LLI0;
        LPC_GPDMACH0->DMACCControl  = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;

        DMA_flag=0;
        /* Fire GPDMA Channel0 */
        LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | 
                                    DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX |
                                    DMA_TRANSFER_TYPE_M2P |
                                    DMA_MASK_IE |
                                    DMA_MASK_ITC;

        if ( feof( fp)) {
            fclose( fp);
            break;
        }    
        /* Read the second chunk of the frame... */
        size=fread( &buffer1[0], sizeof(buffer1[0]), sizeof(buffer1)/sizeof(buffer1[0]), fp);
        /* OK, the buffer from the SDCar is read but now we must check if the DMA it's work... */
        while( !DMA_flag);
        DMA_flag=0;
        /* At this point I check if I'm at end of the file. */
        if ( feof( fp) || size != sizeof(buffer1)/sizeof(buffer1[0]) ) {
            //
            LPC_SSP0->IMSC = (1UL << 3);

            LPC_GPDMACH0->DMACCConfig = 0;
            LPC_GPDMA->DMACIntTCClear = 1;
            
            fclose( fp);
            while(LPC_SSP0->SR & (1UL << 2)) {
                /* This loop ensures we read the last byte in the
                RX FIFO and test that. */
                int sr = LPC_SSP0->DR;
            }

            // lcd_drawstop();
            NVIC_DisableIRQ(DMA_IRQn);
            LPC_GPDMA->DMACIntTCClear = 1;
            LPC_SSP0->DMACR=0;
            LPC_GPDMA->DMACConfig = 0;
            LPC_GPDMA->DMACIntTCClear = 0x1;
            LPC_GPDMA->DMACSoftSReq   = 0;
            LPC_SC->PCONP &= ~(1UL << 29);
            LPC_GPDMA->DMACIntTCClear = 1;
            //
            lcd_drawstop();
            break;
        }        
        /* Now I have a buffer full with new data and the DMA stopped. I can start it again. */
        pframe=&buffer1[0];
        /* I set the new buffer inside the LLI... */
        LLI0.SrcAddr=(uint32_t)&pframe[3200];
        LLI1.SrcAddr=(uint32_t)&pframe[3200+3200];
        LLI2.SrcAddr=(uint32_t)&pframe[3200+3200+3200];
        /* DMA configuration. */    
        LPC_GPDMACH0->DMACCSrcAddr  = (uint32_t)pframe;
        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
        LPC_GPDMACH0->DMACCLLI      = (uint32_t)&LLI0;
        LPC_GPDMACH0->DMACCControl  = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
        /* Fire GPDMA Channel0 */
        LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | 
                                    DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX |
                                    DMA_TRANSFER_TYPE_M2P |
                                    DMA_MASK_IE |
                                    DMA_MASK_ITC;
                
        if ( feof( fp)) {
            fclose( fp);
            break;
        }        
        /* A new read from the SDCad... */
        size=fread( &buffer[0], sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);
        /* just wait is the DMA it's working... */
        while( !DMA_flag);
        DMA_flag=0;
        /* At this point I check if I'm at end of the file. */
        if ( feof( fp) || size != sizeof(buffer)/sizeof(buffer[0]) ) {
            fclose( fp);
            break;
        }        
        /* */
        pframe=&buffer[0];
        /* programmo nella LLI il nvuovo buffer... */
        LLI0.SrcAddr=(uint32_t)&pframe[3200];
        LLI1.SrcAddr=(uint32_t)&pframe[3200+3200];
        LLI2.SrcAddr=(uint32_t)&pframe[3200+3200+3200];
        /* programmo il DMA */    
        LPC_GPDMACH0->DMACCSrcAddr  = (uint32_t)pframe;
        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
        LPC_GPDMACH0->DMACCLLI      = (uint32_t)&LLI0;
        LPC_GPDMACH0->DMACCControl  = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
        /* Fire GPDMA Channel0 */
        LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | 
                                    DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX |
                                    DMA_TRANSFER_TYPE_M2P |
                                    DMA_MASK_IE |
                                    DMA_MASK_ITC;
        if ( feof( fp)) {
            fclose( fp);
            break;
        }
        /* */
        size=fread( &buffer1[0], sizeof(buffer1[0]), sizeof(buffer1)/sizeof(buffer1[0]), fp);
        /* Aspetto che il DMA completi l'ultimo transfer... */
        while( !DMA_flag);
        DMA_flag=0;
        /* At this point I check if I'm at end of the file. */
        if ( feof( fp) || size != sizeof(buffer1)/sizeof(buffer1[0]) ) {
            fclose( fp);
            break;
        }                
        /* */
        pframe=&buffer1[0];
        /* At this point I reset the display area resending the xy value*/
        lcd_drawstop();        
        LPC_SSP0->DMACR=0;
        /* Invio un nuovo comando di lcd_area */
        lcd_area(x_start, y_start, (160-1)+x_start, (120-1)+y_start);
        lcd_drawstart();
        /* */
        LPC_SSP0->DMACR=2;

        /* programmo nella LLI il nvuovo buffer... */
        LLI0.SrcAddr=(uint32_t)&pframe[3200];
        LLI1.SrcAddr=(uint32_t)&pframe[3200+3200];
        LLI2.SrcAddr=(uint32_t)&pframe[3200+3200+3200];
        /* programmo il DMA */    
        LPC_GPDMACH0->DMACCSrcAddr  = (uint32_t)pframe;
        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
        LPC_GPDMACH0->DMACCLLI      = (uint32_t)&LLI0;
        LPC_GPDMACH0->DMACCControl  = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | 3200;
        /* Fire GPDMA Channel0 */
        LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | 
                                    DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX |
                                    DMA_TRANSFER_TYPE_M2P |
                                    DMA_MASK_IE |
                                    DMA_MASK_ITC;

        if ( feof( fp)) {
            fclose( fp);
            break;
        }                
        /* Ultima lettura del buffer da SDCard... */
        size=fread( &buffer[0], sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);
        /* Aspetto che il DMA completi il transfer... */
        while( !DMA_flag);
        DMA_flag=0;
        /* At this point I check if I'm at end of the file. */
        if ( feof( fp) || size != sizeof(buffer)/sizeof(buffer[0]) ) {
            fclose( fp);
            break;
        }        
    }
    //
    LPC_SSP0->IMSC = (1UL << 3);
    while(LPC_SSP0->SR & (1UL << 2)) {
        /* This loop ensures we read the last byte in the
        RX FIFO and test that. */
        int sr = LPC_SSP0->DR;
    }    
    
    LPC_GPDMACH0->DMACCConfig = 0;
    LPC_SSP0->DMACR=0;
    LPC_GPDMA->DMACConfig = 0;
    LPC_GPDMA->DMACIntTCClear = 0x1;
    LPC_GPDMA->DMACSoftSReq   = 0;
    LPC_SC->PCONP &= ~(1UL << 29);
    //
    lcd_drawstop();
    //
    LPC_SSP0->DMACR=0;
    LPC_GPDMA->DMACConfig = 0;
    LPC_GPDMA->DMACIntTCClear = 0x1;
    LPC_GPDMA->DMACSoftSReq   = 0;
    LPC_SC->PCONP &= ~(1UL << 29);
    //
    /* Reset to the slow SPI speed. */
    _spi.frequency( SPISlowClkSpeed);    
    _spi.format(8,SPIMode);    
    //
    lcd_drawstop();
    
    lcd_area(0, 0, (320-1), (240-1));

    /* Disable the IRQ */
    NVIC_DisableIRQ(DMA_IRQn);    
    return 1;
}
#endif      // #if ( LCD_MODE_262K==5 ) 
#endif      // #ifdef _USE_FILE

void GLCD::lcd_drawicon( const unsigned char *icon, unsigned int x, unsigned int y, unsigned int size)
{
  unsigned int i;
  unsigned char r, g, b;

  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area(x, y, ((size-1)+x), ((size-1)+y));

  lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif 
  
  for(i=(size*size); i!=0; i--)
  {
    r=*icon++;
    g=*icon++;
    b=*icon++;

#if ( LCD_MODE_262K==6 )
    _spi.write( (r&0xFC)>>2 );
    _spi.write( (g&0xFC)>>2 );
    _spi.write( (b&0xFC)>>2);
#else
    lcd_draw( RGB( r, g, b ) );
#endif   
  }
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif  
  lcd_drawstop();
  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
  return;
}

void GLCD::lcd_drawicon( const unsigned char *icon, unsigned int x, unsigned int y, unsigned int xsize, unsigned int ysize)
{
  unsigned int i;
  unsigned char r, g, b;
  
  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area(x, y, ((xsize-1)+x), ((ysize-1)+y));

  lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif 
  
  for(i=(xsize*ysize); i!=0; i--)
  {
    r=*icon++;
    g=*icon++;
    b=*icon++;

#if ( LCD_MODE_262K==6 )
    _spi.write( (r&0xFC)>>2 );
    _spi.write( (g&0xFC)>>2 );
    _spi.write( (b&0xFC)>>2);
#else
    lcd_draw( RGB( r, g, b ) );
#endif   
  }
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif  
  lcd_drawstop();
  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
  return;
}


void GLCD::lcd_drawicon( const unsigned int *icon, unsigned int x, unsigned int y, unsigned int size)
{
  unsigned int i, tmp;
  
  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area(x, y, ((size-1)+x), ((size-1)+y));

  lcd_drawstart();
  
#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
#endif 
  
  for(i=(size*size); i!=0; i--)
  {
    tmp = *icon++;
#if ( LCD_MODE_262K==6 )
    _spi.write( (tmp&0x00FC0000)>>18 );
    _spi.write( (tmp&0x0000FC00)>>10 );
    _spi.write( (tmp&0x000000FC)>>2);
#else
    lcd_draw( RGB( (( tmp&0x00FF0000)>>16), ( ( tmp&0x0000FF00)>>8), ( tmp&0x000000FF)) );
#endif   
  }
#if ( LCD_MODE_262K==6 )
    _spi.format(8,SPIMode);
#endif  
  lcd_drawstop();
  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
  return;
}

void GLCD::lcd_drawpixel(unsigned int x0, unsigned int y0, unsigned int color) {

  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area( x0, y0, x0, y0);
  lcd_drawstart();

#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
    _spi.write( (color&0x00FC0000)>>18 );
    _spi.write( (color&0x0000FC00)>>10 );
    _spi.write( (color&0x000000FC)>>2);
    _spi.format(8,SPIMode);
#else  
  lcd_draw(color);
#endif

  lcd_drawstop();
  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);

}

void GLCD::lcd_drawline(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1, unsigned int color) {
  //
  // pInt32U pData = ((pInt32U) LCD_VRAM_BASE_ADDR) + x0 + (y0 * LCD_HEIGHT);
  // pInt32U pData = ((pInt32U) pCurrFrmBuff) + x0 + (y0 * LCD_HEIGHT);
  
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;
  
  if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  
  /* Set the fast SPI speed. */
  _spi.frequency( SPIClkSpeed);
  
  lcd_area( x0, y0, x0, y0);
  lcd_drawstart();

#if ( LCD_MODE_262K==6 )
    _spi.format(6,SPIMode);
    _spi.write( (color&0x00FC0000)>>18 );
    _spi.write( (color&0x0000FC00)>>10 );
    _spi.write( (color&0x000000FC)>>2);
    _spi.format(8,SPIMode);
#else  
  lcd_draw(color);
#endif

  lcd_drawstop();
  
  // *(pData)= color;
  
  if (dx > dy) {
          int fraction = dy - (dx >> 1);          // same as 2*dy - dx
          while (x0 != x1) {
                  if (fraction >= 0) {
                          y0 += stepy;
                          fraction -= dx;           // same as fraction -= 2*dx
                  }
                  x0 += stepx;
                  fraction += dy;                   // same as fraction -= 2*dy
                  // pData = ((pInt32U) LCD_VRAM_BASE_ADDR) + x0 + (y0 * C_GLCD_H_SIZE);
                  // pData = ((pInt32U) pCurrFrmBuff) + x0 + (y0 * C_GLCD_H_SIZE);
                  // *(pData)= color;
                  lcd_area( x0, y0, x0, y0);
                  lcd_drawstart();

#if ( LCD_MODE_262K==6 )
                   _spi.format(6,SPIMode);
                   _spi.write( (color&0x00FC0000)>>18 );
                   _spi.write( (color&0x0000FC00)>>10 );
                   _spi.write( (color&0x000000FC)>>2);
                   _spi.format(8,SPIMode);
#else  
                  lcd_draw(color);
#endif
                  
                  lcd_drawstop();
 
          }
  } else {
          int fraction = dx - (dy >> 1);
          while (y0 != y1) {
                  if (fraction >= 0) {
                          x0 += stepx;
                          fraction -= dy;
                  }
                  y0 += stepy;
                  fraction += dx;
                  // pData = ((pInt32U) LCD_VRAM_BASE_ADDR) + x0 + (y0 * C_GLCD_H_SIZE);
                  // pData = ((pInt32U) pCurrFrmBuff) + x0 + (y0 * C_GLCD_H_SIZE);
                  // *(pData)= color;
                  lcd_area( x0, y0, x0, y0);
                  lcd_drawstart();
                  
#if ( LCD_MODE_262K==6 )
                   _spi.format(6,SPIMode);
                   _spi.write( (color&0x00FC0000)>>18 );
                   _spi.write( (color&0x0000FC00)>>10 );
                   _spi.write( (color&0x000000FC)>>2);
                   _spi.format(8,SPIMode);
#else  
                  lcd_draw(color);
#endif
                  
                  lcd_drawstop();
          }
  }
  /* Reset to the slow SPI speed. */
  _spi.frequency( SPISlowClkSpeed);
}

void GLCD::lcd_reset(void)
{
  //reset
  LCD_CS_DISABLE();
  LCD_RST_ENABLE();
  wait_ms(50);
  LCD_RST_DISABLE();
  wait_ms(50);

  //driving ability
  lcd_cmd(0xEA, 0x0000);
  lcd_cmd(0xEB, 0x0020);
  lcd_cmd(0xEC, 0x000C);
  lcd_cmd(0xED, 0x00C4);
  lcd_cmd(0xE8, 0x0040);
  lcd_cmd(0xE9, 0x0038);
  lcd_cmd(0xF1, 0x0001);
  lcd_cmd(0xF2, 0x0010);
  lcd_cmd(0x27, 0x00A3);

  //power voltage
  lcd_cmd(0x1B, 0x001B);
  lcd_cmd(0x1A, 0x0001);
  lcd_cmd(0x24, 0x002F);
  lcd_cmd(0x25, 0x0057);

  //VCOM offset
  lcd_cmd(0x23, 0x008D); //for flicker adjust

  //power on
  lcd_cmd(0x18, 0x0036);
  lcd_cmd(0x19, 0x0001); //start osc
  lcd_cmd(0x01, 0x0000); //wakeup
  lcd_cmd(0x1F, 0x0088);
  wait_ms(5);
  lcd_cmd(0x1F, 0x0080);
  wait_ms(5);
  lcd_cmd(0x1F, 0x0090);
  wait_ms(5);
  lcd_cmd(0x1F, 0x00D0);
  wait_ms(5);

  //color selection
  lcd_cmd(0x17, LCD_MODE_262K); //0x0005=65k, 0x0006=262k 

  //panel characteristic
  lcd_cmd(0x36, 0x0000);

  //display on
  lcd_cmd(0x28, 0x0038);
  wait_ms(40);
  lcd_cmd(0x28, 0x003C);

  //display options
#ifdef LCD_MIRROR
  lcd_cmd(0x16, 0x0068); //MY=0 MX=1 MV=1 ML=0 BGR=1
#else
  lcd_cmd(0x16, 0x00A8); //MY=1 MX=0 MV=1 ML=0 BGR=1
#endif

  lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));

  return;
}