Nokia Knockoff LCD Arduino Code

The following code is for the SFE Nokia Knockoff 132*132 LCD display (http://www.sparkfun.com/products/8600). This code is a modification of the Epson driver code written by James Lynch. The origianl code was not for an Arduino nor for a processor with limited memory. I modified the code to optimize for size as well as remove the BMP display code that was not appropriate.

To further optimize the code size, a section of enable macros in the Epson.h file allow you to enable and disable various functionality (such as text, lines, circles,…). By setting these bits to zero you can cut out those functions.

I also was able to move the three font tables from RAM (a precious resource) and move them into ROM.

The interface to the LCD was via a simple bit bang done at the “PORT” register level to speed it up. This section might need to be modified based on what pins you use.

A sample application is also provided as a way to test the code.

The next new posts contain the code.

Epson (.c)

// **************************************************************************************************************
// lcd.c
//
// Nokia 6610 LCD Display Driver (Epson S1D15G00 Controller)
//
// Controller used for LCD Display is a Epson S1D15G00 driver
// Note: For Olimex SAM7-EX256 boards with the G8 decal or the Sparkfun Color LCD 128x128 Nokia Knock-Off
//
//
// We will use a 132 x 132 pixel matrix - each pixel has 12 bits of color information.
//
// _____
// | |
// ___________________|___|___
// | ====================== |
// ^ (131,0) |------------------------- |(131,131)
// | | |
// | | |
// | | |
// | | |
// | | |
// | Rows| Nokia 6610 Display | Note: In general, you can't view column 130 or column 131
// | | |
// X | |
// | | |
// | | |
// | | |
// | | |
// | | |
// | |--------------------------|
// (0,0) Columns (0,131)
//
// ------------Y-------------->
//
//
// 132 x 132 pixel matrix has two methods to specify the color info
//
// 1. 12 bits per pixel
// requires command and 1.5 data bytes to specify a single pixel
// (3 data bytes can specify 2 pixels)
//
// 2. 8 bits per pixel
// requires one command and one data byte to specify the single pixel\//
// note: pixel data byte converted by RGB table to 12-bit format above
//
// THIS IMPLEMENTATION USES THE 12 BITS PER PIXEL METHOD!
// -------------------------
//
//
//
//
// HARDWARE INTERFACE
// ------------------
//
// The Nokia 6610 display uses a SPI serial interface (9 bits)
// The SPI is bit-banged on the Arduino for lack of a 9 bit protocol.
//
// The Arduino signals that control the LCD are defined in Epson.h
// Current definitons are:
// Hardware definitions
// #define PIN_MASK_CS    0x01   // ~Chip select
// #define PIN_MASK_CLOCK 0x02   // Clock
// #define PIN_MASK_DATA  0x04   // Data
// #define PIN_MASK_RESET 0x08   // ~Reset
//
// The important thing to note is that you CANNOT read from the LCD!
//
// Functionality that was changed from the original include:
// 1) Different hardware platform
// 2) A knockoff Epson controller that does not work quite the same way
// 3) Removal of the BMP display function. (No room on an Arduino)
// 4) Added #defines to comment out unneeded functions.
// 5) Careful optimization of variables to lower memory footprint
// 6) A few bug fixes
//
//
// Author: James P Lynch August 30, 2007
// Modified from the original by Skye Sweeney February 22, 2011
// ***************************************************************************************************************
// **************************************
// Include Files
// **************************************
#include "Epson.h"




// *****************************************************************************
// WriteSpiCommand.c
//
// Writes 9-bit command to LCD display via SPI interface
//
// Inputs: command - command byte
//
//
// Author: Olimex, James P Lynch August 30, 2007
// *****************************************************************************
void WriteSpiCommand(byte command) {
  byte i;
  
  // Enable chip
  PORTB &= ~PIN_MASK_CS;
  
  // CLock out the zero for a command
  PORTB &= ~PIN_MASK_DATA;
  PORTB &= ~PIN_MASK_CLOCK;
  PORTB |=  PIN_MASK_CLOCK;
  
  // Clock out the 8 bits MSB first  
  for (i=0; i<8; i++) {

    // Set the data bit
    if (command & 0x80) {
      PORTB |= PIN_MASK_DATA;
    } else {
      PORTB &= ~PIN_MASK_DATA;
    }
    // Toggle the clock
    PORTB &= ~PIN_MASK_CLOCK;
    PORTB |=  PIN_MASK_CLOCK;
    
    // Expose the next bit
    command = command << 1;
  }

  // Deslect chip  
  PORTB |= PIN_MASK_CS;
    
}


// *****************************************************************************
// WriteSpiData.c
//
// Writes 9-bit command to LCD display via SPI interface
//
// Inputs: data - data byte
//
//
// Author: Olimex, James P Lynch August 30, 2007
// Modified by Skye Sweeney February 2011
// *****************************************************************************
void WriteSpiData(byte data) {
  byte i;
  
  // Enable chip
  PORTB &= ~PIN_MASK_CS;
  
  // CLock out the one for data
  PORTB |= PIN_MASK_DATA;
  PORTB &= ~PIN_MASK_CLOCK;
  PORTB |=  PIN_MASK_CLOCK;
  
  // Clock out the 8 bits MSB first  
  for (i=0; i<8; i++) {

    // Set the data bit
    if (data & 0x80) {
      PORTB |= PIN_MASK_DATA;
    } else {
      PORTB &= ~PIN_MASK_DATA;
    }
    // Toggle the clock
    PORTB &= ~PIN_MASK_CLOCK;
    PORTB |=  PIN_MASK_CLOCK;
    
    // Expose the next bit
    data = data << 1;
  }

  // Deslect chip  
  PORTB |= PIN_MASK_CS;
  
}


// *****************************************************************************
// InitLcd.c
//
// Initializes the Epson S1D15G00 LCD Controller
//
// Inputs: none
//
// Author: James P Lynch August 30, 2007
// Modified by Skye Sweeney February 2011
// *****************************************************************************
void InitLcd(void) {

  // Set pin directions as outputs for SPI pins
  DDRB |= (PIN_MASK_CS | PIN_MASK_RESET | PIN_MASK_DATA | PIN_MASK_CLOCK);

  // Start with PIN select HIGH  
  PORTB |= PIN_MASK_CS;
  PORTB |= PIN_MASK_CLOCK;
  
  // Hardware reset
  PORTB &= ~PIN_MASK_RESET;
  delay(20);
  PORTB |= PIN_MASK_RESET;
  delay(20);

  // Display control
  WriteSpiCommand(DISCTL);
  WriteSpiData(0x00); // P1: 0x00 = 2 divisions, switching period=8 (default)
  WriteSpiData(0x20); // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32)
  WriteSpiData(0x00); // P3: 0x00 = no inversely highlighted lines
  
  // COM scan
  WriteSpiCommand(COMSCN);
  WriteSpiData(0x01); // P1: 0x01 = Scan 1->80, 160<-81
  
  // Internal oscilator ON
  WriteSpiCommand(OSCON);
  
  // Sleep out
  WriteSpiCommand(SLPOUT);
  
  // Power control
  WriteSpiCommand(PWRCTR);
  WriteSpiData(0x0f); // reference voltage regulator on, circuit voltage follower on, BOOST ON
  
  // Inverse display
  WriteSpiCommand(DISINV);
  
  // Data control
  WriteSpiCommand(DATCTL);
  // Was a 1, 0 fixes the address bug
  WriteSpiData(0x00); // P1: 0x01 = page address inverted, column address normal, address scan in column direction
  WriteSpiData(0x00); // P2: 0x00 = RGB sequence (default value)
  WriteSpiData(0x02); // P3: 0x02 = Grayscale -> 16 (selects 12-bit color, type A)
  
  // Voltage control (contrast setting)
  WriteSpiCommand(VOLCTR);
  // Was 32
  WriteSpiData(42); // P1 = 32 volume value (experiment with this value to get the best contrast)
  WriteSpiData(3); // P2 = 3 resistance ratio (only value that works)
  
  // Allow power supply to stabilize
  delay(250);
  
  // Turn on the display
  WriteSpiCommand(DISON);
  
  // Create the font table based on what is selected
#if EPSON_EN_TEXT == 1
  #if EPSON_EN_TEXT_SMALL == 1
    FontTable[0] = (byte *)FONT6x8;
  #else
    FontTable[0] = NULL;
  #endif
  #if EPSON_EN_TEXT_MEDIUM == 1
    FontTable[1] = (byte *)FONT8x8;
  #else
    FontTable[1] = NULL;
  #endif
  #if EPSON_EN_TEXT_LARGE == 1
    FontTable[2] = (byte *)FONT8x16;
  #else
    FontTable[2] = NULL;
  #endif
#endif
  
  
}




// *****************************************************************************
// LCDClearScreen.c
//
// Clears the LCD screen to single color (BLACK)
//
// Inputs: none
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************
void LCDClearScreen(void) {
  int i; // loop counter
  
  // Row address set (command 0x2B)
  WriteSpiCommand(PASET);
  WriteSpiData(0);
  WriteSpiData(131);
  
  // Column address set (command 0x2A)
  WriteSpiCommand(CASET);
  WriteSpiData(0);
  WriteSpiData(131);
  
  // set the display memory to BLACK
  WriteSpiCommand(RAMWR);
  for(i = 0; i < ((131 * 131) / 2); i++) {
    WriteSpiData((BLACK >> 4) & 0xFF);
    WriteSpiData(((BLACK & 0xF) << 4) | ((BLACK >> 8) & 0xF));
    WriteSpiData(BLACK & 0xFF);
  }
}


// *************************************************************************************
// LCDSetPixel.c
//
// Lights a single pixel in the specified color at the specified x and y addresses
//
// Inputs: x = row address (0 .. 131)
// y = column address (0 .. 131)
// color = 12-bit color value rrrrggggbbbb
// rrrr = 1111 full red
// :
// 0000 red is off
//
// gggg = 1111 full green
// :
// 0000 green is off
//
// bbbb = 1111 full blue
// :
// 0000 blue is off
//
// Returns: nothing
//
// Note: see lcd.h for some sample color settings
//
// Author: James P Lynch August 30, 2007
// *************************************************************************************
void LCDSetPixel(const byte x, const byte y, const int color) {
  
  // Row address set (command 0x2B)
  WriteSpiCommand(PASET);
  WriteSpiData(x);
  WriteSpiData(x);
  
  // Column address set (command 0x2A)
  WriteSpiCommand(CASET);
  WriteSpiData(131-y);
  WriteSpiData(131-y);
  
  // Now illuminate the pixel (2nd pixel will be ignored)
  WriteSpiCommand(RAMWR);
  WriteSpiData((color >> 4) & 0xFF);
  WriteSpiData(((color & 0xF) << 4) | ((color >> 8) & 0xF));
  WriteSpiData(color & 0xFF);
}


// *************************************************************************************************
// LCDSetLine.c
//
// Draws a line in the specified color from (x0,y0) to (x1,y1)
//
// Inputs: x = row address (0 .. 131)
// y = column address (0 .. 131)
// color = 12-bit color value rrrrggggbbbb
// rrrr = 1111 full red
// :
// 0000 red is off
//
// gggg = 1111 full green
// :
// 0000 green is off
//
// bbbb = 1111 full blue
// :
// 0000 blue is off
//
// Returns: nothing
//
// Note: good write-up on this algorithm in Wikipedia (search for Bresenham's line algorithm)
// see lcd.h for some sample color settings
//
// Authors: Dr. Leonard McMillan, Associate Professor UNC
// Jack Bresenham IBM, Winthrop University (Father of this algorithm, 1962)
//
// Note: taken verbatim from Professor McMillan's presentation:
// http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
//
// *************************************************************************************************
#if (EPSON_EN_LINE == 1) || (EPSON_EN_RECTANGLE == 1)
void LCDSetLine(byte x0, byte y0, byte x1, byte y1, int color) {
  byte dy;
  byte dx;
  int fraction;
  byte stepx, stepy;
  
  if (y0 > y1) {
    dy = y0 - y1;
    stepy = -1;
  } else {
    dy = y1 - y0;
    stepy = 1;
  }
  if (x0 > x1) {
    dx = x0 - x1;
    stepx = -1;
  } else {
    dx = x1 - x0;
    stepx = 1;
  }
  
  
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  
  LCDSetPixel(x0, y0, color);
  
  if (dx > dy) {
    fraction = dy - (dx >> 1); // same as 2*dy - dx
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx; // same as fraction -= 2*dx
      }
      x0 += stepx;
      fraction += dy; // same as fraction -= 2*dy
      LCDSetPixel(x0, y0, color);
    }
    
  } else {
    fraction = dx - (dy >> 1);
    while (y0 != y1) {
      if (fraction >= 0) {
        x0 += stepx;
        fraction -= dy;
      }
      y0 += stepy;
      fraction += dx;
      LCDSetPixel(x0, y0, color);
    }
  }
}
#endif

