2011년 6월 7일 화요일

S3C6410 Start Kit Linux Developer Guide

       
 
이 매뉴얼은 JK전자(JK Electronics) 에 의해서 번역, 수정, 작성 되었고 소유권 또한
JK전자(JK Electronics)
의 것입니다. 소유권자의 허가를 받지 않고 무단으로 수정, 삭제하거나 배포 할 수 없습니다.

제품 구매 : http://www.toolparts.co.kr

 

S3C6410 Start Kit Linux Developer Guide


 
* Update history

- 2011.1.13 : 초기 Release


 


1. Environment Setup

1.1 Installation Fedora9

S3C6410 Startkit 의 모든 예제와 컴파일 과정은 VMWare에 설치된 Fedora9 머신에서 실행 하였습니다. 다른 리눅스 환경에서는 테스트 되지 않았습니다. 폐도라 리눅스의 전체 설치 과정은 여기 Installation Fedora9 을 참조하시기 바랍니다.

1.2 Add a new user

부트로더와 커널등을 컴파일 하고 크로스 컴파일러 설치 작업등을 수행할 일반 계정을 생성 합니다.

Step1: Open the "Users and Groups Manager"



Step2: User Management window appears

s3c6410

Step3: Point toolbar "Add User" button to add new users, and set the password:

s3c6410

Point "OK" return, you can see has add "plg" users, while /home directory also add for plg user directory, as shown:

s3c6410

Point Add User button, the window to add new users, according to the prompts on it.


1.3 Access to Windows system files

버츄얼 머신에 설치된 Fedora9 시스템에서 HOST PC인 윈도우즈 파일시스템에 접근 해야 할 필요성이 있는데 한가지 방법은 Host와 Guest OS간의 네트워크를 이용하는 방법과 VMWare의 shared file 기능을 이용하는 방법입니다. 자세한 설정 과정은 다음을 참조하세요.

s3c6410

Step1: In Windows set the shared folder "share_f9" (Example)

s3c6410

Step2: In Fedora9 operating system:

s3c6410

Open figure window:

s3c6410

In Service type select "Windows share"

s3c6410

Enter the desired share Windows Host IP Address and the name of the shared folder:

s3c6410

Click "Connect" prompt window will appear as follows:

s3c6410

Do not care, direct "Connect" can be, you can see Windows Shared the contents of the document, and in this operation other directories as you can, like to use it.

s3c6410

터미널 창의 커맨드 라인에서 접근 하는 방법도 있습니다.

s3c6410

Shared디렉토리와의 연결 해제 방법은 아래 그림과 같이 Fedora 메뉴에서 "Unmount Volume" 을 실행 하면 됩니다.

s3c6410

Samba를 이용하는 방법보다는 리눅스를 VMWare에 설치 하였다면 VMWare의 Shared Folder 를 이용하는 방법이 더 간단 합니다.

1.4 Configure NFS Services

다음의 NFS 서시스 설정 과정은 단지 레펀런스만 하시기 바랍니다. 많은 리눅스 시스템들이 아래에서 설명하는 절차에 의해서 동일한 결과를 내지 않을 수 있습니다. 심지어 동일한 버젼과 Fedora 9 에서 조차도 사용자의 설치 환경에 따라서는 되지 않을 수도 있습니다. 설정 과정중 오류 사항은 인터넷 등 다른 참조 자료를 활용 하시기 바랍니다.

Step1: Set the shared directory

 

"root" 계정으로 로그인한 상태에서 아래 명령들을 실행 하세요.

# gedit /etc/exports

NFS서비스 profile 을 수정 합니다.

/opt/FriendlyARM/mini6410/linux/root_qtopia_qt4 *(rw,sync,no_root_squash)

/opt/FriendlyARM/mini6410/linux/root_qtopia_qt4 : NFS로 공유할 디렉토리 경로 입니다.

rw : read and write 권한

/opt/FriendlyARM/mini6410/linux/root_qtopia_qt4 디렉토리는 미리 생성이 되어 있어야 합니다.

Step2: Start NFS Services

Fedora시스템에서는 기본적으로 파이어월 때문에 NFS 서비스가 올바르게 실행 되지 않습니다. 그래서 먼저 Firewall 을 중지하고 실행 해야 합니다. 명령 라인에서 "lokkit" 명령을 이용해서 Firewall 구성을 시작 합니다.

s3c6410

"Disabled" 를 선택하고 "OK" 를 누룹니다. 그리고 나서 NFS 서비스를 시작 합니다.

# /etc/init.d/nfs start

NFS 서비스가 제대로 시작되었는지 다음과 같이 local 영역을 먼저 마운트 합니다.
# mount -t nfs localhost: /opt/FriendlyARM/mini6410/root_qtopia_qt4 /mnt/

다음은 NFS 서비스를 종료 시키는 명령 입니다.
# /etc/init.d/nfs stop

NFS서비스를 시스템 부팅시에 자동으로 실행하면 좀더 편리 합니다.
# serviceconf

s3c6410

