8. 디바이스 드라이버
8.2. EMPOSⅡ에서 디바이스 드라이버 작성
8.2.5 GPIO OUTPUT
GPIO(General Purpose Input/Output)란 port pins으로 어플리케이션의 목적에 따라 input 이나 output의 신호를 발생하거나 획득을 원할 목적으로 사용되는 것이다. 이를 위해
GFER GPIO 포트 핀이 input일 때 falling-edge를 감지한다.
GEDR GRER이나 GFER로 설정된 값에 따른 결과를 설정한다.
GAFR GPIO 핀을 alternate function으로 전환한다.
이제 실제적으로 사용하는 레지스터들에 관하여 정리하여 보면 아래와 같다.
- GPIO 레지스터 정리 Register
Type
GPIO[31:0] GPIO[63:32] GPIO[84:64]
GPLR GPLR0 GPLR1 GPLR2
GPSR GPSR0 GPSR1 GPSR2
GPCR GPCR0 GPCR1 GPCR2
GPDR GPDR0 GPDR1 GPDR2
GRER GRER0 GRER1 GRER2
GFER GFER0 GFER1 GFER2
GEDR GEDR0 GEDR1 GEDR2
GAFR GAFR0_L GAFR0_U GAFR0_L GAFR0_U GAFR0_L GAFR0_U
위의 GPIO를 출력으로 사용하기 위한 방법은 다음과 같다.
1. GPDR로 포트 핀의 방향을 출력으로 설정한다. 해당 비트를 찾아 셋 하면 된다.
2. GPSR로 해당 비트를 셋 하면 GPIO 포트에 1로 셋 된다.
3. GPCR로 해당 비트를 셋 하면 GPIO 포트가 0으로 셋 된다.
현재 타겟 보드에는 GPIO 17번 포트는 led와 연결되어 있어 GPIO 출력을 사용할 수 있 다. 우리는 이 포트를 이용하여 GPIO 출력 디바이스 드라이버를 작성해 보자.
- gpio_led.c
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#define GPIOLED_MAJOR 0
#define GPIOLED_NAME "GPIO LED"
#define GPIOLED_MODULE_VERSION "GPIO LED V0.1"
//Global variable
static int gpioled_usage = 0;
static int gpioled_major = 0;
// define functions...
int gpioled_open(struct inode *minode, struct file *mfile) { if(gpioled_usage != 0) return -EBUSY;
MOD_INC_USE_COUNT;
gpioled_usage = 1;
GAFR0_U = GAFR0_U & ( 0xc);
GPDR0 = GPDR0 | 0x20000;
return 0;
gpioled_usage = 0;
return 0;
ssize_t gpioled_write_byte(struct file *inode, const char *gdata, size_t length, loff_t *off_what) {
unsigned char c;
get_user(c,gdata);
if (c != 0) GPSR0 = GPSR0 | 0x20000;
else GPCR0 = GPCR0 | 0x20000;
return length;
static struct file_operations gpioled_fops = { write : gpioled_write_byte,
open : gpioled_open, release : gpioled_release,
;
int init_module(void) { int result;
result =
register_chrdev(GPIOLED_MAJOR,GPIOLED_NAME,&gpioled_fops);
if(result < 0) {
printk(KERN_WARNING"Can't get any major n");
return result;
gpioled_major = result;
printk("init module, ledioport major number : %d n",result);
return 0;
void cleanup_module(void) {
if(unregister_chrdev(gpioled_major,GPIOLED_NAME))
printk(KERN_WARNING"%s DRIVER CLEANUP FALLED n", GPIOLED_NAME);
- test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv) {
int dev;
char buff;
if(argc <= 1) {
printf("please input the parameter! ex)./test on or off n");
return -1;
dev = open("/dev/gpio_led", O_WRONLY);
if (dev != -1) {
if(argv[1][0] == 'o' && argv[1][1] == 'n') buff = 1;
else if(argv[1][0] == 'o' && argv[1][1] == 'f' &&
else {
printf( "Device Open ERROR! n");
exit(-1);
return(0);
- Makefile
# led Device Driver Makefile
CC = arm-linux-gcc
KERNELDIR = /usr/local/linux-2.4.19-rmk4-pxa2-empx1 INCLUDEDIR = -I$(KERNELDIR)/include -I./
CFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 -I$(INCLUDEDIR)
MODULE_OBJS = gpio_led.o MODULE_SRCS = gpio_led.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) :
clean:
rm -f *.o
rm -f $(TEST_TARGET)
작성된 디바이스와 응용프로그램의 테스트를 위해 다음과 같이 디바이스 드라이버와 응용 프로그램을 컴파일 하고 시리얼 등을 통해 gpio.o와 test를 타겟 보드로 전송한다.
$ make
전송이 끝나면 insmod를 사용하여 디바이스 드라이버를 커널에 삽입하고 mknod로 특수 장치 파일을 만든다.
[root@EMPOS/root]$ insmod gpio_led.o
[root@EMPOS/root]$ mknod /dev/gpio_led c 253 0
이상으로 응용프로그램을 실행할 준비가 끝났으므로 응용프로그램을 다음과 같이 실행한 다
[root@EMPOS/root]$ ./test on
위와 같이 실행 하면 리셋 버튼 밑에 있은 GPIO led에 불이 들어 오고
“./test off”를 실행 시키면 GPIO led에 불이 꺼진다.
※ 동작 원리
GPIO led 디바이스 드라이버는 GPIO포트 17번을 이용하여 GPIO출력을 사용하기 위해 작성되었다. 우선 gpio_led.c의 open함수에서 해당 비트에 관련한 Alternate Function을 사용하지 않고 General Purpose I/O으로 사용하기 위해 레지스터 GAFR0_U을 사용하여 해당 GPIO 포트를 00으로 설정하고 GPDR0를 이용하여 GPIO 17포트를 출력으로 설정하 였다. write함수에서는 응용프로그램에서 넘겨준 값이 0이면 GPCR0를 이용하여 해당 비 트를 셋하고 0이 아니면 GPSR0를 이용하여 해당 비트를 셋 하여 GPIO LED 빛을 발하게 한다.