메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

한빛랩스 - 지식에 가능성을 머지하다 / 강의 콘텐츠 무료로 수강하시고 피드백을 남겨주세요. ▶︎

IT/모바일

설계와 구현을 통한 임베디드 OS의 이해와 응용(3) - cuteOS의 시작 부분(2)

한빛미디어

|

2005-12-20

|

by HANBIT

18,655

저자: 서민우
출처: 임베디드월드

* 설계와 구현을 통한 임베디드 OS의 이해와 응용(1) - Overview
* 설계와 구현을 통한 임베디드 OS의 이해와 응용(2) - 개발환경 구성 및 부트로더 작성(1)
* 설계와 구현을 통한 임베디드 OS의 이해와 응용(2) - 개발환경 구성 및 부트로더 작성(2)
* 설계와 구현을 통한 임베디드 OS의 이해와 응용(3) - cuteOS의 시작 부분(1)


다음은 Makefile의 내용을 들여다보기로 하자. 먼저 Makefile의 내용은 다음과 같다.

Makefile
# BOOTLOADER
OBJ = start.o led.o clksetup.o memsetup.o cuteOS.bin.o

cute-boot: $(OBJ)
    arm-linux-ld $(OBJ) -o cute-boot -Ttext 0x00000000 -N -T cute-boot.lds
    arm-linux-objcopy cute-boot cute-boot.bin -O binary

start.o: start.S
    arm-linux-gcc start.S -c -DOS_RAM_BASE=0x30100000

led.o: led.S
    arm-linux-gcc led.S -c

clksetup.o: clksetup.S
    arm-linux-gcc clksetup.S -c

memsetup.o: memsetup.S
    arm-linux-gcc memsetup.S -c

# KERNEL
cuteOS.bin.o: cuteOS
    arm-linux-ld -r -o cuteOS.bin.o -b binary cuteOS.bin

cuteOS: head.o main.o
    arm-linux-ld head.o main.o -o cuteOS -Ttext 0x30100000 -N
    arm-linux-objcopy cuteOS cuteOS.bin -O binary

head.o: head.S
    arm-linux-gcc head.S -c

main.o: main.c
    arm-linux-gcc main.c -c

clean:
    rm -f *.o
    rm -f cute-boot
    rm -f cute-boot.bin
    rm -f cuteOS
    rm -f cuteOS.bin

Makefile에 대한 기본적인 내용은 이전 기사에서 언급하였다. 여기서는 새로이 추가 되거나 변경된 부분 위주로 설명하기로 하겠다. Makefile은 크게 두 부분으로 나뉘어져 있다. 하나는 부트로더를 만들어내는 부분이고, 또 하나는 커널을 만들어내는 부분이다. 위의 Makefile을 이용하여 make 명령어를 수행할 경우 다음과 같이 나타난다.

$ make
arm-linux-gcc start.S -c -DOS_RAM_BASE=0x30100000
arm-linux-gcc led.S -c
arm-linux-gcc clksetup.S -c
arm-linux-gcc memsetup.S -c
arm-linux-gcc head.S -c
arm-linux-gcc main.c -c
arm-linux-ld head.o main.o -o cuteOS -Ttext 0x30100000 -N
arm-linux-objcopy cuteOS cuteOS.bin -O binary
arm-linux-ld -r -o cuteOS.bin.o -b binary cuteOS.bin
arm-linux-ld start.o led.o clksetup.o memsetup.o cuteOS.bin.o -o cute-boot -Ttext 0x00000000 -N -T cute-boot.lds
arm-linux-objcopy cute-boot cute-boot.bin -O binary

여기서는 arm-linux-gcc를 이용하여 start.S, led.S, clksetup.S, memsetup.S, head.S, main.c 파일을 각각 start.o, led.o, clksetup.o, memsetup.o, head.o, main.o 파일로 만든다.

그리고 arm-linux-ld 명령어를 이용하여 head.o, main.o 파일로 cuteOS 결과 파일을 만들어낸다(head.S 파일과 main.c 파일은 뒤에서 살펴 보기로 하자). cuteOS가 동작할 메모리 위치는 0x30100000 번지가 된다. –N 옵션은 .data 섹션을 page 경계에 놓지 말고 .text 섹션의 바로 뒤에 붙이는 역할을 한다. 파일의 크기를 줄이기 위해 이 옵션을 사용하였다.

그리고 arm-linux-objcopy 명령어를 이용하여 cuteOS 파일로 순수 바이너리 이미지인 cuteOS.bin 파일을 만들어낸다. 이 파일이 실제 RAM 상에서 동작할 커널의 이미지이다.

