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:
13:2c91cb947161
Parent:
11:9bb71766cafc
Child:
14:ea3206e8e3bd
--- a/SPI_TFT.cpp	Tue Feb 19 21:49:55 2013 +0000
+++ b/SPI_TFT.cpp	Tue Mar 05 14:50:51 2013 +0000
@@ -19,24 +19,25 @@
 // 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.
-// 21.09.12 fix Bug in BMP_16 
+// 21.09.12 fix Bug in BMP_16
 // 11.10.12 patch from Hans Bergles to get SPI1 working again
 // 03.02.13 add a switch to switch off DMA use for LPC11U24
+// 04.03.13 add support for new Kinetis board
 
 #include "SPI_TFT.h"
 #include "mbed.h"
 
 #define BPP         16                  // Bits per pixel    
-            
-#if defined TARGET_LPC1768 
+
+#if defined TARGET_LPC1768
 #define USE_DMA                         // we use dma to speed up
 #define NO_MBED_LIB                     // we write direct to the SPI register to speed up  
 #endif
 
-#if defined NO_DMA
+#if defined NO_DMA                      // if LPC1768 user want no DMA
 #undef USE_DMA
 #endif
-  
+
 
 //extern Serial pc;
 //extern DigitalOut xx;     // debug !!
@@ -46,8 +47,10 @@
 {
     orientation = 0;
     char_x = 0;
+#if defined TARGET_LPC1768
     if (mosi == p11 || mosi == P0_18) spi_port = 0;  // we must know the used SPI port to setup the DMA
     else spi_port = 1;
+#endif
     tft_reset();
 }
 
@@ -90,8 +93,6 @@
 
 void SPI_TFT::wr_cmd(unsigned char cmd)
 {
-    unsigned short spi_d;
-    spi_d =  0x7000 | cmd ;
     _cs = 0;
 #if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
@@ -104,18 +105,24 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
-#else 
+#else
+#if defined TARGET_KL25Z  // 8 Bit SPI
+    _spi.write(0x70);
+    _spi.write(cmd);
+#else                     // 16 Bit SPI  
+    unsigned short spi_d;
+    spi_d =  0x7000 | cmd ;
     _spi.write(spi_d);      // mbed lib
-#endif    
+#endif
+#endif
     _cs = 1;
 }
 
 
-
+// write data to tft register
 void SPI_TFT::wr_dat(unsigned char dat)
 {
-    unsigned short spi_d;
-    spi_d =  0x7200 | dat;
+
     _cs = 0;
 #if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
@@ -128,9 +135,16 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
-#else 
-   _spi.write(spi_d);      // mbed lib
-#endif    
+#else
+#if defined TARGET_KL25Z  // 8 Bit SPI
+    _spi.write(0x72);
+    _spi.write(dat);
+#else                     // 16 Bit SPI
+    unsigned short spi_d;
+    spi_d =  0x7200 | dat;
+    _spi.write(spi_d);      // mbed lib
+#endif
+#endif
     _cs = 1;
 }
 
@@ -149,22 +163,28 @@
     return (val);
 }
 
+// write to a TFT register
 void SPI_TFT::wr_reg (unsigned char reg, unsigned char val)
 {
     wr_cmd(reg);
     wr_dat(val);
 }
 
+// read from a TFT register
 unsigned short SPI_TFT::rd_reg (unsigned char reg)
 {
     wr_cmd(reg);
     return(rd_dat());
 }
 
+// setup TFT controller - this is called by constructor
 void SPI_TFT::tft_reset()
 {
-    //static unsigned short driverCode;
+#if defined TARGET_KL25Z           // 8 Bit SPI
+    _spi.format(8,3);
+#else                              // 16 Bit SPI  
     _spi.format(16,3);                 // 16 bit spi mode 3
+#endif
     _spi.frequency(48000000);          // 48 Mhz SPI clock
     _cs = 1;                           // cs high
     _reset = 0;                        // display reset
@@ -192,7 +212,7 @@
     wr_reg(0x23, 0x8D);                 /* Vcom Control 1                       */
 
     /* Gamma settings  -----------------------------------------------------------*/
-    wr_reg(0x40,0x00);   //
+    wr_reg(0x40,0x00);   //   default setup
     wr_reg(0x41,0x00);   //
     wr_reg(0x42,0x01);   //
     wr_reg(0x43,0x13);   //
@@ -253,20 +273,17 @@
             wr_reg(0x16, 0x00A8);
             break;
     }
-#if defined USE_DMA                     
-    // setup DMA channel 0
-    // Power up the GPDMA.
-    LPC_SC->PCONP |= (1UL << 29);
+#if defined USE_DMA                     // setup DMA channel 0
+    LPC_SC->PCONP |= (1UL << 29);       // Power up the GPDMA.
     LPC_GPDMA->DMACConfig = 1;          // enable DMA controller