Step3: NFS Start System
초기 리눅스 개발시에는 개발보드가 부팅시에 root filesystem 을 NFS를 통해서 Linux host PC 의 root 파일 시스템을 참조하도록 하는것이 편리 합니다. superboot 메뉴에서 Linux 부팅 파라미터에 다음같이 하면 됩니다.
s3c6410

각각의 IP주소에 대한 설명 입니다.

192.168.1.70 : 타겟 개발보드의 IP Address
192.168.1.111 : Linux HOST IP Address
192.168.1.111 : 타겟 개발보드의 Gateway
255.255.255.0 : Subnet mask
eth0 : Linux HOST PC의 네트워크 인터페이스 이름, 마지막으로 Linux HOST PC의 호스트 이름은 어떤 이름이든 문제가 되지 않습니다.

s3c6410

"b" 명령어로 개발보드의 root 파일 시스템은 NFS 서버의 디렉토리에 마운트 되면서 시작 하게 됩니다.

s3c6410


1.5 Install cross-build compiler

임베디드 리눅스의 부트로더, 커널, QT 등을 컴파일 하기 위해서는 개발용 Linux PC에 ARM용 크로스 컴파일러를 설치 해야 합니다. 이 개발보드를 위해서는 arm-linux-gcc-4.5.1 컴파일러를 설치 해야 합니다. 이 컴파일러는 armv6 Instruction set and support hardware floating-point operations 등을 지원 합니다. 자세한 설치 방법은 아래와 같은 절차대로 하시면 됩니다.

Step1 : CD-ROM/Linux/arm-linux-gcc-4.5.1-v6-vfp-20101103.tgz 의 파일을 개발용 PC의 /tmp 디렉토리에 복사 합니다. 그리고 나서 다음 명령을 입력 합니다.

# cd /tmp
# tar xvzf arm-linux-gcc-4.5.1-v6-vfp-20101103.tgz -C /

이 명령어는 arm-linux-gcc 컴파일러를 /opt/FriendlyARM/toolschain/4.5.1 에 설치합니다.

Step2 : 설치 디렉토리를 사용자 계정 shell 파일에 추가 합니다.

# gedit /root/.bashrc
export PATH=$PATH:/opt/FriendlyARM/toolschain/4.5.1/bin

s3c6410

터미널 창을 종료하고 다시 로그인 한 다음 "arm-linux-gcc -v" 명령을 실행 하면 아래과 같은 메세지가 나와야 합니다.

s3c6410

1.6 Install source code and tool

다음과 같은 소스와 툴 들을 설치 합니다.

- Linux kernel source code
- Qtopia-2.2.0 platform source code (x86 and arm platform is divided into two versions)
- Arm-qt-extended-4.4.3 platform source code (that is Qtopia4, divided into two versions of x86 and arm)
- QtE-4.7.0 platform source code (arm version)
- Busybox-1.17 source code
- Linux source code programming examples
- U-boot source code
- Target file system directory
- Target file system image creation tools (including yaffs2 and UBIFS)
- GUI Linux logo creation tools logomaker

1.6.1 Unpacking the source code

먼저 "/opt/FriendlyARM/mini6410/linux" 디렉토리를 생성 합니다. 모든 소스 코드는 이 디렉토리에 압축을 해제해서 설치를 진행 할 것입니다.
# mkdir -p /opt/FriendlyARM/mini6410/linux

(1) Linux source code package 준비, "/tmp/linux" 디렉토리를 생성 합니다.

#mkdir /tmp/linux

CD-ROM안의 Linux 디렉토리의 모든 파일들을 /tmp/linux 에 복사 합니다.

(2) U-boot source code package 준비, "/opt/FriendlyARM/mini6410/linux" 디렉토리로 이동해서 명령들을 수행 합니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/u-boot-mini6410-201012.31.tar.gz

u-boot-mini6410 디렉토리가 생성이 되고 U-boot 소스코드들이 생성될 것입니다.

(3) Unpacking the Linux kernel source code
"/opt/FriendlyARM/mini6410/linux" 을 워킹 디렉토리로 하여 아래 명령을 수행 합니다. "linux-2.6.36-" 이후의 파일 이름은 소스 베포 날짜 이므로 달라 질 수 있습니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/linux-2.6.36-20101115.tar.gz


위의 명령으로 "linux-2.6.36" 디렉토리 안에 전체 커널 소스 코드가 생성 됩니다.

(4) Extract the target file system installation

#cd /opt/FriendlyARM/mini6410/linux
#tar xvzf /tmp/linux/rootfs_qtopia_qt4-20101120.tgz


"rootfs_qtopia_qt4" 디렉토리가 생성되면 qtopia 파일 시스템 소스 파일들이 생성 됩니다. "rootfs_qtopia_qt4-" 이후의 파일 이름은 소스 베포 날짜 이므로 달라 질 수 있습니다.

(5) Unpacking the source code for embedded graphics system qtopia

"/opt/FriendlyARM/mini6410/linux" 을 워킹 디렉토리로 하여 다음 명령들을 실행 시킵니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/x86-qtopia-20100420.tar.gz
# tar xvzf /tmp/linux/arm-qtopia-20101105.tar.gz


