/* * lcd128x64.c: * Graphics-based LCD driver. * This is designed to drive the parallel interface LCD drivers * based on the generic 12864H chips * * There are many variations on these chips, however they all mostly * seem to be similar. * This implementation has the Pins from the Pi hard-wired into it, * in particular wiringPi pins 0-7 so that we can use * digitalWriteByete() to speed things up somewhat. * * Copyright (c) 2013 Gordon Henderson. *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ * * wiringPi is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * wiringPi is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with wiringPi. If not, see . *********************************************************************** */ #include #include #include #include "font.h" #include "lcd128x64.h" // Size #define LCD_WIDTH 128 #define LCD_HEIGHT 64 // Hardware Pins // Note pins 0-7 are the 8-bit data port #define CS1 10 #define CS2 11 #define STROBE 12 #define RS 13 // Software copy of the framebuffer // it's 8-bit deep although the display itself is only 1-bit deep. static unsigned char frameBuffer [LCD_WIDTH * LCD_HEIGHT] ; static int maxX, maxY ; static int lastX, lastY ; static int xOrigin, yOrigin ; static int lcdOrientation = 0 ; /* * strobe: * Toggle the strobe (Really the "E") pin to the device. * According to the docs, data is latched on the falling edge. ********************************************************************************* */ static void strobe (void) { digitalWrite (STROBE, 1) ; delayMicroseconds (1) ; digitalWrite (STROBE, 0) ; delayMicroseconds (5) ; } /* * sentData: * Send an data or command byte to the display. ********************************************************************************* */ static void sendData (const int data, const int chip) { digitalWrite (chip, 0) ; digitalWriteByte (data) ; strobe () ; digitalWrite (chip, 1) ; } /* * sendCommand: * Send a command byte to the display ********************************************************************************* */ static void sendCommand (const int command, const int chip) { digitalWrite (RS, 0) ; sendData (command, chip) ; digitalWrite (RS, 1) ; } /* * setCol: SetLine: * Set the column and line addresses ********************************************************************************* */ static void setCol (int col, const int chip) { sendCommand (0x40 | (col & 0x3F), chip) ; } static void setLine (int line, const int chip) { sendCommand (0xB8 | (line & 0x07), chip) ; } /* * lcd128x64update: * Copy our software version to the real display ********************************************************************************* */ void lcd128x64update (void) { int line, x, y, fbLoc ; unsigned char byte ; // Left side for (line = 0 ; line < 8 ; ++line) { setCol (0, CS1) ; setLine (line, CS1) ; for (x = 63 ; x >= 0 ; --x) { byte = 0 ; for (y = 0 ; y < 8 ; ++y) { fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ; if (frameBuffer [fbLoc] != 0) byte |= (1 << y) ; } sendData (byte, CS1) ; } } // Right side for (line = 0 ; line < 8 ; ++line) { setCol (0, CS2) ; setLine (line, CS2) ; for (x = 127 ; x >= 64 ; --x) { byte = 0 ; for (y = 0 ; y < 8 ; ++y) { fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ; if (frameBuffer [fbLoc] != 0) byte |= (1 << y) ; } sendData (byte, CS2) ; } } } /* * lcd128x64setOrigin: * Set the display offset origin ********************************************************************************* */ void lcd128x64setOrigin (int x, int y) { xOrigin = x ; yOrigin = y ; } /* * lcd128x64setOrientation: * Set the display orientation: * 0: Normal, the display is portrait mode, 0,0 is top left * 1: Landscape * 2: Portrait, flipped * 3: Landscape, flipped ********************************************************************************* */ void lcd128x64setOrientation (int orientation) { lcdOrientation = orientation & 3 ; lcd128x64setOrigin (0,0) ; switch (lcdOrientation) { case 0: maxX = LCD_WIDTH ; maxY = LCD_HEIGHT ; break ; case 1: maxX = LCD_HEIGHT ; maxY = LCD_WIDTH ; break ; case 2: maxX = LCD_WIDTH ; maxY = LCD_HEIGHT ; break ; case 3: maxX = LCD_HEIGHT ; maxY = LCD_WIDTH ; break ; } } /* * lcd128x64orientCoordinates: * Adjust the coordinates given to the display orientation ********************************************************************************* */ void lcd128x64orientCoordinates (int *x, int *y) { register int tmp ; *x += xOrigin ; *y += yOrigin ; *y = maxY - *y - 1 ; switch (lcdOrientation) { case 0: break; case 1: tmp = maxY - *y - 1 ; *y = *x ; *x = tmp ; break; case 2: *x = maxX - *x - 1 ; *y = maxY - *y - 1 ; break; case 3: *x = maxX - *x - 1 ; tmp = *y ; *y = *x ; *x = tmp ; break ; } } /* * lcd128x64getScreenSize: * Return the max X & Y screen sizes. Needs to be called again, if you * change screen orientation. ********************************************************************************* */ void lcd128x64getScreenSize (int *x, int *y) { *x = maxX ; *y = maxY ; } /* ********************************************************************************* * Standard Graphical Functions ********************************************************************************* */ /* * lcd128x64point: * Plot a pixel. ********************************************************************************* */ void lcd128x64point (int x, int y, int colour) { lastX = x ; lastY = y ; lcd128x64orientCoordinates (&x, &y) ; if ((x < 0) || (x >= LCD_WIDTH) || (y < 0) || (y >= LCD_HEIGHT)) return ; frameBuffer [x + y * LCD_WIDTH] = colour ; } /* * lcd128x64line: lcd128x64lineTo: * Classic Bressenham Line code ********************************************************************************* */ void lcd128x64line (int x0, int y0, int x1, int y1, int colour) { int dx, dy ; int sx, sy ; int err, e2 ; lastX = x1 ; lastY = y1 ; dx = abs (x1 - x0) ; dy = abs (y1 - y0) ; sx = (x0 < x1) ? 1 : -1 ; sy = (y0 < y1) ? 1 : -1 ; err = dx - dy ; for (;;) { lcd128x64point (x0, y0, colour) ; if ((x0 == x1) && (y0 == y1)) break ; e2 = 2 * err ; if (e2 > -dy) { err -= dy ; x0 += sx ; } if (e2 < dx) { err += dx ; y0 += sy ; } } } void lcd128x64lineTo (int x, int y, int colour) { lcd128x64line (lastX, lastY, x, y, colour) ; } /* * lcd128x64rectangle: * A rectangle is a spoilt days fishing ********************************************************************************* */ void lcd128x64rectangle (int x1, int y1, int x2, int y2, int colour, int filled) { register int x ; if (filled) { /**/ if (x1 == x2) lcd128x64line (x1, y1, x2, y2, colour) ; else if (x1 < x2) for (x = x1 ; x <= x2 ; ++x) lcd128x64line (x, y1, x, y2, colour) ; else for (x = x2 ; x <= x1 ; ++x) lcd128x64line (x, y1, x, y2, colour) ; } else { lcd128x64line (x1, y1, x2, y1, colour) ; lcd128x64lineTo (x2, y2, colour) ; lcd128x64lineTo (x1, y2, colour) ; lcd128x64lineTo (x1, y1, colour) ; } } /* * lcd128x64circle: * This is the midpoint circle algorithm. ********************************************************************************* */ void lcd128x64circle (int x, int y, int r, int colour, int filled) { int ddF_x = 1 ; int ddF_y = -2 * r ; int f = 1 - r ; int x1 = 0 ; int y1 = r ; if (filled) { lcd128x64line (x, y + r, x, y - r, colour) ; lcd128x64line (x + r, y, x - r, y, colour) ; } else { lcd128x64point (x, y + r, colour) ; lcd128x64point (x, y - r, colour) ; lcd128x64point (x + r, y, colour) ; lcd128x64point (x - r, y, colour) ; } while (x1 < y1) { if (f >= 0) { y1-- ; ddF_y += 2 ; f += ddF_y ; } x1++ ; ddF_x += 2 ; f += ddF_x ; if (filled) { lcd128x64line (x + x1, y + y1, x - x1, y + y1, colour) ; lcd128x64line (x + x1, y - y1, x - x1, y - y1, colour) ; lcd128x64line (x + y1, y + x1, x - y1, y + x1, colour) ; lcd128x64line (x + y1, y - x1, x - y1, y - x1, colour) ; } else { lcd128x64point (x + x1, y + y1, colour) ; lcd128x64point (x - x1, y + y1, colour) ; lcd128x64point (x + x1, y - y1, colour) ; lcd128x64point (x - x1, y - y1, colour) ; lcd128x64point (x + y1, y + x1, colour) ; lcd128x64point (x - y1, y + x1, colour) ; lcd128x64point (x + y1, y - x1, colour) ; lcd128x64point (x - y1, y - x1, colour) ; } } } /* * lcd128x64ellipse: * Fast ellipse drawing algorithm by * John Kennedy * Mathematics Department * Santa Monica College * 1900 Pico Blvd. * Santa Monica, CA 90405 * jrkennedy6@gmail.com * -Confirned in email this algorithm is in the public domain -GH- ********************************************************************************* */ static void plot4ellipsePoints (int cx, int cy, int x, int y, int colour, int filled) { if (filled) { lcd128x64line (cx + x, cy + y, cx - x, cy + y, colour) ; lcd128x64line (cx - x, cy - y, cx + x, cy - y, colour) ; } else { lcd128x64point (cx + x, cy + y, colour) ; lcd128x64point (cx - x, cy + y, colour) ; lcd128x64point (cx - x, cy - y, colour) ; lcd128x64point (cx + x, cy - y, colour) ; } } void lcd128x64ellipse (int cx, int cy, int xRadius, int yRadius, int colour, int filled) { int x, y ; int xChange, yChange, ellipseError ; int twoAsquare, twoBsquare ; int stoppingX, stoppingY ; twoAsquare = 2 * xRadius * xRadius ; twoBsquare = 2 * yRadius * yRadius ; x = xRadius ; y = 0 ; xChange = yRadius * yRadius * (1 - 2 * xRadius) ; yChange = xRadius * xRadius ; ellipseError = 0 ; stoppingX = twoBsquare * xRadius ; stoppingY = 0 ; while (stoppingX >= stoppingY) // 1st set of points { plot4ellipsePoints (cx, cy, x, y, colour, filled) ; ++y ; stoppingY += twoAsquare ; ellipseError += yChange ; yChange += twoAsquare ; if ((2 * ellipseError + xChange) > 0 ) { --x ; stoppingX -= twoBsquare ; ellipseError += xChange ; xChange += twoBsquare ; } } x = 0 ; y = yRadius ; xChange = yRadius * yRadius ; yChange = xRadius * xRadius * (1 - 2 * yRadius) ; ellipseError = 0 ; stoppingX = 0 ; stoppingY = twoAsquare * yRadius ; while (stoppingX <= stoppingY) //2nd set of points { plot4ellipsePoints (cx, cy, x, y, colour, filled) ; ++x ; stoppingX += twoBsquare ; ellipseError += xChange ; xChange += twoBsquare ; if ((2 * ellipseError + yChange) > 0 ) { --y ; stoppingY -= twoAsquare ; ellipseError += yChange ; yChange += twoAsquare ; } } } /* * lcd128x64putchar: * Print a single character to the screen ********************************************************************************* */ void lcd128x64putchar (int x, int y, int c, int bgCol, int fgCol) { int y1, y2 ; unsigned char line ; unsigned char *fontPtr ; // Can't print if we're offscreen //if ((x < 0) || (x >= (maxX - fontWidth)) || (y < 0) || (y >= (maxY - fontHeight))) // return ; fontPtr = font + c * fontHeight ; for (y1 = fontHeight - 1 ; y1 >= 0 ; --y1) { y2 = y + y1 ; line = *fontPtr++ ; lcd128x64point (x + 0, y2, (line & 0x80) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 1, y2, (line & 0x40) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 2, y2, (line & 0x20) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 3, y2, (line & 0x10) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 4, y2, (line & 0x08) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 5, y2, (line & 0x04) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 6, y2, (line & 0x02) == 0 ? bgCol : fgCol) ; lcd128x64point (x + 7, y2, (line & 0x01) == 0 ? bgCol : fgCol) ; } } /* * lcd128x64puts: * Send a string to the display. Obeys \n and \r formatting ********************************************************************************* */ void lcd128x64puts (int x, int y, const char *str, int bgCol, int fgCol) { int c, mx, my ; mx = x ; my = y ; while (*str) { c = *str++ ; if (c == '\r') { mx = x ; continue ; } if (c == '\n') { mx = x ; my -= fontHeight ; continue ; } lcd128x64putchar (mx, my, c, bgCol, fgCol) ; mx += fontWidth ; if (mx >= (maxX - fontWidth)) { mx = 0 ; my -= fontHeight ; } } } /* * lcd128x64clear: * Clear the display to the given colour. ********************************************************************************* */ void lcd128x64clear (int colour) { register int i ; register unsigned char *ptr = frameBuffer ; for (i = 0 ; i < (maxX * maxY) ; ++i) *ptr++ = colour ; } /* * lcd128x64setup: * Initialise the display and GPIO. ********************************************************************************* */ int lcd128x64setup (void) { int i ; for (i = 0 ; i < 8 ; ++i) pinMode (i, OUTPUT) ; digitalWrite (CS1, 1) ; digitalWrite (CS2, 1) ; digitalWrite (STROBE, 0) ; digitalWrite (RS, 1) ; pinMode (CS1, OUTPUT) ; pinMode (CS2, OUTPUT) ; pinMode (STROBE, OUTPUT) ; pinMode (RS, OUTPUT) ; sendCommand (0x3F, CS1) ; // Display ON sendCommand (0xC0, CS1) ; // Set display start line to 0 sendCommand (0x3F, CS2) ; // Display ON sendCommand (0xC0, CS2) ; // Set display start line to 0 lcd128x64clear (0) ; lcd128x64setOrientation (0) ; lcd128x64update () ; return 0 ; }