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)));
}
*/