"x86-qtopia" 와 "arm-qtopia" 디렉토리가 생성되고 qtopia 관련 소스 파일들이 설치 됩니다. "x86-qtopia-" 이후의 파일 이름은 소스 베포 날짜 이므로 달라 질 수 있습니다.

(6) Extract the installation of embedded graphics system qt-extended-4.4.3 source code

"/opt/FriendlyARM/mini6410/linux" 을 워킹 디렉토리로 하여 명령들을 실행 시킵니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/x86-qt-extended-4.4.3-20101003.tgz
# tar xvzf /tmp/linux/arm-qt-extended-4.4.3-20101105.tgz


위의 명령으로 "x86-qt-extended-4.4.3" and "arm-qt-extended-4.4.3" 디렉토리가 생성되고 qt-extendec 소스가 설치 됩니다.

(7) Extract the installation QtE-4.7.0 source code

"/opt/FriendlyARM/mini6410/linux" 을 워킹 디렉토리로 하여 명령들을 실행 시킵니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/x86-qte-4.6.1-20100516.tar.gz
# tar xvzf /tmp/linux/arm-qte-4.7.0-20101105.tar.gz


"x86-qte-4.6.1" and "two arm-qte-4.7.0" 2개의 디렉토리가 생성되고 관련 소스파일 들이 설치 됩니다.

(8) Extract the source code to install busybox