-    // Reset the Interrupt status
-    LPC_GPDMA->DMACIntTCClear = 0x1;
+    LPC_GPDMA->DMACIntTCClear = 0x1;    // Reset the Interrupt status
     LPC_GPDMA->DMACIntErrClr = 0x1;
     LPC_GPDMACH0->DMACCLLI      = 0;
 #endif
     WindowMax ();
 }
 
-
+// Set one pixel
 void SPI_TFT::pixel(int x, int y, int color)
 {
     wr_reg(0x03, (x >> 0));
@@ -275,7 +292,7 @@
     wr_reg(0x06, (y >> 8));
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB    
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
         LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
         LPC_SSP0->DR = 0x72;        // start Data
@@ -296,13 +313,18 @@
 #else
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+#if defined TARGET_KL25Z                          // 8 Bit SPI
+    _spi.write(color >> 8);
+    _spi.write(color & 0xff);
+#else
     _spi.format(16,3);                            // switch to 16 bit Mode 3
     _spi.write(color);                              // Write D0..D15
-#endif        
+#endif
+#endif
     _cs = 1;
 }
 
-
+// define draw area
 void SPI_TFT::window (unsigned int x, unsigned int y, unsigned int w, unsigned int h)
 {
     wr_reg(0x03, x );
@@ -315,14 +337,14 @@
     wr_reg(0x08, ( y+h-1 >> 8));
 }
 
-
+// set draw area to max
 void SPI_TFT::WindowMax (void)
 {
     window (0, 0, width(),  height());
 }
 
 
-
+// clear screen
 void SPI_TFT::cls (void)
 {
     int pixel = ( width() * height());
@@ -394,19 +416,29 @@
     for (i = 0; i < ( width() * height()); i++)
         _spi.write(_background);
 #endif
-#else  // mbed lib
+
+#else  // use mbed lib
     _cs = 0;
+#if defined TARGET_KL25Z                          // 8 Bit SPI    
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+    unsigned int i;
+    for (i = 0; i < ( width() * height()); i++) {
+        _spi.write(_background >> 8);
+        _spi.write(_background & 0xff);
+    }
+#else                                             // 16 bit SPI  
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
-    _spi.format(16,3);                            // switch to 16 bit Mode 3
+    _spi.format(16,3);                            // switch back to 16 bit Mode 3
     unsigned int i;
     for (i = 0; i < ( width() * height()); i++)
-        _spi.write(_background);                     
+        _spi.write(_background);
+#endif
 #endif
     _cs = 1;
 }
 
-
+// draw circle
 void SPI_TFT::circle(int x0, int y0, int r, int color)
 {
 
@@ -523,7 +555,7 @@
 }
 
 
-
+// draw horizontal line
 void SPI_TFT::hline(int x0, int x1, int y, int color)
 {
     int w;
@@ -531,7 +563,7 @@
     window(x0,y,w,1);
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB    
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
 #if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
@@ -567,25 +599,35 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-#else
+#else // USE_DMA
     int i;
     for (i=0; i<w; i++) {
         _spi.write(color);
     }
-#endif    
+#endif
 #else  // use mbed lib    
+#if defined TARGET_KL25Z                          // 8 Bit SPI    
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+    for (int j=0; j<w; j++) {
+        _spi.write(color >> 8);
+        _spi.write(color & 0xff);
+    }
+
+#else                                             // 16 Bit SPI  
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
-    _spi.format(16,3);                            // switch to 16 bit Mode 3
-    for (i=0; i<w; i++) {
+    _spi.format(16,3);                            // switch back to 16 bit Mode 3
+    for (int j=0; j<w; j++) {
         _spi.write(color);
     }
-#endif    
+#endif
+#endif
     _cs = 1;
     WindowMax();
     return;
 }
 
+// draw vertical line
 void SPI_TFT::vline(int x, int y0, int y1, int color)
 {
     int h;
@@ -593,7 +635,7 @@
     window(x,y0,1,h);
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB      
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
 #if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
@@ -636,20 +678,28 @@
     }
 #endif
 #else     // use mbed lib
+#if defined TARGET_KL25Z                          // 8 Bit SPI
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+    for (int y=0; y<h; y++) {
+        _spi.write(color >> 8);
+        _spi.write(color & 0xff);
+    }
+#else                                             // 16 bit SPI  
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
     _spi.format(16,3);                            // switch to 16 bit Mode 3
     for (int y=0; y<h; y++) {
         _spi.write(color);
     }
-#endif    
+#endif
+#endif
     _cs = 1;
     WindowMax();
     return;
 }
 
 
