Library to control a QVGA TFT connected to SPI. You can use printf to print text The lib can handle different fonts, draw lines, circles, rect and bmp

Files at this revision

API Documentation at this revision

Comitter:
dreschpe
Date:
Sat Apr 07 16:05:39 2012 +0000
Parent:
11:3cfa9bb9b070
Child:
13:d525819cb601
Commit message:
Use DMA and direct access to SPI register to speed up to 6 times.

Changed in this revision

SPI_TFT.cpp Show annotated file Show diff for this revision Revisions of this file
SPI_TFT.h Show annotated file Show diff for this revision Revisions of this file
--- a/SPI_TFT.cpp	Sun Jan 01 23:38:13 2012 +0000
+++ b/SPI_TFT.cpp	Sat Apr 07 16:05:39 2012 +0000
@@ -9,11 +9,15 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
- 
- 
-// fix bmp padding for Bitmap function 
-// speed up pixel 
+
+
+// fix bmp padding for Bitmap function
+// speed up pixel
 // 30.12.11 fix cls
+// 11.03.12 use DMA to speed up
+// 15.03.12 use SSEL for TFT CS to enable DMA Register writes
+// 06.04.12 fix SSEL CS problem
+// 06.04.12 use direct access to the spi register to speed up the library.
 
 
 #include "SPI_TFT.h"
@@ -22,13 +26,17 @@
 
 #define BPP         16                  // Bits per pixel                
 