다음은 cuteOS.bin 입력 파일을 cuteOS.bin.o 결과 파일로 만드는 과정이다. 여기서 mmlt;–b binarymmgt; 옵션은 입력 파일 cuteOS.bin 파일이 바이너리 파일이란 의미이며, -o 는 output을 의미한다. 또한 –r 옵션은 arm-linux-ld의 입력 파일로 다시 사용할 수 있도록 결과 파일을 만들라는 의미이며, relocateable의 약자이다. 이 파일은 다음에 오는 arm-linux-ld 명령어를 이용하여 cute-boot 결과 파일을 만드는 과정에서 입력 파일로 사용하게 된다. 즉, arm-linux-ld 명령어를 이용하여 start.o led.o clksetup.o memsetup.o cuteOS.bin.o 입력 파일로 cute-boot 결과 파일을 만든다. mmlt;-T cute-boot.ldsmmgt; 옵션은 arm-linux-ld 가 사용할 링커 스크립트 파일로 cute-boot.lds 파일을 사용하라는 의미이다.

마지막으로 arm-linux-objcopy 명령어를 이용하여 cute-boot.bin 파일을 만든다. 이 파일을 JTAG를 이용하여 ROM 상에 다운 받아 실행하면 된다.

다음은 clksetup.S 파일의 내용이다.

clksetup.S
#define LOCKTIME 0x4c000000
#define UPLLCON 0x4c000008
#define MPLLCON 0x4c000004
#define CLKDIVN 0x4c000014
#define CAMDIVN 0x4c000018

#define UPLLVAL ((60<<12)|(4<<4)|1)
#define MPLLVAL ((0x6e<<12)|(3<<4)|1)

.globl clksetup
clksetup:
    ldr r0,=LOCKTIME
    mov r1,#0xffffffff
    str r1,[r0]

    ldr r0,=CAMDIVN
    mov r1,#0
    str r1,[r0]

    ldr r0,=CLKDIVN
    mov r1,#0xd
    str r1,[r0]

    mrc p15,0,r1,c1,c0,0
    orr r1,r1,#0xc0000000
    mcr p15,0,r1,c1,c0,0

    ldr r0,=UPLLCON
    ldr r1,=UPLLVAL
    str r1,[r0]

    ldr r0,=MPLLCON
    ldr r1,=MPLLVAL
    str r1,[r0]

    mov pc,lr

파일의 내용을 살펴보기 전에 먼저 S3C2440A SOC의 clock과 관련된 기능을 이해해 보자.

S3C2440A SOC에는 CPU, AHB 버스, APB 버스, USB 버스로 clock을 공급하는 clock 생성기가 있다. 이 clock 생성기는 MPLL과 UPLL을 포함하고 있으며 MPLL에서는 CPU, AHB 버스, APB 버스로 공급하는 clock을 생성하며, UPLL에서는 USB 버스로 공급하는 clock을 생성해 낸다.

MPLL로부터 CPU로 공급하는 clock을 FCLK, FCLK을 1,2,3,4, 또는 6으로 나누어 AHB 버스로 공급하는 clock을 HCLK, HCLK를 1 또는 2로 나누어 APB 버스로 공급하는 clock을 PCLK이라 한다. 또 UPLL의 값을 1 또는 2로 나누어 USB 버스로 공급하는 clock을 UCLK이라 한다.

S3C2440A SOC의 clock 생성기는 외부 크리스털(XTIpll)로부터 16.9344MHz의 값을 입력 받아 MPLL과 UPLL로 공급을 한다. 그러면 이 두 PLL은 PLL에 대한 설정에 따라 CPU와 버스에서 사용할 적절한 속도의 높은 주파수의 clock을 생성해 낸다. 참고로 필자는 MPLL로부터 나오는 clock의 속도가 399.65MHz가 되도록 MPLL을 설정하였으며, UPLL로부터 나오는 clock의 속도는 95.96MHz가 되도록 UPLL을 설정하였다.

