Sparkfun's Nokia Color LCD Arduino Shield library for FRDM boards

Dependents:   ColorLCDShield_Conway

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ColorLCDShield.cpp Source File

ColorLCDShield.cpp

00001 // ==================================================== Nov 08 2013, kayeks ==
00002 // ColorLCDShield.cpp
00003 // ===========================================================================
00004 // Sparkfun's Color LCD Shield (LCD-09363) library for mbed FRDM-KL25Z boards.
00005 //   - https://www.sparkfun.com/products/9363
00006 //     This library has modified from Sparkfun's Arduino library code
00007 //   - Command/data transmissions are implemented as software SPI communication
00008 //     because the FRDM board's MCUs are not 9-bit SPI capable :(
00009 //   - License is `CC BY-SA 3.0'
00010 //   - Original descriptions are below
00011 
00012 /*
00013   LCDShield.cpp - Arduino Library to control a Nokia 6100 LCD, 
00014   specifically that found on SparkFun's Color LCD Shield.
00015   This code should work for both Epson and Phillips display drivers 
00016   normally found on the Color LCD Shield.
00017     
00018   License: CC BY-SA 3.0: Creative Commons Share-alike 3.0. Feel free 
00019   to use and abuse this code however you'd like. If you find it useful
00020   please attribute, and SHARE-ALIKE!
00021   
00022   This is based on code by Mark Sproul, and Peter Davenport.
00023   Thanks to Coleman Sellers and Harold Timmis for help getting it to work with the Phillips Driver 7-31-2011
00024 */
00025 
00026 #include "ColorLCDShield.h"
00027 
00028 /*extern "C" {
00029     #include "wiring.h"
00030 }*/
00031 
00032 #include "mbed.h"
00033 // #include "Arduino.h"
00034 
00035 // static char x_offset = 0;
00036 // static char y_offset = 0;
00037 
00038 DigitalOut res(D8);   // Arduino D8
00039 DigitalOut cs(D9);    // Arduino D9
00040 DigitalOut dio(D11);  // Arduino D11
00041 DigitalOut sck(D13);  // Arduino D13
00042 
00043 LCDShield::LCDShield()
00044 {
00045 }
00046 
00047 void LCDShield::LCDCommand(unsigned char data)
00048 {
00049     char jj;
00050 
00051     cs = 0;     // enable chip
00052     dio = 0;   // output low on data out (9th bit low = command)
00053 
00054     sck = 0;   // send clock pulse
00055     // wait_us(1);
00056     sck = 1;
00057 
00058     for (jj = 0; jj < 8; jj++)
00059     {
00060         if ((data & 0x80) == 0x80)
00061             dio = 1;
00062         else
00063             dio = 0;
00064 
00065         sck = 0; // send clock pulse
00066         // wait_us(1);
00067         sck = 1;
00068 
00069         data <<= 1;
00070     }
00071 
00072     cs = 1;     // disable
00073 }
00074 
00075 void LCDShield::LCDData(unsigned char data)
00076 {
00077     char j;
00078 
00079     cs = 0;     // enable chip
00080     dio = 1;   // output high on data out (9th bit high = data)
00081 
00082     sck = 0;   // send clock pulse
00083     // wait_us(1);
00084     sck = 1;   // send clock pulse
00085 
00086     for (j = 0; j < 8; j++)
00087     {
00088         if ((data & 0x80) == 0x80)
00089             dio = 1;
00090         else
00091             dio = 0;
00092     
00093         sck = 0; // send clock pulse
00094         // wait_us(1);
00095         sck = 1;
00096 
00097         data <<= 1;
00098     }
00099 
00100     cs = 1;  // disable
00101 }
00102 
00103 void LCDShield::init(int type, bool colorSwap)
00104 {
00105     driver = type;
00106     
00107     // Initialize the control pins, and reset display:
00108     sck = 0; // CLK = LOW
00109     dio = 0;     // DIO = LOW
00110     wait_us(10);      // 10us delay
00111     cs = 1;       // CS = HIGH
00112     wait_us(10);      // 10uS Delay
00113     res = 0; // RESET = LOW
00114     wait_ms(200);                 // 200ms delay
00115     res = 1; // RESET = HIGH
00116     wait_ms(200);                 // 200ms delay
00117     sck = 1; // SCK_PIN = HIGH
00118     dio = 1;     // DIO = HIGH
00119     wait_us(10);      // 10us delay
00120     
00121     if (driver == EPSON)
00122     {
00123         LCDCommand(DISCTL); // Display control (0xCA)
00124         LCDData(0x0C);      // 12 = 1100 - CL dividing ratio [don't divide] switching period 8H (default)
00125         LCDData(0x20);      // nlines/4 - 1 = 132/4 - 1 = 32 duty
00126         LCDData(0x00);      // No inversely highlighted lines
00127         
00128         LCDCommand(COMSCN); // common scanning direction (0xBB)
00129         LCDData(0x01);      // 1->68, 132<-69 scan direction
00130         
00131         LCDCommand(OSCON);  // internal oscialltor ON (0xD1)
00132         LCDCommand(SLPOUT); // sleep out (0x94)
00133         
00134         LCDCommand(PWRCTR); // power ctrl (0x20)
00135         LCDData(0x0F);      // everything on, no external reference resistors
00136         
00137         LCDCommand(DISINV); // invert display mode (0xA7)
00138         
00139         LCDCommand(DATCTL); // data control (0xBC)
00140         LCDData(0x03);      // Inverse page address, reverse rotation column address, column scan-direction !!! try 0x01
00141         LCDData(0x00);      // normal RGB arrangement
00142         LCDData(0x02);      // 16-bit Grayscale Type A (12-bit color)
00143         
00144         LCDCommand(VOLCTR); // electronic volume, this is the contrast/brightness (0x81)
00145         LCDData(32);        // volume (contrast) setting - fine tuning, original (0-63)
00146         LCDData(3);         // internal resistor ratio - coarse adjustment (0-7)
00147         
00148         LCDCommand(NOP);    // nop (0x25)
00149 
00150         wait_ms(100);
00151 
00152         LCDCommand(DISON);  // display on (0xAF)
00153     }
00154     else if (driver == PHILIPS)
00155     {
00156         LCDCommand(SLEEPOUT);   // Sleep Out (0x11)
00157         LCDCommand(BSTRON);     // Booster voltage on (0x03)
00158         LCDCommand(DISPON);     // Display on (0x29)
00159         
00160         //LCDCommand(INVON);        // Inversion on (0x20)
00161         
00162         // 12-bit color pixel format:
00163         LCDCommand(COLMOD);     // Color interface format (0x3A)
00164         LCDData(0x03);          // 0b011 is 12-bit/pixel mode
00165         
00166         LCDCommand(MADCTL);     // Memory Access Control(PHILLIPS)
00167         if (colorSwap) 
00168             LCDData(0x08);
00169         else
00170             LCDData(0x00);
00171         
00172         LCDCommand(SETCON);     // Set Contrast(PHILLIPS)
00173         LCDData(0x30);
00174         
00175         LCDCommand(NOPP);       // nop(PHILLIPS)
00176     }
00177 }
00178 
00179 void LCDShield::clear(int color)
00180 {
00181     if (driver) // if it's an Epson
00182     {
00183         LCDCommand(PASET);
00184         LCDData(0);
00185         LCDData(131);
00186 
00187         LCDCommand(CASET);
00188         LCDData(0);
00189         LCDData(131);
00190 
00191         LCDCommand(RAMWR);
00192     }
00193     else // otherwise it's a phillips
00194     {
00195         LCDCommand(PASETP);
00196         LCDData(0);
00197         LCDData(131);
00198 
00199         LCDCommand(CASETP);
00200         LCDData(0);
00201         LCDData(131);
00202 
00203         LCDCommand(RAMWRP);
00204     }
00205 
00206     for(unsigned int i=0; i < (131*131)/2; i++)
00207     {
00208         LCDData((color>>4)&0x00FF);
00209         LCDData(((color&0x0F)<<4)|(color>>8));
00210         LCDData(color&0x0FF);
00211     }
00212 
00213     // x_offset = 0;
00214     // y_offset = 0;
00215 }
00216 
00217 void LCDShield::contrast(char setting)
00218 {
00219     if (driver == EPSON)
00220     {
00221         setting &= 0x3F;    // 2 msb's not used, mask out
00222         LCDCommand(VOLCTR); // electronic volume, this is the contrast/brightness(EPSON)
00223         LCDData(setting);   // volume (contrast) setting - course adjustment,  -- original was 24
00224         LCDData(3);         // TODO: Make this coarse adjustment variable, 3's a good place to stay
00225     }
00226     else if (driver == PHILIPS)
00227     {
00228         setting &= 0x7F;    // msb is not used, mask it out
00229         LCDCommand(SETCON); // contrast command (PHILLIPS)
00230         LCDData(setting);   // volume (contrast) setting - course adjustment,  -- original was 24
00231     }
00232 }
00233 
00234 // Added by Steve Sparks @ Big Nerd Ranch.
00235 // This swaps the Epson RGB order into the Philips RGB order. (Or, vice versa, I suppose.)
00236 uint16_t LCDShield::swapColors(uint16_t in) {
00237     return ((in & 0x000F)<<8)|(in & 0x00F0)|((in & 0x0F00)>>8);
00238 }
00239 
00240 void LCDShield::setPixel(int color, unsigned char x, unsigned char y)
00241 {
00242     y   =   (COL_HEIGHT - 1) - y;
00243     x = (ROW_LENGTH - 1) - x;
00244 
00245     if (driver == EPSON) // if it's an epson
00246     {
00247         LCDCommand(PASET);  // page start/end ram
00248         LCDData(x);
00249         LCDData(ENDPAGE);
00250 
00251         LCDCommand(CASET);  // column start/end ram
00252         LCDData(y);
00253         LCDData(ENDCOL);
00254 
00255         LCDCommand(RAMWR);  // write
00256         LCDData((color>>4)&0x00FF);
00257         LCDData(((color&0x0F)<<4)|(color>>8));
00258         LCDData(color&0x0FF);
00259     }
00260     else if (driver == PHILIPS)  // otherwise it's a phillips
00261     {
00262         LCDCommand(PASETP); // page start/end ram
00263         LCDData(x);
00264         LCDData(x);
00265 
00266         LCDCommand(CASETP); // column start/end ram
00267         LCDData(y);
00268         LCDData(y);
00269 
00270         LCDCommand(RAMWRP); // write
00271 
00272         LCDData((unsigned char)((color>>4)&0x00FF));
00273         LCDData((unsigned char)(((color&0x0F)<<4)|0x00));
00274     }
00275 }
00276 // 2/18/2013 This Methos added by Tony Contrada in order to create arc segments in varied line thickness, or Filled
00277 void LCDShield::setArc(int x0, int y0, int radius, int arcSegments[], int numSegments, int lineThickness, int color)
00278 {
00279     //Line Thickness (Num Pixels)
00280     if(lineThickness == FILL) lineThickness = radius;
00281     for(int i = 0; i < lineThickness; i++)
00282     {
00283         int f = 1 - radius;
00284         int ddF_x = 0;
00285         int ddF_y = -2 * radius;
00286         int x = 0;
00287         int y = radius;
00288         while(x < y)
00289         {
00290             if(f >= 0)
00291             {
00292                 y--;
00293                 ddF_y += 2;
00294                 f += ddF_y;
00295             }
00296             x++;
00297             ddF_x += 2;
00298             f += ddF_x + 1;
00299 
00300             for(int i = 0; i < numSegments; i++)
00301             {
00302                 if(arcSegments[i] == NNE) setPixel(color, x0 - y, y0 + x); //SHOW NNE
00303                 if(arcSegments[i] == ENE) setPixel(color, x0 - x, y0 + y); //SHOW ENE
00304                 if(arcSegments[i] == ESE) setPixel(color, x0 + x, y0 + y); //SHOW ESE
00305                 if(arcSegments[i] == SSE) setPixel(color, x0 + y, y0 + x); //SHOW SSE
00306                 if(arcSegments[i] == SSW) setPixel(color, x0 + y, y0 - x); //SHOW SSW
00307                 if(arcSegments[i] == WSW) setPixel(color, x0 + x, y0 - y); //SHOW WSW 
00308                 if(arcSegments[i] == WNW) setPixel(color, x0 - x, y0 - y); //SHOW WNW
00309                 if(arcSegments[i] == NNW) setPixel(color, x0 - y, y0 - x); //SHOW NNW
00310             }
00311         
00312         }
00313         radius--;
00314     }
00315 
00316 }
00317 
00318 // 2/22/2013 - Modified by Tony Contrada to include Line Thickness (in pixels) or a Filled Circle
00319 void LCDShield::setCircle (int x0, int y0, int radius, int color, int lineThickness)
00320 {
00321     if(lineThickness == FILL) lineThickness = radius;
00322     
00323     for(int r = 0; r < lineThickness; r++)
00324     {
00325         int f = 1 - radius;
00326         int ddF_x = 0;
00327         int ddF_y = -2 * radius;
00328         int x = 0;
00329         int y = radius;
00330 
00331         setPixel(color, x0, y0 + radius);
00332         setPixel(color, x0, y0 - radius);
00333         setPixel(color, x0 + radius, y0);
00334         setPixel(color, x0 - radius, y0);
00335 
00336         while(x < y)
00337         {
00338             if(f >= 0)
00339             {
00340                 y--;
00341                 ddF_y += 2;
00342                 f += ddF_y;
00343             }
00344             x++;
00345             ddF_x += 2;
00346             f += ddF_x + 1;
00347 
00348             setPixel(color, x0 + x, y0 + y);
00349             setPixel(color, x0 - x, y0 + y);
00350             setPixel(color, x0 + x, y0 - y);
00351             setPixel(color, x0 - x, y0 - y);
00352             setPixel(color, x0 + y, y0 + x);
00353             setPixel(color, x0 - y, y0 + x);
00354             setPixel(color, x0 + y, y0 - x);
00355             setPixel(color, x0 - y, y0 - x);
00356         }
00357         radius--;
00358     }
00359 
00360 }
00361 
00362 void LCDShield::setChar(char c, int x, int y, int fColor, int bColor)
00363 {
00364     y   =   (COL_HEIGHT - 1) - y; // make display "right" side up
00365     x   =   (ROW_LENGTH - 2) - x;
00366 
00367     int             i,j;
00368     unsigned int    nCols;
00369     unsigned int    nRows;
00370     unsigned int    nBytes;
00371     unsigned char   PixelRow;
00372     unsigned char   Mask;
00373     unsigned int    Word0;
00374     unsigned int    Word1;
00375     const unsigned char   *pFont;
00376     const unsigned char   *pChar;
00377 
00378     // get pointer to the beginning of the selected font table
00379     pFont = *FONT8x16;
00380     // get the nColumns, nRows and nBytes
00381     nCols = *pFont;
00382     nRows = *(pFont + 1);
00383     nBytes = *(pFont + 2);
00384     // get pointer to the last byte of the desired character
00385     pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
00386 
00387     if (driver) // if it's an epson
00388     {
00389         // Row address set (command 0x2B)
00390         LCDCommand(PASET);
00391         LCDData(x);
00392         LCDData(x + nRows - 1);
00393         // Column address set (command 0x2A)
00394         LCDCommand(CASET);
00395         LCDData(y);
00396         LCDData(y + nCols - 1);
00397     
00398         // WRITE MEMORY
00399         LCDCommand(RAMWR);
00400         // loop on each row, working backwards from the bottom to the top
00401         for (i = nRows - 1; i >= 0; i--) {
00402             // copy pixel row from font table and then decrement row
00403             PixelRow = *(pChar++);
00404             // loop on each pixel in the row (left to right)
00405             // Note: we do two pixels each loop
00406             Mask = 0x80;
00407             for (j = 0; j < nCols; j += 2) 
00408             {
00409                 // if pixel bit set, use foreground color; else use the background color
00410                 // now get the pixel color for two successive pixels
00411                 if ((PixelRow & Mask) == 0)
00412                     Word0 = bColor;
00413                 else
00414                     Word0 = fColor;
00415                 Mask = Mask >> 1;
00416                 if ((PixelRow & Mask) == 0)
00417                     Word1 = bColor;
00418                 else
00419                     Word1 = fColor;
00420                 Mask = Mask >> 1;
00421                 // use this information to output three data bytes
00422                 LCDData((Word0 >> 4) & 0xFF);
00423                 LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
00424                 LCDData(Word1 & 0xFF);
00425             }
00426         }
00427     }
00428     else
00429     {
00430         fColor = swapColors(fColor);
00431         bColor = swapColors(bColor);
00432 
00433         // Row address set (command 0x2B)
00434         LCDCommand(PASETP);
00435         LCDData(x);
00436         LCDData(x + nRows - 1);
00437         // Column address set (command 0x2A)
00438         LCDCommand(CASETP);
00439         LCDData(y);
00440         LCDData(y + nCols - 1);
00441     
00442         // WRITE MEMORY
00443         LCDCommand(RAMWRP);
00444         // loop on each row, working backwards from the bottom to the top
00445         pChar+=nBytes-1;  // stick pChar at the end of the row - gonna reverse print on phillips
00446         for (i = nRows - 1; i >= 0; i--) {
00447             // copy pixel row from font table and then decrement row
00448             PixelRow = *(pChar--);
00449             // loop on each pixel in the row (left to right)
00450             // Note: we do two pixels each loop
00451             Mask = 0x01;  // <- opposite of epson
00452             for (j = 0; j < nCols; j += 2) 
00453             {
00454                 // if pixel bit set, use foreground color; else use the background color
00455                 // now get the pixel color for two successive pixels
00456                 if ((PixelRow & Mask) == 0)
00457                     Word0 = bColor;
00458                 else
00459                     Word0 = fColor;
00460                 Mask = Mask << 1; // <- opposite of epson
00461                 if ((PixelRow & Mask) == 0)
00462                     Word1 = bColor;
00463                 else
00464                     Word1 = fColor;
00465                 Mask = Mask << 1; // <- opposite of epson
00466                 // use this information to output three data bytes
00467                 LCDData((Word0 >> 4) & 0xFF);
00468                 LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
00469                 LCDData(Word1 & 0xFF);
00470             }
00471         }
00472     }
00473 }
00474 
00475 
00476 void LCDShield::setStr(char *pString, int x, int y, int fColor, int bColor)
00477 {
00478     x = x + 16;
00479     y = y + 8;
00480     int originalY = y;
00481 
00482     // loop until null-terminator is seen
00483     while (*pString != 0x00) {
00484         // draw the character
00485         setChar(*pString++, x, y, fColor, bColor);
00486         // advance the y position
00487         y = y + 8;
00488         // bail out if y exceeds 131
00489         if (y > 131) {
00490             x = x + 16;
00491             y = originalY;
00492         }
00493         if (x > 123) break;
00494     }
00495 }
00496 
00497 void LCDShield::setLine(int x0, int y0, int x1, int y1, int color)
00498 {
00499     int dy = y1 - y0; // Difference between y0 and y1
00500     int dx = x1 - x0; // Difference between x0 and x1
00501     int stepx, stepy;
00502 
00503     if (dy < 0)
00504     {
00505         dy = -dy;
00506         stepy = -1;
00507     }
00508     else
00509         stepy = 1;
00510 
00511     if (dx < 0)
00512     {
00513         dx = -dx;
00514         stepx = -1;
00515     }
00516     else
00517         stepx = 1;
00518 
00519     dy <<= 1; // dy is now 2*dy
00520     dx <<= 1; // dx is now 2*dx
00521     setPixel(color, x0, y0);
00522 
00523     if (dx > dy) 
00524     {
00525         int fraction = dy - (dx >> 1);
00526         while (x0 != x1)
00527         {
00528             if (fraction >= 0)
00529             {
00530                 y0 += stepy;
00531                 fraction -= dx;
00532             }
00533             x0 += stepx;
00534             fraction += dy;
00535             setPixel(color, x0, y0);
00536         }
00537     }
00538     else
00539     {
00540         int fraction = dx - (dy >> 1);
00541         while (y0 != y1)
00542         {
00543             if (fraction >= 0)
00544             {
00545                 x0 += stepx;
00546                 fraction -= dy;
00547             }
00548             y0 += stepy;
00549             fraction += dx;
00550             setPixel(color, x0, y0);
00551         }
00552     }
00553 }
00554 
00555 void LCDShield::setRect(int x0, int y0, int x1, int y1, unsigned char fill, int color)
00556 {
00557     // check if the rectangle is to be filled
00558     if (fill == 1)
00559     {
00560         int xDiff;
00561     
00562         if(x0 > x1)
00563             xDiff = x0 - x1; //Find the difference between the x vars
00564         else
00565             xDiff = x1 - x0;
00566     
00567         while(xDiff > 0)
00568         {
00569             setLine(x0, y0, x0, y1, color);
00570         
00571             if(x0 > x1)
00572                 x0--;
00573             else
00574                 x0++;
00575         
00576             xDiff--;
00577         }
00578 
00579     }
00580     else 
00581     {
00582         // best way to draw an unfilled rectangle is to draw four lines
00583         setLine(x0, y0, x1, y0, color);
00584         setLine(x0, y1, x1, y1, color);
00585         setLine(x0, y0, x0, y1, color);
00586         setLine(x1, y0, x1, y1, color);
00587     }
00588 }
00589 
00590 void LCDShield::printLogo(void)
00591 {
00592     int x = 4, y = 25, logo_ix = 0, z;
00593     char logo;
00594 
00595     for (logo_ix = 0; logo_ix < 1120; logo_ix++)
00596     {
00597         logo = logo_spark[logo_ix];
00598         for (z = 0; z < 8; z++)
00599         {
00600             if ((logo & 0x80) == 0x80) setPixel(RED, y, x);
00601             x++;
00602             if (x == 132)
00603             {
00604                 x = 4;
00605                 y++;
00606             }
00607             logo <<= 1;
00608         }
00609     }
00610 }
00611 
00612 void LCDShield::off(void)
00613 {
00614     if (driver) // If it's an epson
00615         LCDCommand(DISOFF);
00616     else // otherwise it's a phillips
00617         LCDCommand(DISPOFF);
00618 }
00619 
00620 void LCDShield::on(void)
00621 {
00622     if (driver) // If it's an epson
00623         LCDCommand(DISON);
00624     else // otherwise it's a phillips
00625         LCDCommand(DISPON);
00626 }