Busybox is a lightweight linux command set of tools is used in this version of busybox-1.13.3. Download the latest version from their official website (http://www.busybox.net).

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/busybox-1.17.2-20101110.tgz


"Busybox-1.17.2" 디렉토리가 생성되고 관련 소스가 설치 됩니다.

(9) Extract the installation of Linux sample program

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/examples-mini6410-20101110.tgz


"examples" 디렉토리가 생성되고 리눅스 에제 프로그램들이 설치 됩니다.

1.6.2 Create the target file system extract

파일 시스템은 2개의 압축 파일을 제공하는데 2개의 차이점은 단지 "/etc/friendlyarm-ts-input.conf" 파일만 다릅니다. "-s" 가 붙은 파일 시스템은 four-wire resistive touch screen 에 최적화된 파일 시스템 입니다. 일반적으로는 "rootfs_qtopia_qt4-20101120.tgz" 을 사용하면 됩니다.

* rootfs_qtopia_qt4-20101120.tgz
* rootfs_qtopia_qt4-s-20101120.tgz

아래 명령어로 설치 할 수 있습니다.

# cd /opt/FriendlyARM/mini6410/linux
# tar xvzf /tmp/linux/rootfs_qtopia_qt4-20101120.tgz
# tar xvzf /tmp/linux/rootfs_qtopia_qt4-s-20101120.tgz


"rootfs_qtopia_qt4" and "rootfs_qtopia_qt4-s" 2개의 디텍토리가 생성되고 거기에 알맞은 파일 시스템 소스가 설치 됩니다. 2개의 파일 시스템은 다음과 같은 기능을 제공 합니다.

- Automatic identification NFS or a local start
- Automatic recognition of ordinary or high-speed SD card (maximum support 32G) and USB flash drives
- Automatic detection of USB mouse or touch screen
- Support for USB mouse and touch-screen co-existence (from the beginning to support Linux-2.6.36)

1.6.3 Extract the installation file system image tools

- mkyaffs2image : Nand 플래시가 64MB 인 타겟 시스템용 파일 시스템 툴 입니다.
- mkyaffs2image-128M : Nand 플래시가 128M/256M/512M/1GB 인 타겟 시스템용 파일 시스템 툴 입니다.

위이 2개 툴 이외에서 UBIFS, EXT3 파일 시스템 이미지 툴이 있습니다. 모든 툴 들은 아래 명령에 의해서 설치가 됩니다.

# tar xvzf /tmp/linux/mktools.tar.gz -C /

위위 명령에 의해서 /usr/sbin 디렉토리에 mkyaffs2image, mkyaffs2image-128M, mkubimage,mkext3image 이미지 툴들이 설치 됩니다.

1.6.4 Unpacking LogoMaker

LogoMaker 툴은 리눅스 부트 시작 이미지를 바꿀수 있게 해주는 툴 입니다. 아래 명령으로 설치 할 수 있고 /usr/sbin 디렉토리에 설치가 됩니다. bmp, jpg, png image format 을 부트 로고로 사용 할 수 있습니다. 자세한 사용 방법은 이후의 절에서 다시 설명 합니다.

# tar xvzf /tmp/linux/logomaker.tgz -C /

s3c6410

1.7 U-boot configuration and compilation

삼성전자는 USB download와 Nand boot 기능등을 제공하는 좋은 Uboot 소스를 제공 합니다. 우리는 여기에서 좀더 개선한 UBoot 코드와 바이너리 제공 합니다. 주요 기능은 다음과 같습니다.

- Increase the download menu, similar to the USB download menu Superboot
- Added SD card startup configuration
- Support for direct download file system image programming yaffs2
- Support for the Nboot programming WindowsCE BootLoader
- Support for WindowsCE programming function of the image
- Support for programming single-file image files, is commonly referred to as firmware
- Support for return to the original shell
- Added support for 256M DDR RAM

Here we introduce the configuration and compile it and use it.

1.8.1 Support NAND boot configuration compile U-boot

개발보드의 DDR RAM 용량에 따라서 U-boot 컴파일시 다른 설정 파라미터로 컴파일 해야 합니다.

(1) 128MB DDR RAM 메모리가 실장된 개발보드를 컴파일 하는 예제 입니다.

# cd /opt/FriendlyARM/mini6410/linux/u-boot-mini6410
# make mini6410_nand_config-ram128;make


(2) 256MB DDR RAM 메모리가 실장된 개발보드를 컴파일 하는 예제 입니다.

# cd /opt/FriendlyARM/mini6410/linux/u-boot-mini6410
# make mini6410_nand_config-ram256;make


1.8.2 Support SD boot configuration compile U-boot

(1) 128MB DDR RAM 메모리가 실장된 개발보드를 컴파일 하는 예제 입니다.

# cd /opt/FriendlyARM/mini6410/linux/u-boot-mini6410
# make mini6410_sd_config-ram128;make


(1) 256MB DDR RAM 메모리가 실장된 개발보드를 컴파일 하는 예제 입니다.

# cd /opt/FriendlyARM/mini6410/linux/u-boot-mini6410
# make mini6410_sd_config-ram256;make


1.8.3 Using U-boot

Not finished.

1.9 Configure and compile the kernel

개발보드의 LCD종류에 따라서 다른 설정 파일을 사용해야 합니다. LCD의 종류들은 다음과 같습니다.

config_mini6410_x35 - Sony 3.5" LCD,240x320
config_mini6410_n43 - NEC4.3" LCD,480x272
config_mini6410_l80 - Sharp 8" LCD,640x480
config_mini6410_a70 - Innolux 7" LCD,800x480
config_mini6410_vga1024x768 - 1024x768 VGA Module Adapter board
config_mini6410_vga800x600 - 800x600 VGA Module Adapter board
config_mini6410_vga640x480 - 640x480 VGA Module Adapter board
config_mini6410_ezvga800x600 - 800x600 Simple VGA Module Adapter board

".config" 파일의 기본 설정은 "config_mini6410_n43" 로 되어 있습니다.

# cp config_mini6410_n43 .config

started compiling the kernel, you can also use the make command directly

# make zImage

s3c6410

컴파일이 완료되면 /arm/boot 디렉토리에 zImage 파일이 생성이 됩니다.

1.10 Configue and compiling busybox

busybox 웹사이트에서 다운로드한 소스코드는 사용자의 목적에 따라서 설정을 다시 해서 컴파일 할 수 있습니다. 우리는 기본 설정인 fa.config 파일을 이용해서 컴파일 했습니다. busybox 소스코드가 있는 디렉토리로 이동하여 컴파일 합니다.


# cp fa.config .config
# make


s3c6410

1.11 Make target file system image

1.11.1 Make yaffs2 file system image

"/opt/FriendlyARM/mini6410/linux" 디렉토리로 이동하여 다음 명령을 수행 합니다. 다른 것들과 마찬가지로 DDR RAM용량에 따라서 다른 명령어를 사용해야 합니다.

# mkyaffs2image-128M rootfs_qtopia_qt4 rootfs_qtopia_qt4.img

1.11.2 Make ubifs file system image

"/opt/FriendlyARM/mini6410/linux" 디렉토리로 이동하여 다음 명령을 수행 합니다.

# mkubimage rootfs_qtopia_qt4 rootfs_qtopia_qt4.ubi

1.11.3 Make ext3 file system image

"/opt/FriendlyARM/mini6410/linux" 디렉토리로 이동하여 다음 명령을 수행 합니다.

# mkext3image-128M rootfs_qtopia_qt4 rootfs_qtopia_qt4.ext3


1.12 Example of embedded Linux applications

이번절에서는 embeded linux 기본 예제들을 컴파일 해보고 실행새 보면서 임베디드 어플리케이션의 구조에 대해서 학습해 보도록 합니다. 참고로 앞으로 설명하는 모든 기본 예제들은 "arm-linux-gcc-4.5.1-v6-vfp" 로 컴파일 하고 테스트 하였습니다. 다른 버젼으로 컴파일된 커널의 타겟 보드에서는 제대로 동작하지 않을 수도 있습니다. cross-compiler의 버젼을 검사해 보기 위해서 아래 "arm-linux-gcc ?v" 명령을 수행합니다.


s3c6410

1.12.1 Hello, World!

Hello, World 예제의 소스코드는 "/opt/FriendlyARM/mini6410/linux/examples/hello" 에 있습니다.


#include <stdio.h>

int main(void) {
printf("hello, FriendlyARM!\n");
}


Step1 : Compile Hello, World

# cd /opt/FriendlyARM/mini6410/linux/examples/hello
# make


컴파일이 완료된 바이너리 파일의 정보를 볼 수 있습니다.

s3c6410


Step2 : Download Hello, World example to development board

개발보드에 컴파일된 예제를 다운로드 하는 방법에는 4가지 정도의 방법이 있습니다.

(1) FTP를 이용한 다운로드하는 방법
(2) USB 메모리 or SD 메모리 카드를 이용해서 타겟 보드에 마운트 후 복사하는 방법
(3) 시리얼 포트를 이용해서 다운로드 하는 방법
(4) NFS를 이용해서 바로 실행 하는 방법

(1) FTP를 이용한 다운로드하는 방법 (recommended)

아래와 같이 개발용 Linux PC에서 타겟 보드에 FTP로 접속후 다운로드 합니다.

s3c6410

다운로드가 완료되면 타겟 보드에서 다운로드한 파일에 실행 권한을 부여 합니다.

s3c6410

(2) USB 메모리 or SD 메모리 카드를 이용해서 타겟 보드에 마운트 후 복사하는 방법

PC에서 아래 명령을 이용해서 USB 메모리를 마운트 한다음 예제 파일을 USB메모리에 복사합니다.

# mount /dev/sda1 /mnt
# cp hello /mnt
# umount /mnt


USB 메모리를 타겟 개발보드에 연결 하면 자동으리 /udisk로 마운트가 되고 아래과 같은 명령으로 실행 해 볼 수 있습니다.

# cd /udisk
# ./hello


s3c6410

(3) 시리얼 포트를 이용해서 다운로드 하는 방법

시리얼을 통한 파일 다운로드 하는 방법은 리눅스 사용자 가이드 "1.2.4 시리얼 포트를 이용한 PC파일 전송" 을 참조하시기 바랍니다.
다운로드한 파일에 실행 권한을 부여 합니다.

# chmod +x hello

(4) NFS를 이용해서 바로 실행 하는 방법

"192.168.1.111" 는 NFS서버 PC의 IP 주소 입니다.

# mount -t nfs -o nolock192.168.1.111:/opt/FriendlyARM/mini6410/linux/rootfs_qtopia_qt4 /mnt

NFS마운트가 성공적으로 연결이 되면 /mnt 디렉토리에 NFS서버의 "opt/FriendlyARM/mini6410/linux/rootfs_qtopia_qt4" 디렉토리가 마운트 되어 접근 할 수 있습니다.

# cd /mnt
# ./hello

1.12.2 LED Test Program

드라이버 소스 파일 이름 mini6410_leds.c
Device Type misc
Device Name /dev/leds
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/leds
예제 이름 led.c
예제 실행 파일 이름 led
LED driver has been compiled into the default kernel, so can not be loaded using insmod.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
/* check led control of two parameters, if no parameter input is out. */
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
on < 0 || on > 1 || led_no < 0 || led_no > 3) {
fprintf(stderr, "Usage: leds led_no 0|1\n");
exit(1);
}

