Frank Duignan
/
NRF52832_ili9341
Basic driver working
Embed:
(wiki syntax)
Show/hide line numbers
display.cpp
00001 #include "mbed.h" 00002 #include "display.h" 00003 #include "font5x7.h" 00004 extern Serial g_Serial_pc; 00005 //mosi,miso,clk,ss 00006 SPI spi(P0_25,P0_26,P0_27); 00007 DigitalOut Rst(P0_7); 00008 DigitalOut DC(P0_6); 00009 DigitalOut D_CS(P0_28); 00010 DigitalOut T_CS(P0_5); 00011 DigitalIn PenIRQ(P0_4); 00012 void Display::begin() 00013 { 00014 00015 spi.format(8, 0); 00016 spi.frequency(8000000); 00017 T_CS = 1; // de-assert the touch interface for now 00018 D_CS = 1; 00019 00020 resetDisplay(); 00021 00022 LCD_Write_Data(0x21); // Set GVDD (varies contrast) 00023 00024 LCD_Write_Cmd(0xC0); // Power control 00025 LCD_Write_Data(0x21); // Set GVDD (varies contrast) 00026 00027 LCD_Write_Cmd(0xC1); // Power control 00028 LCD_Write_Data(0x10); // default value 00029 00030 LCD_Write_Cmd(0xC5); //VCM control 00031 LCD_Write_Data(0x31); // default values 00032 LCD_Write_Data(0x3c); // 00033 00034 LCD_Write_Cmd(0xC7); //VCM control2 00035 LCD_Write_Data(0xc0); // default value 00036 00037 LCD_Write_Cmd(0x36); // Memory Access Control 00038 LCD_Write_Data(0x48); // Set display orientation and RGB colour order 00039 00040 LCD_Write_Cmd(0x3A); // Set Pixel format 00041 LCD_Write_Data(0x55); // To 16 bits per pixel 00042 00043 LCD_Write_Cmd(0xB1); // Frame rate control 00044 LCD_Write_Data(0x00); // Use Fosc without divisor 00045 LCD_Write_Data(0x1B); // set 70Hz refresh rate 00046 00047 LCD_Write_Cmd(0xB6); // Display Function Control 00048 LCD_Write_Data(0x00); // Use default values 00049 LCD_Write_Data(0x82); 00050 LCD_Write_Data(0x27); 00051 LCD_Write_Cmd(0x11); //Exit Sleep 00052 wait(0.120); 00053 00054 LCD_Write_Cmd(0x29); //Display on 00055 LCD_Write_Cmd(0x2c); 00056 wait(0.005); 00057 00058 fillRectangle(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,RGBToWord(0x00,0,0)); 00059 D_CS = 1; 00060 00061 } 00062 00063 void Display::CommandMode() 00064 { 00065 DC = 0; 00066 } 00067 void Display::DataMode() 00068 { 00069 DC = 1; 00070 } 00071 void Display::LCD_Write_Cmd(uint8_t cmd) 00072 { 00073 00074 CommandMode(); 00075 D_CS = 0; 00076 spi.write(cmd); 00077 D_CS = 1; 00078 } 00079 void Display::LCD_Write_Data(uint8_t data) 00080 { 00081 00082 DataMode(); 00083 D_CS = 0; 00084 spi.write(data); 00085 D_CS = 1; 00086 } 00087 void Display::resetDisplay() 00088 { 00089 Rst = 0; 00090 wait(0.01); 00091 Rst = 1; 00092 wait(0.12); 00093 } 00094 void Display::openAperture(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) 00095 { 00096 LCD_Write_Cmd(0x2a); 00097 LCD_Write_Data(x1>>8); 00098 LCD_Write_Data(x1); 00099 LCD_Write_Data(x2>>8); 00100 LCD_Write_Data(x2); 00101 LCD_Write_Cmd(0x2b); 00102 LCD_Write_Data(y1>>8); 00103 LCD_Write_Data(y1); 00104 LCD_Write_Data(y2>>8); 00105 LCD_Write_Data(y2); 00106 LCD_Write_Cmd(0x2c); 00107 } 00108 // Simple Pixel drawing routines 00109 void Display::putPixel(uint16_t x, uint16_t y, uint16_t Colour) 00110 { 00111 uint16_t rx; 00112 00113 openAperture(x,y,x+1,y+1); 00114 DataMode(); 00115 D_CS = 0; 00116 spi.write((const char *) &Colour,2,(char *)&rx,0); 00117 D_CS = 1; 00118 } 00119 void Display::putImage(uint16_t xofs, uint16_t yofs, uint16_t width, uint16_t height, const uint16_t *Image) 00120 { 00121 uint16_t rx; 00122 uint16_t Colour; 00123 00124 uint16_t x,y; 00125 for (y = 0; y < height; y++) { 00126 for (x=0; x < width; x++) 00127 { 00128 Colour = *(Image++); 00129 putPixel(x+xofs,y+yofs,Colour); 00130 } 00131 } 00132 } 00133 void Display::fillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t Colour) 00134 { 00135 /* in an effort to reduce overhead here a large word buffer is created. If the number of words to 00136 to write is greater than or equal to the size of this buffer then it is filled with the relevant colour 00137 and used as the source of data in the spi.write function. This greatly speeds up the writing of 00138 large arease of the screen. The choice of buffer size is interesting. 00139 */ 00140 #define BUF_SIZE 32 00141 uint16_t rx; 00142 uint16_t txBuffer[BUF_SIZE]; 00143 int count; 00144 openAperture(x,y,width,height); 00145 DataMode(); 00146 D_CS = 0; 00147 count = (width*height)/BUF_SIZE; 00148 if (count) 00149 { // big area 00150 for (int i=0;i<BUF_SIZE;i++) 00151 { 00152 txBuffer[i]=Colour; 00153 } 00154 while(count--) 00155 { 00156 spi.write((const char *)txBuffer,2*BUF_SIZE,(char *)&rx,0); 00157 } 00158 count = (width*height)%BUF_SIZE; // write remainder of block 00159 while (count--) 00160 { 00161 spi.write((const char *) &Colour,2,(char *)&rx,0); // write a block of colour 00162 } 00163 00164 } 00165 else 00166 { 00167 // small area so write 1 word at a time. 00168 count = (width*height); 00169 while(count--) 00170 { 00171 spi.write((const char *) &Colour,2,(char *)&rx,0); 00172 } 00173 00174 } 00175 D_CS = 1; 00176 } 00177 00178 void Display::drawLineLowSlope(uint16_t x0, uint16_t y0, uint16_t x1,uint16_t y1, uint16_t Colour) 00179 { 00180 // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 00181 int dx = x1 - x0; 00182 int dy = y1 - y0; 00183 int yi = 1; 00184 if (dy < 0) 00185 { 00186 yi = -1; 00187 dy = -dy; 00188 } 00189 int D = 2*dy - dx; 00190 00191 int y = y0; 00192 00193 for (int x=x0; x <= x1;x++) 00194 { 00195 putPixel(x,y,Colour); 00196 if (D > 0) 00197 { 00198 y = y + yi; 00199 D = D - 2*dx; 00200 } 00201 D = D + 2*dy; 00202 00203 } 00204 } 00205 00206 void Display::drawLineHighSlope(uint16_t x0, uint16_t y0, uint16_t x1,uint16_t y1, uint16_t Colour) 00207 { 00208 // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 00209 00210 int dx = x1 - x0; 00211 int dy = y1 - y0; 00212 int xi = 1; 00213 if (dx < 0) 00214 { 00215 xi = -1; 00216 dx = -dx; 00217 } 00218 int D = 2*dx - dy; 00219 int x = x0; 00220 00221 for (int y=y0; y <= y1; y++) 00222 { 00223 putPixel(x,y,Colour); 00224 if (D > 0) 00225 { 00226 x = x + xi; 00227 D = D - 2*dy; 00228 } 00229 D = D + 2*dx; 00230 } 00231 } 00232 void Display::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t Colour) 00233 { 00234 // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 00235 D_CS = 0; 00236 if ( iabs(y1 - y0) < iabs(x1 - x0) ) 00237 { 00238 if (x0 > x1) 00239 { 00240 drawLineLowSlope(x1, y1, x0, y0, Colour); 00241 } 00242 else 00243 { 00244 drawLineLowSlope(x0, y0, x1, y1, Colour); 00245 } 00246 } 00247 else 00248 { 00249 if (y0 > y1) 00250 { 00251 drawLineHighSlope(x1, y1, x0, y0, Colour); 00252 } 00253 else 00254 { 00255 drawLineHighSlope(x0, y0, x1, y1, Colour); 00256 } 00257 00258 } 00259 D_CS = 1; 00260 } 00261 00262 00263 uint16_t Display::RGBToWord(uint16_t R, uint16_t G, uint16_t B) 00264 { 00265 uint16_t rvalue = 0; 00266 rvalue += G >> 5; 00267 rvalue += (G & (0b111)) << 13; 00268 rvalue += (B >> 3) << 8; 00269 rvalue += (R >> 3) << 3; 00270 return rvalue; 00271 } 00272 void Display::drawRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t Colour) 00273 { 00274 drawLine(x,y,x+w,y,Colour); 00275 drawLine(x,y,x,y+h,Colour); 00276 drawLine(x+w,y,x+w,y+h,Colour); 00277 drawLine(x,y+h,x+w,y+h,Colour); 00278 } 00279 00280 void Display::drawCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t Colour) 00281 { 00282 // Reference : https://en.wikipedia.org/wiki/Midpoint_circle_algorithm 00283 int x = radius-1; 00284 int y = 0; 00285 int dx = 1; 00286 int dy = 1; 00287 int err = dx - (radius << 1); 00288 if (radius > x0) 00289 return; // don't draw even parially off-screen circles 00290 if (radius > y0) 00291 return; // don't draw even parially off-screen circles 00292 00293 if ((x0+radius) > SCREEN_WIDTH) 00294 return; // don't draw even parially off-screen circles 00295 if ((y0+radius) > SCREEN_HEIGHT) 00296 return; // don't draw even parially off-screen circles 00297 while (x >= y) 00298 { 00299 putPixel(x0 + x, y0 + y, Colour); 00300 putPixel(x0 + y, y0 + x, Colour); 00301 putPixel(x0 - y, y0 + x, Colour); 00302 putPixel(x0 - x, y0 + y, Colour); 00303 putPixel(x0 - x, y0 - y, Colour); 00304 putPixel(x0 - y, y0 - x, Colour); 00305 putPixel(x0 + y, y0 - x, Colour); 00306 putPixel(x0 + x, y0 - y, Colour); 00307 00308 if (err <= 0) 00309 { 00310 y++; 00311 err += dy; 00312 dy += 2; 00313 } 00314 00315 if (err > 0) 00316 { 00317 x--; 00318 dx += 2; 00319 err += dx - (radius << 1); 00320 } 00321 } 00322 } 00323 void Display::fillCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t Colour) 00324 { 00325 // Reference : https://en.wikipedia.org/wiki/Midpoint_circle_algorithm 00326 // Similar to drawCircle but fills the circle with lines instead 00327 int x = radius-1; 00328 int y = 0; 00329 int dx = 1; 00330 int dy = 1; 00331 int err = dx - (radius << 1); 00332 00333 if (radius > x0) 00334 return; // don't draw even parially off-screen circles 00335 if (radius > y0) 00336 return; // don't draw even parially off-screen circles 00337 00338 if ((x0+radius) > SCREEN_WIDTH) 00339 return; // don't draw even parially off-screen circles 00340 if ((y0+radius) > SCREEN_HEIGHT) 00341 return; // don't draw even parially off-screen circles 00342 while (x >= y) 00343 { 00344 drawLine(x0 - x, y0 + y,x0 + x, y0 + y, Colour); 00345 drawLine(x0 - y, y0 + x,x0 + y, y0 + x, Colour); 00346 drawLine(x0 - x, y0 - y,x0 + x, y0 - y, Colour); 00347 drawLine(x0 - y, y0 - x,x0 + y, y0 - x, Colour); 00348 00349 if (err <= 0) 00350 { 00351 y++; 00352 err += dy; 00353 dy += 2; 00354 } 00355 00356 if (err > 0) 00357 { 00358 x--; 00359 dx += 2; 00360 err += dx - (radius << 1); 00361 } 00362 } 00363 } 00364 void Display::print(const char *Text, uint16_t len, uint16_t x, uint16_t y, uint16_t ForeColour, uint16_t BackColour) 00365 { 00366 // This function draws each character individually. It uses an array called TextBox as a temporary storage 00367 // location to hold the dots for the character in question. It constructs the image of the character and then 00368 // calls on putImage to place it on the screen 00369 uint8_t Index = 0; 00370 uint8_t Row, Col; 00371 const uint8_t *CharacterCode = 0; 00372 uint16_t TextBox[FONT_WIDTH * FONT_HEIGHT]; 00373 for (Index = 0; Index < len; Index++) 00374 { 00375 CharacterCode = &Font5x7[FONT_WIDTH * (Text[Index] - 32)]; 00376 Col = 0; 00377 while (Col < FONT_WIDTH) 00378 { 00379 Row = 0; 00380 while (Row < FONT_HEIGHT) 00381 { 00382 if (CharacterCode[Col] & (1 << Row)) 00383 { 00384 TextBox[(Row * FONT_WIDTH) + Col] = ForeColour; 00385 } 00386 else 00387 { 00388 TextBox[(Row * FONT_WIDTH) + Col] = BackColour; 00389 } 00390 Row++; 00391 } 00392 Col++; 00393 } 00394 putImage(x, y, FONT_WIDTH, FONT_HEIGHT, (const uint16_t *)TextBox); 00395 x = x + FONT_WIDTH + 2; 00396 } 00397 } 00398 void Display::print(uint16_t Number, uint16_t x, uint16_t y, uint16_t ForeColour, uint16_t BackColour) 00399 { 00400 // This function converts the supplied number into a character string and then calls on puText to 00401 // write it to the display 00402 char Buffer[5]; // Maximum value = 65535 00403 Buffer[4] = Number % 10 + '0'; 00404 Number = Number / 10; 00405 Buffer[3] = Number % 10 + '0'; 00406 Number = Number / 10; 00407 Buffer[2] = Number % 10 + '0'; 00408 Number = Number / 10; 00409 Buffer[1] = Number % 10 + '0'; 00410 Number = Number / 10; 00411 Buffer[0] = Number % 10 + '0'; 00412 print(Buffer, 5, x, y, ForeColour, BackColour); 00413 } 00414 void Display::initTouch(void) 00415 { 00416 // This display module has an XPT2046 touch screen controller connected over the SPI interface 00417 // The XPT2046 00418 T_CS = 0; 00419 spi.write(0b10011000); // 8 bit conversion, ratiometric measurement, read XP 00420 //wait_us(100); 00421 uint16_t indata,outdata; 00422 outdata = 0xffff; 00423 spi.write((const char *) &outdata,2,(char *)&indata,2); // write a block of colour 00424 T_CS = 1; 00425 } 00426 uint16_t Display::readYTouch(void) 00427 { 00428 // This display module has an XPT2046 touch screen controller connected over the SPI interface 00429 // The XPT2046 00430 /* 00431 Format of command word : 00432 b7 : must be 1 00433 b6,5,4 : A2,A1,A0 00434 000 : temperature 00435 00436 b3 : Mode 00437 b2 : SER,DFR 00438 b1,0 : PD1,PD0 00439 */ 00440 uint16_t indata,outdata; 00441 spi.frequency(2000000); // Can't run the touch screen controller at high speed 00442 T_CS = 0; 00443 spi.write((uint8_t)0b10011000); // 12 bit conversion, ratiometric measurement, reference off 00444 // read XP which tells us Y (see diagram in datasheet) 00445 wait_us(20); 00446 outdata = 0xffff; 00447 spi.write((const char *) &outdata,2,(char *)&indata,2); 00448 T_CS = 1; 00449 spi.frequency(8000000); 00450 int calibrated_return= (indata>>12)+((indata & 0xff)<<4); 00451 calibrated_return = (calibrated_return - Y_TOUCH_MIN); 00452 if (calibrated_return < 0) 00453 calibrated_return = 0; 00454 calibrated_return = (calibrated_return * SCREEN_HEIGHT) / (Y_TOUCH_MAX - Y_TOUCH_MIN) ; 00455 return calibrated_return; 00456 } 00457 uint16_t Display::readXTouch(void) 00458 { 00459 // This display module has an XPT2046 touch screen controller connected over the SPI interface 00460 // The XPT2046 00461 /* 00462 Format of command word : 00463 b7 : must be 1 00464 b6,5,4 : A2,A1,A0 00465 000 : temperature 00466 00467 b3 : Mode 00468 b2 : SER,DFR 00469 b1,0 : PD1,PD0 00470 */ 00471 uint16_t indata,outdata; 00472 spi.frequency(2000000);// Can't run the touch screen controller at high speed 00473 T_CS = 0; 00474 spi.write((uint8_t)0b11011000); // 12 bit conversion, ratiometric measurement, reference off 00475 // read YP which tells us X (see diagram in datasheet) 00476 wait_us(20); 00477 outdata = 0xffff; 00478 spi.write((const char *) &outdata,2,(char *)&indata,2); 00479 T_CS = 1; 00480 spi.frequency(8000000); 00481 int calibrated_return= (indata>>12)+((indata & 0xff)<<4); 00482 calibrated_return = (calibrated_return - X_TOUCH_MIN); 00483 if (calibrated_return < 0) 00484 calibrated_return = 0; 00485 calibrated_return = (calibrated_return * SCREEN_WIDTH) / (X_TOUCH_MAX - X_TOUCH_MIN); 00486 // The X reading is backwards so need to subtract it from the screen width 00487 calibrated_return = SCREEN_WIDTH - calibrated_return; 00488 if (calibrated_return < 0) 00489 calibrated_return = 0; 00490 return calibrated_return; 00491 } 00492 int Display::penDown(void) 00493 { 00494 if (PenIRQ.read()==0) 00495 return 1; 00496 else 00497 return 0; 00498 }
Generated on Sun Jul 17 2022 14:12:37 by 1.7.2