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

Dependents:   TFT_Test1 SourceCodePro31-SB Mandelbrot Mindwave-screen ... more

See http://mbed.org/cookbook/SPI-driven-QVGA-TFT for details.

Revision:
1:17e12e4e149f
Parent:
0:de9d1462a835
Child:
2:f30ea1eb3681
--- a/SPI_TFT.cpp	Mon Sep 10 19:23:26 2012 +0000
+++ b/SPI_TFT.cpp	Tue Sep 11 15:51:52 2012 +0000
@@ -18,6 +18,7 @@
 // 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.
+// 11.09.12 switch back to using io pin as cs to avoid problems with SSEL CS. 
 
 
 #include "SPI_TFT.h"
@@ -31,7 +32,7 @@
 //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), _reset(reset),GraphicsDisplay(name) {
+        : _spi(mosi, miso, sclk), _cs(cs), _reset(reset),GraphicsDisplay(name) {
     tft_reset();
     orientation = 0;
     char_x = 0;
@@ -76,9 +77,10 @@
 void SPI_TFT::wr_cmd(unsigned char cmd) {
     unsigned short spi_d;
     spi_d =  0x7000 | cmd ;
+    _cs = 0;
     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
+        // we have to wait for SPI IDLE to set CS back to high
         do {
         } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
     } else {
@@ -86,7 +88,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
-
+    _cs = 1;
 }
 
 
@@ -94,9 +96,10 @@
 void SPI_TFT::wr_dat(unsigned char dat) {
     unsigned short spi_d;
     spi_d =  0x7200 | dat;
+    _cs = 0;
     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
+        // we have to wait for SPI IDLE to set CS back to high
         do {
         } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
     } else {
@@ -104,19 +107,20 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
+    _cs = 1;
 }
 
 
 
 // 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
+// This is a bug - ?
+// A read will return 0 at the moment
 
 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                 */
+    //val = _spi.write(0x73ff);                /* Dummy read 1           */
+    //val   = _spi.write(0x0000);              /* Read D8..D15           */
     return (val);
 }
 
@@ -131,17 +135,19 @@
 }
 
 void SPI_TFT::tft_reset() {
-    static unsigned short driverCode;
+    //static unsigned short driverCode;
     _spi.format(16,3);                 // 16 bit spi mode 3
     _spi.frequency(48000000);          // 48 Mhz SPI clock
+    _cs = 1;                           // cs high
     _reset = 0;                        // display reset
-    if (spi_port == 0) {    // TFT on SSP0
+   // 
+   // 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);
-    }
+   //     LPC_PINCON->PINSEL1 |= (1UL << 1);
+   // } else {
+   //     // Set up SSEL1
+   //     LPC_PINCON->PINSEL0 |= (1UL << 13);
+   // }
     wait_us(50);
     _reset = 1;                       // end reset
     wait_ms(5);
@@ -240,8 +246,6 @@
 }
 
 
-
-
 void SPI_TFT::pixel(int x, int y, int color) {
     unsigned char u,l;
     wr_reg(0x03, (x >> 0));
@@ -251,14 +255,14 @@
     wr_cmd(0x22);
     u = color  >> 8;
     l = color & 0xff;
-      
+    _cs = 0;  
     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
+        // we have to wait for SPI IDLE to set CS back to high
         do {
         } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI0 not idle
     } else {
@@ -267,10 +271,11 @@
         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
+        // we have to wait for SPI IDLE to set CS back to high
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
+    _cs = 1;
 }
 
 
@@ -303,27 +308,25 @@
     // 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;
 
+    _cs = 0;
     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 {
@@ -355,7 +358,7 @@
         /* disable SSP1 for DMA. */
         LPC_SSP1->DMACR = 0x0;
     }
-
+    _cs = 1;
 }
 
 
@@ -479,25 +482,21 @@
     w = x1 - x0 + 1;
     window(x0,y,w,1);
     wr_cmd(0x22);
-
+    _cs = 0;
     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;
@@ -515,6 +514,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -524,25 +524,21 @@
     h = y1 - y0 + 1;
     window(x,y0,1,h);
     wr_cmd(0x22);
-
+    _cs = 0;
     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 {
+     } 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;
@@ -561,6 +557,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -665,25 +662,21 @@
     int dma_count;
     window(x0,y0,w,h);
     wr_cmd(0x22);
-
+    _cs = 0;
     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 {
+     } 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
     }
 
     do {
@@ -712,7 +705,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -808,24 +801,21 @@
 
     // copy the buffer with DMA SPI to display
     dma_off = 0;  // offset for DMA transfer
+    _cs = 0;
     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
@@ -861,7 +851,7 @@
         /* disable SSP1 for DMA. */
         LPC_SSP1->DMACR = 0x0;
     }
-
+    _cs = 1;
     WindowMax();
     if ((w + 2) < hor) {                   // x offset to next char
         char_x += w + 2;
@@ -887,25 +877,21 @@
     } while (2*(w + padd)%4 != 0);
     window(x, y, w, h);
     wr_cmd(0x22);
-
+    _cs = 0;
     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));
     for (j = 0; j < h; j++) {        //Lines
@@ -929,7 +915,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     WindowMax();
 }
 
@@ -960,7 +946,6 @@
 
     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 !
@@ -987,7 +972,6 @@
     }
 
     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) {
@@ -1002,7 +986,7 @@
 
     window(x, y,PixelWidth+1,PixelHeigh);
     wr_cmd(0x22);
-
+    _cs = 0;
     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);
@@ -1012,20 +996,16 @@
             /* 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 {
+         } 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;
@@ -1045,7 +1025,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     free (line);
     fclose(Image);
     WindowMax();