Driver - verzió 1.00, kiadás dátuma 2007. Október 30.
Ez a driver csak 2 soros HD44780 chip kompatibilis vezérlővel szerelt LCD képernyőkkel működik együtt.
A driver egy EW162G0 típusú LCD kijelzővel lett tesztelve.
A driverrel kapcsolatos bugokat és kéréseket a következő címre írjátok: swap@inf.elte.hu
A teljes driver csomag, beleértve a forrásokat, binárisokat, stb.: >> AKTUÁLIS VERZIÓJA LETÖLTHETŐ ITT <<
!!! DRIVER HASZNÁLAT !!!
- Töltsd le a driver-t
- Csomagold ki az mc (midnight commander) vagy a tar program segítségével
- Ha használat előtt újra akarod fordítani, akkor
- Telepítsd fel a gcc-t
- Bizonyosodj meg róla, hogy a kernel verziódnak megfelelő kernel header csomagot telepítetted
- Futtasd a make parancsot: make
- Ha sikeres volt a make futása, akkor a következő kernel modul fájlt kell kapnod: hd44780.ko
- Driver installálása: ./install_hd44780_device install
Ha mindent jól csináltál, akkor a következő jelenik meg az LCD kijelzőn:
- Driver eltávolítása: ./install_hd44780_device remove
Ha sikeres az driver eltávolítása, akkor az LCD törli a képernyőtartalmát. - A driver tesztelése: cat > /dev/hd44780_lcd
Bármit beírhatsz szövegnek.
ENTER hatására az LCD kurzorja a 2. sor elejére ugrik,
TAB hatására az képernyő törlődik és a kurzor visszaugrik az 1. sor elejére. - Egyszerűen használhatod a driver fájlt /dev/hd44780_lcd, mint bármely hagyományos fájlt.
- MEGJEGYZÉS: A driver kölcsönös kizárást használ! Egyszerre csak egy alkalmazás tudja az LCD-t használni. A Driver az első open() kivételével nem enged további fájlmegnyitást mindaddig, amíg nem zárjuk le a fájlt close() művelettel.
hd44780.h - fejlécállomány (a chip-et vezérlő függvények)
Alapértékek, Include-ok, Függvény prototípusok
#define LCD_INSTRUCTION 0
#define LCD_DATA 1
#define LCD_WRITE 0
#define LCD_READ 1
#define WAIT_TIME 10
#include < asm/io.h >
#include < linux/delay.h >
void lcd_send_4_bits(char, char, int);
void lcd_send_byte(char, char, int);
void lcd_clear(void);
void lcd_putc(char);
void lcd_write(const char*, int);
void lcd_gohome(void);
void lcd_gotoxy(int, int);
void lcd_setcharpattern(char, const char*);
void lcd_init(void);
4-bites alacsony szintű adatátvitel
void lcd_send_4_bits(char c, char rs, int Wait)
{
c = c << 4;
outb((c | 0x04) | rs, LPT_PORT); // ENABLE (Prepare)
outb((c & 0xf0) | rs, LPT_PORT); // DISABLE (Transmit)
mdelay(Wait);
}
A 8-bites üzemmódú adatátvitel emulálása 4-bites módban
void lcd_send_byte(char c, char rs, int Wait)
{
lcd_send_4_bits( (c >> 4), rs, Wait );
lcd_send_4_bits( (c & 15), rs, Wait );
}
Egyszerű műveletek: képernyő törlése, karakter kiírása, kurzor pozicionálása
void lcd_clear()
{
lcd_send_byte( 0x01, LCD_INSTRUCTION, 5 );
}
void lcd_putc(char c)
{
lcd_send_byte( c, LCD_DATA, 1 );
}
void lcd_gohome()
{
lcd_send_byte( 0x02, LCD_INSTRUCTION, 5 );
}
void lcd_gotoxy(int x = 0, int y = 0)
{
char c = 0x80 | (x & 0x3f) | (y << 6);
lcd_send_byte( c, LCD_INSTRUCTION, 1);
}
Függvény a karakterek bittérképének átdefiniálására
void lcd_setcharpattern(char c_pos, char* pattern)
{
char c = 0x40 | ((c_pos & 0x3f) << 3);
// SELECT CGRAM ADDRESS
lcd_send_byte( c, LCD_INSTRUCTION, 1);
// UPLOAD FONT PATTERN
lcd_send_byte( pattern[0], LCD_DATA, 1 );
lcd_send_byte( pattern[1], LCD_DATA, 1 );
lcd_send_byte( pattern[2], LCD_DATA, 1 );
lcd_send_byte( pattern[3], LCD_DATA, 1 );
lcd_send_byte( pattern[4], LCD_DATA, 1 );
lcd_send_byte( pattern[5], LCD_DATA, 1 );
lcd_send_byte( pattern[6], LCD_DATA, 1 );
lcd_send_byte( pattern[7], LCD_DATA, 1 );
}
A képernyő inicializálása
void lcd_init(void)
{
int i;
char init[10];
init[0] = 0x03; // INIT
init[1] = 0x02;
init[2] = 0x08;
init[3] = 0x0C; // DISPLAY ON
init[4] = 0x06; // ENTRY MODE SET
outb(0, LPT_PORT);
// FUNCTION SET 4 BIT INIT
for (i = 0; i < 3; i++)
lcd_send_4_bits( init[0], LCD_INSTRUCTION, 20 );
// FUNCTION SET 4 BIT INIT
for (i = 0; i < 2; i++)
lcd_send_4_bits( init[1], LCD_INSTRUCTION, 20 );
// LINES 2, 5x8 FONT
lcd_send_4_bits( init[2], LCD_INSTRUCTION, 20 );
// DISPLAY ON
lcd_send_byte( init[3], LCD_INSTRUCTION, 10 );
// DISPLAY CLEAR
lcd_clear();
// ENTRY MODE SET
lcd_send_byte( init[4], LCD_INSTRUCTION, 5 );
}
Example 1. Szöveg kiírása az LCD képernyőre (a driver-ben)
char str[] = {"Testing 1,2,3 "
"It' Works ! "};
int len = strlen(str);
for(int j = 0; j < len; j++) lcd_putc(str[j]);
Mint látható, minden sorhoz 40 bájtnyi RAM tartozik, noha csak 16 karakter látható.
Ennek két oka van: az egyik, hogy gördíteni tudjuk a szöveget a képernyőn anélkül, hogy
újra kéne írnunk a memória tartalmát, másrészt nagyobb kijelzőkhöz is használható a
gyártáskor ugyanaz a chip.
Example 2. Kurzor pozicionálása a 2. sor 10. helyére (a driver-ben)
lcd_gotoxy(10,1);
Example 3. Az ASCII 2-es karakter megjelenésének átdefiniálása és megjelenítése a kijelzőn (a driver-ben)
char pattern_temp[] = { 0x0F, 0x0C, 0x0F, 0x0C, \
0x0E, 0x11, 0x1F, 0x0E };
lcd_setcharpattern(2, (char*)pattern_temp);
lcd_putc(2);
Ez a példa jól mutatja, hogy minden karakter 8 sorból áll, és minden sort egy-egy bájt ábrázol, de mivel
egy karakter csak 5 pixel széles, ezért csak az alsó 5 bitet használjuk az adott sor bájtjából.
hd44780.c - modul forrása
Includ-ok, Licensz beállítása a kernel számára, Változók deklarációja
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >
#include < linux/tty.h >
#include < linux/ioport.h >
#include < linux/fs.h >
#include < asm/uaccess.h >
#include < linux/cdev.h >
MODULE_LICENSE("GPL");
#define DEVNAME "HD44780_LCD"
static char msg[200];
static dev_t dev;
static struct cdev my_cdev;
static int DevMajor;
static int isOpened = 0;
static int LPT_PORT = 0x378;
/* LOOKING FOR COMMAND LINE ARGUMENTS */
module_param(LPT_PORT, int, 0);
LCD core driver include-ja, Függvény prototípusok
/* INCLUDE THE DRIVER CORE */
#include "hd44780.h"
/* FUNCTION PROTOTYPES */
int print_msg(char*);
static int device_open(struct inode*, struct file*);
static int device_release(struct inode*, struct file*);
static ssize_t device_write(struct file*, const char*, size_t, loff_t*);
A karakteres device létrehozásához szükséges adatok és függvények definiálása
/* FILE OPERATION STRUCT TO REGISTER CHARACTER DEVICE */
static struct file_operations fops = {
.write = device_write,
.open = device_open,
.release = device_release,
.owner = THIS_MODULE
};
/* DEVICE OPERATIONS */
static int device_open(struct inode* in, struct file* f)
{
if (isOpened) return -EBUSY;
isOpened = 1;
return 0;
}
static int device_release(struct inode* in, struct file* f)
{
isOpened = 0;
return 0;
}
static ssize_t device_write(struct file* f, const char* buf, \
size_t len, loff_t* off)
{
int i;
for (i = 0; i < len; ++i)
{
switch(buf[i])
{
case 9:
lcd_clear();
break;
case 10:
case 13:
lcd_gotoxy(0,1);
break;
default:
lcd_putc(buf[i]);
}
}
return len;
}
Fontos, hogy a hd44780.h include-ját megelőzze az LPT_PORT változó deklarálása, ezért ezek nem felcserélhetőek.
Helper függvény az aktuáls tty konzolra való íráshoz
/* HELPER FUNCTION TO DEBUG MESSAGES TO CONSOLE*/
int print_msg(char* str)
{
struct tty_struct *driver_tty = current->signal->tty;
if (!driver_tty) return -ENOTTY;
(driver_tty->driver->write)(driver_tty, str, strlen(str));
return 0;
}
Module Inicializálás és Felszabadítás
/* MODULE INITIALISATION */
int LCD_driver_init(void)
{
int res;
res = alloc_chrdev_region(&dev, 0, 1, DEVNAME);
if (res < 0) return res;
DevMajor = MAJOR(dev);
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;
res = cdev_add(&my_cdev, dev, 1);
if (res < 0)
{
unregister_chrdev_region(dev, 1);
return res;
}
// INIT LCD
lcd_init();
lcd_write("HD44780 Driver", 14);
lcd_gotoxy(0,1);
lcd_write("Loaded!", 7);
print_msg("HD44780 LCD Driver loaded.\n\r");
sprintf(msg, "Major number: %d.\n\r", DevMajor);
print_msg(msg);
return 0;
}
/* MODULE EXIT */
void LCD_driver_exit(void)
{
lcd_clear();
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
sprintf(msg, "HD44780 LCD Driver unloaded.\n\r");
print_msg(msg);
}
module_init(LCD_driver_init);
module_exit(LCD_driver_exit);
Makefile - Kernel > 2.6.00 verzióhoz
ifneq ($(KERNELRELEASE),)
obj-m := hd44780.o
else
KDIR := /lib/modules/`uname -r`/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
endif
clean:
@rm -rf *~ *.o *.mod.c .*.cmd .tmp_versions
install_44780_device - Driver telepítő / eltávolító szkript
#!/bin/bash
module="hd44780"
devname="HD44780_LCD"
device="hd44780_lcd"
if [ "$1" = "install" ]
then
echo "Installing...";
shift;
insmod ./$module.ko $*
major=`awk "\\$2==\"$devname\" {print \\$1}" /proc/devices`
echo "Device major = $major"
mknod /dev/$device c $major 0
elif [ "$1" = "remove" ]
then
echo "Removing...";
rm /dev/$device
rmmod $module
else
echo "To install driver: ./$0 install";
echo "To remove driver: ./$0 remove";
fi