// *****************************************************************************************
// LCDSetRect.c
//
// Draws a rectangle in the specified color from (x1,y1) to (x2,y2)
// Rectangle can be filled with a color if desired
//
// Inputs: x = row address (0 .. 131)
// y = column address (0 .. 131)
// fill = 0=no fill, 1-fill entire rectangle
// color = 12-bit color value for lines rrrrggggbbbb
// rrrr = 1111 full red
// :
// 0000 red is off
//
// gggg = 1111 full green
// :
// 0000 green is off
//
// bbbb = 1111 full blue
// :
// 0000 blue is off
//
// Returns: nothing
//
// Notes:
//
// The best way to fill a rectangle is to take advantage of the "wrap-around" featute
// built into the Epson S1D15G00 controller. By defining a drawing box, the memory can
// be simply filled by successive memory writes until all pixels have been illuminated.
//
// 1. Given the coordinates of two opposing corners (x0, y0) (x1, y1)
// calculate the minimums and maximums of the coordinates
//
// xmin = (x0 <= x1) ? x0 : x1;
// xmax = (x0 > x1) ? x0 : x1;
// ymin = (y0 <= y1) ? y0 : y1;
// ymax = (y0 > y1) ? y0 : y1;
//
// 2. Now set up the drawing box to be the desired rectangle
//
// WriteSpiCommand(PASET); // set the row boundaries
// WriteSpiData(xmin);
// WriteSpiData(xmax);
// WriteSpiCommand(CASET); // set the column boundaries
// WriteSpiData(ymin);
// WriteSpiData(ymax);
//
// 3. Calculate the number of pixels to be written divided by 2
//
// NumPixels = ((((xmax - xmin + 1) * (ymax - ymin + 1)) / 2) + 1)
//
// You may notice that I added one pixel to the formula.
// This covers the case where the number of pixels is odd and we
// would lose one pixel due to rounding error. In the case of
// odd pixels, the number of pixels is exact.
// in the case of even pixels, we have one more pixel than
// needed, but it cannot be displayed because it is outside
// the drawing box.
//
// We divide by 2 because two pixels are represented by three bytes.
// So we work through the rectangle two pixels at a time.
//
// 4. Now a simple memory write loop will fill the rectangle
//
// for (i = 0; i < ((((xmax - xmin + 1) * (ymax - ymin + 1)) / 2) + 1); i++) {
// WriteSpiData((color >> 4) & 0xFF);
// WriteSpiData(((color & 0xF) << 4) | ((color >> 8) & 0xF));
// WriteSpiData(color & 0xFF);
// }
//
//
// In the case of an unfilled rectangle, drawing four lines with the Bresenham line
// drawing algorithm is reasonably efficient.
//
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************************
#if (EPSON_EN_RECTANGLE == 1)
void LCDSetRect(const byte x0, 
                const byte y0, 
                const byte x1, 
                const byte y1, 
                const byte fill, 
                const int color) {
  byte xmin, xmax, ymin, ymax;
  int i;
  
  // check if the rectangle is to be filled
  if (fill == FILL) {
    
    // best way to create a filled rectangle is to define a drawing box
    // and loop two pixels at a time
    // calculate the min and max for x and y directions
    xmin = (x0 <= x1) ? x0 : x1;
    xmax = (x0 > x1)  ? x0 : x1;
    ymin = (y0 <= y1) ? y0 : y1;
    ymax = (y0 > y1)  ? y0 : y1;
    
    // specify the controller drawing box according to those limits
    // Row address set (command 0x2B)
    WriteSpiCommand(PASET);
    WriteSpiData(xmin);
    WriteSpiData(xmax);
    
    // Column address set (command 0x2A)
    WriteSpiCommand(CASET);
    WriteSpiData(131-ymax);
    WriteSpiData(131-ymin);
    
    // WRITE MEMORY
    WriteSpiCommand(RAMWR);
    
    // loop on total number of pixels / 2
    for (i = 0; i < ((((xmax - xmin + 1) * (ymax - ymin + 1)) / 2)); i++) {
      
      // use the color value to output three data bytes covering two pixels
      WriteSpiData((color >> 4) & 0xFF);
      WriteSpiData(((color & 0xF) << 4) | ((color >> 8) & 0xF));
      WriteSpiData(color & 0xFF);

    }
    
  // No FILL  
  } else {
    
    // best way to draw un unfilled rectangle is to draw four lines
    LCDSetLine(x0, y0, x1, y0, color);
    LCDSetLine(x0, y1, x1, y1, color);
    LCDSetLine(x0, y0, x0, y1, color);
    LCDSetLine(x1, y0, x1, y1, color);
  }
}
#endif


