lcm.h
#ifndef LCMMODULE_H #define LCMMODULE_H #define ENTER_KEY 0xA7 #define ESC_KEY 0x87 #define UP_KEY 0x8F #define DOWN_KEY 0xAF #define ENTER_ROKEY 0xE7 #define ESC_ROKEY 0xC7 #define UP_ROKEY 0xCF #define DOWN_ROKEY 0xEF #ifdef LCM_DEBUG #define DPRINT(fmt, args...) printk(KERN_ERR fmt, ## args) #else #define DPRINT(fmt, args...) #endif /* * IOCTL Codes */ #define LCM_MAGIC_NUM 0x95 #define KPAD_MAGIC_NUM 0x96 /* Default IO port addresses for lpt ports 0, 1 and 2. */ #define LPT0_ADDRESS 0x03bc // corresponds to lpt0: on most PCs #define LPT1_ADDRESS 0x0378 // corresponds to lpt1: on most PCs #define LPT2_ADDRESS 0x0278 // corresponds to lpt2: on most PCs /* IO port base address of your parallel port connect to LCD panel. */ #define LCD_ADDRESS LPT1_ADDRESS // corresponds to lpt port with LCD /* IO port address for data, status and control bytes of LPT port. */ #define LCD_DATA_ADDRESS LCD_ADDRESS+0 // Data Port at base address + 0 #define LCD_STATUS_ADDRESS LCD_ADDRESS+1 // Status Port at base address + 1 #define LCD_CONTROL_ADDRESS LCD_ADDRESS+2 // Control Port at base address + 2 /* LCD Display specific information */ #define LCD_ROWS 2 // number of rows (lines) displayed #define LCD_COLS 16 // number of columns (characters) per row #define LCD_SIZE (LCD_ROWS * LCD_COLS) // total chars displayed #endif /* end LCMMODULE_H */
lcm.c
/************************************************************************* This program demostrates how the LCD module and keypad work. It will print out designated strings on the LCD module and get in a loop of echoing values back from Keypad when you press/release any buttom in the keypad. release: Apr, 6, 2009 developer: ginlin@nexcom stevenwu@nexcom ***************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <sys/io.h> #include "lcm.h" #define DEBUG #define NEX_INVALID -1 #ifdef DEBUG #define MYPRINT(msg...) printf(msg) #else #define MYPRINT(msg...) do { } while(0) #endif //mapping from offset value to Address Counter, for 2*16 display static char offToDDr[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; static int f_pos = 0; // user functions void lcm_init(void); // init LCM controller void lcm_clear(void); // clear display and reset cursor position int lcm_write(char *s); // write message to LCM display int lcm_lseek(int offset, int whence); // move cursor unsigned char kpad_poll(); // check if key pressed // internal functions int acquire_io_privilege(); void release_io_privilege(); unsigned char inb(unsigned short port); void outb(unsigned char data, unsigned short port); void lcm_write_control(unsigned char cmd); void lcm_write_data(unsigned char data); int main(int argc, char *argv[]) { int i; int access; char *string1 = "booting..."; char *string2 = "shutting down..."; // do this once at the beginning of program if ((access = acquire_io_privilege()) < 0) { fprintf(stderr, "Couldn't get io privilege\n"); exit(1); } MYPRINT("1\n"); // demo how to init LCM lcm_init(); MYPRINT("2\n"); // demo how to clear LCM display lcm_clear(); sleep(2); // demo how to move cursor to second line if (lcm_lseek(16, 0) < 0) { fprintf(stderr, "lseek() failed\n"); exit(-1); } // demo how to write the desired string lcm_write(string1); sleep(1); // demo how to move cursor to first line if (lcm_lseek(0, 0) < 0) { fprintf(stderr, "lseek() failed\n"); exit(-1); } // demo how to write the desired string lcm_write(string2); // demo how to check keypad while (1) { switch (kpad_poll()) { case ENTER_KEY: printf("Enter_key\n"); break; case ENTER_ROKEY: printf("Enter_ROkey\n"); break; case ESC_KEY: printf("ESC_key\n"); break; case ESC_ROKEY: printf("ESC_ROkey\n"); break; case UP_KEY: printf("UP_key\n"); break; case UP_ROKEY: printf("UP_ROkey\n"); break; case DOWN_KEY: printf("DOWN_key\n"); break; case DOWN_ROKEY: printf("DOWN_ROkey\n"); break; default: printf("The value you got is %x\n", i); break; } sleep(1); } // do this once at end of program release_io_privilege(access); exit(0); } void lcm_clear() { //clear display - write 0x20 to DDRAM and set its address to AC lcm_write_control(0x01); //move current position to the head f_pos = 0; } unsigned char kpad_poll() { return (inb(LCD_STATUS_ADDRESS)); } int lcm_lseek(int offset, int whence) { int newpos; int ddram_addr; if ((f_pos < 0) || (f_pos > LCD_SIZE)) { MYPRINT("LCM: device llseek: file position out of range (0x%x)\n", f_pos); return (-1); } switch (whence) { case 0: /* SEEK_SET */ newpos = offset; break; case 1: /* SEEK_CUR */ newpos = f_pos + offset; break; case 2: /* SEEK_END */ newpos = LCD_SIZE - offset; // max size - offset break; default: /* can't happen */ return (NEX_INVALID); } if ((newpos < 0) || (newpos > LCD_SIZE)) { MYPRINT("LCM: device llseek: new position out of range (0x%x)\n", (int) newpos); return (NEX_INVALID); } f_pos = newpos; //map the corresponding Address Counter ddram_addr = offToDDr[newpos]; lcm_write_control(0x80 | ddram_addr); // 0x80 - set ddram address cmd MYPRINT("LCM: device llseek: new position (0x%x)\n", f_pos); return (newpos); } int lcm_write(char *s) { int length = strlen(s); char c = 0; int cur = f_pos; /* * debug: Determine if position is at or past end of LCD. shouldn't be */ if ((cur > (LCD_SIZE - 1)) || (cur < 0)) { MYPRINT("LCM: device write: file position out of range (0x%x)\n", (int) cur); return (-1); } /* * Determine if write will go past end. If so, modify length. */ if ((cur + length) > LCD_SIZE) length = LCD_SIZE - cur; /* * Start writing (length) bytes at current location, length now won't be out of range */ for (; length > 0; length--) { /* * Set real Address Counter to the current file position before write data */ lcm_write_control(0x80 | offToDDr[f_pos]); c = *s; s++; //MYPRINT("LCM: device write: get_user (%c)\n", c); lcm_write_data(c); (f_pos)++; } MYPRINT("LCM: device write: current file position (0x%x)\n", f_pos); MYPRINT("LCM: device write: current file position address (0x%x)\n", offToDDr[f_pos]); return (length); // return number of bytes written } /* End of lcm_write() */ /* ** lcm_init: Initialize the display. */ void lcm_init(void) { lcm_write_control(0x30); // delay >4.1ms usleep(5000); lcm_write_control(0x30); // delay >100us usleep(200); lcm_write_control(0x30); lcm_write_control(0x3e); // 0x1110, 8 bits xfer, 2 lines and 5x10 dots lcm_write_control(0x01); // clear display lcm_write_control(0x06); // entry mode - increment on, no display shift lcm_write_control(0x0e); // display on, cursor on, blanking off lcm_write_control(0x02); // return cursor home (from sample code) } /* Mapping of Control bits to LCD device * * bit 7: N/A * bit 6: N/A * bit 5: N/A * bit 4: N/A * bit 3: LCD RS (HW INV) 0 -> DATA, 1 -> CMD * bit 2: LCD R/W 0 -> WRITE, 1 -> READ * bit 1: LCD Enable (HW INV) 0 -> HIGH, 1 -> LO * bit 0: N/A */ /* ** lcm_write_control: Write one byte control instruction to the LCD */ void lcm_write_control(unsigned char cmd) { if (ioperm(0x08, LCD_CONTROL_ADDRESS, 1)) return; outb(0x08, LCD_CONTROL_ADDRESS); //command mode, RS = 1 usleep(600); outb(cmd, LCD_DATA_ADDRESS); usleep(600); outb(0x08, LCD_CONTROL_ADDRESS); //cmmand mode plus the E -> 0 (hi) usleep(600); outb(0x0A, LCD_CONTROL_ADDRESS); //command mode but E -> 1 (lo) usleep(600); } /* ** lcm_write_data: Write one byte of data to the LCD */ void lcm_write_data(unsigned char data) { outb(0x02, LCD_CONTROL_ADDRESS); //data mode, E -> 1 (lo) usleep(100); outb(data, LCD_DATA_ADDRESS); usleep(100); outb(0x00, LCD_CONTROL_ADDRESS); //cmmand mode plus the E -> 0 (hi) usleep(100); outb(0x02, LCD_CONTROL_ADDRESS); //command mode but E -> 1 (lo) } int acquire_io_privilege() { int io; if ((io = open("/dev/parport0", O_RDONLY)) == -1) { printf("fail to get i/o privilege\n"); return -1; } else return io; } void release_io_privilege(int access) { close(access); } /* unsigned char inb(unsigned short port) { unsigned char data; __asm __volatile("inb %1,%0":"=a"(data):"id"((unsigned short) (port))); return (data); } void outb(unsigned char data, unsigned short port) { __asm __volatile("outb %0,%1"::"a"(data), "id"((unsigned short) (port))); } */