-//DigitalOut led(LED1);
+
+//extern Serial pc;
+//extern DigitalOut xx;     // debug !!
 
 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) {
+        : _spi(mosi, miso, sclk), _reset(reset),GraphicsDisplay(name) {
     tft_reset();
     orientation = 0;
     char_x = 0;
+    if (mosi == p11 || mosi == P0_18) spi_port = 0;  // we must know the used SPI port to setup the DMA
+    else spi_port = 1;
 }
 
 int SPI_TFT::width() {
@@ -43,131 +51,118 @@
 }
 
 
-
 void SPI_TFT::set_orientation(unsigned int o) {
     orientation = o;
     switch (orientation) {
         case 0:
-            wr_reg(0x16, 0x0008);
+            wr_reg(0x16, 0x08);
             break;
         case 1:
-            wr_reg(0x16, 0x0068);
+            wr_reg(0x16, 0x68);
             break;
         case 2:
-            wr_reg(0x16, 0x00C8);
+            wr_reg(0x16, 0xC8);
             break;
         case 3:
-            wr_reg(0x16, 0x00A8);
+            wr_reg(0x16, 0xA8);
             break;
     }
-    WindowMax(); 
+    WindowMax();
 }
 
 
-
-void SPI_TFT::wr_cmd(int cmd) {
-    _cs = 0;
-    _spi.write(SPI_START | SPI_WR | SPI_INDEX);   /* Write : RS = 0, RW = 0   */
-    _spi.write(cmd);
-    _cs = 1;
-}
-
-
+// write command to tft register
 
-void SPI_TFT::wr_dat(int dat) {
-    _cs = 0;
-    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
-    _spi.format(16,3);                            // switch to 16 bit Mode 3
-    _spi.write(dat);                              // Write D0..D15
-    _spi.format(8,3);                             // 8 bit Mode 3
-    _cs = 1;
-}
-
+void SPI_TFT::wr_cmd(unsigned char cmd) {
+    unsigned short spi_d;
+    spi_d =  0x7000 | cmd ;
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_SSP0->DR = spi_d;
+        // we have to wait for SPI IDLE to get SSEL (CS) back to high
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
+    } else {
+        LPC_SSP1->DR = spi_d;
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
+    }
 
-
-void SPI_TFT::wr_dat_start(void) {
-    _cs = 0;
-    _spi.write(SPI_START | SPI_WR | SPI_DATA);    /* Write : RS = 1, RW = 0       */
-}
-
-
-
-void SPI_TFT::wr_dat_stop (void) {
-    _cs = 1;
 }
 
 
 
-void SPI_TFT::wr_dat_only (unsigned short dat) {
-
-    _spi.format(16,3);                        // switch to 16 bit Mode 3
-    _spi.write(dat);                          // Write D0..D15
-    _spi.format(8,3);                         // 8 bit Mode 3
-}
-
-
-
-unsigned short SPI_TFT::rd_dat (void) {
-    unsigned short val = 0;
-
-    _cs = 0;
-    _spi.write(SPI_START | SPI_RD | SPI_DATA);    /* Read: RS = 1, RW = 1         */
-    _spi.write(0);                                /* Dummy read 1                 */
-    val   = _spi.write(0);                        /* Read D8..D15                 */
-    val <<= 8;
-    val  |= _spi.write(0);                        /* Read D0..D7                  */
-    _cs = 1;
-    return (val);
-}
-
-
-
-void SPI_TFT::wr_reg (unsigned char reg, unsigned short val) {
-
-    wr_cmd(reg);
-    wr_dat(val);
+void SPI_TFT::wr_dat(unsigned char dat) {
+    unsigned short spi_d;
+    spi_d =  0x7200 | dat;
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_SSP0->DR = spi_d;
+        // we have to wait for SPI IDLE to get SSEL (CS) back to high
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
+    } else {
+        LPC_SSP1->DR = spi_d;
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
+    }
 }
 
 
 
+// the HX8347-D controller do not use the MISO (SDO) Signal.
+// The controller use the MOSI signal bidirectional.
+// To read from the controller we have to make some bit banging
+
+unsigned short SPI_TFT::rd_dat (void) {
+    unsigned short val = 0;
+
+    //val = _spi.write(0x73ff);                                /* Dummy read 1                 */
+    //val   = _spi.write(0x0000);                        /* Read D8..D15                 */
+    return (val);
+}
+
+void SPI_TFT::wr_reg (unsigned char reg, unsigned char val) {
+    wr_cmd(reg);
+    wr_dat(val);
+}
+
 unsigned short SPI_TFT::rd_reg (unsigned char reg) {
-
     wr_cmd(reg);
     return(rd_dat());
 }
 
-
-
 void SPI_TFT::tft_reset() {
     static unsigned short driverCode;
-    _spi.format(8,3);                 // 8 bit spi mode 3
-    _spi.frequency(48000000);         // 48Mhz SPI clock
-    _reset = 0;                       // reset
-    _cs = 1;
+    _spi.format(16,3);                 // 16 bit spi mode 3
+    _spi.frequency(48000000);          // 48 Mhz SPI clock
+    _reset = 0;                        // display reset
+    if (spi_port == 0) {    // TFT on SSP0
+        // Set up SSEL0 for CS
+        LPC_PINCON->PINSEL1 |= (1UL << 1);
+    } else {
+        // Set up SSEL1
+        LPC_PINCON->PINSEL0 |= (1UL << 13);
+    }
     wait_us(50);
     _reset = 1;                       // end reset
     wait_ms(5);
 
-    driverCode = rd_reg(0x00);        // read controller ID
-    //printf("Disp_ID = %x",driverCode);
-
     /* Start Initial Sequence ----------------------------------------------------*/
-    wr_reg(0xEA, 0x0000);                 /* Reset Power Control 1                */
-    wr_reg(0xEB, 0x0020);                 /* Power Control 2                      */
-    wr_reg(0xEC, 0x000C);                 /* Power Control 3                      */
-    wr_reg(0xED, 0x00C4);                 /* Power Control 4                      */
-    wr_reg(0xE8, 0x0040);                 /* Source OPON_N                        */
-    wr_reg(0xE9, 0x0038);                 /* Source OPON_I                        */
-    wr_reg(0xF1, 0x0001);                 /*                                      */
-    wr_reg(0xF2, 0x0010);                 /*                                      */
-    wr_reg(0x27, 0x00A3);                 /* Display Control 2                    */
+    wr_reg(0xEA, 0x00);                 /* Reset Power Control 1                */
+    wr_reg(0xEB, 0x20);                 /* Power Control 2                      */
+    wr_reg(0xEC, 0x0C);                 /* Power Control 3                      */
+    wr_reg(0xED, 0xC4);                 /* Power Control 4                      */
+    wr_reg(0xE8, 0x40);                 /* Source OPON_N                        */
+    wr_reg(0xE9, 0x38);                 /* Source OPON_I                        */
+    wr_reg(0xF1, 0x01);                 /*                                      */
+    wr_reg(0xF2, 0x10);                 /*                                      */
+    wr_reg(0x27, 0xA3);                 /* Display Control 2                    */
 
     /* Power On sequence ---------------------------------------------------------*/
-    wr_reg(0x1B, 0x001B);                 /* Power Control 2                      */
-    wr_reg(0x1A, 0x0001);                 /* Power Control 1                      */
-    wr_reg(0x24, 0x002F);                 /* Vcom Control 2                       */
-    wr_reg(0x25, 0x0057);                 /* Vcom Control 3                       */
-    wr_reg(0x23, 0x008D);                 /* Vcom Control 1                       */
+    wr_reg(0x1B, 0x1B);                 /* Power Control 2                      */
+    wr_reg(0x1A, 0x01);                 /* Power Control 1                      */
+    wr_reg(0x24, 0x2F);                 /* Vcom Control 2                       */
+    wr_reg(0x25, 0x57);                 /* Vcom Control 3                       */
+    wr_reg(0x23, 0x8D);                 /* Vcom Control 1                       */
 
     /* Gamma settings  -----------------------------------------------------------*/
     wr_reg(0x40,0x00);   //
@@ -232,6 +227,15 @@
             break;
     }
 
+    // setup DMA channel 0
+    // Power up the GPDMA.
+    LPC_SC->PCONP |= (1UL << 29);
+    LPC_GPDMA->DMACConfig = 1;          // enable DMA controller
+    // Reset the Interrupt status
+    LPC_GPDMA->DMACIntTCClear = 0x1;
+    LPC_GPDMA->DMACIntErrClr = 0x1;
+    LPC_GPDMACH0->DMACCLLI      = 0;
+
     WindowMax ();
 }
 
