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:
Tue Sep 11 20:44:49 2012 +0000
Parent:
12:b2dd49f04d5d
Commit message:
Switch back to io mode CS. The automatic spi cs can cause problems with interrupts or RTOS.

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	Sat Apr 07 16:05:39 2012 +0000
+++ b/SPI_TFT.cpp	Tue Sep 11 20:44:49 2012 +0000
@@ -18,7 +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"
 #include "mbed.h"
@@ -31,7 +31,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 +76,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 +87,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI1 not idle
     }
-
+    _cs = 1;
 }
 
 
@@ -94,9 +95,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 +106,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 +134,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 +245,6 @@
 }
 
 
-
-
 void SPI_TFT::pixel(int x, int y, int color) {
     unsigned char u,l;
     wr_reg(0x03, (x >> 0));
@@ -251,14 +254,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 +270,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 +307,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 +357,7 @@
         /* disable SSP1 for DMA. */
         LPC_SSP1->DMACR = 0x0;
     }
-
+    _cs = 1;
 }
 
 
@@ -479,25 +481,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 +513,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -524,25 +523,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 +556,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -665,25 +661,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 +704,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     WindowMax();
     return;
 }
@@ -808,24 +800,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 +850,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 +876,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 +914,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     WindowMax();
 }
 
@@ -960,7 +945,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 +971,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 +985,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 +995,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 +1024,7 @@
         do {
         } while ((LPC_SSP1->SR & 0x10) == 0x10); // SPI FIFO not empty
     }
-
+    _cs = 1;
     free (line);
     fclose(Image);
     WindowMax();
--- a/SPI_TFT.h	Sat Apr 07 16:05:39 2012 +0000
+++ b/SPI_TFT.h	Tue Sep 11 20:44:49 2012 +0000
@@ -291,7 +291,7 @@
   void set_orientation(unsigned int o);
     
   SPI _spi;
-  // DigitalOut _cs; we use SSEL0/1
+  DigitalOut _cs;
   DigitalOut _reset;
   unsigned char* font;