-
+// draw line
 void SPI_TFT::line(int x0, int y0, int x1, int y1, int color)
 {
     //WindowMax();
@@ -721,7 +771,7 @@
     return;
 }
 
-
+// draw rect
 void SPI_TFT::rect(int x0, int y0, int x1, int y1, int color)
 {
 
@@ -741,20 +791,20 @@
 }
 
 
-
+// fill rect
 void SPI_TFT::fillrect(int x0, int y0, int x1, int y1, int color)
 {
 
     int h = y1 - y0 + 1;
     int w = x1 - x0 + 1;
     int pixel = h * w;
-    #if defined USE_DMA
+#if defined USE_DMA
     int dma_count;
-    #endif
+#endif
     window(x0,y0,w,h);
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB     
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
 #if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
@@ -801,26 +851,36 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-   
+
 #else  // no DMA 
     for (int p=0; p<pixel; p++) {
         _spi.write(color);
     }
 #endif
+
 #else // use mbed lib
+#if defined TARGET_KL25Z                          // 8 Bit SPI
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+    for (int p=0; p<pixel; p++) {
+        _spi.write(color >> 8);
+        _spi.write(color & 0xff);
+    }
+
+#else                                             // 16 bit SPI
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
     _spi.format(16,3);                            // switch to 16 bit Mode 3
     for (int p=0; p<pixel; p++) {
         _spi.write(color);
     }
-#endif  
+#endif
+#endif
     _cs = 1;
     WindowMax();
     return;
 }
 
-
+// set cursor position
 void SPI_TFT::locate(int x, int y)
 {
     char_x = x;
@@ -828,21 +888,19 @@
 }
 
 
-
+// calculate num of chars in a row
 int SPI_TFT::columns()
 {
     return width() / font[1];
 }
 
-
-
+// calculate num of rows on the screen
 int SPI_TFT::rows()
 {
     return height() / font[2];
 }
 
-
-
+// print a char on the screen
 int SPI_TFT::_putc(int value)
 {
     if (value == '\n') {    // new line
@@ -857,18 +915,18 @@
     return value;
 }
 
-
+// consrtuct the char out of the font
 void SPI_TFT::character(int x, int y, int c)
 {
     unsigned int hor,vert,offset,bpl,j,i,b;
     unsigned char* zeichen;
     unsigned char z,w;
-    #if defined USE_DMA
+#if defined USE_DMA
     unsigned int pixel;
     unsigned int p;
     unsigned int dma_count,dma_off;
     uint16_t *buffer;
-    #endif
+#endif
 
     if ((c < 31) || (c > 127)) return;   // test char range
 
@@ -967,10 +1025,10 @@
         /* disable SSP1 for DMA. */
         LPC_SSP1->DMACR = 0x0;
     }
-    
+
 #else  // no dma
     _cs = 0;
-#if defined NO_MBED_LIB    
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
         LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
         LPC_SSP0->DR = 0x72;        // start Data
@@ -981,20 +1039,34 @@
         LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
     }
 #else // mbed lib
+#if defined TARGET_KL25Z                          // 8 Bit SPI
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);   // Write : RS = 1, RW = 0
+#else                                             // 16 bit SPI  
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
-    _spi.format(16,3);                            // switch to 16 bit Mode 3
-#endif        
-    zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
-    w = zeichen[0];                          // width of actual char
-     for (j=0; j<vert; j++) {  //  vert line
+    _spi.format(16,3);                            // switch back to 16 bit Mode 3
+#endif
+#endif
+    zeichen = &font[((c -32) * offset) + 4];    // start of char bitmap
+    w = zeichen[0];                             // width of actual char
+    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) {
+#if defined TARGET_KL25Z  // 8 Bit SPI
+                _spi.write(_background >> 8);
+                _spi.write(_background & 0xff);
+#else
                 _spi.write(_background);
+#endif
             } else {
+#if defined TARGET_KL25Z  // 8 Bit SPI
+                _spi.write(_foreground >> 8);
+                _spi.write(_foreground & 0xff);
+#else
                 _spi.write(_foreground);
+#endif
             }
         }
     }
