Sparkfun's Nokia Color LCD Arduino Shield library for FRDM boards
Dependents: ColorLCDShield_Conway
ColorLCDShield.cpp
- Committer:
- kayekss
- Date:
- 2015-02-19
- Revision:
- 2:f4f7b91314a0
- Parent:
- 1:2d65bfd1218c
File content as of revision 2:f4f7b91314a0:
// ==================================================== Nov 08 2013, kayeks == // ColorLCDShield.cpp // =========================================================================== // Sparkfun's Color LCD Shield (LCD-09363) library for mbed FRDM-KL25Z boards. // - https://www.sparkfun.com/products/9363 // This library has modified from Sparkfun's Arduino library code // - Command/data transmissions are implemented as software SPI communication // because the FRDM board's MCUs are not 9-bit SPI capable :( // - License is `CC BY-SA 3.0' // - Original descriptions are below /* LCDShield.cpp - Arduino Library to control a Nokia 6100 LCD, specifically that found on SparkFun's Color LCD Shield. This code should work for both Epson and Phillips display drivers normally found on the Color LCD Shield. License: CC BY-SA 3.0: Creative Commons Share-alike 3.0. Feel free to use and abuse this code however you'd like. If you find it useful please attribute, and SHARE-ALIKE! This is based on code by Mark Sproul, and Peter Davenport. Thanks to Coleman Sellers and Harold Timmis for help getting it to work with the Phillips Driver 7-31-2011 */ #include "ColorLCDShield.h" /*extern "C" { #include "wiring.h" }*/ #include "mbed.h" // #include "Arduino.h" // static char x_offset = 0; // static char y_offset = 0; DigitalOut res(D8); // Arduino D8 DigitalOut cs(D9); // Arduino D9 DigitalOut dio(D11); // Arduino D11 DigitalOut sck(D13); // Arduino D13 LCDShield::LCDShield() { } void LCDShield::LCDCommand(unsigned char data) { char jj; cs = 0; // enable chip dio = 0; // output low on data out (9th bit low = command) sck = 0; // send clock pulse // wait_us(1); sck = 1; for (jj = 0; jj < 8; jj++) { if ((data & 0x80) == 0x80) dio = 1; else dio = 0; sck = 0; // send clock pulse // wait_us(1); sck = 1; data <<= 1; } cs = 1; // disable } void LCDShield::LCDData(unsigned char data) { char j; cs = 0; // enable chip dio = 1; // output high on data out (9th bit high = data) sck = 0; // send clock pulse // wait_us(1); sck = 1; // send clock pulse for (j = 0; j < 8; j++) { if ((data & 0x80) == 0x80) dio = 1; else dio = 0; sck = 0; // send clock pulse // wait_us(1); sck = 1; data <<= 1; } cs = 1; // disable } void LCDShield::init(int type, bool colorSwap) { driver = type; // Initialize the control pins, and reset display: sck = 0; // CLK = LOW dio = 0; // DIO = LOW wait_us(10); // 10us delay cs = 1; // CS = HIGH wait_us(10); // 10uS Delay res = 0; // RESET = LOW wait_ms(200); // 200ms delay res = 1; // RESET = HIGH wait_ms(200); // 200ms delay sck = 1; // SCK_PIN = HIGH dio = 1; // DIO = HIGH wait_us(10); // 10us delay if (driver == EPSON) { LCDCommand(DISCTL); // Display control (0xCA) LCDData(0x0C); // 12 = 1100 - CL dividing ratio [don't divide] switching period 8H (default) LCDData(0x20); // nlines/4 - 1 = 132/4 - 1 = 32 duty LCDData(0x00); // No inversely highlighted lines LCDCommand(COMSCN); // common scanning direction (0xBB) LCDData(0x01); // 1->68, 132<-69 scan direction LCDCommand(OSCON); // internal oscialltor ON (0xD1) LCDCommand(SLPOUT); // sleep out (0x94) LCDCommand(PWRCTR); // power ctrl (0x20) LCDData(0x0F); // everything on, no external reference resistors LCDCommand(DISINV); // invert display mode (0xA7) LCDCommand(DATCTL); // data control (0xBC) LCDData(0x03); // Inverse page address, reverse rotation column address, column scan-direction !!! try 0x01 LCDData(0x00); // normal RGB arrangement LCDData(0x02); // 16-bit Grayscale Type A (12-bit color) LCDCommand(VOLCTR); // electronic volume, this is the contrast/brightness (0x81) LCDData(32); // volume (contrast) setting - fine tuning, original (0-63) LCDData(3); // internal resistor ratio - coarse adjustment (0-7) LCDCommand(NOP); // nop (0x25) wait_ms(100); LCDCommand(DISON); // display on (0xAF) } else if (driver == PHILIPS) { LCDCommand(SLEEPOUT); // Sleep Out (0x11) LCDCommand(BSTRON); // Booster voltage on (0x03) LCDCommand(DISPON); // Display on (0x29) //LCDCommand(INVON); // Inversion on (0x20) // 12-bit color pixel format: LCDCommand(COLMOD); // Color interface format (0x3A) LCDData(0x03); // 0b011 is 12-bit/pixel mode LCDCommand(MADCTL); // Memory Access Control(PHILLIPS) if (colorSwap) LCDData(0x08); else LCDData(0x00); LCDCommand(SETCON); // Set Contrast(PHILLIPS) LCDData(0x30); LCDCommand(NOPP); // nop(PHILLIPS) } } void LCDShield::clear(int color) { if (driver) // if it's an Epson { LCDCommand(PASET); LCDData(0); LCDData(131); LCDCommand(CASET); LCDData(0); LCDData(131); LCDCommand(RAMWR); } else // otherwise it's a phillips { LCDCommand(PASETP); LCDData(0); LCDData(131); LCDCommand(CASETP); LCDData(0); LCDData(131); LCDCommand(RAMWRP); } for(unsigned int i=0; i < (131*131)/2; i++) { LCDData((color>>4)&0x00FF); LCDData(((color&0x0F)<<4)|(color>>8)); LCDData(color&0x0FF); } // x_offset = 0; // y_offset = 0; } void LCDShield::contrast(char setting) { if (driver == EPSON) { setting &= 0x3F; // 2 msb's not used, mask out LCDCommand(VOLCTR); // electronic volume, this is the contrast/brightness(EPSON) LCDData(setting); // volume (contrast) setting - course adjustment, -- original was 24 LCDData(3); // TODO: Make this coarse adjustment variable, 3's a good place to stay } else if (driver == PHILIPS) { setting &= 0x7F; // msb is not used, mask it out LCDCommand(SETCON); // contrast command (PHILLIPS) LCDData(setting); // volume (contrast) setting - course adjustment, -- original was 24 } } // Added by Steve Sparks @ Big Nerd Ranch. // This swaps the Epson RGB order into the Philips RGB order. (Or, vice versa, I suppose.) uint16_t LCDShield::swapColors(uint16_t in) { return ((in & 0x000F)<<8)|(in & 0x00F0)|((in & 0x0F00)>>8); } void LCDShield::setPixel(int color, unsigned char x, unsigned char y) { y = (COL_HEIGHT - 1) - y; x = (ROW_LENGTH - 1) - x; if (driver == EPSON) // if it's an epson { LCDCommand(PASET); // page start/end ram LCDData(x); LCDData(ENDPAGE); LCDCommand(CASET); // column start/end ram LCDData(y); LCDData(ENDCOL); LCDCommand(RAMWR); // write LCDData((color>>4)&0x00FF); LCDData(((color&0x0F)<<4)|(color>>8)); LCDData(color&0x0FF); } else if (driver == PHILIPS) // otherwise it's a phillips { LCDCommand(PASETP); // page start/end ram LCDData(x); LCDData(x); LCDCommand(CASETP); // column start/end ram LCDData(y); LCDData(y); LCDCommand(RAMWRP); // write LCDData((unsigned char)((color>>4)&0x00FF)); LCDData((unsigned char)(((color&0x0F)<<4)|0x00)); } } // 2/18/2013 This Methos added by Tony Contrada in order to create arc segments in varied line thickness, or Filled void LCDShield::setArc(int x0, int y0, int radius, int arcSegments[], int numSegments, int lineThickness, int color) { //Line Thickness (Num Pixels) if(lineThickness == FILL) lineThickness = radius; for(int i = 0; i < lineThickness; i++) { int f = 1 - radius; int ddF_x = 0; int ddF_y = -2 * radius; int x = 0; int y = radius; while(x < y) { if(f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x + 1; for(int i = 0; i < numSegments; i++) { if(arcSegments[i] == NNE) setPixel(color, x0 - y, y0 + x); //SHOW NNE if(arcSegments[i] == ENE) setPixel(color, x0 - x, y0 + y); //SHOW ENE if(arcSegments[i] == ESE) setPixel(color, x0 + x, y0 + y); //SHOW ESE if(arcSegments[i] == SSE) setPixel(color, x0 + y, y0 + x); //SHOW SSE if(arcSegments[i] == SSW) setPixel(color, x0 + y, y0 - x); //SHOW SSW if(arcSegments[i] == WSW) setPixel(color, x0 + x, y0 - y); //SHOW WSW if(arcSegments[i] == WNW) setPixel(color, x0 - x, y0 - y); //SHOW WNW if(arcSegments[i] == NNW) setPixel(color, x0 - y, y0 - x); //SHOW NNW } } radius--; } } // 2/22/2013 - Modified by Tony Contrada to include Line Thickness (in pixels) or a Filled Circle void LCDShield::setCircle (int x0, int y0, int radius, int color, int lineThickness) { if(lineThickness == FILL) lineThickness = radius; for(int r = 0; r < lineThickness; r++) { int f = 1 - radius; int ddF_x = 0; int ddF_y = -2 * radius; int x = 0; int y = radius; setPixel(color, x0, y0 + radius); setPixel(color, x0, y0 - radius); setPixel(color, x0 + radius, y0); setPixel(color, x0 - radius, y0); while(x < y) { if(f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x + 1; setPixel(color, x0 + x, y0 + y); setPixel(color, x0 - x, y0 + y); setPixel(color, x0 + x, y0 - y); setPixel(color, x0 - x, y0 - y); setPixel(color, x0 + y, y0 + x); setPixel(color, x0 - y, y0 + x); setPixel(color, x0 + y, y0 - x); setPixel(color, x0 - y, y0 - x); } radius--; } } void LCDShield::setChar(char c, int x, int y, int fColor, int bColor) { y = (COL_HEIGHT - 1) - y; // make display "right" side up x = (ROW_LENGTH - 2) - x; int i,j; unsigned int nCols; unsigned int nRows; unsigned int nBytes; unsigned char PixelRow; unsigned char Mask; unsigned int Word0; unsigned int Word1; const unsigned char *pFont; const unsigned char *pChar; // get pointer to the beginning of the selected font table pFont = *FONT8x16; // get the nColumns, nRows and nBytes nCols = *pFont; nRows = *(pFont + 1); nBytes = *(pFont + 2); // get pointer to the last byte of the desired character pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1; if (driver) // if it's an epson { // Row address set (command 0x2B) LCDCommand(PASET); LCDData(x); LCDData(x + nRows - 1); // Column address set (command 0x2A) LCDCommand(CASET); LCDData(y); LCDData(y + nCols - 1); // WRITE MEMORY LCDCommand(RAMWR); // loop on each row, working backwards from the bottom to the top for (i = nRows - 1; i >= 0; i--) { // copy pixel row from font table and then decrement row PixelRow = *(pChar++); // loop on each pixel in the row (left to right) // Note: we do two pixels each loop Mask = 0x80; for (j = 0; j < nCols; j += 2) { // if pixel bit set, use foreground color; else use the background color // now get the pixel color for two successive pixels if ((PixelRow & Mask) == 0) Word0 = bColor; else Word0 = fColor; Mask = Mask >> 1; if ((PixelRow & Mask) == 0) Word1 = bColor; else Word1 = fColor; Mask = Mask >> 1; // use this information to output three data bytes LCDData((Word0 >> 4) & 0xFF); LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF)); LCDData(Word1 & 0xFF); } } } else { fColor = swapColors(fColor); bColor = swapColors(bColor); // Row address set (command 0x2B) LCDCommand(PASETP); LCDData(x); LCDData(x + nRows - 1); // Column address set (command 0x2A) LCDCommand(CASETP); LCDData(y); LCDData(y + nCols - 1); // WRITE MEMORY LCDCommand(RAMWRP); // loop on each row, working backwards from the bottom to the top pChar+=nBytes-1; // stick pChar at the end of the row - gonna reverse print on phillips for (i = nRows - 1; i >= 0; i--) { // copy pixel row from font table and then decrement row PixelRow = *(pChar--); // loop on each pixel in the row (left to right) // Note: we do two pixels each loop Mask = 0x01; // <- opposite of epson for (j = 0; j < nCols; j += 2) { // if pixel bit set, use foreground color; else use the background color // now get the pixel color for two successive pixels if ((PixelRow & Mask) == 0) Word0 = bColor; else Word0 = fColor; Mask = Mask << 1; // <- opposite of epson if ((PixelRow & Mask) == 0) Word1 = bColor; else Word1 = fColor; Mask = Mask << 1; // <- opposite of epson // use this information to output three data bytes LCDData((Word0 >> 4) & 0xFF); LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF)); LCDData(Word1 & 0xFF); } } } } void LCDShield::setStr(char *pString, int x, int y, int fColor, int bColor) { x = x + 16; y = y + 8; int originalY = y; // loop until null-terminator is seen while (*pString != 0x00) { // draw the character setChar(*pString++, x, y, fColor, bColor); // advance the y position y = y + 8; // bail out if y exceeds 131 if (y > 131) { x = x + 16; y = originalY; } if (x > 123) break; } } void LCDShield::setLine(int x0, int y0, int x1, int y1, int color) { int dy = y1 - y0; // Difference between y0 and y1 int dx = x1 - x0; // Difference between x0 and x1 int stepx, stepy; if (dy < 0) { dy = -dy; stepy = -1; } else stepy = 1; if (dx < 0) { dx = -dx; stepx = -1; } else stepx = 1; dy <<= 1; // dy is now 2*dy dx <<= 1; // dx is now 2*dx setPixel(color, x0, y0); if (dx > dy) { int fraction = dy - (dx >> 1); while (x0 != x1) { if (fraction >= 0) { y0 += stepy; fraction -= dx; } x0 += stepx; fraction += dy; setPixel(color, x0, y0); } } else { int fraction = dx - (dy >> 1); while (y0 != y1) { if (fraction >= 0) { x0 += stepx; fraction -= dy; } y0 += stepy; fraction += dx; setPixel(color, x0, y0); } } } void LCDShield::setRect(int x0, int y0, int x1, int y1, unsigned char fill, int color) { // check if the rectangle is to be filled if (fill == 1) { int xDiff; if(x0 > x1) xDiff = x0 - x1; //Find the difference between the x vars else xDiff = x1 - x0; while(xDiff > 0) { setLine(x0, y0, x0, y1, color); if(x0 > x1) x0--; else x0++; xDiff--; } } else { // best way to draw an unfilled rectangle is to draw four lines setLine(x0, y0, x1, y0, color); setLine(x0, y1, x1, y1, color); setLine(x0, y0, x0, y1, color); setLine(x1, y0, x1, y1, color); } } void LCDShield::printLogo(void) { int x = 4, y = 25, logo_ix = 0, z; char logo; for (logo_ix = 0; logo_ix < 1120; logo_ix++) { logo = logo_spark[logo_ix]; for (z = 0; z < 8; z++) { if ((logo & 0x80) == 0x80) setPixel(RED, y, x); x++; if (x == 132) { x = 4; y++; } logo <<= 1; } } } void LCDShield::off(void) { if (driver) // If it's an epson LCDCommand(DISOFF); else // otherwise it's a phillips LCDCommand(DISPOFF); } void LCDShield::on(void) { if (driver) // If it's an epson LCDCommand(DISON); else // otherwise it's a phillips LCDCommand(DISPON); }