CLCD + 키메트릭스 조합
1.Make
2.comfile_led
3.
run
4.
소스코드
Makefile
KDIR := /home/hwanseung/270/kernel/linux-2.6.11-h270-tku_v1.1-app
obj-m := clcd_key.o
build: make -C $(KDIR) SUBDIRS=$(PWD) modules
clean: rm -rf *.o *.ko *.mod.c |
Clcd_key.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/fs.h>
#include <linux/delay.h> #include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/hardware.h> #include <asm/io.h>
#define CLCD_MAJOR 238 #define CLCD_NAME "CLCD"
#define FPGA_CLCD_WR_ADD (0x12300000) #define FPGA_CLCD_RS_ADD (0x12380000) #define CLCD_CMD_ADDR (*((volatile unsigned char *)(mem_base_wr))) #define CLCD_DATA_ADDR (*((volatile unsigned char *)(mem_base_rs)))
static void *mem_base_wr, *mem_base_rs; static unsigned long mem_addr_wr, mem_addr_rs, mem_len;
#define KEY_MAJOR 233 #define KEY_NAME "KEY" #define SCAN_NUM 4
#define FPGA_KEY_OUT (0x11D00000) #define FPGA_KEY_IN (0x11E00000)
#define KEYOUT (*(volatile unsigned char *)mem_key_out) #define KEYIN (*(volatile unsigned char *)mem_key_in)
static void *mem_key_out, *mem_key_in;
//전역변수 선언 static struct timer_list key_timer_str; static unsigned char key_data; static pid_t id; static int n = 1;
static void lcd_init(void) // LCD 초기화 { CLCD_CMD_ADDR = 0x38; // 8-비트, 2 라인, 5x8 iounmap(mem_base_wr); mdelay(300); CLCD_CMD_ADDR = 0x0e; // LCD 디스플레이 ON, 커서 ON mdelay(100); CLCD_CMD_ADDR = 0x02; // 커서를 홈으로 이동 mdelay(100); CLCD_CMD_ADDR = 0x01; // 화면 정리 mdelay(100); }
static void string_out(char *str) { char *s; int i=0;
printk("%s\n", str); lcd_init(); for (s=str; *s; s++) { CLCD_DATA_ADDR = *s; if(i == 15) { // 출력할 문자가 0 ~ 15열을 초과하므로 udelay(100); // 2번 행에 문자를 출력 CLCD_CMD_ADDR = 0xC0; // D7=1, D6=1, D5 ~ D0는 모두 1 } udelay(100); i++; } }
int clcd_open (struct inode *inode, struct file *filp) { return 0; // success }
int clcd_release (struct inode *inode, struct file *filp) { return 0; }
ssize_t clcd_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) { char data[32];
memset(data, 0 , 32); copy_from_user(data, buf, count); string_out(data); return 0; }
struct file_operations clcd_fops = { .owner = THIS_MODULE, .write = clcd_write, .open = clcd_open, .release = clcd_release, };
int key_open (struct inode *inode, struct file *filp) { return 0; }
int key_release (struct inode *inode, struct file *filp) { del_timer(&key_timer_str); // 타이머 리스트에서 타이머 제거 return 0; }
ssize_t key_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { copy_to_user(buf, &key_data, sizeof(key_data)); // 커널 영역에서 사용자 영역으로 return 0; // 복사 }
void timer_function(unsigned long data) { unsigned int i, in, out;
for(i=0;i<4;i++){ out = (1 << i); KEYOUT = out; in = ((KEYIN) & (0x0F)); out =((out) << 4); if (in != 0) { key_data = ((out) | (in)); kill_proc(id, SIGUSR1, 1); // 커널에서 시그널을 응용프로그램에게 전달 } } /* if (n > SCAN_NUM) n = 1; else n++; */ key_timer_str.expires = jiffies + (HZ/100); // 타이머의 만기 기간 설정 add_timer(&key_timer_str); // 타이머를 타이머 리스트에 추가 }
ssize_t key_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) { get_user(id,(int*)buf); // user id 값 저장 init_timer(&key_timer_str); // 타이머 초기화 key_timer_str.expires = jiffies + (HZ/100); key_timer_str.data = (unsigned long)n; key_timer_str.function = &timer_function; add_timer(&key_timer_str); // 타이머를 타이머 리스트에 추가 return 0; }
struct file_operations key_fops = { .owner = THIS_MODULE, .read = key_read, .write = key_write, .open = key_open, .release = key_release, };
static int clcd_key_init(void) { int result;
result = register_chrdev(CLCD_MAJOR, CLCD_NAME, &clcd_fops); if (result < 0) { printk(KERN_WARNING " can't get major \n"); return result; } mem_addr_wr = FPGA_CLCD_WR_ADD; mem_addr_rs = FPGA_CLCD_RS_ADD; mem_len = 0x1000;
mem_base_wr = ioremap_nocache ( mem_addr_wr, mem_len); if( !mem_base_wr) { printk("Error mapping clcd_wr memery"); return -EBUSY; } mem_base_rs = ioremap_nocache ( mem_addr_rs, mem_len); if( !mem_base_rs) { printk("Error mapping clcd_rs memery"); return -EBUSY; } printk("FPGA %s MAJOR %d\n",CLCD_NAME, result); return 0;
unsigned long mem_addr_out, mem_addr_in, mem_len;
result = register_chrdev(KEY_MAJOR, KEY_NAME, &key_fops); if (result < 0) { printk(KERN_WARNING"Failed to register the driver. \n"); return result; } mem_addr_out = FPGA_KEY_OUT; mem_addr_in = FPGA_KEY_IN; mem_len = 0x1000; mem_key_out = ioremap_nocache (mem_addr_out, mem_len); if(!mem_key_out) { printk(" Error mapping key_out memory\n"); return -EBUSY; } mem_key_in = ioremap_nocache (mem_addr_in, mem_len); if(!mem_key_in) { printk(" Error mapping key_in memory\n"); return -EBUSY; } printk("FPGA %s MAJOR %d\n", KEY_NAME, KEY_MAJOR); return 0; }
static void clcd_key_exit(void) { unregister_chrdev(CLCD_MAJOR, CLCD_NAME); iounmap(mem_base_wr); iounmap(mem_base_rs);
unregister_chrdev (KEY_MAJOR, KEY_NAME);
}
MODULE_LICENSE("GPL"); module_init(clcd_key_init); module_exit(clcd_key_exit);
|
Test_clcd_key.c
#include <stdio.h> #include <stdlib.h> #include <signal.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
#include <linux/delay.h>
static int dev; static unsigned char vkey;
static char lcdDev[] = "/dev/CLCD"; static int lcdFd = -1;
#define MAXCHR 32
void keysignal(int sig) // ½Ã±×³ÎÀ» ¹Þ¾ÒÀ» ¶§ ½ÇÇàµÉ { read(dev, &vkey, 1); printf("SIGNAL occur!!!!\n"); }
int main(void) { pid_t id;
int n; char buf[MAXCHR]; if ((dev = open("/dev/KEY", O_RDWR)) < 0) { printf("return Value is %d\n",dev); perror("open failed /dev/KEY"); close(dev); exit(-1); }
lcdFd = open(lcdDev, O_RDWR); if (lcdFd < 0) { fprintf(stderr, "cannot open CLCD (%d)", lcdFd); exit(2); }
(void) signal (SIGUSR1, keysignal); // keysignal ÇÔ¼ö¸¦ id = getpid(); // µð¹ÙÀ̽º µå¶óÀ̹ö¿¡°Ô write(dev, &id, 4); // ÇÁ·Î¼¼¼ ID¸¦ printf("press the push button!\n"); (void) signal (SIGUSR1, keysignal); while(1) { if(vkey != 0) { sprintf(buf,"vkey is 0x%x\n", vkey); write(lcdFd, buf, MAXCHR); vkey=0; } } close(dev); return 0; } |
5.
결과물