/* open /dev/ leds device file */
fd = open("/dev/leds0", 0);
if (fd < 0) {
fd = open("/dev/leds", 0);
}
if (fd < 0) {
perror("open device leds");
exit(1);
}

/* the ioctl system call and input the parameter control led */
ioctl(fd, on, led_no);

/* close the device handle */
close(fd);
return 0;
}


컴파일하고 타겟보드에 다운로드 해서 실행하는 방법은 Hello, World 예제와 동일 합니다.

1.12.3 Button Test Program

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/char
드라이버 소스 파일 이름 Mini6410_buttons.c
Device Type misc
Device Name /dev/buttons
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/buttons
예제 이름 buttons_test.c
예제 실행 파일 이름 buttons
Button driver has been compiled into the default kernel, so can not be loaded using insmod.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>

int main(void)
{

int buttons_fd;
char buttons[6] = {'0', '0', '0', '0', '0', '0'};
buttons_fd = open("/dev/buttons", 0);
if (buttons_fd < 0) {
perror("open device buttons");
exit(1);
}

for (;;) {
char current_buttons[6];
int count_of_changed_key;
int i;
if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons) {
perror("read buttons:");
exit(1);
}
for (i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++) {
if (buttons[i] != current_buttons[i]) {
buttons[i] = current_buttons[i];
printf("%skey %d is %s", count_of_changed_key? ", ": "", i+1, buttons[i] ==
'0' ? "up" : "down");
count_of_changed_key++;
}
}
if (count_of_changed_key) {
printf("\n");
}
}

close(buttons_fd);
return 0;

}


1.12.4 PWM Buzzer Test Program

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/char
드라이버 소스 파일 이름 Mini6410_pwm.c
Device Type misc
Device Name /dev/pwm
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/pwm
예제 이름 pwm_test.c
예제 실행 파일 이름 Pwm_test
PWM driver has been compiled into the default kernel, so can not be loaded using insmod.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#define PWM_IOCTL_SET_FREQ 1
#define PWM_IOCTL_STOP 2
#define ESC_KEY 0x1b