Power-On Reset시, 즉, S3C2440A SOC에 전원을 넣을 때, PLL이 일시적으로 불안정하기 때문에 외부 크리스털(XTIpll)로부터 오는 clock(16.9344MHz)을 직접 FCLK으로 공급하며, 부팅 초기 루틴에서 PLLCON 레지스터를 이용하여 PLL의 clock 속도를 설정한 후에야 MPLL로부터 나오는 clock을 FCLK으로 공급할 수 있다. 그런데 PLL을 설정할 경우 PLL에서 나오는 clock이 일시적으로 불안정하게 되며, 따라서 일정기간 clock의 공급을 차단하게 되는데 그 차단되는 시간을 LOCKTIME 레지스터를 이용하여 조절한다. 즉, PLL을 설정한 후, LOCKTIME 레지스터에 설정된 값에 해당하는 시간동안 MPLL로부터 나오는 clock이 FCLK으로 전달되지 않으며, LOCKTIME 레지스터에 설정된 값에 해당하는 시간이 흐른 이후에야 MPLL로부터 FCLK으로 clock이 공급된다. 이 경우 LOCKTIME 레지스터의 시간 기준은 외부 크리스털(XTIpll)로부터 오는 clock에 의해 결정된다.

또한 PLL로부터 CPU나 각각의 버스로 clock이 공급되는 도중이라도 그 설정 내용을 변경할 경우 LOCKTIME 레지스터에 설정된 값에 해당하는 시간이 흐른 이후에야 CPU나 각각의 버스로 clock이 공급된다.

그러면 clksetup.S 의 내용을 자세히 들여다보기로 하자.

ldr r0,=LOCKTIME
mov r1,#0xffffffff
str r1,[r0]

이 부분은 LOCKTIME 레지스터의 내용을 설정하는 부분이다. LOCKTIME 레지스터는 0x4c000000 번지에 있으며, 다음과 같은 구조로 되어 있다.




ldr r0,=CAMDIVN
mov r1,#0
str r1,[r0]

ldr r0,=CLKDIVN
mov r1,#0xd
str r1,[r0]

이 부분은 FCLK, HCLK, PCLK의 속도 비율을 1 대 4 대 8로 맞추는 부분이다. CAMDIVN 레지스터와 CLKDIVN 레지스터는 각각 0x4c000018, 0x4c000014 번지에 있다.

먼저 CAMDIVN 레지스터는 다음과 같은 구조로 되어 있다.



또한 CAMDIVN 레지스터의 속도 비율과 관련된 9 번 비트는 다음과 같은 의미를 갖는다.



다음으로 CLKDIVN 레지스터는 다음과 같은 구조로 되어 있다. (258P 참조)




mrc p15,0,r1,c1,c0,0
orr r1,r1,#0xc0000000
mcr p15,0,r1,c1,c0,0

이 부분은 CPU의 버스 모드를 fast 버스 모드로부터 asynchronous 버스 모드로 변경하는 부분이다. CLKDIVN 레지스터의 HDIVN 부분이 0 이 아니고, CPU 버스 모드가 fast 버스 모드일 경우, CPU는 HCLK에 동기해서 동작을 하기 때문에 위의 코드가 필요하다. 코드의 내용을 좀 더 살펴 보자.

mrc p15,0,r1,c1,c0,0

이 명령어는 15 번 코프로세서의 c1 레지스터의 값을 r1 레지스터로 가져오는 역할을 한다. 15 번 코프로세서는 cache나 MMU에 대한 설정 등을 할 때도 사용한다. c1 레지스터는 컨트롤 레지스터이다.

orr r1,r1,#0xc0000000
mcr p15,0,r1,c1,c0,0

c1 레지스터의 최상위 두 비트를 이진수 11로 설정함으로써 CPU의 버스 모드를 asynchronous 버스 모드로 변경한다.

ldr r0,=UPLLCON
ldr r1,=UPLLVAL
str r1,[r0]

이 부분은 USB 버스로 공급하는 clock의 속도를 (95.96/2)MHz로 설정하는 부분이다.

ldr r0,=MPLLCON
ldr r1,=MPLLVAL
str r1,[r0]

이 부분은 CPU로 공급하는 clock의 속도를 399.65MHz로 설정하는 부분이다.

MPLLCON 레지스터와 UPLLCON 레지스터는 다음과 같은 구조로 되어 있다.



MPLL과 UPLL로부터 생성되는 clock의 속도는 다음의 공식을 따른다.

Mpll = (2*m*Fin)/(p*2^s), m = (MDIV+8), p = (PDIV+2), s = SDIV
Upll = (m*Fin)/(p*2^s), m = (MDIV+8), p = (PDIV+2), s = SDIV

참고로 S3C2440A SOC에서 Fin은 16.9344MHz이다.

이상에서 clksetup.S 파일의 내용을 살펴 보았다.
TAG :
댓글 입력
자료실

최근 본 상품0