// *************************************************************************************
// LCDSetCircle.c
//
// Draws a line in the specified color at center (x0,y0) with radius
//
// Inputs: x0 = row address (0 .. 131)
// y0 = column address (0 .. 131)
// radius = radius in pixels
// color = 12-bit color value rrrrggggbbbb
//
// Returns: nothing
//
// Author: Jack Bresenham IBM, Winthrop University (Father of this algorithm, 1962)
//
// Note: taken verbatim Wikipedia article on Bresenham's line algorithm
// http://www.wikipedia.org
//
// *************************************************************************************
#if EPSON_EN_CIRCLE == 1
void LCDSetCircle(byte x0, byte y0, int radius, int color) {
  int f = 1 - radius;
  int ddF_x = 0;
  int ddF_y = -2 * radius;
  int x = 0;
  int y = radius;
  
  LCDSetPixel(x0, y0 + radius, color);
  LCDSetPixel(x0, y0 - radius, color);
  LCDSetPixel(x0 + radius, y0, color);
  LCDSetPixel(x0 - radius, y0, color);
  
  while(x < y) {
    if(f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x + 1;
    LCDSetPixel(x0 + x, y0 + y, color);
    LCDSetPixel(x0 - x, y0 + y, color);
    LCDSetPixel(x0 + x, y0 - y, color);
    LCDSetPixel(x0 - x, y0 - y, color);
    LCDSetPixel(x0 + y, y0 + x, color);
    LCDSetPixel(x0 - y, y0 + x, color);
    LCDSetPixel(x0 + y, y0 - x, color);
    LCDSetPixel(x0 - y, y0 - x, color);
  }
}
#endif


// *****************************************************************************
// LCDPutChar.c
//
// Draws an ASCII character at the specified (x,y) address and color
//
// Inputs: c = character to be displayed
// x = row address (0 .. 131)
// y = column address (0 .. 131)
// size = font pitch (SMALL, MEDIUM, LARGE)
// fcolor = 12-bit foreground color value rrrrggggbbbb
// bcolor = 12-bit background color value rrrrggggbbbb
//
// Returns: nothing
//
// Notes: Here's an example to display "E" at address (20,20)
//
// LCDPutChar('E', 20, 20, MEDIUM, WHITE, BLACK);
//
// (27,20) (27,27)
// | |
// | |
// ^ V V
// : _ # # # # # # # 0x7F
// : _ _ # # _ _ _ # 0x31
// : _ _ # # _ # _ _ 0x34
// x _ _ # # # # _ _ 0x3C
// : _ _ # # _ # _ _ 0x34
// : _ _ # # _ _ _ # 0x31
// : _ # # # # # # # 0x7F
// : _ _ _ _ _ _ _ _ 0x00
// ^ ^
// | |
// | |
// (20,20) (20,27)
//
// ------y----------->
//
//
// The most efficient way to display a character is to make use of the "wrap-around" feature
// of the Epson S1D16G00 LCD controller chip.
//
// Assume that we position the character at (20, 20) that's a (row, col) specification.
// With the row and column address set commands, you can specify an 8x8 box for the SMALL and MEDIUM
// characters or a 16x8 box for the LARGE characters.
//
// WriteSpiCommand(PASET); // set the row drawing limits
// WriteSpiData(20); //
// WriteSpiData(27); // limit rows to (20, 27)
//
// WriteSpiCommand(CASET); // set the column drawing limits
// WriteSpiData(20); //
// WriteSpiData(27); // limit columns to (20,27)
//
// When the algorithm completes col 27, the column address wraps back to 20
// At the same time, the row address increases by one (this is done by the controller)
//
// We walk through each row, two pixels at a time. The purpose is to create three
// data bytes representing these two pixels in the following format
//
// Data for pixel 0: RRRRGGGGBBBB
// Data for Pixel 1: RRRRGGGGBBBB
//
// WriteSpiCommand(RAMWR); // start a memory write (96 data bytes to follow)
//
// WriteSpiData(RRRRGGGG); // first pixel, red and green data
// WriteSpiData(BBBBRRRR); // first pixel, blue data; second pixel, red data
// WriteSpiData(GGGGBBBB); // second pixel, green and blue data
// :
// and so on until all pixels displayed!
// :
// WriteSpiCommand(NOP); // this will terminate the RAMWR command
//
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************


#if EPSON_EN_TEXT == 1
void LCDPutChar(char c, 
                const byte x, 
                const byte y, 
                const byte size, 
                const int fColor, 
                const int bColor) {
  int i,j;
  byte nCols;
  byte nRows;
  byte nBytes;
  unsigned char PixelRow;
  unsigned char Mask;
  unsigned int Word0;
  unsigned int Word1;
  unsigned char *pFont;
  unsigned char *pChar;

 
  // Get pointer to the beginning of the selected font table
  pFont = (unsigned char *)FontTable[size];
  
  // Exit if font is not defined
  if (pFont == NULL) return;
  
  // Use a '?' if character is not in font
  if ( (c < ' ') || (c > '~') ) c = '?';
  
  // Get the nColumns, nRows and nBytes
  nCols  = pgm_read_byte(pFont + 0);
  nRows  = pgm_read_byte(pFont + 1);
  nBytes = pgm_read_byte(pFont + 2);
  
  // Get pointer to the last byte of the desired character
  pChar = pFont + (nBytes * (c - 0x1F) + nBytes - 1);
 
  // Row address set (command 0x2B)
  WriteSpiCommand(PASET);
  WriteSpiData(x);                 // 10          = 10
  WriteSpiData(x + nRows - 1);     // 10 + 8 - 1  = 17
  
  // Column address set (command 0x2A)
  WriteSpiCommand(CASET);
  WriteSpiData(131-(y + nCols - 1));    // 131 - (10+8-1) = 114
  WriteSpiData(131-y);                  // 131 - 10       = 121
  
  // WRITE MEMORY
  WriteSpiCommand(RAMWR);
  
  // loop on each row, working backwards from the bottom to the top
  for (i = 0; i < nRows; i++) {
    
    // Copy pixel data from font table
    PixelRow = pgm_read_byte(pChar);

    // Decrement font data pointer
    pChar--;
    
    // Loop on each pixel in the row (left to right)
    // Note: we do two pixels each loop
    Mask = 0x01;
    
    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
      WriteSpiData((Word0 >> 4) & 0xFF);
      WriteSpiData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
      WriteSpiData(Word1 & 0xFF);
  
    } // Next two pixels
  } // Next row

  // terminate the Write Memory command
  WriteSpiCommand(NOP);
  

}