static int getch(void)
{
struct termios oldt,newt;
int ch;
if (!isatty(STDIN_FILENO)) {
fprintf(stderr, "this problem should be run at a terminal\n");
exit(1);
}

// save terminal setting
if(tcgetattr(STDIN_FILENO, &oldt) < 0) {
perror("save the terminal setting");
exit(1);
}
// set terminal as need
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {
perror("set terminal");
exit(1);
}
ch = getchar();

// restore termial setting
if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {
perror("restore the termial setting");
exit(1);
}
return ch;
}
static int fd = -1;
static void close_buzzer(void);
static void open_buzzer(void)
{
fd = open("/dev/pwm", 0);
if (fd < 0) {
perror("open pwm_buzzer device");
exit(1);
}
// any function exit call will stop the buzzer
atexit(close_buzzer);
}
static void close_buzzer(void)
{
if (fd >= 0) {
ioctl(fd, PWM_IOCTL_STOP);
close(fd);
fd = -1;
}
}

static void set_buzzer_freq(int freq)
{
// this IOCTL command is the key to set frequency
int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq);
if(ret < 0) {
perror("set the frequency of the buzzer");
exit(1);
}

}
static void stop_buzzer(void)
{
int ret = ioctl(fd, PWM_IOCTL_STOP);
if(ret < 0) {
perror("stop the buzzer");
exit(1);
}
}

int main(int argc, char **argv)
{
int freq = 1000 ;
open_buzzer();
printf( "\nBUZZER TEST ( PWM Control )\n" );
printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ;
printf( "Press 'ESC' key to Exit this program\n\n" );
while( 1 )
{
int key;
set_buzzer_freq(freq);
printf( "\tFreq = %d\n", freq );
key = getch();
switch(key) {
case '+':
if( freq < 20000 )
freq += 10;
break;
case '-':
if( freq > 11 )
freq -= 10 ;
break;
case ESC_KEY:
case EOF:
stop_buzzer();
exit(0);
default:
break;
}
}
}

 

1.12.5 I2C-EEPROM programming example

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/i2c/busses
드라이버 소스 파일 이름 I2c-s3c2410.c
Device Type Char device
Device Name /dev/i2c/0
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/i2c
예제 이름 eeprog.c 24cXX.c
예제 실행 파일 이름 i2c
PWM driver has been compiled into the default kernel, so can not be loaded using insmod.
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "24cXX.h"

#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
void do_usage_if(int b, int line)
{
const static char *eeprog_usage =
"I2C-24C08(256 bytes) Read/Write Program, ONLY FOR TEST!\n"
"FriendlyARM Computer Tech. 2009\n";
if(!b)
return;
fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
exit(1);
}
#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0);
void do_die_if(int b, char* msg, int line)
{
if(!b)
return;
fprintf(stderr, "Error at line %d: %s\n", line, msg);
fprintf(stderr, " sysmsg: %s\n", strerror(errno));
exit(1);
}
static int read_from_eeprom(struct eeprom *e, int addr, int size)
{
int ch, i;
for(i = 0; i < size; ++i, ++addr)
{
die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error");
if( (i % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (i % 8) == 0 )
printf(" ");
printf("%.2x ", ch);
fflush(stdout);
}
fprintf(stderr, "\n\n");
return 0;
}

static int write_to_eeprom(struct eeprom *e, int addr)
{
int i;
for(i=0, addr=0; i<256; i++, addr++)
{
if( (i % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (i % 8) == 0 )
printf(" ");
printf("%.2x ", i);
fflush(stdout);
die_if(eeprom_write_byte(e, addr, i), "write error");
}
fprintf(stderr, "\n\n");
return 0;
}
int main(int argc, char** argv)
{
struct eeprom e;
int op;
op = 0;
usage_if(argc != 2 || argv[1][0] != '-' || argv[1][2] != '\0');
op = argv[1][1];
fprintf(stderr, "Open /dev/i2c/0 with 8bit mode\n");
die_if(eeprom_open("/dev/i2c/0", 0x50, EEPROM_TYPE_8BIT_ADDR, &e) < 0,
"unable to open eeprom device file "
"(check that the file exists and that it's readable)");
switch(op)
{
case 'r':
fprintf(stderr, " Reading 256 bytes from 0x0\n");
read_from_eeprom(&e, 0, 256);
break;
case 'w':
fprintf(stderr, " Writing 0x00-0xff into 24C08 \n");

write_to_eeprom(&e, 0);
break;
default:
usage_if(1);
exit(1);
}
eeprom_close(&e);
return 0;
}




1.12.6 Serial Programming Example

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/serial/
드라이버 소스 파일 이름 S3c6400.c
Device Name /dev/ttySAC0,1,2,4
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/comtest
예제 이름 comtest.c
예제 실행 파일 이름 armcomtest
Test program compiled x86 version and arm version available, and its source code is exactly the same
# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>

# include <errno.h>
# include <string.h>
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(1);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString)
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
static void PrintUsage(void)
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
static inline void WaitFdWriteable(int Fd)
{
fd_set WriteSetFD;
FD_ZERO(&WriteSetFD);
FD_SET(Fd, &WriteSetFD);
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {
Error(strerror(errno));
}
}
int main(int argc, char **argv)
{
int CommFd, TtyFd;
struct termios TtyAttr;
struct termios BackupTtyAttr;
int DeviceSpeed = B115200;
int TtySpeed = B115200;
int ByteBits = CS8;
const char *DeviceName = "/dev/ttyS0";
const char *TtyName = "/dev/tty";
int OutputHex = 0;
int OutputToStdout = 0;
int UseColor = 0;
opterr = 0;
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");
if (c == -1)
break;
switch(c) {
case 'd':
DeviceName = optarg;
break;
case 't':
TtyName = optarg;
break;
case 's':
if (optarg[0] == 'd') {
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);
break;
case 'o':
OutputToStdout = 1;
break;
case '7':
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;
break;
case 'c':
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();
}
}
if (optind != argc)
PrintUsage();
CommFd = open(DeviceName, O_RDWR, 0);
if (CommFd < 0)
Error("Unable to open device");
if (fcntl(CommFd, F_SETFL, O_NONBLOCK) < 0)
Error("Unable set to NONBLOCK mode");
memset(&TtyAttr, 0, sizeof(struct termios));
TtyAttr.c_iflag = IGNPAR;
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;
TtyAttr.c_cc[VMIN] = 1;
if (tcsetattr(CommFd, TCSANOW, &TtyAttr) < 0)
Warning("Unable to set comm port");
TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0);
if (TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(TtyFd, &BackupTtyAttr) < 0)
Error("Unable to get tty");
if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) < 0)
Error("Unable to set tty");
for (;;) {
unsigned char Char = 0;
fd_set ReadSetFD;
void OutputStdChar(FILE *File) {
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", Char);
fwrite(Buffer, 1, Len, File);
}
FD_ZERO(&ReadSetFD);
FD_SET(CommFd, &ReadSetFD);
FD_SET( TtyFd, &ReadSetFD);
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {
Error(strerror(errno));
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {
while (read(CommFd, &Char, 1) == 1) {
WaitFdWriteable(TtyFd);
if (write(TtyFd, &Char, 1) < 0) {
Error(strerror(errno));
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;34m", 1, 8, stdout);
OutputStdChar(stdout);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);
}
}
}
if (FD_ISSET(TtyFd, &ReadSetFD)) {
while (read(TtyFd, &Char, 1) == 1) {
static int EscKeyCount = 0;
WaitFdWriteable(CommFd);
if (write(CommFd, &Char, 1) < 0) {
Error(strerror(errno));
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;31m", 1, 8, stderr);
OutputStdChar(stderr);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stderr);
fflush(stderr);
}
if (Char == '\x1b') {
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
} else
EscKeyCount = 0;
}
}
}
ExitLabel:
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)
Error("Unable to set tty");
return 0;
}


