GPIO

Linux/Embedded 2008/01/23 21:42

GPIO (General Purpose Input Output) 장치는 임베디드 환경처럼 새로운 포트의 추가가 용이하지 않을 때 사용할 수 있는 방법이다. GPIO를 사용하면 특정 포트를 입력 혹은 출력 용으로 변경하여 사용할 수 있다.

각 보드에는 GPIO 포트 관련 레지스터에 대한 정보들이 같이 제공된다.

GPIO를 제어하는 레지스터는 세 가지로 나누어 볼 수 있다.

GP?CON : 핀의 사용 방법을 결정한다.
GP?DAT : GPIO의 출력으로 사용될 때 이 레지스터에 1을 쓰면 전압이 구동되고, 0을 쓰면 0V가 된다. 입력으로 사용될 때에는 전압이 구동된 상태이면 1이 되고, 0V인 경우에는 레지스터값이 0이 된다.
GP?UP : Pullup 레지스터로서 입력신호에 대해서 약하게 전압이 구동될 수 있는 풀업 저항이며, 출력 신호의 경우에는 풀업 저항을 제거한다.

사용자 삽입 이미지

Rebis 보드의 경우 S3C2440을 사용하는데, 여기에서는 GPIO 포트는 다음과 같다.

s3c2440x는 130개의 다기능(Multi-functional) Input/Output 포트핀을 가지고 있으며, 총 8개의 포트 그룹으로 나누어 관리한다.

- Port A (GPA) : 25-output port
- Port B (GPB) :11-input/output port
- Port C (GPC) : 16-input/output port
- Port D (GPD) : 16-input/output port
- Port E (GPE) : 16-input/output port
- Port F (GPF) : 8-input/output port
- Port G (GPG) : 16-input/output port
- Port H (GPH) : 9-input/output port
- Port J (GPJ) : 13-input/output port

각 포트 핀은 일반적인 Input/Output 기능 외에 다른 신호 핀으로 사용될 수 있도록 다중 송신 (Multiplexed) 방식으로 되어 있다.

각 레지스터의 하드웨어 주소는 마찬가지로 보드에서 제공해주며, s3c2440 계열인 경우에는 커널의 include/asm/arch-s3c2440/s3c2440.h 에서 확인할 수 있다. 여기서는 Rebis 보드에 대해 LED 테스트와 Keypad 테스트를 다루고자 한다.

LED 테스트

먼저, LED에 대한 회로도를 보겠다.

사용자 삽입 이미지
Rebis 보드에는 세 개의 LED가 있으며, 회로도에서 보는 것처럼 GPE 12번 핀, GPG 5번 핀, GPE 11번 핀을 사용한다.

해당 포트를 쓰기 위해서는 각각에 대한 Control 레지스터에 대해서 다음과 같이 설정한다.
GPECON[23:22] 를 01로 설정 : GPE11을 output 모드로 설정하게 됨
GPGCON[11:10] 를 01로 설정 : GPG5를 output 모드로 설정하게 됨
GPECON[25:24] 를 01로 설정 : GPE12를 output 모드로 설정하게 됨
GPEUP, GPGUP 은 disable 상태로 둠

해당 LED를 설정하려면 먼저 해당 레지스터에서 값을 읽으려는 부분을 clear 시킨 후 값을 서야만 정상적으로 동작한다(이때, clear 한 부분에 대해서만 값을 변경한다). 레지스터의 주소는 다음과 같다.

rGPGCON : 0xF0E00000 + 0x60
rGPGDAT : 0xF0E0000 + 0x64
rGPGUP : 0xF0E00000 + 0x68

rGPECON : 0xF0E00000 + 0x40
rGPEDAT : 0xF0E00000 + 0x44
rGPEUP : 0xF0E00000 + 0x48

미완성 예제


컴파일 방법 : arm-linux-gcc led_drv.c -c -D__KERNEL__ -DMODULE -I<커널소스의 헤더파일 디렉토리>
컴파일된 파일을 보드가 가져갈 수 있는 NFS export 경로에 올리고, 보드에서 insmod로 테스트하면 된다.



Keypad 테스트
 

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