// *************************************************************************************************
// LCDPutStr.c
//
// Draws a null-terminates character string at the specified (x,y) address, size and color
//
// Inputs: pString = pointer to character string to be displayed
// x = row address (0 .. 131)
// y = column address (0 .. 131)
// Size = font pitch (SMALL, MEDIUM, LARGE)
// fColor = 12-bit foreground color value rrrrggggbbbb
// bColor = 12-bit background color value rrrrggggbbbb
//
//
// Returns: nothing
//
// Notes: Here's an example to display "Hello World!" at address (20,20)
//
// LCDPutChar("Hello World!", 20, 20, LARGE, WHITE, BLACK);
//
//
// Author: James P Lynch August 30, 2007
// *************************************************************************************************
void LCDPutStr(const char *pString, 
               const byte x, 
               const byte y, 
               const int fontSize, 
               const int fColor, 
               const int bColor) 
{
  byte nCols;
  byte yp;
  unsigned char *pFont;

 
  // Get pointer to the beginning of the selected font table
  pFont = (unsigned char *)FontTable[fontSize];
  
  // Exit if font is not defined
  if (pFont == NULL) return;
  
  // Get the nCols
  nCols = pgm_read_byte(pFont + 0);
  
  yp = y;
  
  // Loop until null-terminator is seen
  while (*pString != 0x00) {
    
    // draw the character
    LCDPutChar(*pString++, x, yp, fontSize, fColor, bColor);
    
    // Advance the y position
    yp += nCols;
    
    // Bail out if y exceeds 131
    if (yp > 131) break;
  }
}
#endif

