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.
Diff: SPI_TFT.cpp
- Revision:
- 1:17e12e4e149f
- Parent:
- 0:de9d1462a835
- Child:
- 2:f30ea1eb3681
diff -r de9d1462a835 -r 17e12e4e149f SPI_TFT.cpp --- 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();