Sparkfun's Nokia Color LCD Arduino Shield library for FRDM boards
Dependents: ColorLCDShield_Conway
Diff: ColorLCDShield.cpp
- Revision:
- 0:86bb740bcaf7
- Child:
- 1:2d65bfd1218c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ColorLCDShield.cpp Wed May 08 19:43:34 2013 +0000 @@ -0,0 +1,625 @@ +// 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(PTA13); // Arduino D8 +DigitalOut cs(PTD5); // Arduino D9 +DigitalOut dio(PTD2); // Arduino D11 +DigitalOut sck(PTD1); // 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); +}