Epson.h

// *****************************************************************************
// lcd.h
//
// include file for Epson S1D15G00 LCD Controller
//
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************

#ifndef _Epson_h__
#define _Epson_h__

#include "WProgram.h"


// Hardware definitions. Thse are all on port B
#define PIN_MASK_CS    0x01   // ~Chip select
#define PIN_MASK_CLOCK 0x02   // Clock
#define PIN_MASK_DATA  0x04   // Data
#define PIN_MASK_RESET 0x08   // ~Reset


// Enable subsystems
#define EPSON_EN_LINE        1
#define EPSON_EN_CIRCLE      1
#define EPSON_EN_RECTANGLE   1
#define EPSON_EN_TEXT        1
#define EPSON_EN_TEXT_SMALL  0
#define EPSON_EN_TEXT_MEDIUM 1
#define EPSON_EN_TEXT_LARGE  0

// Command definitions
#define DISON   0xAF // Display on
#define DISOFF  0xAE // Display off
#define DISNOR  0xA6 // Normal display
#define DISINV  0xA7 // Inverse display
#define COMSCN  0xBB // Common scan direction
#define DISCTL  0xCA // Display control
#define SLPIN   0x95 // Sleep in
#define SLPOUT  0x94 // Sleep out
#define PASET   0x75 // Page address set
#define CASET   0x15 // Column address set
#define DATCTL  0xBC // Data scan direction, etc.
#define RGBSET8 0xCE // 256-color position set
#define RAMWR   0x5C // Writing to memory
#define RAMRD   0x5D // Reading from memory
#define PTLIN   0xA8 // Partial display in
#define PTLOUT  0xA9 // Partial display out
#define RMWIN   0xE0 // Read and modify write
#define RMWOUT  0xEE // End
#define ASCSET  0xAA // Area scroll set
#define SCSTART 0xAB // Scroll start set
#define OSCON   0xD1 // Internal oscillation on
#define OSCOFF  0xD2 // Internal oscillation off
#define PWRCTR  0x20 // Power control
#define VOLCTR  0x81 // Electronic volume control
#define VOLUP   0xD6 // Increment electronic control by 1
#define VOLDOWN 0xD7 // Decrement electronic control by 1
#define TMPGRD  0x82 // Temperature gradient set
#define EPCTIN  0xCD // Control EEPROM
#define EPCOUT  0xCC // Cancel EEPROM control
#define EPMWR   0xFC // Write into EEPROM
#define EPMRD   0xFD // Read from EEPROM
#define EPSRRD1 0x7C // Read register 1
#define EPSRRD2 0x7D // Read register 2
#define NOP     0x25 // NOP instruction