위 회로도를 보면 KEYOUT은 GPB0~GPB4핀에 연결되어 있으며, KEYIN은 GPF3~GPF7에 연결되어 있는 것을 알 수 있다. 아무 키도 눌리지 않았을 때에는 KEYIN이 VDD에 연결되어 있기 때문에 기본값으로 '1' 값이 들어오게 된다. 따라서, 키가 눌렸는지 확인하려면 KEYOUT의 GPBDAT 값을 '0'으로 먼저 설정해 주어야 한다.

rGPBCON : 0xF0E00000 + 0x10
rGPBDAT : 0xF0E0000 + 0x14
rGPBUP : 0xF0E00000 + 0x18

rGPFCON : 0xF0E00000 + 0x50
rGPFDAT : 0xF0E00000 + 0x54
rGPFUP : 0xF0E00000 + 0x58

rGPFDAT를 통해서 현재 눌려진 키스캔 값을 얻을 수 있다.

rGPFDAT값을 읽기 위해서는 먼저 rGPBCON에 다음과 같은 형태로 얻고자 하는 키보드 관련 부분을 설정해 준다. 먼저 GPBCON을 output 모드로 설정한다. 또한, GPBDAT를 1(High)로 설정하고 GPBUP은 disable 시킨다.

rGPBCON &= ~(0x3ff); // GPxCON은 2비트씩이 하나를 나타내기 때문에 총 10비트 clear
rGPBCON |= (0x1 << 8); // 읽고자 하는 키의 위치를 01(Output 모드)로 함

키 값을 읽기 위해서는 GPFCON3~7을 Input 모드로 설정해 주고 GPFUP은 Disable 시킨다. 키값을 읽기 위해서는 GPFDAT부분에 대해서 0이 되었는지를 확인하면 된다. REBIS 보드의 경우에는 총 25개의 키가 있기 때문에 각각에 대해서 체크하면 된다. 즉, KEYOUT부분이 바뀔때마다 KEYIN0~4를 각각 체크해서 값이 0인 경우 키가 눌린 것이다.


크리에이티브 커먼즈 라이선스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by Daniel Kwon

임베디드 리눅스를 설치할 때 커널 이미지와 함께 반드시 꼭 작성해야 하는 것이 루트 파일 시스템이다. 루트 파일 시스템은 "/"로 마운트될 수 있는 파일 시스템을 말한다. 즉, /etc, /usr, /var, /tmp 등등 중요한 모든 파일 디렉토들이 설정되어 있으며, 필요한 명령이나 설정 파일이 들어 있는 이미지를 생각하면 된다.

임베디드 장비는 리소스의 제한이 많기 때문에 루트 파일 시스템에 들어가는 내용을 필요한 내용만 가지도록 최소화 시킬 필요가 있다. 따라서, 실행을 위한 프로그램 뿐만 아니라 관련된 라이브러리들도 필요한 것들로만 배치해야 한다. 일반적인 리눅스 명령과 연관된 프로그램들의 경우에는 busybox와 같은 프로그램을 대신 사용하면 용량을 절약할 수 있다. 라이브러리의 경우에는 glibc의 경량화 버전을 찾아서 사용하면(이전 포스팅 중에 몇몇 사이트를 적어놨다) 도움이 된다. 추가적으로 필요한 라이브러리가 어떤 것이 있는지 확인하려면 'ldd' 명령을 사용하면 된다.

[ ~]# ldd /bin/bash



이 명령을 사용하면 관련된 라이브러리 목록을 볼 수 있다.

다음은 필요한 파일들이 선택된 상태에서 루트 파일 시스템을 만드는 방법을 두 가지 형태로 살펴보도록 하겠다.

램 디스크

램디스크를 사용하기 위해서는 루프백 디바이스 지원과 램디스크 지원을 먼저 설정해야 한다.
각각은 커널 설정화면에서 "Block devices" 메뉴에서 "Loopback device support"와 "RAM disk support"를 통해서 할 수 있다.

이미지를 만들기 위해서는 먼저 루프백 디바이스가 사용 가능한지 확인해 봐야 한다.

ls /dev/loop*

