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:
- 13:2c91cb947161
- Parent:
- 11:9bb71766cafc
- Child:
- 14:ea3206e8e3bd
diff -r 9bb71766cafc -r 2c91cb947161 SPI_TFT.cpp --- 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