// Enums for fill
#define NOFILL  0
#define FILL    1

// Enums for text sizes
#define SMALL   0
#define MEDIUM  1
#define LARGE   2



// 12-bit color definitions
#define WHITE   0xFFF
#define BLACK   0x000
#define RED     0xF00
#define GREEN   0x0F0
#define BLUE    0x00F
#define CYAN    0x0FF
#define MAGENTA 0xF0F
#define YELLOW  0xFF0
#define BROWN   0xB22
#define ORANGE  0xFA0
#define PINK    0xF6A




void InitLcd(void);
void WriteSpiCommand(byte command);
void WriteSpiData(byte data);
void LCDClearScreen(void);
void LCDSetPixel(const byte x, const byte y, const int color);

#if (EPSON_EN_LINE == 1) || (EPSON_EN_RECTANGLE == 1)
  void LCDSetLine(byte x1, byte y1, byte x2, byte y2, int color);
#endif

#if EPSON_EN_RESTANGLE == 1
  void LCDSetRect(byte x0, byte y0, byte x1, byte y1, byte fill, int color);
#endif

#if EPSON_EN_CIRCLE == 1
  void LCDSetCircle(byte x0, byte y0, int radius, int color);
#endif

#if EPSON_EN_TEXT == 1
  void LCDPutChar(const char c, 
                  const byte x, 
                  const byte y, 
                  const byte size, 
                  const int fColor, 
                  const int bColor);
  void LCDPutStr(const char *pString, 
                 const byte x, 
                 const byte y, 
                 const int fontSize, 
                 const int fColor, 
                 const int bColor);
               


  extern const byte *FontTable[3];
  
  #if EPSON_EN_TEXT_SMALL == 1
    extern const unsigned char FONT6x8[97][8];
  #endif
  #if EPSON_EN_TEXT_MEDIUM == 1
    extern const unsigned char FONT8x8[97][8];
  #endif
  #if EPSON_EN_TEXT_LARGE == 1
    extern const unsigned char FONT8x16[97][16];
  #endif
  
#endif

#endif

Font (.c)

// *********************************************************************************
//
// Font tables for Nokia 6610 LCD Display Driver (S1D15G00 Controller)
//
// FONT6x8 - SMALL font (mostly 5x7)
// FONT8x8 - MEDIUM font (8x8 characters, a bit thicker)
// FONT8x16 - LARGE font (8x16 characters, thicker)
//
// Note: ASCII characters 0x00 through 0x1F are not included in these fonts.
//
// Author: Jim Parise, James P Lynch August 30, 2007
// *********************************************************************************

