LPC1768 Mini-DK board with 2.8" SPI TFT and SPI touch

Dependencies:   Mini-DK mbed SDFileSystem

WARNING: filetoflash (SD to CPU flash)

The SPI_TFT library called from Mini-DK.lib contains an option to copy an image from the SD card to the CPU flash memory. This allows you to use an image as background without speed loss when writing other text and graphics.

By default, this option is enabled.

It can be disabled by uncommenting the #define mentioned below in Mini_DK.h:

#define NO_FLASH_BUFFER

Since the flash memory has limited write endurance, DO NOT use this feature when you intend to read multiple images from the SD card (eg: when used as a photo frame).

Revision:
0:ee7076d8260a
Child:
1:557df792279c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_TFT/SPI_TFT.cpp	Tue Dec 11 08:58:06 2012 +0000
@@ -0,0 +1,812 @@
+/* mbed library for 240*320 pixel TFT with ILI9320 LCD Controller
+ * Rewrite from Peter Drescher code - http://mbed.org/cookbook/SPI-driven-QVGA-TFT
+ *
+ * TODO : BMP routine
+ */
+
+
+
+#include "SPI_TFT.h"
+#include "mbed.h"
+
+
+#define BPP         16                  // Bits per pixel
+
+
+SPI_TFT::SPI_TFT(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset, const char *name)
+    : _spi(mosi, miso, sclk), _cs(cs), _reset(reset),GraphicsDisplay(name)
+{
+    char_x = 0;
+    tft_reset();
+    set_orientation(0);
+}
+
+int SPI_TFT::width()
+{
+    if (orientation == 0 || orientation == 2) return 240;
+    else return 320;
+}
+
+int SPI_TFT::height()
+{
+    if (orientation == 0 || orientation == 2) return 320;
+    else return 240;
+}
+
+//
+void SPI_TFT::set_orientation(unsigned int o)
+{
+    orientation = o;
+    WindowMax();
+}
+
+// ILI9320
+// Orientation is only set before a window command (registers 0x50..0x53)
+// reg 03h (Entry Mode) : BGR = 1 - ORG = 1 - ID0, ID1 and AM are set according to the orientation variable.
+// IMPORTANT : when ORG = 1, the GRAM writing direction follows the orientation (ID0, ID1, AM bits)
+//             AND we need to use the window command (reg 50h..53h) to write to an area on the display
+//             because we cannot change reg 20h and 21h to set the GRAM address (they both remain at 00h).
+//             This means that the pixel routine does not work when ORG = 1.
+//             Routines relying on the pixel routine first need to set reg 03h = 0x1030
+//             (cls, circle and line do so) AND need to write the data according to the orientation variable.
+
+void SPI_TFT::mod_orientation(void)
+{
+    switch (orientation)
+    {
+        case 0:
+            wr_reg(0x03, 0x10b0);        // ID1 = 1, ID0 = 1, AM = 0 - Portrait
+            break;
+        case 1:
+            wr_reg(0x03, 0x10a8);        // ID1 = 1, ID0 = 0, AM = 0 - Landscape
+            break;
+        case 2:
+            wr_reg(0x03, 0x1080);        // ID1 = 0, ID0 = 0, AM = 1 - Portrait upside down
+            break;
+        case 3:
+            wr_reg(0x03, 0x1098);        // ID1 = 0, ID0 = 1, AM = 1 - Landscape upside down
+            break;
+    }
+}
+
+void SPI_TFT::wr_cmd(unsigned char cmd)
+{
+    _cs = 0;
+    _spi.write(0x70);
+    _spi.write(0x00);
+    _spi.write(cmd);
+    _cs = 1;
+}
+
+void SPI_TFT::wr_dat(unsigned short dat)
+{
+    unsigned char u,l;
+    u = (dat >> 0x08);
+    l = (dat & 0xff);
+    _cs = 0;
+    _spi.write(0x72);
+    _spi.write(u);
+    _spi.write(l);
+    _cs = 1;
+}
+
+void SPI_TFT::wr_dat_start(void)
+{
+    _spi.write(0x72);
+}
+
+void SPI_TFT::wr_dat_only(unsigned short dat)
+{
+    unsigned char u,l;
+    u = (dat >> 0x08);
+    l = (dat & 0xff);
+    _spi.write(u);
+    _spi.write(l);
+}
+
+unsigned short SPI_TFT::rd_dat(void)              // SPI frequency needs to be lowered on read
+{
+    unsigned short val = 0;
+    _cs = 0;
+    _spi.frequency(SPI_F_LO);
+    _spi.write(0x73);
+    _spi.write(0x00);
+    val = _spi.write(0);                          // Dummy read
+    val = _spi.write(0);                          // Read D8..D15
+    val <<= 8;
+    val |= _spi.write(0);                         // Read D0..D7
+    _cs = 1;
+    _spi.frequency(SPI_F_HI);
+    return (val);
+}
+
+void SPI_TFT::wr_reg(unsigned char reg, unsigned short val)
+{
+    wr_cmd(reg);
+    wr_dat(val);
+}
+
+unsigned short SPI_TFT::rd_reg(unsigned char reg)
+{
+    wr_cmd(reg);
+    return(rd_dat());
+}
+
+unsigned short SPI_TFT::Read_ID(void)             // IMPORTANT : SPI frequency needs to be lowered when reading
+{
+    unsigned short val = 0;
+    _cs = 0;
+    _spi.write(0x70);
+    _spi.write(0x00);
+    _spi.write(0X00);
+    _cs = 1;
+    _spi.frequency(SPI_F_LO);
+    _cs = 0;
+    _spi.write(0x73);
+    val = _spi.write(0x00);                       // Dummy read
+    val = _spi.write(0x00);                       // Read D8..D15
+    val <<= 8;
+    val |= _spi.write(0x00);                      // Read D0..D7
+    _cs = 1;
+    _spi.frequency(SPI_F_HI);
+    return (val);
+}
+
+void SPI_TFT::SetCursor( unsigned short Xpos, unsigned short Ypos )
+{
+    wr_reg(0x20, Xpos );
+    wr_reg(0x21, Ypos );
+}
+
+void SPI_TFT::tft_reset()
+{
+    _spi.format(8,3);                    // 8 bit spi mode 3
+    _spi.frequency(SPI_F_HI);            // 48 Mhz SPI clock
+
+    wr_reg(0x00,0x0000);
+    wr_reg(0x01,0x0100); // Driver Output Control
+    wr_reg(0x02,0x0700); // LCD Driver Waveform Control
+    wr_reg(0x03,0x1030); // Set the scan mode
+    wr_reg(0x04,0x0000); // Scaling Control
+    wr_reg(0x08,0x0202); // Display Control 2
+    wr_reg(0x09,0x0000); // Display Control 3
+    wr_reg(0x0a,0x0000); // Frame Cycle Contal
+    wr_reg(0x0c,(1<<0)); // Extern Display Interface Control 1
+    wr_reg(0x0d,0x0000); // Frame Maker Position
+    wr_reg(0x0f,0x0000); // Extern Display Interface Control 2
+
+    wait_ms(50);
+
+    wr_reg(0x07,0x0101); // Display Control
+
+    wait_ms(50);
+
+    wr_reg(0x10,(1<<12)|(0<<8)|(1<<7)|(1<<6)|(0<<4)); // Power Control 1
+    wr_reg(0x11,0x0007);                              // Power Control 2
+    wr_reg(0x12,(1<<8)|(1<<4)|(0<<0));                // Power Control 3
+    wr_reg(0x13,0x0b00);                              // Power Control 4
+    wr_reg(0x29,0x0000);                              // Power Control 7
+    wr_reg(0x2b,(1<<14)|(1<<4));
+
+    wr_reg(0x50,0);      // Set X Start
+    wr_reg(0x51,239);    // Set X End
+    wr_reg(0x52,0);      // Set Y Start
+    wr_reg(0x53,319);    // Set Y End
+
+    wait_ms(50);
+
+    wr_reg(0x60,0x2700); // Driver Output Control
+    wr_reg(0x61,0x0001); // Driver Output Control
+    wr_reg(0x6a,0x0000); // Vertical Srcoll Control
+
+    wr_reg(0x80,0x0000); // Display Position Partial Display 1
+    wr_reg(0x81,0x0000); // RAM Address Start Partial Display 1
+    wr_reg(0x82,0x0000); // RAM Address End-Partial Display 1
+    wr_reg(0x83,0x0000); // Displsy Position Partial Display 2
+    wr_reg(0x84,0x0000); // RAM Address Start Partial Display 2
+    wr_reg(0x85,0x0000); // RAM Address End Partial Display 2
+
+    wr_reg(0x90,(0<<7)|(16<<0)); // Frame Cycle Control
+    wr_reg(0x92,0x0000);         // Panel Interface Control 2
+    wr_reg(0x93,0x0001);         // Panel Interface Control 3
+    wr_reg(0x95,0x0110);         // Frame Cycle Control
+    wr_reg(0x97,(0<<8));
+    wr_reg(0x98,0x0000);         // Frame Cycle Control
+    wr_reg(0x07,0x0133);
+
+    wait_ms(100);
+    WindowMax();
+}
+
+
+void SPI_TFT::pixel(int x, int y, int color)
+{
+    switch (orientation)
+    {
+        case 0:
+            wr_reg(0x20, x);
+            wr_reg(0x21, y);
+            break;
+        case 1:
+            wr_reg(0x20, 239-y);
+            wr_reg(0x21, x);
+            break;
+        case 2:
+            wr_reg(0x20, 239-x);
+            wr_reg(0x21, 319-y);
+            break;
+        case 3:
+            wr_reg(0x20, y);
+            wr_reg(0x21, 319-x);
+            break;
+    }
+    wr_cmd(0x22);
+    wr_dat(color);
+}
+
+
+void SPI_TFT::window(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+{
+    unsigned int xw1, yh1;
+    xw1 = x + w - 1;
+    yh1 = y + h - 1;
+    wr_reg(0x20, x);
+    wr_reg(0x21, y);
+    switch (orientation)
+    {
+        case 0:
+            wr_reg(0x50, x);
+            wr_reg(0x51, xw1);
+            wr_reg(0x52, y);
+            wr_reg(0x53, yh1);
+            break;
+        case 1:
+            wr_reg(0x50, 239 - yh1);
+            wr_reg(0x51, 239 - y);
+            wr_reg(0x52, x);
+            wr_reg(0x53, xw1);
+            break;
+        case 2:
+            wr_reg(0x50, 239 - xw1);
+            wr_reg(0x51, 239 - x);
+            wr_reg(0x52, 319 - yh1);
+            wr_reg(0x53, 319 - y);
+            break;
+        case 3:
+            wr_reg(0x50, y);
+            wr_reg(0x51, yh1);
+            wr_reg(0x52, 319 - xw1);
+            wr_reg(0x53, 319 - x);
+            break;
+    }
+}
+
+
+void SPI_TFT::WindowMax(void)
+{
+    window(0, 0, width(),  height());
+}
+
+
+void SPI_TFT::cls (void)
+{
+    unsigned long int index=0;
+    int color = _background;
+    wr_reg(0x03, 0x1030);
+    WindowMax();
+    SetCursor(0,0);
+    wr_cmd(0x22);
+     _cs = 0;
+     wr_dat_start();
+    for( index = 0; index < width() * height(); index++ )
+    {
+        wr_dat_only(color);
+    }
+    _cs = 1;
+}
+
+
+void SPI_TFT::circle(int x0, int y0, int r, int color)
+{
+    wr_reg(0x03, 0x1030);
+    WindowMax();
+
+    int draw_x0, draw_y0;
+    int draw_x1, draw_y1;
+    int draw_x2, draw_y2;
+    int draw_x3, draw_y3;
+    int draw_x4, draw_y4;
+    int draw_x5, draw_y5;
+    int draw_x6, draw_y6;
+    int draw_x7, draw_y7;
+    int xx, yy;
+    int di;
+    if (r == 0) {       /* no radius */
+        return;
+    }
+
+    draw_x0 = draw_x1 = x0;
+    draw_y0 = draw_y1 = y0 + r;
+    if (draw_y0 < height()) {
+        pixel(draw_x0, draw_y0, color);     /* 90 degree */
+    }
+
+    draw_x2 = draw_x3 = x0;
+    draw_y2 = draw_y3 = y0 - r;
+    if (draw_y2 >= 0) {
+        pixel(draw_x2, draw_y2, color);    /* 270 degree */
+    }
+
+    draw_x4 = draw_x6 = x0 + r;
+    draw_y4 = draw_y6 = y0;
+    if (draw_x4 < width()) {
+        pixel(draw_x4, draw_y4, color);     /* 0 degree */
+    }
+
+    draw_x5 = draw_x7 = x0 - r;
+    draw_y5 = draw_y7 = y0;
+    if (draw_x5>=0) {
+        pixel(draw_x5, draw_y5, color);     /* 180 degree */
+    }
+
+    if (r == 1) {
+        return;
+    }
+
+    di = 3 - 2*r;
+    xx = 0;
+    yy = r;
+    while (xx < yy) {
+
+        if (di < 0) {
+            di += 4*xx + 6;
+        } else {
+            di += 4*(xx - yy) + 10;
+            yy--;
+            draw_y0--;
+            draw_y1--;
+            draw_y2++;
+            draw_y3++;
+            draw_x4--;
+            draw_x5++;
+            draw_x6--;
+            draw_x7++;
+        }
+        xx++;
+        draw_x0++;
+        draw_x1--;
+        draw_x2++;
+        draw_x3--;
+        draw_y4++;
+        draw_y5++;
+        draw_y6--;
+        draw_y7--;
+
+        if ( (draw_x0 <= width()) && (draw_y0>=0) ) {
+            pixel(draw_x0, draw_y0, color);
+        }
+
+        if ( (draw_x1 >= 0) && (draw_y1 >= 0) ) {
+            pixel(draw_x1, draw_y1, color);
+        }
+
+        if ( (draw_x2 <= width()) && (draw_y2 <= height()) ) {
+            pixel(draw_x2, draw_y2, color);
+        }
+
+        if ( (draw_x3 >=0 ) && (draw_y3 <= height()) ) {
+            pixel(draw_x3, draw_y3, color);
+        }
+
+        if ( (draw_x4 <= width()) && (draw_y4 >= 0) ) {
+            pixel(draw_x4, draw_y4, color);
+        }
+
+        if ( (draw_x5 >= 0) && (draw_y5 >= 0) ) {
+            pixel(draw_x5, draw_y5, color);
+        }
+        if ( (draw_x6 <=width()) && (draw_y6 <= height()) ) {
+            pixel(draw_x6, draw_y6, color);
+        }
+        if ( (draw_x7 >= 0) && (draw_y7 <= height()) ) {
+            pixel(draw_x7, draw_y7, color);
+        }
+    }
+    return;
+}
+
+void SPI_TFT::fillcircle(int x, int y, int r, int color)
+{
+    int i;
+    for (i = 0; i <= r; i++)
+        circle(x,y,i,color);
+}
+
+
+
+void SPI_TFT::hline(int x0, int x1, int y, int color)
+{
+    unsigned int index=0;
+    int w;
+    w = x1 - x0 + 1;
+    mod_orientation();
+    window(x0,y,w,1);
+    wr_cmd(0x22);
+     _cs = 0;
+     wr_dat_start();
+    for( index = 0; index < (x1 - x0); index++ )
+    {
+        wr_dat_only(color);
+    }
+    _cs = 1;
+    return;
+}
+
+void SPI_TFT::vline(int x, int y0, int y1, int color)
+{
+    unsigned int index=0;
+    int h;
+    h = y1 - y0 + 1;
+    mod_orientation();
+    window(x,y0,1,h);
+    wr_cmd(0x22);
+     _cs = 0;
+     wr_dat_start();
+    for( index = 0; index < (y1 - y0); index++ )
+    {
+        wr_dat_only(color);
+    }
+    _cs = 1;
+    return;
+}
+
+void SPI_TFT::line(int x0, int y0, int x1, int y1, int color)
+{
+    wr_reg(0x03, 0x1030);
+    WindowMax();
+    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);
+    }
+    return;
+}
+
+
+void SPI_TFT::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);
+
+    return;
+}
+
+
+
+void SPI_TFT::fillrect(int x0, int y0, int x1, int y1, int color)
+{
+    unsigned long int index=0;
+    int h = y1 - y0 + 1;
+    int w = x1 - x0 + 1;
+    mod_orientation();
+    window(x0,y0,w,h);
+    wr_cmd(0x22);
+     _cs = 0;
+     wr_dat_start();
+
+    for( index = 0; index < h * w; index++ )
+    {
+        wr_dat_only(color);
+    }
+    _cs = 1;
+    return;
+}
+
+void SPI_TFT::locate(int x, int y)
+{
+    char_x = x;
+    char_y = y;
+}
+
+int SPI_TFT::columns()
+{
+    return width() / font[1];
+}
+
+int SPI_TFT::rows()
+{
+    return height() / font[2];
+}
+
+int SPI_TFT::_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;
+}
+
+void SPI_TFT::character(int x, int y, int c)
+{
+    unsigned int hor,vert,offset,bpl,j,i,b;
+    unsigned char* bitmap_char;
+    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;
+        }
+    }
+    mod_orientation();
+    window(char_x, char_y,hor,vert); // char box
+    wr_cmd(0x22);
+    _cs = 0;
+    wr_dat_start();
+    bitmap_char = &font[((c -32) * offset) + 4]; // start of char bitmap
+    w = bitmap_char[0];                          // width of actual char
+
+    for (j=0; j<vert; j++)                         //  vert line
+    {
+        for (i=0; i<hor; i++)                    //  horz line
+        {
+            z =  bitmap_char[bpl * i + ((j & 0xF8) >> 3)+1];
+            b = 1 << (j & 0x07);
+            if (( z & b ) == 0x00)
+            {
+                wr_dat_only(_background);
+            }
+            else
+            {
+                wr_dat_only(_foreground);
+            }
+        }
+    }
+    _cs = 1;
+    if ((w + 2) < hor)                   // x offset to next char
+    {
+        char_x += w + 2;
+    }
+    else char_x += hor;
+}
+
+
+void SPI_TFT::set_font(unsigned char* f)
+{
+    font = f;
+}
+
+
+void SPI_TFT::Bitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h,unsigned char *bitmap)
+{
+    unsigned int    i,j;
+    unsigned short *bitmap_ptr = (unsigned short *)bitmap;
+    mod_orientation();
+    window(x, y, w, h);
+    wr_cmd(0x22);
+    _cs = 0;
+    wr_dat_start();
+    _spi.format(16,3);
+    bitmap_ptr += ((h - 1)*w);
+    for (j = 0; j < h; j++)             //Lines
+    {
+        for (i = 0; i < w; i++)         // copy pixel data to TFT
+        {
+            _spi.write(*bitmap_ptr);    // one line
+            bitmap_ptr++;
+        }
+        bitmap_ptr -= 2*w;
+    }
+    _spi.format(8,3);
+    _cs = 1;
+}
+
+int SPI_TFT::BMP_16(unsigned int x, unsigned int y, const char *Name_BMP)
+{
+/* // Current code unusable : Rewrite without DMA is needed
+#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
+    LocalFileSystem local("local");
+    sprintf(&filename[0],"/local/");
+    i=7;
+    while (*Name_BMP!='\0') {
+        filename[i++]=*Name_BMP++;
+    }
+
+    fprintf(stderr, "filename : %s \n\r",filename);
+
+    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);
+
+
+//fseek(Image, 70 ,SEEK_SET);
+    window(x, y,PixelWidth ,PixelHeigh);
+    wr_cmd(0x22);
+    _cs = 0;
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+//        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        // Enable SSP0 for DMA.
+        LPC_SSP0->DMACR = 0x2;
+
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+//        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        // Enable SSP1 for DMA.
+        LPC_SSP1->DMACR = 0x2;
+    }
+    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 !
+
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)line;
+        LPC_GPDMACH0->DMACCControl = PixelWidth | (0UL << 18) | (0UL << 21) | (1UL << 31) |  DMA_CHANNEL_SRC_INC ; // 8 bit transfer , address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P | (spi_port ? DMA_DEST_SSP1_TX : DMA_DEST_SSP0_TX);
+        LPC_GPDMA->DMACSoftSReq = 0x1;
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+
+    }
+
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI FIFO not empty
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+    }
+    _cs = 1;
+    free (line);
+    fclose(Image);
+    WindowMax();
+*/
+    return(1);
+}