LPC1768 Mini-DK EasyWeb application with SPI TFT output. Started from EasyWebCR and modified for DM9161 PHY support.

Dependencies:   Mini-DK mbed

This is a very basic EasyWeb application.

No error checking is performed during initialisation.

Information

If the webpage is not reachable or the 'Webserver running' message does not appear, press the reset button on the Mini-DK and wait until the message 'Webserver running' appears.
This happens sometimes when powering up the Mini-DK because the DM9161 reset pin is NOT controlled by the LPC1768, it is directly connected to the reset button.

IP adress/mask/gateway in tcpip.h : 192.168.0.200 / 255.255.255.0 / 192.168.0.1

MAC address in ethmac.h : 6-5-4-3-2-1

SPI_TFT/SPI_TFT.cpp

Committer:
frankvnk
Date:
2012-12-21
Revision:
0:636056c0b5e1

File content as of revision 0:636056c0b5e1:

/* 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::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 w, int h, int color)
{
    hline(x0,x0+w,y0,color);
    vline(x0,y0,y0+h,color);
    hline(x0,x0+w,y0+h,color);
    vline(x0+w,y0,y0+h,color);

    return;
}

void SPI_TFT::fillrect(int x0, int y0, int w, int h, int color)
{
    unsigned long int index=0;
    if (w < 0)
    {
        x0 = x0 + w;
        w = -w;
    }
    if (h < 0)
    {
        y0 = y0 + h;
        h = -h;
    }
    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::draw_ellipse(int xc, int yc, int a, int b, unsigned int color)
{           /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
    wr_reg(0x03, 0x1030);
    WindowMax();
    int x = 0, y = b;
    long a2 = (long)a*a, b2 = (long)b*b;
    long crit1 = -(a2/4 + a%2 + b2);
    long crit2 = -(b2/4 + b%2 + a2);
    long crit3 = -(b2/4 + b%2);
    long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
    long dxt = 2*b2*x, dyt = -2*a2*y;
    long d2xt = 2*b2, d2yt = 2*a2;

    while (y>=0 && x<=a)
    {
        pixel(xc+x, yc+y, color);
        if (x!=0 || y!=0)
            pixel(xc-x, yc-y, color);
        if (x!=0 && y!=0)
        {
            pixel(xc+x, yc-y, color);
            pixel(xc-x, yc+y, color);
        }
        if (t + b2*x <= crit1 ||   /* e(x+1,y-1/2) <= 0 */
            t + a2*y <= crit3)     /* e(x+1/2,y) <= 0 */
            incx();
        else if (t - a2*y > crit2) /* e(x+1/2,y-1) > 0 */
            incy();
        else
        {
            incx();
            incy();
        }
    }
}

void SPI_TFT::fill_ellipse(int xc, int yc, int a, int b, unsigned int color)
{           /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
    int x = 0, y = b;
    int rx = x, ry = y;
    unsigned int width = 1;
    unsigned int height = 1;
    long a2 = (long)a*a, b2 = (long)b*b;
    long crit1 = -(a2/4 + a%2 + b2);
    long crit2 = -(b2/4 + b%2 + a2);
    long crit3 = -(b2/4 + b%2);
    long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
    long dxt = 2*b2*x, dyt = -2*a2*y;
    long d2xt = 2*b2, d2yt = 2*a2;

    if (b == 0)
    {
        fillrect(xc-a, yc, 2*a+1, 1, color);
        return;
    }

    while (y>=0 && x<=a)
    {
        if (t + b2*x <= crit1 ||    /* e(x+1,y-1/2) <= 0 */
            t + a2*y <= crit3)      /* e(x+1/2,y) <= 0 */
        {
            if (height == 1)
                ; /* draw nothing */
            else if (ry*2+1 > (height-1)*2)
            {
                fillrect(xc-rx, yc-ry, width, height-1, color);
                fillrect(xc-rx, yc+ry+1, width, 1-height, color);
                ry -= height-1;
                height = 1;
            }
            else
            {
                fillrect(xc-rx, yc-ry, width, ry*2+1, color);
                ry -= ry;
                height = 1;
            }
            incx();
            rx++;
            width += 2;
        }
        else if (t - a2*y > crit2)      /* e(x+1/2,y-1) > 0 */
        {
            incy();
            height++;
        }
        else
        {
            if (ry*2+1 > height*2)
            {
                fillrect(xc-rx, yc-ry, width, height, color);
                fillrect(xc-rx, yc+ry+1, width, -height, color);
            }
            else
            {
                fillrect(xc-rx, yc-ry, width, ry*2+1, color);
            }
            incx();
            incy();
            rx++;
            width += 2;
            ry -= height;
            height = 1;
        }
    }

    if (ry > height)
    {
        fillrect(xc-rx, yc-ry, width, height, color);
        fillrect(xc-rx, yc+ry+1, width, -height, color);
    }
    else
    {
        fillrect(xc-rx, yc-ry, width, ry*2+1, color);
    }
}


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);
}