#ifdef EPSON_EN_TEXT

const byte *FontTable[3];



#ifdef EPSON_EN_TEXT_SMALL
static const byte FONT6x8[97][8] = PROGMEM {
0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20
0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, // !
0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00, // "
0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00, // #
0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00, // $
0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00, // %
0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00, // &
0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00, // '
0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00, // (
0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00, // )
0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00, // *
0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00, // +
0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40, // ,
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, // -
0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00, // .
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00, // / (forward slash)
0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00, // 0 0x30
0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00, // 1
0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00, // 2
0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00, // 3
0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00, // 4
0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00, // 5
0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00, // 6
0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00, // 7
0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00, // 8
0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00, // 9
0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00, // :
0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00, // ;
0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00, // <
0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00, // =
0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00, // >
0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00, // ?
0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00, // @ 0x40
0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00, // A
0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00, // B
0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00, // C
0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00, // D
0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00, // E
0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00, // F
0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00, // G
0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00, // H
0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00, // I
0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00, // J
0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00, // K
0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00, // L
0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00, // M
0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00, // N
0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, // O
0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00, // P 0x50
0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00, // Q
0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00, // R
0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00, // S
0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00, // T
0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, // U
0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00, // V
0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00, // W
0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00, // X
0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00, // Y
0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00, // Z
0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00, // [
0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00, // \ (back slash)
0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00, // ]
0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00, // ^
0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00, // _
0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00, // ` 0x60
0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00, // a
0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00, // b
0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00, // c
0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00, // d
0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00, // e
0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00, // f
0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70, // g
0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00, // h
0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00, // i
0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00, // j
0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00, // k
0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00, // l
0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00, // m
0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00, // n
0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, // o
0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80, // p 0x70
0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08, // q
0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00, // r
0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00, // s
0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00, // t
0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00, // u
0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00, // v
0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00, // w
0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00, // x
0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70, // y
0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00, // z
0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00, // {
0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00, // |
0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00, // }
0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00, // ~
0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00}; // DEL
#endif


#ifdef EPSON_EN_TEXT_MEDIUM
const unsigned char FONT8x8[97][8] = PROGMEM {
0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20
0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, // !
0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00, // "
0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00, // #
0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00, // $
0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00, // %
0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00, // &
0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, // '
0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00, // (
0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00, // )
0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, // *
0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00, // +
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, // ,
0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // -
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // .
0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, // / (forward slash)
0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00, // 0 0x30
0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00, // 1
0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00, // 2
0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00, // 3
0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00, // 4
0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00, // 5
0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00, // 6
0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00, // 7
0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00, // 8
0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00, // 9
0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, // :
0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, // ;
0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00, // <
0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00, // =
0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00, // >
0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00, // ?
0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00, // @ 0x40
0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00, // A
0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00, // B
0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00, // C
0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00, // D
0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00, // E
0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00, // F
0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00, // G
0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00, // H
0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // I
0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // J
0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00, // K
0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00, // L
0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00, // M
0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00, // N
0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00, // O
0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00, // P 0x50
0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00, // Q
0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00, // R
0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00, // S
0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00, // T
0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00, // U
0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00, // V
0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, // W
0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00, // X
0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00, // Y
0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00, // Z
0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, // [
0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // \ (back slash)
0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, // ]
0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // ^
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, // _
0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00, // ` 0x60
0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00, // a
0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00, // b
0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00, // c
0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00, // d
0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00, // e
0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00, // f
0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C, // g
0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00, // h
0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00, // i
0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C, // j
0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00, // k
0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // l
0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00, // m
0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00, // n
0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00, // o
0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78, // p 0x70
0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F, // q
0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00, // r
0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00, // s
0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00, // t
0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00, // u
0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00, // v
0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00, // w
0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00, // x
0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C, // y
0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00, // z
0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00, // {
0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00, // |
0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00, // }
0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00, // ~
0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}; // DEL
#endif