@@ -239,31 +243,46 @@
 
 
 void SPI_TFT::pixel(int x, int y, int color) {
+    unsigned char u,l;
     wr_reg(0x03, (x >> 0));
     wr_reg(0x02, (x >> 8));
     wr_reg(0x07, (y >> 0));
     wr_reg(0x06, (y >> 8));
-    //wr_reg(0x05, (x+1 >> 0));
-    //wr_reg(0x04, (x+1 >> 8));
-    //wr_reg(0x09, (y+1 >> 0));
-    //wr_reg(0x08, (y+1 >> 8));
     wr_cmd(0x22);
-    wr_dat(color);
+    u = color  >> 8;
+    l = color & 0xff;
+      
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->DR = u;           // high byte
+        LPC_SSP0->DR = l;           // low byte
+        LPC_SSP0->CR0 |= 0x08UL;    // set back to 16 bit
+        // we have to wait for SPI IDLE to get SSEL (CS) back to high
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
+    } else {
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->DR = u;
+        LPC_SSP1->DR = l;
+        LPC_SSP1->CR0 |= 0x08UL;    // set back to 16 bit
+        // we have to wait for SPI IDLE to get SSEL (CS) back to high
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
+    }
 }
 
 
-
-
 void SPI_TFT::window (unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
-    wr_reg(0x03, (x >> 0));
+    wr_reg(0x03, x );
     wr_reg(0x02, (x >> 8));
-    wr_reg(0x05, (x+w-1 >> 0));
+    wr_reg(0x05, x+w-1 );
     wr_reg(0x04, (x+w-1 >> 8));
-    wr_reg(0x07, ( y >> 0));
+    wr_reg(0x07,  y );
     wr_reg(0x06, ( y >> 8));
-    wr_reg(0x09, ( y+h-1 >> 0));
+    wr_reg(0x09, ( y+h-1 ));
     wr_reg(0x08, ( y+h-1 >> 8));
-    //wr_cmd(0x22);
 }
 
 
