도와주세요!!
안녕하세요.
gpio제어 학습을 해보려고 여기저기 참고해서 소스를 작성했습니다만, 역시 실력이 개발이라 오류가 발생하네요.
전체 소스입니다. 제가 무엇을 잘못했는지.. 조언 부탁드립니다.
아래는 s3c2440a 메뉴얼에서 발췌한 GPF 레지스터 정보입니다.
PORT F CONTROL REGISTERS (GPFCON, GPFDAT)
If GPF0–GPF7 will be used for wake-up signals at power down mode, the ports will be set in interrupt mode.
Register Address R/W Description Reset Value
GPFCON 0x56000050 R/W Configures the pins of port F 0x0
GPFDAT 0x56000054 R/W The data register for port F Undef.
GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000
Reserved 0x5600005c – – –
gpio_dev.c 디바이스 파일입니다.
#include <linux/module.h> // 모듈에 관한 정의
#include <linux/init.h> // init_module()과 cleanup_module()
#include <linux/fs.h> // file_operations 구조체
#include <asm/uaccess.h> // copy_to_user()
#include <asm/io.h> // GPIO controller에 관한 정의
#define DEV_NAME "gpio"
#define DEV_MAJOR 250
#define rGPFCON (*(volatile unsigned *)0x56000050)
#define rGPFDAT (*(volatile unsigned *)0x56000054)
#define rGPFUP (*(volatile unsigned *)0x56000058)
int gpio_open(struct inode *inode, struct file *filp)
{
printk("gpio driver open\n");
return 0;
}
ssize_t gpio_write(struct file *filp, void *buf, size_t count, loff_t *f_pos)
{
unsigned int buffer;
copy_from_user(buffer,(int *)buf, sizeof(buffer));
rGPFCON = (rGPFCON &~(0x3<<14))|(0x1<<14); // GPF 7번 핀을 출력으로 설정
rGPFUP = rGPFUP|(0x1<<7); // 출력으로 사용하기 위해 GPF 7번 핀의 풀업제거
rGPFDAT = (rGPFDAT &~(0x1<<7))|((buffer & 0x1)<<7); // GPF 7번핀에 데이터 쓰기
return 0;
}
int gpio_release(struct inode *inode, struct file *filp)
{
printk("gpio driver close\n");
return 0;
}
struct file_operations gpio_fops =
{
.owner = THIS_MODULE,
.write = gpio_write,
.open = gpio_open,
.release = gpio_release,
};
int gpio_init(void)
{
int result;
printk("call gpio_init\n");
result = register_chrdev(DEV_MAJOR, DEV_NAME, &gpio_fops);
if(result < 0) return result;
return 0;
}
int gpio_exit(void)
{
printk("call gpio_exit\n");
unregister_chrdev(DEV_MAJOR, DEV_NAME);
}
module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("Dual BSD/GPL");
gpio_app.c 응용프로그램 파일입니다..
#include <stdio.h>
#include <fcntl.h> // open()의 flag 정의
#include <errno.h> // error 값 정의
int main(void)
{
int fd, buf;
printf("device file open\n");
fd=open("/dev/gpio", O_RDWR|O_NDELAY);
if(fd<0) {
perror("/dev/gpio open error");
exit(1);
}
for(buf=0;buf<10;buf++) {
write(fd, buf, sizeof(buf));
sleep(1);
}
close(fd);
return 0;
}
make 메시지 입니다.
[hdd@hdd-server nfs]$ make
make -C /opt/linux-2.6.21 SUBDIRS=/home/nfs modules
make[1]: Entering directory `/opt/linux-2.6.21'
CC [M] /home/nfs/gpio_dev.o
/home/nfs/gpio_dev.c: In function `gpio_write':
/home/nfs/gpio_dev.c:25: warning: passing arg 1 of `copy_from_user' makes pointer from integer without a cast
/home/nfs/gpio_dev.c: At top level:
/home/nfs/gpio_dev.c:44: warning: initialization from incompatible pointer type
/home/nfs/gpio_dev.c: In function `__exittest':
/home/nfs/gpio_dev.c:69: warning: return from incompatible pointer type
/home/nfs/gpio_dev.c: In function `gpio_write':
/home/nfs/gpio_dev.c:23: warning: 'buffer' might be used uninitialized in this function
/home/nfs/gpio_dev.c: In function `gpio_exit':
/home/nfs/gpio_dev.c:66: warning: control reaches end of non-void function
Building modules, stage 2.
MODPOST 1 modules
CC /home/nfs/gpio_dev.mod.o
LD [M] /home/nfs/gpio_dev.ko
make[1]: Leaving directory `/opt/linux-2.6.21'
arm-linux-gcc -o gpio_app gpio_app.c
타켓 시스템으로 옮겨와서 실행
[root@falinux nfs]$ insmod gpio_dev.ko
[root@falinux nfs]$ mknod /dev/gpio c 250 0
[root@falinux nfs]$ lsmod
Module Size Used by Not tainted
gpio_dev 1888 0
[root@falinux nfs]$ ./gpio_app
device file open
Segmentation fault
커널 메시지를 살펴보니...
[root@falinux nfs]$ dmesg
...
call gpio_init
gpio driver open
Unable to handle kernel NULL pointer dereference at virtual address 00000004
pgd = c0df0000
[00000004] *pgd=30dee031, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1]
Modules linked in: gpio_dev
CPU: 0
PC is at __memzero+0x60/0x80
LR is at __lock_text_end+0x638/0x8f0
pc : [<c014aa60>] lr : [<c02c8718>] Not tainted
sp : c0d95f38 ip : 0000001c fp : c0d95f54
r10: 40135f6c r9 : c0d94000 r8 : 00000000
r7 : c0d95f78 r6 : 00000000 r5 : c05b5520 r4 : 00000004
r3 : 00000000 r2 : 00000000 r1 : 00000004 r0 : 00000004
Flags: nzcv IRQs on FIQs on Mode SVC_32 Segment user
Control: C000717F
Table: 30DF0000 DAC: 00000015
Process gpio_app (pid: 978, stack limit = 0xc0d94250)
Stack: (0xc0d95f38 to 0xc0d96000)
5f20: 00000004 00000004
5f40: bf00005c 00000004 c0d95f74 c0d95f58 c0086450 bf000030 c05b5540 c05b5520
5f60: c0d95f78 00000000 c0d95fa4 c0d95f78 c0086544 c00863a0 00000000 00000000
5f80: 00000000 4001c3bc bed93c84 00008694 00000004 c0028dc4 00000000 c0d95fa8
5fa0: c0028c20 c0086508 4001c3bc bed93c84 00000003 00000000 00000004 00000000
5fc0: 4001c3bc bed93c84 00008694 00000001 401397fc 000085e8 40135f6c bed93c54
5fe0: 00000000 bed93c3c 00003d10 400df400 60000010 00000003 00000000 00000000
Backtrace:
[<bf000020>] (gpio_write+0x0/0x9c [gpio_dev]) from [<c0086450>] (vfs_write+0xc0/0xf4)
r4 = 00000004
[<c0086390>] (vfs_write+0x0/0xf4) from [<c0086544>] (sys_write+0x4c/0x74)
r7 = 00000000 r6 = C0D95F78 r5 = C05B5520 r4 = C05B5540
[<c00864f8>] (sys_write+0x0/0x74) from [<c0028c20>] (ret_fast_syscall+0x0/0x2c)
r8 = C0028DC4 r7 = 00000004 r6 = 00008694 r5 = BED93C84
r4 = 4001C3BC
Code: e49de004 e3110008 18a0000c e3110004 (14802004)
gpio driver close
안녕하세요..
소스상에서 GPIO 레지스트의 물리주소를 직접제어하셨네요...
이미 S3C2440에는 커널에서 GPIO를 접근할 수 있는 함수를 제공하고 있습니다.
arch/arm/plat-s3c24xx/gpio.c 를 참조하세요.
GPIO 상태 설정
s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
GPIO 출력
s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
GPIO 입력
s3c2410_gpio_getpin(unsigned int pin)
관련 Pin 과 function 은 include/asm/arch/regs-gpio.h 를 참조하세요..
예로 설명하자면...
rGPFCON = (rGPFCON &~(0x3<<14))|(0x1<<14); // GPF 7번 핀을 출력으로 설정
-->> s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
rGPFUP = rGPFUP|(0x1<<7); // 출력으로 사용하기 위해 GPF 7번 핀의 풀업제거
---> s3c2410_gpio_pullup(S3C2410_GPF7, 0);
rGPFDAT = (rGPFDAT &~(0x1<<7))|((buffer & 0x1)<<7); // GPF 7번핀에 데이터 쓰기
---> s3c2410_gpio_setpin(S3C2410_GPF7, 1);
그럼 좋은 하루 되세요..