1.12.7 UDP Network Programming

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/net/
드라이버 소스 파일 이름 dm9000.c
Device Name eth0
소스 디렉토리 /opt/FriendlyARM/mini6410/linux/examples/udptak
예제 이름 udptalk.c
예제 실행 파일 이름 udptalk
Test program compiled x86 version and arm version available, and its source code is exactly the same

예제의 전체 코드는 소스파일을 참조하세요.

1.13 Device Driver Programming

1.12 절에서는 리눅스 User mode 에서의 예제들에 대해서 살펴 보았습니다. 이번 절에서는 커널 모드에서의 리눅스 디바이스 작성 예제들을 살펴 보도록 합니다.

1.13.1 Hello, Module-simple Device Driver Example

드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/char
드라이버 소스 파일 이름 Mini6410_hello_module.c
The driver will not load any device in the dev node

#include <linux/kernel.h>
#include <linux/module.h>

static int __init mini6410_hello_module_init(void)
{
printk("Hello, Mini6410 module is installed !\n");
return 0;
}

static void __exit mini6410_hello_module_cleanup(void)
{
printk("Good-bye, Mini6410 module was removed!\n");
}

module_init(mini6410_hello_module_init);
module_exit(mini6410_hello_module_cleanup);
MODULE_LICENSE("GPL");



(1) "Hello, Module" 을 커널 소스 트리에 넣어서 컴파일 하는 방법(added to the kernel source tree, and compile)

General compile the driver module version 2.6 driver code need to be added to the kernel source tree, and make the appropriate configuration. make menuconfig 명령에 의해서 선택 할 수 있도록 합니다.


Step1 : Kconfig 파일을 열어 다음과 같이 수정 합니다. Open "linux-2.6.36/drivers/char/Kconfig" file

s3c6410

linux-2.6.36 커널이 있는 디렉토리에서 "make menuconfig" 명령을 실행 합니다.

s3c6410


Device
Drivers -> Character devices -> "Mini6410 module sample" 에서 <M> 을 선택하면 모듈로 컴파일 된다는 의미이고 "*" 를 선택하면 커널에 포함해서 컴파일 한다는 의미 입니다. 여기에서는 <M> 으로 선택합니다.

Step2: Step1에서의 설정은 커널 컨피규레이션상의 설정이고 실제로는 이번 단계에서 Makefile을 수정 한것이 컴파일시 반영이 됩니다. "linux-2.6.36/drivers/char/Makefile" 파일을 Open 합니다.