루프백 디바이스가 존재한다면, 원하는 크기만큼의 파일을 만든 다음 루프백 디바이스와 연결해 주어야 한다.

dd if=/dev/zero of=my_ram_disk bs=1k count=8192

losetup /dev/loop0 my_ram_disk

mke2fs -j /dev/loop0



먼저 8MB짜리 파일을 하나 만든 후 루프백 디바이스 0번과 연결해 준다(용량은 필요에 따라 조절해 주면 된다). 다음에는 my_ram_disk를 포맷하기 위해 연결된 루프백 장치에 대해서 저널링 형태로 포맷하도록 mke2fs 명령을 호출한다. ext3 형태로 해당 파일이 포맷된다.

파일 시스템 내에 내용을 채워 넣기 위해서는 (디렉토리 구조나 필요한 명령어들의 배치), 우선 해당 파일을 마운트를 시켜야 한다. 여기에서는 기존에 ramdisk 이미지가 하나 있는 상태를 가정하겠다. ramdisk-rebis.gz이 있는 경우에 먼저 이것을 풀어 놓고 진행한다.

gunzip ramdisk-rebis.gz
mkdir my_old
mount -o loop ramdisk-rebis ./my_old

mkdir my_tmp
mount -o loop my_ram_disk  ./my_tmp
mv ./my_old/*  ./my_tmp/
cd ./my_tmp



먼저 기존 램디크를 푼다. 다음에는 새로 마운트하려는 파일에 대한 디렉토리를 생성해주고 루프백 디바이스 형태로 my_ram_disk를 my_tmp에 마운트 한다. 일단, 기존에 가지고 있던 내용들을 my_tmp에 넣은 후에 필요하면 추가적인 내용 변경을 해주면 된다.

내용의 추가 및 변경이 모두 이루어졌으면 다음에는 해당 디렉토리를 언마운트하고 파일을 압축한다.

cd ..
umount ./my_tmp
gzip my_ram_disk
file my_ram_disk.gz


먼저 해당 디렉토리에서 빠져 나온 후 언마운트를 한다. 다음에는 해당하는 파일을 gzip을 사용해서 압축한다. 마지막으로 해당 파일이 정상적인 형태로 압축되었는지 확인해 본다.

JFFS2 파일 시스템 만들기

램디스크는 램에 올라가 있는 파일 시스템으로서 전원이 나가면 내용도 사라져 버리게 된다. 플래쉬 메모리를 하드 디스크처럼 사용할 수 있다면 이러한 문제를 겪지 않아도 될 것이다. 플래쉬는 Read-Write의 횟수에 제한이 있기 때문에 균등하게 영역을 사용할 수 있도록 해주는 것이 필요하다. 이러한 점을 고려해서 나온게 JFFS, JFFS2 파일 시스템이다. JFFS는 MTD(Memory Technology Device) 계층 위에서 동작하기 때문에 보드용 커널을 컴파일 할 때 이 부분도 같이 설정해 주어야 한다.

커널 설정 화면에서 "Filesystems" > "Miscellaneous filesystems" 에 보면 "Journalling Flash File System v2 (JFFS2) support" 화면을 볼 수 있다. 이것을 선택해 준다.  또한, MTD를 설정하기 위해서는 "Device Drivers" 에서 "Memory Technology Device (MTD) support"를 선택해 주면 된다. 추가로 "RAM/ROM/Flash chip drivers" 및 "Mappping drivers for chip access"에서 하드웨어에 관련되서 필요한 내용들을 선택한다.

이와 함께 해당 보드와 연관된 디렉토리 (drivers/mtd/maps/<보드파일>)에서 타겟 시스템을 위한 메모리 맵 정보를 확인할 수 있고 수정할 수 도 있다.

jffs 파일 시스템을 만드는 것도 램디스크를 만드는 것과 유사하다. 약간의 차이점은 단순히 압축하는 것이 아니고, mkfs.jffs2 명령을 사용해서 이미지를 만든 다는 점이다.  mkfs.jffs2 명령도 미리 설치해 두어야 한다.

예) mkfs.jffs2 -e 0x40000 -d my_disk_dir -p -o my_jffs.img


만들어진 my_jffs.img는 플래쉬에 퓨징(Fusing)하면 된다.

JFFS2의 공식 사이트 : http://sourceware.org/jffs2/

크리에이티브 커먼즈 라이선스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by Daniel Kwon
먼저, Rebis 보드에 딸려 오는 커널 소스 파일을 작업 디렉토리로 복사한 후 압축을 푼다.

tar zxvf s3c2440_kernel2.4.18.tar.gz

cd s3c2440_kernel2.4.18


간단한 시스템 호출을 추가하기 kernel/sys.c 파일을 연후 제일 마지막에 다음 내용을 추가한다.

asmlinkage int sys_my_hello(int i) {
    printk("Hello %s\n", current->comm);
    return i + 1;
}
EXPORT_SYMBOL(sys_my_hello);


작성한 함수를 시스템 호출로 등록하기 위해 arch/arm/kernel 디렉토리에서 calls.S의 끝 부분쯤에 있는 __syscall_end: 바로 앞줄에 다음과 같이 추가한다.

    .long SYMBOL_NAME(sys_my_hello)

이렇게 하면 일단 시스템 호출이 등록된다. 하지만, 사용자가 이걸 호출할 때 번호를 알 수 있도록 하나를 더 추가해 주는 것이 좋다. 그것은 바로 include/asm/ 디렉토리에 있는 unistd.h 헤더 파일에 다음과 같은 내용을 추가하는 것이다. 이때 심볼 테이블내에서 sys_my_hello가 위치하는 번호를 알고 있어야 한다. 만약 그 번호가 226이라면 다음과 같이 작성하면 된다.

#define __NR_my_hello  (__NR_SYSCALL_BASE + 226)


이렇게 하고 나면 이제 커널 컴파일을 해서 보드에 올리면 된다.

커널 소스 디렉토리에서 다음 명령을 수행한다.

make clean
make dep
make zImage

다음에는 이것을 이용하는 어플리케이션을 작성해야 한다.
간단히 다음과 같이 작성한다.

#include <stdio.h>
#include <asm/unistd.h>

_syscall1(int, my_hello, int, i);

int main() {
    printf("Hello\n");
    my_hello(50);
    return 0;
}


이것을 컴파일 할 때에는 반드시 위에서 작성한 커널의 헤더 파일을 사용하도록 해 주어야 한다. 헤더 파일 경로를 바꾸기 위해서는 -I 옵션을 사용하면 된다.

arm-linux-gcc test.c -I~/Work/s3c2440_kernel2.4.18/include

하지만, 크로스 컴파일 환경에서 헤더 파일을 다시 설정해 주는 것도 번거롭기 때문에 컴파일러 안에 있는 헤더 파일을 수정하는 형태로 하겠다. 즉, asm/unistd.h 파일을 다시 수정하겠다.

vi /usr/local/arm/2.95.3/arm-linux/sys-include/asm/unistd.h


위 파일을 앞에서 unistd.h에 했던 것과 같은 방식으로 작성해 준다.

컴파일 된 코드를 보드에 올려서 테스트해 본다.


크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Daniel Kwon
디바이스 드라이버 강의 자료입니다.

# u-boot  올리기  (WinIDEA, JTAGProbe 등등 사용)

# Linux Server에서
# xinetd 설치
  yum install -y xinetd
# tftp-server 설치
  yum install -y tftp-server
# 메뉴중에서 '데스크탑->관리->서버설정->서비스' 에서 xinetd와 tftp 활성화
# /tftpboot 디렉토리에 관련 파일들 올리기
# 보안 설정 제거
  system-config-securitylevel
  # Firewall과 SELinux 모두 Disabled로 설정

# 크로스 컴파일러 설정
  tar jxvf arm-linux-tools.tar.bz2
  mkdir /usr/local/arm
  mv 2.95.3 /usr/local/arm
# /etc/profile의 제일 마지막에 한 줄 추가
  PATH=$PATH:/usr/local/arm/2.95.3/bin

# NFS 서버 설정
# nfs 설치
  yum install -y nfs
# 공유할 디렉토리 만들기
  mkdir /srv/host_dir
# /etc/exports 파일에 다음 내용 추가
  /srv/host_dir   *(rw,sync,no_root_squash)
# nfs 재 가동
  service nfs restart

--------------------------------------------
# 보드에서 설정할 내용들
# u-boot에서 설정할 내용
setenv serverip 호스트의 IP 주소
setenv ipaddr 보드의 IP 주소
setenv bootcmd '자동으로 실행할 명령들'
# 예)  setenv bootcmd 't 30800000 ramdisk-rebis.gz; t 32000000 zImage-rebis; go 32000000'
setenv bootdelay 딜레이할 시간(초단위)
saveenv

# 보드에 리눅스가 실행 중일 때
# NFS 설정
# IP 설정
  ifconfig eth0 보드의 IP 주소
# Mount 할 디렉토리 생성
  mkdir /mnt/host
# NFS 파일 시스템 마운트
  mount -t nfs 서버IP주소:/srv/host_dir  /mnt/host

=========================================
# 프로그램 컴파일 및 실행
# 프로그램 작성
# At the Server
vi test.c
>#include 
>int main() {
>	printf("Hello\n");
>	return 0;
>}

# 컴파일 At the server
  arm-linux-gcc test.c -o test
# 컴파일한 파일을 /srv/host_dir 디렉토리에 복사
  cp test  /srv/host_dir

# 실행 at the board
  cd /mnt/host
  ./test



크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Daniel Kwon
Embedded Linux를 사용할 경우에 가장 문제가 되는 점 중의 하나는 바로 용량일것이다.

어떻게 하면, 용량을 최소화하면서 필요한 기능들을 해당 장비에 다 구겨 넣을 것인가가 중요한 관건이 될 것이다.

여기에는 여러가지 관점에서 살펴 봐야 할 것들이 있을텐데, 몇가지 관련 링크들을 정리해 보고자 한다.

먼저, 유틸리티를 최소화 할 수 있는 방법으로는 많이 사용하는 것이 Erik Anderson이 관리하고 있는 tinylogin과 busybox 프로그램이 있을 것이다. 이들은 각각 http://tinylogin.busybox.net 과 http://www.busybox.net 에서 구할 수 있다. 이것은 관련된 유틸리티들을 하나의 프로그램에서 처리하게 함으로써 전체적으로 필요한 공간의 양을 줄여주는 프로그램이다.

프로그램 개발에는 많은 라이브러리들이 따라오게 마련이며 이런 라이브러리를 최소화시키는 것도 전체 용량을 줄일수 있는 한가지 방법이 된다. 그중에서도 libc 는 가장 기본이 되는 라이브러리로서 이것을 최소화 시킨 여러 프로젝트들이 있다. 다음은 그 중 유명한 몇몇 프로젝트이다.

uClibc (http://www.uclibc.org) : glibc와 유사하며, 공유 라이브러리와 멀티 쓰레드를 지원한다. MMU가 없는 ARM과 같은 장비에서도 작동된다.

sglibc (http://sourceforge.net/projects/sglibc) : glibc 호환되는 임베디드용 런타임 라이브러리

dietlibc (http://www.fefe.de/dietlibc/) : 정적 링크 방식으로 사용되며 전체적으로 크기를 줄이는데 목적이 있다.


만약, 임베디드 장비가 그래픽 화면을 사용한다면, X 윈도우가 필요하게 될 것이다. 보통은 XFree86 (http://www.xfree86.org)를 사용하며, 여기에 덧붙여서 gtk (http://www.gtk.org)나 qt를 사용할 것이다. 하지만, 이것들만으로도 5~10메가 가까이의 용량을 소모한다. 따라서, 용량이 작은 장비에서는 다음과 같은 프로그램들을 사용하기도 한다.

DinX (http://dinx.sourceforge.net) : 작은 윈도우 시스템으로서 프레임 버퍼를 사용함.

FLTK - Fast Light Toolkit (http://fltk.sourceforge.net) : C++로 작성되었으며 GUI 및 3D 그래픽을 지원함

Microwindows (Nano-X) (http://www.microwindows.org) : Xlib형 API 제공

크리에이티브 커먼즈 라이선스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by Daniel Kwon