240 likes | 646 Views
LED Device Driver 설계 및 응용. LED 란 ?. 일반적으로 Light Emitting Diode ( 발광 다이오드 ) 의 약자로 불리며 순방향으로 전압을 가할 때 다이오드의 접합부에서 빛을 발생하는 다이오드 이다. LED 회로도. LED 제어. LED Port 주소 및 Data 입력 bit (PXA255 Pro). LED 제어. LED 의 제어 방법 (PXA255 Pro). LED 1 번을 ON 하는 예제 #define LED_IO_ADDR 0x0C000016
E N D
LED 란? • 일반적으로 Light Emitting Diode (발광 다이오드)의약자로 불리며 순방향으로 전압을 가할 때 다이오드의 접합부에서 빛을 발생하는 다이오드 이다.
LED 제어 • LED Port 주소 및 Data 입력 bit (PXA255 Pro)
LED 제어 • LED의 제어 방법 (PXA255 Pro) LED 1번을 ON 하는 예제 #define LED_IO_ADDR 0x0C000016 *(LED_IO_ADDR) = 0xFE;
모듈 사용 횟수 관리 • 커널2.4 • 디바이스 드라이버의 사용 횟수를 자체에서 관리 • 수행 매크로 • MOD_INC_USE_COUNT • 모듈 사용 횟수를 증가 • MOD_DEC_USE_COUNT • 모듈 사용 횟수를 감소 • MOD_IN_USE • 모듈 사용 횟수가 0이 아니면 참 • 커널2.6 • 커널에서 디바이스 사용 횟수를 관리
모듈 사용 횟수 관리 • 커널2.4 intxxx_open (structinode *inode, struct file *filp) { if(MOD_IN_USE) return –EBUSY; MOD_INC_USE_COUNT; return 0; } Intxxx_release (structinode *inode, struct file *filp) { MOD_DEC_USE_COUNT; return 0; }
읽기와 쓰기의 구현 • 함수 • read 사용 함수 • copy_to_user(to,from,n) • 커널 메모리 from을 사용자 메모리 to로 n만큼 복사 • put_user(x,ptr) • x변수 값을 사용자 영역인 ptr로 sizeof(ptr) 만큼 메모리에 복사 • write 사용 함수 • copy_from_user(to,from,n) • 사용자 메모리 from을 커널 메모리 to로 n만큼 복사 • get_user(x,prt) • x변수 값에 사용자 영역인 ptr의 값을 sizeof(ptr)만큼 대입
I/O 처리 • 프로세서 입장에서 하드웨어의 I/O는 시스템 마다 상이 • I/O 맵드 입출력 • 메모리와 하드웨어 I/O 처리 방식이 다른 경우 • I386 인텔 계열의 프로세스 in, out 이라는 별도의 명령이 존재 • 메모리 맵드 입출력 • 메모리와 하드웨어 I/O 처리 방식이 같은 경우 • 68계열이나 ARM계열 • ARM이나 68계열의 프로세서에서 동작하는 리눅스커널에서는inb(), outb()같은 I/O 맵드 입출력 함수는 불필요 하지만, 호환성 때문에 사용 • 메모리 맵드 입출력으로 맵핑 시켜줌
I/O 처리 • I/O 맵드 입출력 처리 함수 • #include<asm/io.h> • 하드웨어에서 데이터를 읽기 • unsigned char inb(unsigned short port); • unsigned short inw(unsigned short port); • unsigned long inl(unsigned short port); • void insb(unsigned short port, void *addr, unsigned long count); • void insw(unsigned short port, void *addr, unsigned long count); • void insl(unsigned short port, void *addr, unsigned long count)
I/O 처리 • I/O 맵드 입출력 처리 함수 • 하드웨어에 데이터를 쓰기 • void outb(unsigned char data, unsigned short port); • void outw(unsigned short data, unsigned short port); • void outl(unsigned long data, unsigned short port); • void outsb(unsigned short port, void *addr, unsigned long count); • void outsw(unsigned short port, void *addr, unsigned long count); • void outsl(unsigned short port, void *addr, unsigned long count);
메모리 매핑 • 물리 주소 공간을 커널 주소 공간으로 매핑 • MMU(Memory Management Unit) • 초기 리눅스의 프로세스간의 메모리 보호 장치가 없어 다른 프로세스의 공간을 침범하는 것을 막기 위해 사용 • 프로세스에서 전달되는 주소를 다른 주소로 변환 • 프로세서가 메모리에 접근하는 주소가 메모리에 직접 전달되는 것이 아니라 먼저 MMU에 전달 • MMU는 변환 테이블을 참고해 이 주소를 실제 물리 주소로 변환하여 전달 • 프로세스는 MMU에 가상 주소를 전달하며, MMU가 이 가상 주소를 해석하여 나온 물리주소를 실제 메모리에 전달 • 주소 변환 함수 • void *ioremap(unsigned long offset, unsinged long size); • void *iounmap(void *addr);
led_driver.c #include <linux/ioport.h> #include <asm/uaccess.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/io.h> #include <linux/init.h> #include <linux/version.h> #define IOM_LED_MAJOR 240 //ioboard led device major number #define IOM_LED_NAME "LEDS" //ioboard led device name #define IOM_LED_ADDRESS 0xC000016 // pysical address #define IOM_LED_ADDRESS_RANGE 1 // address range //Global variable static intledport_major = 0; static unsigned short *iom_led_addr;
led_driver.c // define functions... ssize_t iom_led_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); int iom_led_open(struct inode *minode, struct file *mfile); int iom_led_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_led_fops = { open: iom_led_open, write: iom_led_write, release: iom_led_release, }; // when led device open ,call this function int iom_led_open(struct inode *minode, struct file *mfile) { if(MOD_IN_USE) return -EBUSY; MOD_INC_USE_COUNT; return 0; }
led_driver.c // when led device close ,call this function intiom_led_release(structinode *minode, struct file *mfile) { MOD_DEC_USE_COUNT; return 0; } // when write to led device ,call this function ssize_tiom_led_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) { unsigned char value; const char *tmp = gdata; copy_from_user(&value,tmp,length); outb(value,iom_led_addr); return length; }
led_driver.c intinit_module(void) { int result; result = register_chrdev(IOM_LED_MAJOR,IOM_LED_NAME,&iom_led_fops); if(result < 0) { printk(KERN_WARNING"Can't get any major\n"); return result; } ledport_major = IOM_LED_MAJOR; iom_led_addr = ioremap(IOM_LED_ADDRESS,0x01); printk("init module, %s major number : %d\n",IOM_LED_NAME,ledport_major); return 0; } void cleanup_module(void) { iounmap(iom_led_addr); if(unregister_chrdev(ledport_major,IOM_LED_NAME)) printk(KERN_WARNING"%s DRIVER CLEANUP FALLED\n",IOM_LED_NAME); }
test_led.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(intargc, char **argv) { intdev; unsigned char buff; if(argc <= 1) { printf("please input the parameter! \n"); printf("ex)./test_led 0xa1\n"); printf("ex)./test_led a1\n"); return -1; }
test_led.c dev = open("/dev/LEDS", O_WRONLY); if (dev != -1){ if(argv[1][0] == '0' && (argv[1][1] =='x'||argv[1][1] == 'X')) buff = (unsigned char)strtol(&argv[1][2], NULL,16); else buff = (unsigned char)strtol(&argv[1][0], NULL,16); write(dev,&buff,1); close(dev); } else{ printf( "Device Open ERROR!\n"); exit(-1); } return(0); }
Makefile INCLUDEDIR := /lect/linux-2.4.19-pro3_nlcd/include CFLAGS := -D__KERNEL__ -I$(INCLUDEDIR) -Wall -O2 -DMODULE CROSS_COMPILE := arm-linux- CC=$(CROSS_COMPILE)gcc all: led_drivertest_led led_driver: $(CC) $(CFLAGS) -c led_driver.c -o led_driver.o test_led: $(CC) -o test_ledtest_led.c clean: rm -f *.o rm -f test_led
커널파일 복사 • Target의 디바이스 드라이버 모듈을 생성하기 위해서는 컴파일 과정에서 Target의 커널 정보가 필요 • 따라서, CD에서 Target의 커널 파일을 복사 해야 함 • 커널 파일 복사 순서 • 1. CD 삽입 후 마운트 확인 • 2. 커널 파일 복사 • # cp /mnt/cdrom/Kernel/linux-2.4.19-pro3_nlcd.tar.gz • 3. 커널 압축해제 • # tarzxvf linux-2.4.19-pro3_nlcd.tar.gz
프로그램 테스트 (@Target) • 1. Minicom연결 • 2. nfs를 통해 호스트에 있는 디렉토리공유 및 파일 확인 • led_driver.o, test_led • 3. 장치 특수 파일을 생성 • # mknod /dev/LEDS c 240 0 • 4. 디바이스 드라이버를 커널에 추가한다. • # insmodled_driver.o • 5. 테스트 프로그램을 이용해 LED를 제어해 본다. • # ./test_led [16진수 unsigned char 데이터] • ex)./test_led 0xa5 • ex)./test_led a5