#ifdef EPSON_EN_TEXT_LARGE
const unsigned char FONT8x16[97][16] = PROGMEM {
0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20
0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // !
0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00, // #
0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00, // $
0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00, // %
0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00, // &
0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00, // (
0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00, // )
0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00, // *
0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00, // +
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00, // ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // -
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // .
0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, // / (forward slash)
0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // 0 0x30
0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00, // 1
0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00, // 2
0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00, // 3
0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00, // 4
0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00, // 5
0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // 6
0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // 7
0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // 8
0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00, // 9
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // :
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00, // ;
0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, // <
0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, // =
0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, // >
0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00, // ?
0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00, // @ 0x40
0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00, // A
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00, // B
0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00, // C
0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00, // D
0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00, // E
0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, // F
0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00, // G
0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00, // H
0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // I
0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, // J
0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00, // K
0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00, // L
0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00, // M
0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00, // N
0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00, // O
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, // P 0x50
0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00, // Q
0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00, // R
0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // S
0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // T
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // U
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00, // V
0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00, // W
0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00, // X
0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // Y
0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00, // Z
0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, // [
0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00, // \ (back slash)
0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, // ]
0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, // _
0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` 0x60
0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00, // a
0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00, // b
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00, // c
0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00, // d
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00, // e
0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, // f
0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00, // g
0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00, // h
0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, // i
0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00, // j
0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00, // k
0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, // l
0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00, // m
0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00, // n
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00, // o
0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00, // p 0x70
0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00, // q
0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00, // r
0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00, // s
0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00, // t
0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00, // u
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00, // v
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00, // w
0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // x
0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00, // y
0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00, // z
0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, // {
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00, // |
0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, // }
0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // DEL
#endif

#endif

App (.c)

//
// 
//
//
//


#include "Epson.h"


#define PIN_LED   13



//********************************************************************
//
// This gets executed before anything else
//
//********************************************************************
void setup() {
  
  // Open serial port
  Serial.begin(9600);

  // Define pin direction
  pinMode(PIN_LED,   OUTPUT);

  // Initialize the LCD display  
  InitLcd();
  LCDClearScreen();

}



//********************************************************************
//
// Main loop
//
//********************************************************************
void loop() {
  
  byte b;
  byte i, j;

  const int TempColor[11] = { WHITE, 
                              BLACK, 
                              RED, 
                              GREEN, 
                              BLUE, 
                              CYAN, 
                              MAGENTA,
                              YELLOW, 
                              BROWN, 
                              ORANGE, 
                              PINK };

  const char *TempChar[11] = { "White", 
                               "Black", 
                               "Red", 
                               "Green", 
                               "Blue", 
                               "Cyan",
                               "Magenta", 
                               "Yellow", 
                               "Brown", 
                               "Orange", 
                               "Pink" };
  
  if (Serial.available() > 0) {

    b = Serial.read();

    switch(b) {
      
      case 'i':
        InitLcd();
        Serial.println("Initialize");
        break;    
      
      case 'C':
        LCDClearScreen();
        Serial.println("Clear");
        break;    
     
      case '0':
        WriteSpiCommand(DISOFF);
        Serial.println("Display off");
        break;
     
      case '1':
        WriteSpiCommand(DISON);
        Serial.println("Display on");
        break;
     
     
      case 'p':
        
        // set a few pixels
        LCDSetPixel(30, 120, RED);
        LCDSetPixel(34, 120, GREEN);
        LCDSetPixel(38, 120, BLUE);
        LCDSetPixel(40, 120, WHITE);
        break;
        
      case 's':  
        
#if EPSON_EN_TEXT == 1

        // draw some characters
        LCDPutChar('b', 20, 20, MEDIUM, WHITE, BLACK);
        
        // draw a string
        LCDPutStr("Hello World", 60, 5, MEDIUM, WHITE, BLACK);
        LCDPutStr("Hello World", 40, 5, MEDIUM, ORANGE, BLACK);
        LCDPutStr("Hello World", 20, 5, MEDIUM, PINK, BLACK);
#endif
        break;
        
      case 'r':

#if EPSON_EN_RECTANGLE == 1     
        // draw a filled box
        LCDSetRect(120, 60, 80, 80, FILL, BROWN);
        
        // draw a empty box
        LCDSetRect(120, 85, 80, 105, NOFILL, CYAN);
#endif        
        break;
        
      case 'l':  
        
        // draw some lines
#if EPSON_EN_LINE  == 1
        LCDSetLine(120, 10, 120, 50, YELLOW);
        LCDSetLine(120, 50, 80, 50, YELLOW);
        LCDSetLine(80, 50, 80, 10, YELLOW);
        LCDSetLine(80, 10, 120, 10, YELLOW);
        LCDSetLine(120, 85, 80, 105, YELLOW);
        LCDSetLine(80, 85, 120, 105, YELLOW);
#endif        
        break;
        
      case 'c':  
        // draw a circle
#if EPSON_EN_CIRCLE == 1        
        LCDSetCircle(65, 100, 10, RED);
#endif
        break;
        
      case 't':
      
        // ***************************************************************
        // * color test - show boxes of different colors
        // ***************************************************************
        for (j = 0; j < 11; j++) {
          
          // draw a filled box
#if EPSON_EN_RECTANGLE == 1     
          LCDSetRect(120, 10, 25, 120, FILL, TempColor[j]);
#endif          
          
          // label the color
#if EPSON_EN_TEXT == 1
          LCDPutStr(TempChar[j], 15, 40, SMALL,  YELLOW, BLACK);
          LCDPutStr(TempChar[j], 25, 40, MEDIUM, YELLOW, BLACK);
#endif          
          
          // wait a bit
          delay(1000*1);
        }
        
        break;
      
      default:
        Serial.println("Bad byte");
        break;  
      
    } // end switch  

  } else {
    
    delay(100);
    
  } // end if

}

fll-freak:

// | Rows| Nokia 6610 Display | Note: In general, you can't view column 130 or column 131
In my case, I couldn't view column 0 or 1, or row 0 or 1, or row 130 or 131 either unless I looked at the display from crazy angles. So, my 132 x 132 display was effectively knocked down to a 128x128. Good enough though...