@@ -273,15 +292,70 @@
 
 
 void SPI_TFT::cls (void) {
-    unsigned int i;
+    //unsigned int i
+
+    int pixel = ( width() * height());
+    int dma_count;
+    int color = _background;
     WindowMax();
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);         // 16 bit Mode 3
-    for (i = 0; i < ( width() * height()); i++)
-        _spi.write(_background);
-    _spi.format(8,3);         // 8 bit Mode 3
-    wr_dat_stop();
+
+    // The SSEL signal is held low until the spi FIFO is emty.
+    // We have to lower the SPI clock for the 8 bit start to get the spi running
+    // until the next data word
+    LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&color;
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4 slow down to prevent a fifo emty
+        LPC_SSP0->DR = 0x72;        // start byte
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
+    }
+
+    // start DMA
+    do {
+        if (pixel > 4095) {
+            dma_count = 4095;
+            pixel = pixel - 4095;
+        } else {
+            dma_count = pixel;
+            pixel = 0;
+        }
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCControl = dma_count | (1UL << 18) | (1UL << 21) | (1UL << 31) ; // 16 bit transfer , no address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+        LPC_GPDMA->DMACSoftSReq = 0x1;   // DMA request
+
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+
+    } while (pixel > 0);
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((0x0010 & LPC_SSP0->SR) == 0x10); // SPI FIFO not empty
+        /* disable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x0;
+    } else {
+        do {
+        } while ((0x0010 & LPC_SSP1->SR) == 0x10); // SPI FIFO not empty
+        /* disable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x0;
+    }
+
 }
 
 
@@ -405,31 +479,88 @@
     w = x1 - x0 + 1;
     window(x0,y,w,1);
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);          // pixel are send in 16 bit mode to speed up
-    for (int x=0; x<w; x++) {
-        _spi.write(color);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
     }
-    _spi.format(8,3);
-    wr_dat_stop();
+
+    LPC_GPDMA->DMACIntTCClear = 0x1;
+    LPC_GPDMA->DMACIntErrClr = 0x1;
+    LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&color;
+    LPC_GPDMACH0->DMACCControl = w | (1UL << 18) | (1UL << 21) | (1UL << 31) ; // 16 bit transfer , no address increment, interrupt
+    LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+    LPC_GPDMA->DMACSoftSReq = 0x1;   // start DMA
+    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
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+    }
     WindowMax();
     return;
 }
 
-
-
 void SPI_TFT::vline(int x, int y0, int y1, int color) {
     int h;
     h = y1 - y0 + 1;
     window(x,y0,1,h);
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);          // pixel are send in 16 bit mode to speed up
-    for (int y=0; y<h; y++) {
-        _spi.write(color);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
     }
-    _spi.format(8,3);
-    wr_dat_stop();
+
+    LPC_GPDMA->DMACIntTCClear = 0x1;
+    LPC_GPDMA->DMACIntErrClr = 0x1;
+    LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&color;
+    LPC_GPDMACH0->DMACCControl = h | (1UL << 18) | (1UL << 21) | (1UL << 31) ; // 16 bit transfer , no address increment, interrupt
+    LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+    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
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+    }
     WindowMax();
     return;
 }
@@ -507,8 +638,6 @@
 }
 
 
-
-
 void SPI_TFT::rect(int x0, int y0, int x1, int y1, int color) {
 
     if (x1 > x0) hline(x0,x1,y0,color);
@@ -533,21 +662,62 @@
     int h = y1 - y0 + 1;
     int w = x1 - x0 + 1;
     int pixel = h * w;
+    int dma_count;
     window(x0,y0,w,h);
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);          // pixel are send in 16 bit mode to speed up
-    for (int p=0; p<pixel; p++) {
-        _spi.write(color);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
     }
-    _spi.format(8,3);
-    wr_dat_stop();
+
+    do {
+        if (pixel > 4095) {
+            dma_count = 4095;
+            pixel = pixel - 4095;
+        } else {
+            dma_count = pixel;
+            pixel = 0;
+        }
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&color;
+        LPC_GPDMACH0->DMACCControl = dma_count | (1UL << 18) | (1UL << 21) | (1UL << 31) ; // 16 bit transfer , no address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+        LPC_GPDMA->DMACSoftSReq = 0x1;
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+
+    } while (pixel > 0);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI FIFO not empty
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+    }
+
     WindowMax();
     return;
 }
 
 
-
 void SPI_TFT::locate(int x, int y) {
     char_x = x;
     char_y = y;
@@ -576,7 +746,7 @@
         }
     } else {
         character(char_x, char_y, value);
-     }
+    }
     return value;
 }
 
@@ -584,9 +754,12 @@
 
 
 void SPI_TFT::character(int x, int y, int c) {
-    unsigned int hor,vert,offset,bpl,j,i,b;
+    unsigned int hor,vert,offset,bpl,j,i,b,p;
     unsigned char* zeichen;
     unsigned char z,w;
+    unsigned int pixel;
+    unsigned int dma_count,dma_off;
+    uint16_t *buffer;
 
     if ((c < 31) || (c > 127)) return;   // test char range
 
@@ -599,41 +772,104 @@
     if (char_x + hor > width()) {
         char_x = 0;
         char_y = char_y + vert;
-       if (char_y >= height() - font[2]) {
+        if (char_y >= height() - font[2]) {
             char_y = 0;
         }
     }
-
     window(char_x, char_y,hor,vert); // char box
     wr_cmd(0x22);
-    wr_dat_start();
+
+    pixel = hor * vert;  // calculate buffer size
+
+    buffer = (uint16_t *) malloc (2*pixel); // we need a buffer for the 16 bit
+    if (buffer == NULL) {
+        //led = 1;
+        //pc.printf("Malloc error !\n\r");
+        return;         // error no memory
+    }
+
     zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
     w = zeichen[0];                          // width of actual char
-    _spi.format(16,3);                       // pixel are 16 bit
-
+    p = 0;
+    // construct the char into the buffer
     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) {
-                _spi.write(_background);
+                buffer[p] = _background;
             } else {
-                _spi.write(_foreground);
+                buffer[p] = _foreground;
             }
+            p++;
         }
     }
-    _spi.format(8,3);                      // 8 bit
-    wr_dat_stop();
+
+
+    // copy the buffer with DMA SPI to display
+    dma_off = 0;  // offset for DMA transfer
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
+    }
+
+    // start DMA
+    do {
+        if (pixel > 4095) {         // this is a giant font !
+            dma_count = 4095;
+            pixel = pixel - 4095;
+        } else {
+            dma_count = pixel;
+            pixel = 0;
+        }
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCSrcAddr = (uint32_t) (buffer + dma_off);
+        LPC_GPDMACH0->DMACCControl = dma_count | (1UL << 18) | (1UL << 21) | (1UL << 31) |  DMA_CHANNEL_SRC_INC ; // 16 bit transfer , address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+        LPC_GPDMA->DMACSoftSReq = 0x1;
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+        dma_off = dma_off + dma_count;
+    } while (pixel > 0);
+
+    free ((uint16_t *) buffer);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
+        /* disable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x0;
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
+        /* disable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x0;
+    }
+
     WindowMax();
     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;
 }
@@ -641,29 +877,59 @@
 
 
 void SPI_TFT::Bitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h,unsigned char *bitmap) {
-    unsigned int    i,j,padd;
+    unsigned int    j;
+    int padd;
     unsigned short *bitmap_ptr = (unsigned short *)bitmap;
-    // the lines are padded to multiple of 4 bytes in a bitmap 
+    // 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);
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);
+
+    if (spi_port == 0) {    // TFT on SSP0
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+        /* Enable SSP0 for DMA. */
+        LPC_SSP0->DMACR = 0x2;
+        LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+        LPC_SSP0->DR = 0x72;        // start Data
+        LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+    } else {
+        LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+        /* Enable SSP1 for DMA. */
+        LPC_SSP1->DMACR = 0x2;
+        LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+        LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+        LPC_SSP1->DR = 0x72;        // start Data
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+        LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
+    }
     bitmap_ptr += ((h - 1)* (w + padd));