@@ -1018,7 +1090,11 @@
 {
     unsigned int  j;
     int padd;
+#if defined TARGET_KL25Z  // 8 Bit SPI
+    unsigned char *bitmap_ptr = (unsigned char *)bitmap;
+#else
     unsigned short *bitmap_ptr = (unsigned short *)bitmap;
+#endif
     // the lines are padded to multiple of 4 bytes in a bitmap
     padd = -1;
     do {
@@ -1027,30 +1103,30 @@
     window(x, y, w, h);
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB        
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
-#if defined USE_DMA    
+#if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
         /* Enable SSP0 for DMA. */
         LPC_SSP0->DMACR = 0x2;
-#endif        
+#endif
         LPC_SSP0->CR0 &= ~(0x08UL); // set to 8 bit
         LPC_SSP0->DR = 0x72;        // start Data
         LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
 
     } else {
-#if defined USE_DMA    
+#if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
         /* Enable SSP1 for DMA. */
-        LPC_SSP1->DMACR = 0x2;   
-#endif        
+        LPC_SSP1->DMACR = 0x2;
+#endif
         LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
         LPC_SSP1->DR = 0x72;        // start Data command
         LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
     }
 
     bitmap_ptr += ((h - 1)* (w + padd));
-#if defined USE_DMA      
+#if defined USE_DMA
     for (j = 0; j < h; j++) {        //Lines
         LPC_GPDMA->DMACIntTCClear = 0x1;
         LPC_GPDMA->DMACIntErrClr = 0x1;
@@ -1073,8 +1149,8 @@
         }
         bitmap_ptr -= 2*w;
         bitmap_ptr -= padd;
-    }   
-#endif    
+    }
+#endif
     if (spi_port == 0) {    // TFT on SSP0
         do {
         } while ((LPC_SSP0->SR & 0x10) == 0x10); // SPI FIFO not empty
@@ -1083,24 +1159,39 @@
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
 #else // use mbed lib
+#if defined TARGET_KL25Z  // 8 Bit SPI
+    _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
+#else
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
     _spi.format(16,3);                            // switch to 16 bit Mode 3
+#endif
     unsigned int i;
     for (j = 0; j < h; j++) {        //Lines
         for (i = 0; i < w; i++) {     // copy pixel data to TFT
+#if defined TARGET_KL25Z  // 8 Bit SPI
+            _spi.write(*bitmap_ptr);
+            bitmap_ptr++;
+            _spi.write(*bitmap_ptr);
+            bitmap_ptr++;
+#else
             _spi.write(*bitmap_ptr);    // one line
             bitmap_ptr++;
+#endif
         }
         bitmap_ptr -= 2*w;
         bitmap_ptr -= padd;
     }
-#endif       
+#endif
     _cs = 1;
     WindowMax();
 }
 
 
+// local filesystem is not implemented in kinetis board
+#if defined TARGET_LPC1768  || defined TARGET_LPC11U24
+
+
 int SPI_TFT::BMP_16(unsigned int x, unsigned int y, const char *Name_BMP)
 {
 
@@ -1171,7 +1262,7 @@
     window(x, y,PixelWidth ,PixelHeigh);
     wr_cmd(0x22);
     _cs = 0;
-#if defined NO_MBED_LIB 
+#if defined NO_MBED_LIB
     if (spi_port == 0) {    // TFT on SSP0
 #if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; // we send to SSP0
@@ -1183,14 +1274,14 @@
         LPC_SSP0->CR0 |= 0x08UL;    // set to 16 bit
 
     } else {
-#if defined USE_DMA    
+#if defined USE_DMA
         LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP1->DR; // we send to SSP1
         /* Enable SSP1 for DMA. */
         LPC_SSP1->DMACR = 0x2;
 #endif
         LPC_SSP1->CR0 &= ~(0x08UL); // set to 8 bit
         LPC_SSP1->DR = 0x72;        // start Data
-        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit     
+        LPC_SSP1->CR0 |= 0x08UL;    // set to 16 bit
     }
     for (j = PixelHeigh - 1; j >= 0; j--) {               //Lines bottom up
         off = j * (PixelWidth  * 2 + padd) + start_data;   // start of line
@@ -1206,10 +1297,10 @@
         do {
         } while ((LPC_GPDMA->DMACRawIntTCStat & 0x01) == 0); // DMA is running
 #else
-    for (i = 0; i < PixelWidth; i++) {        // copy pixel data to TFT
+        for (i = 0; i < PixelWidth; i++) {        // copy pixel data to TFT
             _spi.write(line[i]);                  // one 16 bit pixel
-        } 
-#endif            
+        }
+#endif
     }
     if (spi_port == 0) {    // TFT on SSP0
         do {
@@ -1218,7 +1309,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-    
+
 #else // use mbed lib
     _spi.format(8,3);                             // 8 bit Mode 3
     _spi.write(SPI_START | SPI_WR | SPI_DATA);    // Write : RS = 1, RW = 0
@@ -1229,12 +1320,14 @@
         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
-        } 
-     }
-#endif        
+        }
+    }
+#endif
     _cs = 1;
     free (line);
     fclose(Image);
     WindowMax();
     return(1);
-}
\ No newline at end of file
+}
+
+#endif