Basic driver working

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers display.cpp Source File

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 }