-    //bitmap_ptr -= padd;      
     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;
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)bitmap_ptr;
+        LPC_GPDMACH0->DMACCControl = w | (1UL << 18) | (1UL << 21) | (1UL << 31) |  DMA_CHANNEL_SRC_INC ; // 16 bit transfer , address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+        LPC_GPDMA->DMACSoftSReq = 0x1;
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+
+        bitmap_ptr -= w;
         bitmap_ptr -= padd;
     }
-    _spi.format(8,3);
-    wr_dat_stop();
+
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI FIFO not empty
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+    }
+
     WindowMax();
 }
 
@@ -691,6 +957,10 @@
     while (*Name_BMP!='\0') {
         filename[i++]=*Name_BMP++;
     }
+
+    fprintf(stderr, "filename : %s \n\r",filename);
+
+
     FILE *Image = fopen((const char *)&filename[0], "r");  // open the bmp file
     if (!Image) {
         return(0);      // error file not found !
@@ -718,31 +988,64 @@
 
     start_data = BMP_Header[OffsetPixData] + (BMP_Header[OffsetPixData + 1] << 8) + (BMP_Header[OffsetPixData + 2] << 16) + (BMP_Header[OffsetPixData + 3] << 24);
 
-    line = (unsigned short *) malloc (PixelWidth); // we need a buffer for a line
+    
+    line = (unsigned short *) malloc (2 * PixelWidth); // we need a buffer for a line
     if (line == NULL) {
         return(-4);         // error no memory
     }
 
-    // the lines are padded to multiple of 4 bytes
+    // 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);
+    window(x, y,PixelWidth+1,PixelHeigh);
     wr_cmd(0x22);
-    wr_dat_start();
-    _spi.format(16,3);    
+
     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
-            _spi.write(line[i]);                  // one 16 bit pixel
-        } 
+        if (spi_port == 0) {    // TFT on SSP0
+            LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
+            /* Enable SSP0 for DMA. */
+            LPC_SSP0->DMACR = 0x2;
+            LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
+            LPC_SSP0->CR0 |= 0x300UL;      // clock div / 4
+            LPC_SSP0->DR = 0x72;        // start Data
+            LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
+            LPC_SSP0->CR0 &= ~(0x300UL); // reset clock div
+        } else {
+            LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
+            /* Enable SSP1 for DMA. */
+            LPC_SSP1->DMACR = 0x2;
+            LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
+            LPC_SSP1->CR0 |= 0x300UL;  // clock div / 4
+            LPC_SSP1->DR = 0x72;        // start Data
+            LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
+            LPC_SSP1->CR0 &= ~(0x300UL); // reset clock div
+        }
+
+        LPC_GPDMA->DMACIntTCClear = 0x1;
+        LPC_GPDMA->DMACIntErrClr = 0x1;
+        LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)line;
+        LPC_GPDMACH0->DMACCControl = PixelWidth | (1UL << 18) | (1UL << 21) | (1UL << 31) |  DMA_CHANNEL_SRC_INC ; // 16 bit transfer , address increment, interrupt
+        LPC_GPDMACH0->DMACCConfig  = DMA_CHANNEL_ENABLE | DMA_TRANSFER_TYPE_M2P ;
+        LPC_GPDMA->DMACSoftSReq = 0x1;
+        do {
+        } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
+
     }
