Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
TFT.cpp
00001 /* mbed UniGraphic library - universal TFT driver class 00002 * Copyright (c) 2015 Giuliano Dianda 00003 * Released under the MIT License: http://mbed.org/license/mit 00004 * 00005 * Derived work of: 00006 * 00007 * mbed library for 240*320 pixel display TFT based on ILI9341 LCD Controller 00008 * Copyright (c) 2013 Peter Drescher - DC2PD 00009 * 00010 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00011 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00012 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00013 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00014 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00015 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00016 * THE SOFTWARE. 00017 */ 00018 00019 #include "TFT.h" 00020 00021 //#include "mbed_debug.h" 00022 00023 #define SWAP(a, b) { a ^= b; b ^= a; a ^= b; } 00024 00025 #if DEVICE_PORTINOUT 00026 TFT::TFT(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const char *name) 00027 : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y) 00028 { 00029 if(displayproto==PAR_8) proto = new PAR8(port, CS, reset, DC, WR, RD); 00030 else if(displayproto==PAR_16) proto = new PAR16(port, CS, reset, DC, WR, RD); 00031 useNOP=false; 00032 scrollbugfix=0; 00033 mipistd=false; 00034 set_orientation(0); 00035 foreground(White); 00036 background(Black); 00037 set_auto_up(false); //we don't have framebuffer 00038 topfixedareasize=0; 00039 scrollareasize=0; 00040 usefastwindow=false; 00041 fastwindowready=false; 00042 is18bit=false; 00043 isBGR=false; 00044 // cls(); 00045 // locate(0,0); 00046 } 00047 #endif 00048 00049 TFT::TFT(proto_t displayproto, PinName* buspins, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const char *name) 00050 : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y) 00051 { 00052 if(displayproto==BUS_8) 00053 { 00054 PinName pins[16]; 00055 for(int i=0; i<16; i++) pins[i]=NC; 00056 for(int i=0; i<8; i++) pins[i]=buspins[i]; 00057 proto = new BUS8(pins, CS, reset, DC, WR, RD); 00058 } 00059 else if(displayproto==BUS_16) 00060 { 00061 proto = new BUS16(buspins, CS, reset, DC, WR, RD); 00062 } 00063 useNOP=false; 00064 scrollbugfix=0; 00065 mipistd=false; 00066 set_orientation(0); 00067 foreground(White); 00068 background(Black); 00069 set_auto_up(false); //we don't have framebuffer 00070 topfixedareasize=0; 00071 scrollareasize=0; 00072 usefastwindow=false; 00073 fastwindowready=false; 00074 is18bit=false; 00075 isBGR=false; 00076 // cls(); 00077 // locate(0,0); 00078 } 00079 TFT::TFT(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC, const int lcdsize_x, const int lcdsize_y, const char *name) 00080 : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y) 00081 { 00082 if(displayproto==SPI_8) 00083 { 00084 proto = new SPI8(Hz, mosi, miso, sclk, CS, reset, DC); 00085 useNOP=false; 00086 } 00087 else if(displayproto==SPI_16) 00088 { 00089 proto = new SPI16(Hz, mosi, miso, sclk, CS, reset, DC); 00090 useNOP=true; 00091 } 00092 scrollbugfix=0; 00093 mipistd=false; 00094 set_orientation(0); 00095 foreground(White); 00096 background(Black); 00097 set_auto_up(false); 00098 topfixedareasize=0; 00099 scrollareasize=0; 00100 usefastwindow=false; 00101 fastwindowready=false; 00102 is18bit=false; 00103 isBGR=false; 00104 // locate(0,0); 00105 } 00106 void TFT::wr_cmd8(unsigned char cmd) 00107 { 00108 if(useNOP) proto->wr_cmd16(cmd); // 0x0000|cmd, 00 is NOP cmd for TFT 00109 else proto->wr_cmd8(cmd); 00110 } 00111 void TFT::wr_data8(unsigned char data) 00112 { 00113 proto->wr_data8(data); 00114 } 00115 void TFT::wr_data16(unsigned short data) 00116 { 00117 proto->wr_data16(data); 00118 } 00119 void TFT::wr_gram(unsigned short data) 00120 { 00121 proto->wr_gram(data); 00122 } 00123 void TFT::wr_gram(unsigned short data, unsigned int count) 00124 { 00125 proto->wr_gram(data, count); 00126 } 00127 void TFT::wr_grambuf(unsigned short* data, unsigned int lenght) 00128 { 00129 proto->wr_grambuf(data, lenght); 00130 } 00131 unsigned short TFT::rd_gram() 00132 { 00133 return proto->rd_gram(is18bit); // protocol will handle 18to16 bit conversion 00134 } 00135 unsigned int TFT::rd_reg_data32(unsigned char reg) 00136 { 00137 return proto->rd_reg_data32(reg); 00138 } 00139 unsigned int TFT::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd) 00140 { 00141 return proto->rd_extcreg_data32(reg, SPIreadenablecmd); 00142 } 00143 //for TFT, just send data, position counters are in hw 00144 void TFT::window_pushpixel(unsigned short color) 00145 { 00146 proto->wr_gram(color); 00147 } 00148 void TFT::window_pushpixel(unsigned short color, unsigned int count) 00149 { 00150 proto->wr_gram(color, count); 00151 } 00152 void TFT::window_pushpixelbuf(unsigned short* color, unsigned int lenght) 00153 { 00154 proto->wr_grambuf(color, lenght); 00155 } 00156 void TFT::hw_reset() 00157 { 00158 proto->hw_reset(); 00159 BusEnable(true); 00160 } 00161 void TFT::BusEnable(bool enable) 00162 { 00163 proto->BusEnable(enable); 00164 } 00165 // color TFT can rotate in hw (swap raw<->columns) for landscape views 00166 void TFT::set_orientation(int o) 00167 { 00168 orientation = o; 00169 wr_cmd8(0x36); 00170 switch (orientation) { 00171 case 0:// default, portrait view 0° 00172 if(mipistd) wr_data8(0x0A); // this is in real a vertical flip enabled, seems most displays are vertical flipped 00173 else wr_data8(0x48); //for some other ILIxxxx 00174 set_width(screensize_X); 00175 set_height(screensize_Y); 00176 break; 00177 case 1:// landscape view +90° 00178 if(mipistd) wr_data8(0x28); 00179 else wr_data8(0x29);//for some other ILIxxxx 00180 set_width(screensize_Y); 00181 set_height(screensize_X); 00182 break; 00183 case 2:// portrait view +180° 00184 if(mipistd) wr_data8(0x09); 00185 else wr_data8(0x99);//for some other ILIxxxx 00186 set_width(screensize_X); 00187 set_height(screensize_Y); 00188 break; 00189 case 3:// landscape view -90° 00190 if(mipistd) wr_data8(0x2B); 00191 else wr_data8(0xF8);//for some other ILIxxxx 00192 set_width(screensize_Y); 00193 set_height(screensize_X); 00194 break; 00195 } 00196 } 00197 void TFT::invert(unsigned char o) 00198 { 00199 if(o == 0) wr_cmd8(0x20); 00200 else wr_cmd8(0x21); 00201 } 00202 void TFT::FastWindow(bool enable) 00203 { 00204 usefastwindow=enable; 00205 } 00206 // TFT have both column and raw autoincrement inside a window, with internal counters 00207 void TFT::window(int x, int y, int w, int h) 00208 { 00209 fastwindowready=false; // end raw/column going to be set to lower value than bottom-right corner 00210 wr_cmd8(0x2A); 00211 wr_data16(x); //start column 00212 wr_data16(x+w-1);//end column 00213 00214 wr_cmd8(0x2B); 00215 wr_data16(y); //start page 00216 wr_data16(y+h-1);//end page 00217 00218 wr_cmd8(0x2C); //write mem, just send pixels color next 00219 } 00220 void TFT::window4read(int x, int y, int w, int h) 00221 { 00222 fastwindowready=false; 00223 wr_cmd8(0x2A); 00224 wr_data16(x); //start column 00225 wr_data16(x+w-1);//end column 00226 00227 wr_cmd8(0x2B); 00228 wr_data16(y); //start page 00229 wr_data16(y+h-1);//end page 00230 00231 wr_cmd8(0x2E); //read mem, just pixelread next 00232 } 00233 void TFT::pixel(int x, int y, unsigned short color) 00234 { 00235 if(usefastwindow) //ili9486 does not like truncated 2A/2B cmds, at least in par mode 00236 { 00237 if(fastwindowready) //setting only start column/page does speedup, but needs end raw/column previously set to bottom-right corner 00238 { 00239 wr_cmd8(0x2A); 00240 wr_data16(x); //start column only 00241 wr_cmd8(0x2B); 00242 wr_data16(y); //start page only 00243 wr_cmd8(0x2C); //write mem, just send pixels color next 00244 } 00245 else 00246 { 00247 window(x,y,width()-x,height()-y); // set also end raw/column to bottom-right corner 00248 fastwindowready=true; 00249 } 00250 } 00251 else window(x,y,1,1); 00252 // proto->wr_gram(color); // 2C expects 16bit parameters 00253 wr_gram(color); 00254 } 00255 unsigned short TFT::pixelread(int x, int y) 00256 { 00257 if(usefastwindow) //ili9486 does not like truncated 2A/2B cmds, at least in par mode 00258 { 00259 if(fastwindowready) //setting only start column/page does speedup, but needs end raw/column previously set to bottom-right corner 00260 { 00261 wr_cmd8(0x2A); 00262 wr_data16(x); //start column only 00263 wr_cmd8(0x2B); 00264 wr_data16(y); //start page only 00265 wr_cmd8(0x2E); //read mem, just pixelread next 00266 } 00267 else 00268 { 00269 window4read(x,y,width()-x,height()-y); // set also end raw/column to bottom-right corner 00270 fastwindowready=true; 00271 } 00272 } 00273 else window4read(x,y,1,1); 00274 00275 unsigned short color; 00276 // proto->wr_gram(color); // 2C expects 16bit parameters 00277 color = rd_gram(); 00278 if(isBGR) color = BGR2RGB(color); // in case, convert BGR to RGB (should depend on cmd36 bit3) but maybe is device specific 00279 return color; 00280 } 00281 void TFT::setscrollarea (int startY, int areasize) // ie 0,480 for whole screen 00282 { 00283 unsigned int bfa; 00284 topfixedareasize=startY; 00285 scrollareasize=areasize; 00286 wr_cmd8(0x33); 00287 wr_data16(topfixedareasize); //num lines of top fixed area 00288 wr_data16(scrollareasize+scrollbugfix); //num lines of vertical scroll area, +1 for ILI9481 fix 00289 if((areasize+startY)>screensize_Y) bfa=0; 00290 else bfa = screensize_Y-(areasize+startY); 00291 wr_data16(bfa); //num lines of bottom fixed area 00292 } 00293 void TFT::scroll (int lines) // ie 1= scrollup 1, 479= scrolldown 1 00294 { 00295 wr_cmd8(0x37); 00296 wr_data16(topfixedareasize+(lines%scrollareasize)); // select the (absolute)line which will be displayed as first scrollarea line 00297 } 00298 void TFT::scrollreset() 00299 { 00300 wr_cmd8(0x13); //normal display mode 00301 } 00302 void TFT::cls (void) 00303 { 00304 WindowMax(); 00305 // proto->wr_gram(_background,screensize_X*screensize_Y); 00306 // proto->wr_gram(0,screensize_X*screensize_Y); 00307 wr_gram(_background,screensize_X*screensize_Y); 00308 } 00309 // try to get read gram pixel format, could be 16bit or 18bit, RGB or BGR 00310 void TFT::auto_gram_read_format() 00311 { 00312 unsigned short px=0xCDB1; 00313 unsigned short rback, rback18; 00314 pixel(0,0,px); 00315 window4read(0,0,1,1); 00316 rback=proto->rd_gram(0); // try 16bit 00317 window4read(0,0,1,1); 00318 rback18=proto->rd_gram(1); // try 18bit converted to 16 00319 if((rback18==px) || (BGR2RGB(rback18)==px)) 00320 { 00321 is18bit=true; 00322 if(BGR2RGB(rback18)==px) isBGR=true; 00323 } 00324 else if((rback==px) || (BGR2RGB(rback)==px)) 00325 { 00326 if(BGR2RGB(rback)==px) isBGR=true; 00327 } 00328 // debug("\r\nIdentify gram read color format,\r\nsent %.4X read16 %.4X(bgr%.4X) read18 %.4X(bgr%.4X)", px, rback, BGR2RGB(rback), rback18, BGR2RGB(rback18)); 00329 } 00330 // try to identify display controller 00331 void TFT::identify() 00332 { 00333 // MIPI std read ID cmd 00334 tftID=rd_reg_data32(0xBF); 00335 mipistd=true; 00336 // debug("ID MIPI : 0x%8X\r\n",tftID); 00337 if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF))) 00338 { 00339 mipistd=false; 00340 // ILI specfic read ID cmd 00341 tftID=rd_reg_data32(0xD3)>>8; 00342 // debug("ID ILI : 0x%8X\r\n",tftID); 00343 } 00344 if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF))) 00345 { 00346 // ILI specfic read ID cmd with ili9341 specific spi read-in enable 0xD9 cmd 00347 tftID=rd_extcreg_data32(0xD3, 0xD9); 00348 // debug("ID D9 extc ILI : 0x%8X\r\n",tftID); 00349 } 00350 if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF))) 00351 { 00352 // ILI specfic read ID cmd with ili9486/88 specific spi read-in enable 0xFB cmd 00353 tftID=rd_extcreg_data32(0xD3, 0xFB); 00354 // debug("ID D9 extc ILI : 0x%8X\r\n",tftID); 00355 } 00356 if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF))) tftID=0xDEAD; 00357 if ((tftID&0xFFFF)==0x9481) scrollbugfix=1; 00358 else scrollbugfix=0; 00359 hw_reset(); // in case wrong cmds messed up important settings 00360 } 00361 int TFT::sizeX() 00362 { 00363 return screensize_X; 00364 } 00365 int TFT::sizeY() 00366 { 00367 return screensize_Y; 00368 }
Generated on Fri Jul 15 2022 13:58:04 by
