임베디드 시스템 개발을 위한 리눅스 환경설정
차례 하드웨어 환경 설치 소프트웨어 환경 설치 호스트와 임베디드 시스템 사이의 통신 리눅스 포팅
하드웨어 환경 설치
JTAG(Joint Access Group) 배경 개발된 하드웨어의 테스트 : 기존의 방법 지그라는 장비를 사용 : 고가의 장비 오실로스코프 사용 기타의 장비 사용 효과적인 테스트가 불가능 하드웨어의 손상을 유발할 수 있음 => JTAG가 탄생 JTAG 칩 내부에 boundry cell이란 것을 두어 외부의 핀과 일대일로 연결시켜 이 셀을 통해 프로세서가 할 수 있는 모든 동작을 인위적으로 수행할 수 있음 특별한 별도의 장비 없이 하드웨어 테스트나 연결 상태 등을 확인할 수 있음
JTAG의 기능 디바이스 내에서 모든 외부와의 연결점을 가로챈다. 각각의 셀은 시리얼 쉬프트 레지스터를 형성하기 위해 서로 연결한다. 전체적인 인터페이스는 5개의 핀(TDI, TMS, Ntrst, TDO)에 의해서 제어 JTAG을 사용하는 궁극적인 이유
JTAG 케이블 사용 예 임베디드 시스템의 개발에서 JTAG 케이블을 사용하는 경우 이 경우 Jflash, jtag_garnet, Jflash-linux-linuette-box 프로그램 등을 이용 JTAG용 병렬 케이블을 이용
직렬(serial) 케이블 호스트 시스템의 사용자와 임베디드 시스템의 대화를 위해 사용 저속의 데이터 통신을 위해 사용 호스트 시스템을 임베디드 시스템의 콘솔로 사용 호스트 시스템은 임베디드 시스템에 명령을 내려보내는데 사용 임베디드 시스템은 자신의 상태나 명령어 수행 결과를 호스트 시스템에 올려 보내는데 사용 커널이나 파일 시스템 이미지 등 대량의 데이터를 내려보내는데도 사용
이더넷/USB 케이블 호스트 시스템의 사용자와 임베디드 시스템의 대화를 위해 사용 고속의 데이터 통신을 위해 사용 커널이나 파일 시스템 이미지 등 대량의 데이터를 내려보내는데 사용 원격에서 임베디드 시스템을 부팅해야 할 때 사용
소프트웨어 환경 설치 임베디드 리눅스, 디바이스 드라이버, 응용프로그램의 개발에 필요한 소프트웨어 호스트 시스템에서 실행 가능한 임베디드 시스템용 크로스 컴파일러 본 교재에서는 ARM용 크로스 컴파일러 만을 언급 호스트 시스템에서 구동되는 원격 디버깅 도구 임베디드 시스템의 프로세서 명령어를 이해할 수 있어야 함 린눅스에서는 GNU의 gdb를 사용
크로스 컴파일러 크로스 컴파일러 툴 체인의 구성 ARM용 툴 체인의 획득 임베디드 시스템용 프로그램 소스들을 컴파일하고 빌드하여 실행 가능한 바이너리를 생성하기 위한 개발도구 어셈블러, 링커, C 컴파일러, C 라이브러리 등을 포함 ARM용 툴 체인의 획득 ftp://ftp.netwinder/org/users/c/chagas/arm-linux-cross/RPM/
ARM용 툴 체인 설치 Step 1 Step 2 ARM용 rpm을 위에서 언급한 사이트에서 내려받는다. arm-linux-gcc-2.95.2-2.i386.rpm arm-linux-binutils-2.10-1.i386.rpm arm-linux-glibc-2.1.3-2.i386.rpm Step 2 각 rpm을 아래 명령어의 예와 같이 설치 $rpm -i arm-linux-binutils-2.10-1.i386.rpm $rpm -i arm-linux-glibc-2.1.3-2.i386.rpm $rpm -i arm-linux-gcc-2.95.2-2.i386.rpm
ARM용 툴 체인 설치 Step 3 ARM 디렉토리의 실행 파일들의 위치경로를 .bash_profile 또는 .profile의 PATH 변수에 아래와 같이 추가 PATH=/usr/local/arm/bin:/usr/local/sbin:/usr/bin:/bin:/usr/X11R6/bin export PATH
디버깅 도구 임베디드 시스템 환경에서의 디버깅 : 원격 디버깅 제한된 환경 : 데스크탑용 디버거와 같이 많은 자원을 사용하는 프로그램은 사용하기 쉽지 않다. 실질적인 디버깅 기능만을 수행하는 서버 프로그램을 임베디드 시스템에 설치 호스트 시스템에서 서버 프로그램으로부터의 정보를 가공하여 화면에 표시 사용자의 디버깅 명령어를 서버 프로그램에 전달 둘 사이의 통신은 콘솔이 사용하지 않는 직렬 포트를 이용 동일한 실행 파일이 호스트와 임베디드 시스템 양쪽에 모두 있어야 함 gdb GNU에서 제공하는 리눅스에서 일반적으로 사용되는 디버거 원격 디버깅을 위한 기능이 이미 데스크탑용 gdb에 포함되어 있음
디버깅 실행 절차 1. 소스 프로그램을 아래와 같이 컴파일 $gcc –g –o prg1 prg1.c 2. 실행 파일을 복사한 후 심복을 제거(크기를 작게 만든다) $cp prg1 prg1.strip $strip prg1.strip 3. 실행파일 prg1.strip을 임베디드 시스템으로 전송 minicom의 파일 전송 툴을 이용하거나 NFS 시스템을 이용
디버깅 실행 절차 4. 아래와 같이 gdb 서버를 실행 항상 gdb 서버부터 실행 $./gdbserver /dev/ttyS1 prg1.strip /dev/ttyS1은 임베디드 시스템에서 사용할 직렬포트의 이름 : 시스템에 따라 달라질 수 있다. 5. 호스트의 gdb의 실행 ./gdb –b 11520 prg1 -b 옵션은 통신 속도의 설정을 위해 이후 아래와 같은 메시지와 프롬프트가 나타남
디버깅 실행 절차 GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i586-unknown-linux), Copyright 1996 Free Software Foundation, Inc... (gdb)
디버깅 실행 절차 6. 아래와 같이 gdb 서버에의 접속 (gdb) target remote /dev/ttyS1 7. 디버깅 참고 gdb 실행 후 list를 이용하여 소스를 확인 필요한 부분에 break를 설정하고 run을 하면 break된 부분까지 실행됨 확인할 변수가 있으면 display 변수명을 이용
gdb 명령어 리스트 list 현재 위치에서 source file을 10줄 보여줌 list first, last source file을 first 줄에서 last 줄까지 보여줌 list function function에 해당하는 source file을 보여줌 break n n줄에 break를 설정 run 현재의 인수를 사용하여 프로그램의 끝(만약 break가 있으면 break까지)까지 실행 run args 새로운 인수 args를 사용하여 프로그램의 끝(만약 break가 있으면 break까지)까지 실행 cont 현재 위치에서 프로그램의 끝(만약 break가 있으면 break까지)까지 실행 next 한줄씩 실행. 이때 함수를 포함하고 있으면 함수를 완전히 실행하고 다음줄로 이동 next n 현재줄에서 n줄 실행 step 한줄씩 실행. 이때 함수를 포함하고 함수내부로 이동하여 실행 step n 현재줄에서 n줄까지 실행. 이때 함수를 포함하고 함수내부로 이동하여 실행 print eval eval에 지정된 식의 값을 보여줌(만약 변수에 대해서 하면 현재의 변수값을 보여줌) display varname 변수 varname의 현재 값을 보여줌 display 이제까지 display되었던 varname들의 현재 값을 모두 보여줌 quit gdb를 종료
호스트와 임베디드 시스템 사이의 통신 직렬 통신 TCP/IP 통신 호스트 시스템을 콘솔로 사용하기 위해 리눅스 : minicom을 이용 MS Windows : 하이퍼터미널을 이용 본서에서는 minicom만을 설명 TCP/IP 통신 Bootp/tftp NFS USB를 이용한 통신
minicom 설정 1. minicom을 환경 설정 모드로 실행 $minicom -s 2. 메뉴가 뜨면 “Serial port setup” 항목을 선택 3. 새로운 메뉴가 뜨면 “A-Serial Device”를 선택하여 직렬 케이블이 연결된 포트를 선택 /dev/ttyS0 또는 /dev/ttyS1 4. “E-bps/Par/Bits” 항목을 선택 : 예 bps를 11520 Data bit를 8로 Stop bit를 1로 parity를 NO로
minicom 설정 5. “F-Hardware Flow Control” 항목을 선택 : 예 NO 로 6. “G-Hardware Flow Control” 항목을 선택 : 예 7. 설정이 끝나면 Enter 키를 누른다. 8. Esc 키를 눌러 다시 메인 메뉴가 뜨면 “Save setup as dfl” 을 선택 9. 구성 메뉴에서 빠져 나온다. “Exit” 항목을 선택 => 이 후 minicom 프로그램이 실행되는 호스트 시스템은 임베디드 리눅스의 콘솔 역할을 하게 된다.
Bootp/tftp bootp bootp는 TCP/IP 상에서 자동 부팅을 위한 최초의 표준 udp와 tftp 프로토콜을 이용 설치 및 설정이 TCP super server(inetd 또는 xinetd)에 따라 달라짐 bootp와 관련된 데몬 bootpd inetd
Bootp/tftp bootp의 설정 Bootp 설정에 필요한 데몬과 구성 파일들
Bootp/tftp bootp의 설정 Bootp 설정에 필요한 데몬과 구성 파일들
Bootp/tftp bootpd 자신의 구성파일(/etc/bootptab)을 읽어서 해당 MAC 주소를 가진 항목을 확인 존재하면 들어있는 정보를 이용하여 응답 패킷을 구성 다음과 같은 정보가 임베디드 시스템으로 가게된다. sm : 로컬 랜의 서브넷 마스크 hd : 호스트 디렉토리 ht : 랜의 하드웨어 형태 ha : 타겟의 이더넷 MAC 주소 inetd 통신 패킷을 검출하여 bootpd 데몬을 요청하면 해당 bootpd 데몬이 호출되도록 전달해주는 역할 /etc/inetd.conf에 설정된 데몬들을 관리
Bootp/tftp bootp 와 관련된 환경 설정 파일 bootptab .default:\ :hd=/bootp/:\ :ds=xxx.xxx.xxx.xxx:\ :gw=xxx.xxx.xxx.xxx:\ :sm=255.255.255.0 Embedded_System:\ ht=ethernet:\ ha=0x00D0CAF12A20:\ tc=.default:
Bootp/tftp bootp 와 관련된 환경 설정 파일 Inetd.conf 파일을 수정하여 홈 디렉토리를 설정 UDP를 사용 속도가 빠름 xinetd를 사용하는 경우 /etc/xinetd.d/tftp 를 수정 tftp dgram udp wait root /usr/sbin/tcpd in.tftpd /tftpdir bootps dgram udp wait root /usr/sbin/tcpd bootpd
Bootp/tftp bootp 와 관련된 환경 설정 파일 Inetd.conf : tftp 와 관련된 부분 service tftp { disable = no socket_type =dgram protocol = udp wait = yes user = root service = /usr/sbin/in.tftp.d server_args = -s /tftpdir }
Bootp/tftp bootp 와 관련된 환경 설정 파일 hosts 호스트 시스템에 연결된 IP 주소를 포함 이 IP 주소에 임베디드 시스템에 할당된 IP 주소를 입력하고, 호스트 이름 부분에 /etc/bootptab 파일에 있는 임베데드 시스템 이름 (위에서는 Embedded_System)을 입력 변경한 inetd.conf파일의 내용을 적용하기 위해서는 아래와 같이 inetd 서버를 재시동 /etc/rc.d/init.d/inet restart (xinetd를 사용하는 경우 service xinetd restart)
NFS(Network File System) 선 마이크로시스템즈사가 개발 원격지의 컴퓨터에 있는 파일을 마치 자신의 컴퓨터에 있는것 처럼 조작 클라이언트/서버형 응용프로그램 사용자 시스템에는 NFS 클라이언트가 존재 원격지 컴퓨터에는 NFS 서버가 존재 임베디드 시스템 개발에 이용하면 호스트 시스템의 특정 디렉토리를 임베디드 시스템에서 공유 : 임베디드 시스템에서 호스트 시스템의 하드디스크를 공유할 수 있어 개발 시 매우 유용
NFS NFS 마운트 과정 호스트 시스템의 NFS 서버 설정 임베디드 시스템과 공유할 디렉토리(예:/nfs_home)를 만든다. /etc/exports 파일에 다음과 같은 내용을 추가한다. /nfs_home xxx.xxx.xxx.xxx (rw, no_root_squash) /nfs_home은 공유할 디렉토리의 절대 패스 xxx.xxx.xxx.xxx는 임베디드 시스템의 IP 주소 NFS 서버를 이래와 같은 명령어로 재시동 /etc/rc.d/init.d/nfs stop /etc/rc.d/init.d/nfs start
NFS NFS 마운트 과정 임베디드 시스템의 설정 마운팅 포인터로 사용할 빈 디렉토리(예:/nfs_host)를 만든다. 아래 명령어를 이용하여 호스트 시스템에 존재하는 공유할 디렉토리를 마운트 한다. mount xxx.xxx.xxx.xxx:/nfs_home /nfs_host xxx.xxx.xxx.xxx는 NFS 서버(호스트 시스템)의 IP 주소 /nfs_home은 호스트 시스템의 공유될 디렉토리 /nfs_host는 임베디드 시스템의 마운팅 포인터
USB USB USB 포트를 이용하여 이더넷 처럼 통신 직렬 포트를 이용하는 것보다 매우 빠름 이 디바이스 드라이버가 커널에 포함되어 있거나 모듈로 커널에 삽입되어 있을 때 사용 가능 관련된 소스코드는 ftp://ftp.kernel.org/pbu/linux/kernel/people/alan/2.4/에서 내려 받을 수 있다.
USB USB 설정 호스트 시스템의 USB 설정 /lib/modules 디렉토리에서 아래와 같이 모듈을 확인 find -name usbcore.o fint -name usb-uhci.o 파일이 있으면 모듈의 형태로 드라이버가 지원되고 있음 모듈이 없으면 아래와 같이 커널 안의 기능을 확인 cat /proc/devices 출력 결과에서 “180 usb”가 발견되면 커널에 기능이 있음 커널에 USB 기능이 없으면 아래와 같이 모듈을 설치 make modules make modules_install /lib/modules 디렉토리에서 모듈 파일들을 확인
USB USB 설정 호스트 시스템과 임베디드 시스템의 연결 두 시스템을 USB 케이블로 연결 아래와 같이 새로운 네트워크 인터페이스가 두 시스템 모두에 생성되었는지 확인 cat /proc/net/dev 호스트 시스템에서는 usb0로, 임베디드 시스템에서는 usbf 호스트 시스템에서 이래와 같이 네트워크 인터페이스를 활성화 ifconfig usb0 1.1.1.1 임의의 IP 주소 사용 가능 임베디드 시스템에서 이래와 같이 네트워크 인터페이스를 활성화 ifconfig usbf 1.1.1.2
리눅스 포팅 커널 소스 구하기 패치의 적용 원하는 버전의 커널 소스를 ftp.kernel.org에서 구함 Linux-2.4.0-test4.tar.gz 임베디드 시스템의 프로세서와 관련된 패치 파일들을 획득 ARM 패치 : patch-2.4.0-test4-rmkl.gz SA1100 패치 : diff-2.4.0-test4-rmkl-npl.gz 패치의 적용 ㅣ
리눅스 포팅 패치의 적용 리눅스 커널의 압축 해제 ARM 패치 적용 SA1100 패치 적용 임베디드 시스템의 패치 적용 $tar xvzf linux-2.4.0-test4.tar.gz ARM 패치 적용 $cd linux(압축을 해제한 디렉토리) $gzip –cd patch-2.4.0-test4-rmkl.gz | patch –pl SA1100 패치 적용 $cd linux $ gzip –cd diff-2.4.0-test4-rmkl-npl.gz | patch –pl 임베디드 시스템의 패치 적용
리눅스 포팅 커널 컴파일 커널 소스의 압축을 해제한 곳으로 이동 $cd /usr/src/linux 이전 설정을 모두 제거 $make mrproper 임베디드 시스템용의 config를 적용 $make target_config Menuconfig make 하기 : 원하는 것은 설정하고 필요 없는 것은 삭제 $make menuconfig dependency 검사 $make dep 소스 사이의 이존 관계를 분석하여 .depend 파일에 저장 삭제 : 필요 없는 내용을 삭제 $make clean zImage 생성 : ./arch/arm/boot 밑에 zImage 파일이 생성됨 $make zImage 이 파일을 부트로더를 통해 내려보낸 후 부팅
리눅스 포팅 커널 컴파일 아무 서브 명령어 없이 make 하면 make zImage를 하면 vmlinux 파일이 생성 디버깅 정보를 포함 압축되지 않았음 make zImage를 하면 zImage가 생성됨 디버깅 정보가 없음 압축되어 있음 임베디드 시스템에 적당
리눅스 포팅 램디스크(Ramdisk)의 생성 램의 일부를 할당하여 마치 하드디스크 처럼 사용 읽기, 쓰기가 빠름 전원을 끄면 내용이 모두 사라짐 램디스크의 소스파일 ftp.netwinder.org/users/n/nico/ramdisk_img.gz
리눅스 포팅 램디스크 이미지 변경 램디스크 압축 해제 마운팅 포인트를 작성하고 마운트 $gunzip –d ramdisk_img.gz $mkdir /mnt $mount –t ext2 –o loop ramdisk_img /mnt 또다른 방법 : 루프백 디바이스와 연결 $loseup /dev/loop0 ramdisk_img $mount /dev/loop0 /mnt 작업이 끝나면 마운트를 해제 $umount /mnt $loseup –d /dev/loop0 (루프백 디바이스와 연결됬을 때) 램디스크를 압축 $gzip ramdisk_img
리눅스 포팅 시스템 초기화 설정 루트 파일 시스템이 마운트 되면 /sbin/init가 실행됨 init는 설정 파일 /etc/inittab을 읽어서 초기화 수행 중간에 /etc/rc.d/rc.sysinit를 호출 이 두 파일의 변경을 통하여 시스템 초기화 설정에 변화를 줄 수 있음