s3c6410

Step3: 이번 단계에서는 실제로 모듈로 소스 파일을 컴파일 하는 단계 입니다.

s3c6410

(2) "Hello, Module download and install it using the development board

FTP를 이용해서 타겟 개발보드의 "/lib/modules/2.6.36-FriendlyARM" 위치에 "mini6410_hello_module.ko" 파일을 다운로드 합니다. 그리고 나서 "modprobe" 명령을 위해서 모듈을 커널에 Load 합니다 modprobe 명령시 "ko" 확장자는 붙이지 않습니다.

# modprobe mini6410_hello_module

다음 명령은 모듈은 Unload 하는 명령 입니다.

# rmmod mini6410_hello_module

s3c6410

1.13.2 LED Driver

LED1 ~ LED4까지를 컨트롤 하는 디바이스 드라이버 예제 입니다. 각 LED들의 6410 CPU에 할당된 리소스 입니다.

LED IO 포트 이름 CPU Pin name
LED1 GPK4 R23
LED2 GPK5 R22
LED3 GPK6 R24
LED4 GPK7 R25



드라이버 소스 디렉토리 /opt/FriendlyARM/mini6410/linux/linux-2.6.36/drivers/char
드라이버 소스 파일 이름 Mini6410_leds.c
Device Type misc
Device Name /dev/leds
예제 소스 디렉토리 위치 /opt/FriendlyARM/mini6410/linux/examples/leds
드라이버 소스 파일 이름 led.c
드라이버 파일 이름 led
The driver will not load any device in the dev node

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
//#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-k.h>

#define DEVICE_NAME "leds"

static long sbc2440_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
unsigned tmp;
case 0:
case 1:
if (arg > 4) {
return -EINVAL;
}
tmp = readl(S3C64XX_GPKDAT);
tmp &= ~(1 << (4 + arg));
tmp |= ( (!cmd) << (4 + arg) );
writel(tmp, S3C64XX_GPKDAT);
//printk (DEVICE_NAME": %d %d\n", arg, cmd);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = sbc2440_leds_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
{
unsigned tmp;
(tmp & ~(0xffffU<<16))|(0x1111U<<16);
writel(tmp, S3C64XX_GPKCON);
tmp = readl(S3C64XX_GPKDAT);
tmp |= (0xF << 4);
writel(tmp, S3C64XX_GPKDAT);
}
ret = misc_register(&misc);
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");


1.14 Compile Qtopia-2.2.0

Qtopia-2.2.0을 컴파일 하는 방법은 앞에서 했던 커널이나 부트로더 컴파일 방법보다 좀더 복잡합니다. 아래에서 자세한 과정을 설명 합니다. x86, ARM 버젼의 "run" 스크립트는 아주 동일 합니다.

1.14.1 Compile and run x86 versions of Qtopia-2.2.0

작업 디렉토리로 이동 해서 빌드, 컴파일 하는시간은 시스템에 따라서 약간 차이가 있을수는 있지만 30분 정도가 소요 됩니다.


# cd /opt/FriendlyARM/mini6410/linux/x86-qtopia
# ./build-all

"build-all" 옵션으로 컴파일 하면 Complete Qtopia and embedded browser 가 모두 포함이 되어 컴파일이 되고,
"build-konq" 옵션으로 컴파일 하면 각각 모듈별로 컴파일 할 수 있습니다. 컴파일이 완료되고 실행을 시키는 것은 간단 합니다. 빌드가 완료된 디렉토리에서

# ./run

Qtopia가 실행된 화면 입니다.

s3c6410


s3c6410

1.14.2 Compile and run ARM versions of Qtopia-2.2.0

반드시 "arm-linux-gcc-4.4.1" 크로스 컴파일러를 이용해서 빌드 해야 합니다.

# cd /opt/FriendlyARM/mini6410/linux/arm-qtopia
# ./build-all
# ./mktarget


Produced for target root file system image file binary package, will generate "target-qtopia-konq.tgz"

컴파일된 Qtopia를 개발 보드에 설치 합니다.

#tar xvzf /home/plg/target-qtopia-konq.tgz -C /

s3c6410

"build-all" 이라는 스크립트를 이용해서 빌드 과정을 매우 간소화 시켰습니다. 전체 빌드가 아니라 항목별 빌드 하기 위해서는 "build-all" 파일을 수정해서 사용하시기 바랍니다.


1.14 Compile QtE-4.7.0

1.15.1 compile and run ARM versions QtE-4.7.0

반드시

"arm-linux-gcc-4.5.1" 를 이용해서 빌드해야 합니다. 컴파일 하는 방법은 "Qtopia-2.2.0" 컴파일과 동일 합니다.


# cd /opt/FriendlyARM/mini6410/linux/arm-qte-4.7.0
# ./build-all


컴파일이 완료되면 타겟 개발보드에 설치 합니다.

#tar xvzf target-qte-4.7.0.tgz -C /



       
       

댓글 없음:

댓글 쓰기