-    _spi.format(8,3);
-    wr_dat_stop();
+
+    if (spi_port == 0) {    // TFT on SSP0
+        do {
+        } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI FIFO not empty
+    } else {
+        do {
+        } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
+    }
+
     free (line);
     fclose(Image);
     WindowMax();
--- a/SPI_TFT.h	Sun Jan 01 23:38:13 2012 +0000
+++ b/SPI_TFT.h	Sat Apr 07 16:05:39 2012 +0000
@@ -51,6 +51,17 @@
 #define GreenYellow     0xAFE5      /* 173, 255,  47 */
 
 
+// some defines for the DMA use
+#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_SSP1_TX             (1UL << 2)
+#define DMA_SSP0_TX             (0) 
+
+
 /** Display control class, based on GraphicsDisplay and TextDisplay
  *
  * Example:
@@ -118,7 +129,7 @@
    * @param y vertical position
    * @param color 16 bit pixel color
    */    
-  virtual void pixel(int x, int y, int colour);
+  virtual void pixel(int x, int y,int colour);
     
   /** draw a circle
    *
@@ -280,7 +291,7 @@
   void set_orientation(unsigned int o);
     
   SPI _spi;
-  DigitalOut _cs;
+  // DigitalOut _cs; we use SSEL0/1
   DigitalOut _reset;
   unsigned char* font;
   
@@ -335,24 +346,25 @@
    * @param dat data written to LCD controller
    * 
    */   
-  void wr_dat(int value);
+  //void wr_dat(unsigned int value);
+  void wr_dat(unsigned char value);
     
   /** Write a command the LCD controller 
    *
    * @param cmd: command to be written   
    *
    */   
-  void wr_cmd(int value);
+  void wr_cmd(unsigned char value);
     
    /** Start data sequence to the LCD controller
    * 
    */   
-  void wr_dat_start();
+  //void wr_dat_start();
     
   /** Stop of data writing to the LCD controller
    *   
    */  
-  void wr_dat_stop();
+  //void wr_dat_stop();
     
   /** write data to the LCD controller
    *
@@ -373,7 +385,7 @@
    * @param reg register to be written
    * @param val data to be written
    */   
-  void wr_reg (unsigned char reg, unsigned short val);
+  void wr_reg (unsigned char reg, unsigned char val);
     
   /** Read a LCD register
    *
@@ -382,6 +394,7 @@
    */    
   unsigned short rd_reg (unsigned char reg);
     
+  unsigned char spi_port; 
   unsigned int orientation;
   unsigned int char_x;
   unsigned int char_y;