• 검색 결과가 없습니다.

GPIO INPUT

문서에서 GettingStarted-with-HBE-EMPOSII (페이지 138-145)

8. 디바이스 드라이버

8.2. EMPOSⅡ에서 디바이스 드라이버 작성

8.2.6 GPIO INPUT

위에서 GPIO의 일반적인 성질과 GPIO OUTPUT에 관하여 설명하였다. 여기에서는 GPIO 에서 가장 중요하다고 생각되는 인터럽트 소스로 사용되는 방법에 대하여 관찰해보자.

인터럽트란 장치가 디바이스 드라이버의 주의를 끌고 어떻게 동작할 필요가 있는지 알려 주는 방법이므로 장치 디바이스 드라이버를 만들기 위한 중요한 부분 중에 하나이다.

프로그램에서 인터럽트를 받는 방법은 아래와 같다.

z request_irq()를 이용하여 자신만의 irq를 요청한다.

z set_GPIO_IRQ_edge()를 이용하여 GPIO 포트번호와 감지할 상태를 설정한다.

z enable_irq()로 인터럽트를 활성화 시킨다.

z 모든 사용이 끝났을 때 disable_irq()와 free_irq()를 사용하여 irq를 제거한다.

현재 타겟 보드에는 GPIO포트의 16번이 LCD의 아래에 있는 버튼 중 가장 아래에 있는 버튼이다. 여기서는 이 GPIO16번을 이용하여 인터럽트를 감지하는 디바이스 드라이버를 만들기 위해 아래와 같이 소스 파일을 작성한다.

- gpio.c

#include <linux/init.h>

#include <linux/config.h>

#include <linux/sched.h>

#include <linux/string.h>

#include <linux/delay.h>

#include <linux/errno.h>

#include <linux/types.h>

#include <asm/hardware.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/param.h>

#define IRQ_BUTTON IRQ_GPIO(16)

static void button_interrupt(int irq, void *dev_id, struct pt_regs *regs);

static int GPIO_MAJOR = 0;

static void button_interrupt(int irq, void *dev_id, struct pt_regs *regs){

wake_up_interruptible(&wait_queue);

static ssize_t gpio_read(struct file *filp, char *buf, size_t count, loff_t *l){

char hello[] = "GPIO_16 port was pushed!";

interruptible_sleep_on(&wait_queue);

copy_to_user(buf,&hello,sizeof(hello));

return 0;

static int gpio_open(struct inode *inode, struct file *filp){

int res;

unsigned int gafr;

gafr = 0x3;

GAFR0_U &= gafr;

GPDR(IRQ_TO_GPIO_2_80(IRQ_BUTTON)) &= GPIO_bit (IRQ_TO_GPIO_2_80(IRQ_BUTTON));

set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(IRQ_BUTTON), GPIO_FALLING_EDGE);

res = request_irq(IRQ_BUTTON,&button_interrupt, SA_INTERRUPT,

"Button",NULL);

if(res < 0)

printk(KERN_ERR "%s: Request for IRQ %d failed n", __FUNCTION__,IRQ_BUTTON);

MOD_INC_USE_COUNT;

return 0;

static int gpio_release(struct inode *inode, struct file *filp) {

free_irq(IRQ_BUTTON,NULL);

disable_irq(IRQ_BUTTON);

MOD_DEC_USE_COUNT;

return 0;

static struct file_operations gpio_fops = { read: gpio_read,

open: gpio_open,

release: gpio_release,

;

int init_module(void){

int result;

result = register_chrdev(GPIO_MAJOR,

"GPIO INTERRUPT",&gpio_fops);

if(result < 0) {

printk(KERN_WARNING"Can't get major %d n

",GPIO_MAJOR);

return result;

if(GPIO_MAJOR == 0) GPIO_MAJOR = result;

printk("init module, GPIO major number : %d n",result);

void cleanup_module(void){

unregister_chrdev(GPIO_MAJOR,"GPIO INTERRUPT");

return;

- test.c

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <errno.h>

static int dev;

int main(void) {

char buff[40];

dev = open("/dev/gpio",O_RDWR);

if(dev < 0) {

printf( "Device Open ERROR! n");

exit(1);

printf("Please push the GPIO_16 port! n");

read(dev,buff,40);

printf("%s n",buff);

- Makefile

CC = arm-linux-gcc

KERNELDIR = /working/empos2/kernel/linux-2.4.19-rmk4-pxa2-empx1 INCLUDEDIR = -I$(KERNELDIR)/include -I./

CFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 -I$(INCLUDEDIR)

MODULE_OBJS = gpio.o MODULE_SRCS = gpio.c

TEST_TARGET = test TEST_OBJS = test.o TEST_SRCS = test.c

all: $(MODULE_OBJS) $(TEST_TARGET)

#$(MODULE_OBJS) :

# $(CC) $(CFLAGS) -c $(MODULE_SRCS)

$(TEST_TARGET) : $(TEST_OBJS)

$(CC) $(TEST_OBJS) -o $@

clean:

rm -f *.o

rm -f $(TEST_TARGET)

작성된 디바이스와 응용프로그램의 테스트를 위해 다음과 같이 디바이스 드라이버와 응용 프로그램을 컴파일 하고 시리얼 등을 통해 gpio.o와 test를 타겟 보드로 전송한다.

$ make

전송이 끝나면 insmod를 사용하여 디바이스 드라이버를 커널에 삽입하고 mknod로 특수 장치 파일을 만든다.

[root@Hanback/root]$ mknod /dev/gpio c 254 0

이상으로 응용프로그램을 실행할 준비가 끝났으므로 응용프로그램을 다음과 같이 실행한 다

[root@Hanback/root]$ ./test

작성된 소스파일과 실행에 문제가 없다면 위의 테스트 프로그램은 “Please push the GPIO_16 port!” 이라는 문장을 콘솔에 출력하고. 타겟 보드의 GPIO 0 버튼을 누를 시 콘 솔에 “GPIO_16 port was pushed!”를 출력 후 프로그램을 종료한다.

※ 동작 원리

GPIO 디바이스 드라이버는 GPIO포트 16번을 이용하여 gpio 인터럽트를 사용하기 위해 작성되었다. 우선 open()에서 request_irq()를 사용하여 irq를 요청 하고

set_GPIO_IRQ_edge함수를 사용하여 GPIO포트 번호와 Falling edge일 때 인터럽트를 발 생시키도록 설정한 후 enable_irq()를 사용하여 인터럽트를 활성화 시킨다. 사용자 어플리 케이션에서 read()를 하면 이 드라이버에서는 interruptible_sleep_on()을 사용하여 인터럽 트가 발생되기를 기다리며. 인터럽트가 발생되면 wake_up_interruptible()를 사용하여 인터 럽트를 깨우고 “GPIO_16 port was pushed!”라는 스트링을 어플리케이션에 넘긴다. 어플 리케이션은 이 스트링을 콘솔에 출력 후 드라이버를 닫고 프로그램을 종료한다.

문서에서 GettingStarted-with-HBE-EMPOSII (페이지 138-145)