/*! \file ks0108.c \brief Graphic LCD driver for HD61202/KS0108 displays. */ //***************************************************************************** // // File Name : 'ks0108.c' // Title : Graphic LCD driver for HD61202/KS0108 displays // Author : Pascal Stang - Copyright (C) 2001-2003 // Date : 10/19/2002 // Revised : 5/5/2003 // Version : 0.5 // Target MCU : Atmel AVR // Editor Tabs : 4 // // NOTE: This code is currently below version 1.0, and therefore is considered // to be lacking in some functionality or documentation, or may not be fully // tested. Nonetheless, you can expect most functions to work. // // This code is distributed under the GNU Public License // which can be found at http://www.gnu.org/licenses/gpl.txt // //***************************************************************************** #ifndef WIN32 // AVR specific includes #include #include #endif #include "global.h" #include "ks0108.h" // global variables GrLcdStateType GrLcdState; /*************************************************************/ /********************** LOCAL FUNCTIONS **********************/ /*************************************************************/ void glcdInitHW(void) { // initialize I/O ports // if I/O interface is in use #ifdef GLCD_PORT_INTERFACE //TODO: make setup of chip select lines contingent on how // many controllers are actually in the display // initialize LCD control lines levels cbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS0); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS1); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS2); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS3); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RESET); // initialize LCD control port to output sbi(GLCD_CTRL_DDR, GLCD_CTRL_RS); sbi(GLCD_CTRL_DDR, GLCD_CTRL_RW); sbi(GLCD_CTRL_DDR, GLCD_CTRL_E); sbi(GLCD_CTRL_DDR, GLCD_CTRL_CS0); sbi(GLCD_CTRL_DDR, GLCD_CTRL_CS1); sbi(GLCD_CTRL_DDR, GLCD_CTRL_CS2); sbi(GLCD_CTRL_DDR, GLCD_CTRL_CS3); sbi(GLCD_CTRL_DDR, GLCD_CTRL_RESET); // initialize LCD data outb(GLCD_DATA_PORT, 0x00); // initialize LCD data port to output outb(GLCD_DATA_DDR, 0xFF); #endif } void glcdControllerSelect(u08 controller) { #ifdef GLCD_PORT_INTERFACE //TODO: make control of chip select lines contingent on how // many controllers are actually in the display // unselect all controllers cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS0); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS1); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS2); cbi(GLCD_CTRL_PORT, GLCD_CTRL_CS3); // select requested controller switch(controller) { case 0: sbi(GLCD_CTRL_PORT, GLCD_CTRL_CS0); break; case 1: sbi(GLCD_CTRL_PORT, GLCD_CTRL_CS1); break; case 2: sbi(GLCD_CTRL_PORT, GLCD_CTRL_CS2); break; case 3: sbi(GLCD_CTRL_PORT, GLCD_CTRL_CS3); break; default: break; } #endif } void glcdBusyWait(u08 controller) { #ifdef GLCD_PORT_INTERFACE cli(); // wait until LCD busy bit goes to zero // select the controller chip glcdControllerSelect(controller); // do a read from control register outb(GLCD_DATA_PORT, 0xFF); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); outb(GLCD_DATA_DDR, 0x00); sbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); asm volatile ("nop"); asm volatile ("nop"); while(inb(GLCD_DATA_PIN) & GLCD_STATUS_BUSY) { cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); } cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); outb(GLCD_DATA_DDR, 0xFF); sei(); #else // sbi(MCUCR, SRW); // enable RAM waitstate // wait until LCD busy bit goes to zero while(*(volatile unsigned char *) (GLCD_CONTROLLER0_CTRL_ADDR + GLCD_CONTROLLER_ADDR_OFFSET*controller) & GLCD_STATUS_BUSY); // cbi(MCUCR, SRW); // disable RAM waitstate #endif } void glcdControlWrite(u08 controller, u08 data) { #ifdef GLCD_PORT_INTERFACE cli(); glcdBusyWait(controller); // wait until LCD not busy cbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); outb(GLCD_DATA_DDR, 0xFF); outb(GLCD_DATA_PORT, data); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); sei(); #else //sbi(MCUCR, SRW); // enable RAM waitstate glcdBusyWait(controller); // wait until LCD not busy *(volatile unsigned char *) (GLCD_CONTROLLER0_CTRL_ADDR + GLCD_CONTROLLER_ADDR_OFFSET*controller) = data; //cbi(MCUCR, SRW); // disable RAM waitstate #endif } u08 glcdControlRead(u08 controller) { register u08 data; #ifdef GLCD_PORT_INTERFACE cli(); glcdBusyWait(controller); // wait until LCD not busy cbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); outb(GLCD_DATA_DDR, 0x00); sbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); data = inb(GLCD_DATA_PIN); cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); outb(GLCD_DATA_DDR, 0xFF); sei(); #else //sbi(MCUCR, SRW); // enable RAM waitstate glcdBusyWait(controller); // wait until LCD not busy data = *(volatile unsigned char *) (GLCD_CONTROLLER0_CTRL_ADDR + GLCD_CONTROLLER_ADDR_OFFSET*controller); //cbi(MCUCR, SRW); // disable RAM waitstate #endif return data; } void glcdDataWrite(u08 data) { register u08 controller = (GrLcdState.lcdXAddr/GLCD_CONTROLLER_XPIXELS); #ifdef GLCD_PORT_INTERFACE cli(); glcdBusyWait(controller); // wait until LCD not busy sbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); outb(GLCD_DATA_DDR, 0xFF); outb(GLCD_DATA_PORT, data); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); sei(); #else //sbi(MCUCR, SRW); // enable RAM waitstate glcdBusyWait(controller); // wait until LCD not busy *(volatile unsigned char *) (GLCD_CONTROLLER0_CTRL_ADDR + GLCD_CONTROLLER_ADDR_OFFSET*controller) = data; //cbi(MCUCR, SRW); // disable RAM waitstate #endif // increment our local address counter GrLcdState.ctrlr[controller].xAddr++; GrLcdState.lcdXAddr++; if(GrLcdState.lcdXAddr >= GLCD_XPIXELS) { GrLcdState.lcdYAddr++; glcdSetYAddress(GrLcdState.lcdYAddr); glcdSetXAddress(0); } } u08 glcdDataRead(void) { register u08 data; register u08 controller = (GrLcdState.lcdXAddr/GLCD_CONTROLLER_XPIXELS); #ifdef GLCD_PORT_INTERFACE cli(); glcdBusyWait(controller); // wait until LCD not busy sbi(GLCD_CTRL_PORT, GLCD_CTRL_RS); outb(GLCD_DATA_DDR, 0x00); sbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sbi(GLCD_CTRL_PORT, GLCD_CTRL_E); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); data = inb(GLCD_DATA_PIN); cbi(GLCD_CTRL_PORT, GLCD_CTRL_E); cbi(GLCD_CTRL_PORT, GLCD_CTRL_RW); sei(); #else //sbi(MCUCR, SRW); // enable RAM waitstate glcdBusyWait(controller); // wait until LCD not busy data = *(volatile unsigned char *) (GLCD_CONTROLLER0_CTRL_ADDR + GLCD_CONTROLLER_ADDR_OFFSET*controller); //cbi(MCUCR, SRW); // disable RAM waitstate #endif // increment our local address counter GrLcdState.ctrlr[controller].xAddr++; GrLcdState.lcdXAddr++; if(GrLcdState.lcdXAddr >= GLCD_XPIXELS) { GrLcdState.lcdYAddr++; glcdSetYAddress(GrLcdState.lcdYAddr); glcdSetXAddress(0); } return data; } void glcdReset(u08 resetState) { // reset lcd if argument is true // run lcd if argument is false #ifdef GLCD_PORT_INTERFACE if(resetState) cbi(GLCD_CTRL_PORT, GLCD_CTRL_RESET); else sbi(GLCD_CTRL_PORT, GLCD_CTRL_RESET); #endif } void glcdSetXAddress(u08 xAddr) { u08 i; // record address change locally GrLcdState.lcdXAddr = xAddr; // clear y (col) address on all controllers for(i=0; i>3); pageAddr++) { // set page address glcdSetAddress(0, pageAddr); // clear all lines of this page of display memory for(xAddr=0; xAddr