제 10 장 디바이스 드라이버
DESCRIPTION
제 10 장 디바이스 드라이버. 목차. 10.1 GPIO PIN 설명 10.2 GPIO 제어용 Device Driver 10.3 FND 어드레스 디코딩 회로 설명 11.4 FND 제어용 Device Driver. 10.1.1 GPIO. GPIO 와 Interrupt 를 이용한 char device driver 를 제작해보자 . XHYPER270-TKU board 에 GPIO test 를 위한 2 개의 key 와 led 가 있다 . - PowerPoint PPT PresentationTRANSCRIPT
제 10 장 디바이스 드라이버
2
10.1 GPIO PIN 설명
10.2 GPIO 제어용 Device Driver
10.3 FND 어드레스 디코딩 회로 설명
11.4 FND 제어용 Device Driver
목차
3
GPIO 와 Interrupt 를 이용한 char device driver를 제작해보자 . XHYPER270-TKU board 에 GPIO test 를 위한
2 개의 key 와 led 가 있다 . key 를 눌렸을 때 interrupt 발생하게 하여 interrupt
service routine 이 실행되면서 LED 를 점등하게 한다 .
GPIO 35, 36, 37,41 은 interrupt 를 위해 입력 I/O로 셋팅하고 , GPIO 3, 4 는 led 점등을 위한 출력 I/O 로 셋팅한다 .
10.1.1 GPIO
4
GPIO – LED GPIO Pin Alignment
10.1.1 GPIO
GPIO_LED0 와 GPIO_ LED1 이 GPIO 3, 4 에
물려 있음 .
GPIO 는 General-purpost I/O ports 의 의미로 일반적인 목적으로 입출력 하는 포트를 말함 . PXA270 는 118 개의
GPIO 포트가 chip 의 pin 으로 나와 있다 .
5
GPIO Control Register(1)
10.1.1 GPIO
6
GPIO – GPIO Control Register(2) 27 개의 32bit registers 를 가지고 GPIO 를 control 한다 .
Three monitor pin state(GPLR) GPIO 핀이 입력모드일 때 GPIO 핀의 현재 입력 상태값 (0 혹은 1) 을
표시한다 . 해당 필드가 1 이면 입력이 high 이고 0 이면 low 이다 .
Six control output pin state(GPSR, GPCR) GPSR 은 GPIO 핀의 출력을 high 로 설정한다 . 해당 필드에 1 을 입력하면
출력이 high 로 유지되고 0 을 입력하면 아무런 영향이 없다 . 즉 해당 핀의 출력을 low 로 설정하고자 한다면 GPCR 을 set 해야 한다 .
GPCR 은 GPIO 핀의 출력을 low 로 설정한다 . 해당 필드에 1 을 입력하면 출력이 low 로 유지되고 0 을 입력하면 아무런 영향이 없다 . 해당 핀을 hith로 출력 하려면 GPSR 을 1 로 set 하여야 한다 .
Three control pin direction(GPDR) GPIO 핀을 입력방향으로 할 것인지 출력방향으로 할 것인지를 결정한다 .
해당 필드가 1 이면 출력이고 , 0 이면 입력이다 .
10.1.1 GPIO
7
GPIO – GPIO Control Register(3)
10.1.1 GPIO
8
GPIO – GPIO Control Register(4) Six control whether rising edges and/or falling edges are detected (G
RER & GFER) GRER 의 특정 bit 를 1 로 set 하면 그 bit 에 해당 하는 GPIO 핀의 상승 에지를
감시하여 상승 에지가 발생하면 GEDR 의 해당 필드의 값이 1 이 된다 . 즉 GPIO 입력 값의 변화 (low->high) 를 감시하고자 할 때 사용하며 상승 에지가 발생하면 인터럽트를 발생시킬 수 있다 .
GFER 의 특정 bit 를 1 로 set 하면 그 bit 에 해당하는 GPIO 핀의 하강 에지를 감시하여 하강 에지가 발생하면 GEDR 의 해당 필드의 값이 1 이 된다 . 즉 GPIO입력 값의 변화 (high->low) 를 감시하고자 할 때 사용하며 하강 에지가 발생하면 인터럽트를 발생 시킬 수 있다 . GPIO 핀의 하강 에지를 감시하여 하강 에지가 발생하면 해당필드의 값이 1 이된다 .
Three indicate when specified edge types have been detected on pins(GEDR) GPIO 핀이 입력으로 설정되고 GRER 이나 GFER 이 set 되어 있다면 GPIO 핀에
상승 에지나 하강 에지가 발생 하게 되면 GEDR 의 해당 필드가 1 이 된다 . 0 은 에지가 발생하지 않은 상태이다 . GEDR 이 1 로 set 되면 인터럽트를 발생시킬 수 있는 요건이 되기 때문에 매번 에지가 발생하였는지 이 레지스터의 값을 읽어 볼 필요가 없게 된다 . GEDR 을 해당 bit 를 clear 하려면 그 bit 에 1 을 써 주면 된다 . 0 을 쓰면 아무런 변화를 발생시키지 않는다 .
10.1.1 GPIO
9
GPIO – GPIO Control Register(5) Six determine whether a pin is used as a normal GPIO or whe
ther it is to be taken over by one of three possible alternate functions (GAFR_L, GAFR_U) GPIO 핀을 특정 기능을 위한 핀으로 쓸 것인지 GPIO 핀으로 쓸
것인지를 결정한다 . 1 이면 특정 기능으로 설정하고 , 0 이면 GPIO 로 설정한다 .
10.1.1 GPIO
10
GPIO – GPIO Control Register(6) 앞 슬라이드에서 보았던 우리가 다룰 Register Definition
10.1.1 GPIO
11
GPIO – GPIO Control Register(7)
10.1.1 GPIO
12
GPIO – GPIO Control Register(8)
10.1.1 GPIO
13
Key Hardware – scheme(1)
10.1.2 Key Button
GPIO LED Device Driver
15
LED 제어용 device driver – 작업개요 GPIO 를 이용한 led device driver 를 제작해보자 .
XHYPER270-TKU board 에 2 개의 led 가 있다 . 2 개의 LED 는 GPIO3 와 4 에 연결되어 있다 . 2 개의 LED 를 켜기 위한 방법으로 GPIO 에 연결되어있는 key 중에서 36, 37 번 GPIO 에 연결된 KEY 를 사용한다 . 36,37 번의 GPIO 에 해당하는 버튼을 누르면 인터럽트 루틴이 호출되고 , 인터럽트 루틴에 의해 2 개의 LED 를 점등하게 하게 한다 .
10.2 GPIO 제어용 Device Driver
16
LED 제어용 device driver 우리가 다룰 Register Definition(1) GPIO 3, 4 번의 입 / 출력 방향을 결정한다 .
10.2 GPIO 제어용 Device Driver
17
LED 제어용 device driver 우리가 다룰 Register Definition(2)
10.2 GPIO 제어용 Device Driver
18
LED 제어용 device driver – driver coding(1)
#include <linux/module.h> // 모듈에 관한 정의
#include <linux/init.h> //init_module() 과 cleanup_module()
#include <asm/uaccess.h> //copy_to_user()
#include <asm/io.h>
#include <asm/arch/pxa-regs.h> //GPIO controller 에 관한 정의
10.2 GPIO 제어용 Device Driver
19
LED 제어용 device driver – driver coding(2)
#define GPIO_LED1 GPIO_bit(3) //gpio 3 번 핀#define GPIO_LED2 GPIO_bit(4) //gpio 4 번 핀….#define GPIO_TEST_MAJOR 241 // 메이저 번호#define GPIO_TEST_NAME "GPIO_TEST“ // 디바이스 이름….#define GPIO_LED1_ON_OFF0x2000 //IOCTL 매직번호#define GPIO_LED2_ON_OFF0x2100 //IOCTL 매직번호
10.2 GPIO 제어용 Device Driver
20
LED 제어용 device driver – driver coding(3)
static int gpio_test_open(struct inode *inode, struct file *filp){ printk("GPIO TEST OPEN\n");
GPSR1 = (GPIO_bit(3) | GPIO_bit(4)); // LED Inital Clearif(led_usage != 0) return -EBUSY;led_usage = 1; return 0;}
…..static int gpio_test_release(struct inode *inode, struct file *filp){
led_usage = 0; return 0;}
10.2 GPIO 제어용 Device Driver
21
LED 제어용 device driver – driver coding(5)
static struct file_operations gpio_test_fops = { .open = gpio_test_open,.read = gpio_test_read,.write = gpio_test_write,.ioctl = gpio_test_ioctl,.release= gpio_test_release,};
10.2 GPIO 제어용 Device Driver
22
LED 제어용 device driver – driver coding(6)
static int gpio_test_init(void){……// GPLED1, GPLED2 Setting
GAFR1_L &= ~((1<<9)|(1<<8) | (1<<7)|(1<<6)); //GPIO3,4GPDR1 |= (GPIO_LED1 | GPIO_LED2); //Output Pin
GPSR1 = (GPIO_LED1 | GPIO_LED2); // 켜기GPCR1 = (GPIO_LED1 | GPIO_LED2); // 끄기
10.2 GPIO 제어용 Device Driver
23
LED 제어용 device driver – application coding(2)static void gpio_test_exit(void){
GPSR1 = (GPIO_bit(35) | GPIO_bit(41)); // LED Clear
GPIO 셋팅을 통해 LED 쪽 드라이버 부분은 완성되었다 . 이제 key 입력을 위한 드라이버 코딩을 살펴보자 .
10.2 GPIO 제어용 Device Driver
24
GPIO 와 Interrupt 를 이용한 GPIO device driver 를 완성해보자 .
- XHYPER270-TKU board 에 있는 key button 중 4 개가 GPIO 로 연결되어 있다 .
- 이 key 를 눌렀을 때 interrupt 를 발생하고 service routine 이 실행되게
한다 .
- 서비스 루틴에 의해 넘어온 인자값을 가지고 키입력에 따른 명령을 드라이버에 전달하여 LED 가 동작 하도록 한다 .
10.2 GPIO 제어용 Device Driver
25
Driver start Application start
module_init()
key_init()
Key_read() read()
open()
Interruptible_sleep_on()
key_handler()
wakeup_interruptible()
key_read() 함수 call
waiting key interrupt
waiting read() blocking
read() waking
10.2 GPIO 제어용 Device Driver
26
우리가 다룰 Register Definition(1)
10.2 GPIO 제어용 Device Driver
27
우리가 다룰 Register Definition(2)
10.2 GPIO 제어용 Device Driver
28
우리가 다룰 Register Definition(2)
10.2 GPIO 제어용 Device Driver
29
GFER 을 통하여 GPIO falling edge 일때 검출 설정 GAFR 을 통하여 alternate function 설정 GPDR 을 통하여 GPIO 입출력 방향 설정 request_irq() 함수로 interrupt 등록 set_irq_type() 함수로 interrupt 검출 설정
10.2 GPIO 제어용 Device Driver
30
LED 제어용 device driver – application coding(1)
…..#define IRQ_KEY1 IRQ_GPIO(36)#define IRQ_KEY2 IRQ_GPIO(37)….#define GPIO_KEY_READ 0x1000 //IOCTL 매직번호…..char key_buf;…..DECLARE_WAIT_QUEUE_HEAD(key_queue);
10.2 GPIO 제어용 Device Driver
31
LED 제어용 device driver – application coding(2)
static int gpio_test_init(void){ int result, ret; …..
if ((ret = request_irq(IRQ_KEY1, &key_interrupt SA_INTERRUPT, "GPIO36_KEY1", NULL))),
{ printk("failed to register IRQ KEY1\n"); return ret;}
......
set_irq_type(IRQ_KEY1, IRQT_FALLING); // 2.6 Kernel….GFER1 |= (GPIO_bit(36) | GPIO_bit(37)); // falling edge
falling edge 일때 인터럽트 검출하도록
설정
10.2 GPIO 제어용 Device Driver
Interrupt 를 등록하는 함수 . Int request_irq(unsingned int irq_number, void (*handler)(int,struct pt_regs
*), unsigned long irqflags, const char *devicename, void *dev_id);Key_handler 는 interrupt 가 걸렸을때 처리하는 함수 , 등록이 성공하면
# cat /proc/interrupts 명령으로 interrupt 가 등록되어 있는 것을 확인
32
LED 제어용 device driver – application coding(3)
static irqreturn_t key_interrupt(int irq, void *dev_id, struct pt_regs *regs){DUMMY_DELAY;if((GEDR1 & GPIO_bit(36))) {
key_buf = 1;}if((GEDR1 & GPIO_bit(37))) {
key_buf = 2;}
wake_up_interruptible(&key_queue);return IRQ_HANDLED;}
10.2 GPIO 제어용 Device Driver
33
LED 제어용 device driver – application coding(4)int gpio_test_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){
int data = 0;int ret = 0; /*You can add any ioctl command*/switch (cmd) {
case GPIO_KEY_READ: copy_to_user((void *)arg, &key_buf,sizeof(key_buf)); key_buf = 0;
return 0;case GPIO_LED1_ON_OFF:
copy_from_user(&data, (void *)arg, sizeof(data));if( data == 1)GPSR1 = GPIO_LED1; //GPIO 35 SET LED OFFelseGPCR1 = GPIO_LED1; //GPIO 35 CLEAR LED ON
return 0;case GPIO_LED2_ON_OFF:
copy_from_user(&data, (void *)arg, sizeof(data));if( data == 1)GPSR1 = GPIO_LED2; //GPIO 41 SET LED OFFelseGPCR1 = GPIO_LED2; //GPIO 41 CLEAR LED ON
return 0;default: return -EINVAL; }
10.2 GPIO 제어용 Device Driver
사용자 프로그램에서 값을 받아 온다 .
사용자 프로그램으로 값을 넘긴다 .
34
application 만들기
static char gpio_testDev[] = "/dev/GPIO_TEST";#define GPIO_KEY_READ 0x1000 #define GPIO_LED1_ON_OFF 0x2000#define GPIO_LED2_ON_OFF 0x2100int ON = 0;int OFF = 1;
10.2 GPIO 제어용 Device Driver
IOCTL 매직 번호
35
int main(){int dev;char buf;if((dev = open(gpio_testDev, O_RDWR )) < 0){ perror("open faile /dev/GPIO_TEST\n"); exit(-1);}while(1){
read(dev , &buf, sizeof(buf)); // Key READprintf("KEY %d PUSH \n",buf);
switch(buf){case 1:{ ioctl(dev, GPIO_LED1_ON_OFF, &ON);
10.2 GPIO 제어용 Device Driver
36
MakefileCC := /opt/iwmmxt-1.0.0/bin/arm-linux-gccKDIR := /PXA270/kernel/linux-2.6.11-h270-tku_v1.1TEST_TARGET = testTEST_OBJS = $(TEST_TARGET).oTEST_SRCS = test.cobj-m := gpio_test.obuild: $(TEST_TARGET)
make -C $(KDIR) SUBDIRS=`pwd` modules$(TEST_TARGET): $(TEST_OBJS)$(CC) -o $@ $(TEST_OBJS)
clean:rm -rf *.0 *.ko *.mod.crm -f $(TEST_TARGET)
10.2 GPIO 제어용 Device Driver
37
이후 과정은 앞장에서 배운 디바이스 드라이버 과정을 참조하여 결과를 확인한다 .
개략적인 과정은 host 에서 위의 3파일을 make 를 이용하여 컴파일한 후 드라이버와 응용프로그램을 target 으로 전송한다 .
#insmod gpio_test.ko 를 디바이스 등록과 함께 irq 등록을 한다 .
#mknod 로 해당 디바이스 노드를 생성한다 .
응용프로그램을 실행한 후 key 를 눌려보면서 결과를 확인한다 .
10.2 GPIO 제어용 Device Driver
38
10.3 FND 어드레스 디코딩 회로 설명
개요 7 세그먼트라고도 하고 숫자나 간단한 기호 표현에 많이 이용 . 7-segment LED는 A-G 의 7개의 LED와 소수점 표시를 한
DP (Decimal Point)의 LED 1개로 구성된다 . 각 LED는 표시되는 문자의 일부분을 구성하므로 각각을 세그먼트 (segment : 부분 , 구분 )라 부른다 .
39
10.3 FND 제어용 Device Driver
FND 디바이스 물리 주소 영역
nCS4번 영역인 0x1000_0000 ~ 0x13FF_FFFF 사이에 FND 존재
40
10.3 FND 제어용 Device Driver
IEB 보드 어드레스 디코딩 회로
CS4 에 의해 어드레스 디코딩과 버퍼의 역할을 하는 FPGA 칩이 활성화
41
10.3 FND 제어용 Device Driver
FND 어드레스 FND 물리주소 (접근번지 ) 는 0x1100_0000 ~ 0x1170_0000 영역에 8개가 할당 되어있는데 adress table 을 구성해서 보면 최상위 6bit(A31~26)가 CS4해당하고 , 나머지 26bit 중 최상위 6bit(A25~20) 가 실질적인 어드레스 디코딩을 위해 사용되고 있다 .
42
10.3 FND 제어용 Device Driver
FND 어드레스 디코딩 회로 구성
FND 의 물리주소 FND_CS0 ~ FND_CS7 가 주어지면 CS4 에 의해 FPGA 가
선택되고 FPGA 내부에 있는 어드레드 디코딩 논리 회로에 의해 활성화
신호가 발생하고 해당 FND 에 D-플리플롭에 상승엣지가 공급되어 FND 에
연결된 데이타버스 하위 8 비트가 FND 에 전달되어 FND 의 불을 켜게 된다 .
data[31..0]
D-플리플롭
D-플리플롭
D-플리플롭
D-플리플롭
43
10.3 FND 제어용 Device Driver
FND 제어 방법 (해당 비트에 데이터를 보냄 )
FND
3 : FND_CS = (0x01 << 2)5 : FND_CS = (0x01 << 4)
4 : FND_CS = (0x01 << 3)
6 : FND_CS = (0x01 << 5)
7 : FND_CS = (0x01 << 6)
1 : FND_CS = (0x01 << 0)
2 : FND_CS = (0x01 << 1)
8 : FND_CS = (0x01 << 7)
44
10.3 FND 제어용 Device Driver
가상주소 맵핑
MMU 를 사용하는 리눅스에서는 물리주소를 가지고 디바이스에 접근하면 페이지 폴트가 발생한다 . 따라서 커널이 사용하는 가상주소를 할당받아 야 한다 .
ioremap 함수는 해당하는 디바이스를 위해 메모리 상에 일정영역을 커널이 관리하는 가상주소를 맵핑하여 준다 .
따라서 FND 에 해당하는 가상주소로 ioremap 함수를 이용하여 FND 를 위한
가상주소를 얻어와야 한다 .
45
10.3 FND 제어용 Device Driver
소스 설명 Makefile fnd.c : lcd 디바이스 드라이버 소스이다 . fnd.ko : lcd 디바이스 드라이버를 컴파일하면 생성되는 object
파일이다 . fnd_test.c : lcd 디바이스 드라이버를 테스트하는 어플리케이션
소스이다 .
46
10.3 FND 제어용 Device Driver
FND 드라이버 소스 설명 (fnd.c)#define FPGA_FND_CS0 (0x11000000) //FND 물리주소#define FPGA_FND_CS1 (0x11100000)#define FPGA_FND_CS2 (0x11200000)#define FPGA_FND_CS3 (0x11300000)#define FPGA_FND_CS4 (0x11400000)#define FPGA_FND_CS5 (0x11500000)#define FPGA_FND_CS6 (0x11600000)#define FPGA_FND_CS7 (0x11700000)
47
10.3 FND 제어용 Device Driver
FND 드라이버 소스 설명 (fnd.c)
mem_addr_fnd0 = FPGA_FND_CS0;
……mem_len = 0x1000;…..static int fnd_init(void){mem_fnd_cs0 = ioremap_nocache ( mem_addr_fnd0, mem_len); // 가상주소 얻기 if( !mem_fnd_cs0) { printk("Error mapping fnd0 memery"); return -EBUSY; }…….static void fnd_exit(void){
fnd_clear();unregister_chrdev(FND_MAJOR, FND_NAME);iounmap(mem_fnd_cs0);
48
10.3 FND 제어용 Device Driver
FND 응용프로그램 소스 설명 (fnd_test.c)
unsigned char asc_to_fnd(int n){unsigned char c;
switch (n) { /* 여러가지 문자를 추가할수 있다 */case 0: c = 0x3f; break;case 1: c = 0x06; break;case 2: c = 0x5b; break;case 3: c = 0x4f; break;case 4: c = 0x66; break;case 5: c = 0x6d; break;case 6: c = 0x7d; break;case 7: c = 0x07; break; ….. }
return c;}
49
10.3 FND 제어용 Device Driver
FND 응용프로그램 소스 설명 (fnd_test.c)
main(int ac, char *av[]){int n, count, dev;unsigned char buf[MAXFND+1];dev = open( fnd_dev, O_RDWR);if (dev < 0) {fprintf(stderr, "cannot open FND (%d)", dev);exit(2); }memset(buf, 0, sizeof(buf));for (n = 0 ; n <= 9; n++) {
for( count = 0 ; count < MAXFND; count++){buf[count]= asc_to_fnd(n);}write(dev, buf,MAXFND);
usleep(500000); }}
50
10.3 FND 제어용 Device Driver
Makefile 설명
CC := /opt/iwmmxt-1.0.0/bin/arm-linux-gccKDIR := /PXA270/kernel/linux-2.6.11-h270-tku_v1.1TEST_TARGET = fnd_testTEST_OBJS = fnd_test.oTEST_SRCS = fnd_test.c obj-m := fnd.obuild: $(TEST_TARGET) make -C $(KDIR) SUBDIRS=`pwd` modules$(TEST_TARGET) : $(TEST_OBJS)
$(CC) -o $@ $(TEST_OBJS)clean: rm -rf *.o *.ko *.mod.c
rm -f $(TEST_TARGET)
51
10.3 FND 제어용 Device Driver
실행방법 이미 타겟보드에 fnd 의 드라이버가 올라가 있으므로 rmmod 로 제거한 후 자신이 만든 fnd 드라이버를 올리고 실행시켜보자 .
(host)
# make clean# make
다운로드 : fnd.ko, fnd_test
실행 hybus~>#./fnd_test”