'[D-01] Linux' 카테고리의 다른 글

[Fedora10] Linux에 nfs 설치  (0) 2010.03.22
[Fedora10] Linux에 Samba 서버 설치하기  (0) 2010.03.22
[Fedora10] Fedora 10 네트워크 설치  (0) 2010.03.19
텔넷 접속 프로그램  (0) 2009.12.27
부팅디스트 만들기  (0) 2009.12.26
Posted by eoseontaek

Link : http://wiz.pe.kr/448


1. 부팅이미지 다운로드
http://mirrors.fedoraproject.org/publiclist//Fedora/ 에서 Fedora의 Version과 Architecture를 확인한 후, Fedora-10-i386-netinst.iso 를 다운받는다.

2. 설치
다운 받은 iso 이미지를 구워서 DVD Rom에 넣고 DVD Rom 부팅이 가능하게 설정한 후 서버를 부팅한다.

2.1 설치화면 로딩
정상적으로 부팅이 된다면 설치옵션을 선택하는 화면이 나타난다. Fedora 10 시스템을 설치 할 것이기 때문에 첫번째 "Install or upgrade an existing system"을 선택하고 Enter를 쳐서 넘어 간다. 선택하지 않으면 60초 후에 자동으로 다음 화면으로 진행된다.

2.2 언어 선택
DVD나 CD로 설치하는 경우 언어 설정은 그래픽모드에 들어가서 나오지만 네트워크 설치 시에는 그래픽 모드 이전에 설정하게 되어 있다. 한글을 사용하기 위해 "Korean"을 선택하고 넘어 간다.

한국어 사용에 대한 경고 문구가 뜨지만 그냥 OK를 누르고 넘어 간다.

2.3 키보드 선택
키보드 선택 화면은 Default인 "us"를 선택하고 넘어간다.

2.4 설치 방법 선택
네트워크를 이용해 파일을 다운받아 설치할 것이기 때문에 URL을 선택한다.

2.5 네트워크 설정
네트워크 설치기 때문에 그래픽모드가 시작되기 전에 네트워크 관련 설정을 진행합니다. 그래픽모드에서 한번 더 설정 확인을 할 수 있습니다. IPv6 지원을 해제하고 DHCP를 이용했다. 설치 환경에 따라 설정 하면 된다.
"Manual configuration"을 선택하면 IP 및 DNS 설정 등을 할 수 있는 화면으로 넘어 간다.

2.6 리포지터리(소스 저장소) 설정
설치에 사용 할 패키지가 있는 리포지터리(저장소)를 설정 하는 화면이다. 보통 CD 이미지를 다운받은 사이트에서 마지막 iso 대신 os 로 변경하면 접근이 가능하다. 

2.7 그래픽 모드 설치 실행
잠시 명령어가 출력된 후 그래픽모드 설치화면이 시작된다. 이 화면에서 다음을 누르고 넘어간다.

2.8 드라이브 초기화 관련 경고
파티션이 없는 시스템의 경우 위 화면과 같은 경고 창이 출력 된다. 그냥 "예(Y)"를 선택한다.

2.9 네트워크 설정 확인
편집을 눌러서 IP와 IPv6에 대한 설정이 가능하다. 예제에서는 IPv6 지원을 해제하고, DHCP로 IP를 할당 받기 때문에 동적 IP 설정(DHCP)로 설정을 했다. 호스트 명은 fedora.wiz.pe.kr 로 설정을 했다.
설치 환경에 맞는 설정을 하면 된다. 여기에 설정한 정보가 시스템에 기본으로 적용된다.

2.10 시간대 설정
서버의 기준시간은 대한민국이기 때문에 "아시아/서울(Seoul)"과 UTC 맞춤 옵션을 기본으로 하고 다음으로 넘어 간다.

2.11 관리자(root) 계정 암호 설정
시스템 관리를 위한 root 계정의 암호를 입력한다.

2.12 HDD 파티션 설정
디폴트 레이아웃을 만들기로 선택하고 넘어 간다. Windows와 멀티 부팅을 하거나 중요데이터가 있을 경우 주의 해야 한다.  HDD의 데이터가 모두 날아갈 수 있다.

"다음"버튼을 클릭하면 정말 적용을 할지 여부를 확인하는 창이 뜬다. 실행을 하려면 "디스크에 변경 사항 기록(W)"버튼을 누르면 된다.

설치이미지를 HDD로 전송하고 파티션을 새로 설정하는 작업을 진행한다. 작업이 끝날 때까지 기다리면 된다.

2.13 리포지터리(소스 저장소) 수정
텍스트 모드에서 설정한 저장소에 접근이 불가능 할 경우 오류 메시지가 나타난다. 편집을 눌러서 다른 곳으로 수정하면 된다.

"리포지터리 URL" 만 수정하면 된다. 계속 오류가 나면 네트워크 상태를 확인 후 재설치해야 한다.

 2.14 설치 패키지 설정 화면
우선 기본 패키지 설정 화면에서 위 화면처럼 시스템 설정을 "소프트웨어 개발"로 선택하고, 리포지터리 설정은 "Fedora"만 설정 한다. 그리고 "지금 사용자 설정"을 선택해 준다. 이렇게 선택해야 다음 화면에서 상세한 패키지 설치 구성이 가능하다. 설정이 되면 다음을 눌러서 상세 설정 화면으로 이동한다.

상세 설정 화면에서는 아래와 같이 설정 한다. 데스크탑 환경 및 관련 없는 기능은 최대한 제거 하고 서버로 사용 하기 위한 설정 이다.

데스크탑 환경 - 모두 체크 해제
응용 프로그램 - 모두 체크 해제
개발용 도구 - 개발용 도구, 개발용 라이브러리 만 기본으로 선택 후 나머지 해제
기반 시스템 - X윈도우 시스템, 전화연결 네트워크 선택 해제 후 나머지는 모두 기본선택 사용
언어 지원 - 모두 체크 해제

2.15 설치화면
설치가 진행이 된다.

2.16 설치 완료
이렇게 설치는 완료 된다.
재부팅 된 후에 기본 설정을 하는 부분이 있다.
Posted by eoseontaek

LM3S8962에 RTOS인 uC/OS-II를 포팅해보기 위해 관련 Application note 검토해 보았다.
우선 아래 링크에 가서 자료를 다운받는다.

Link : http://micrium.com/page/support/application_notes#AN-1


위의 링크에서 AN-1018 관련 자료를 다운받는다.

다운로드 된 실행파일을 설치하면
C:\Micrium\AppNotes\AN1xxx-RTOS\AN1018-uCOS-II-Cortex-M3
위의 path에서 AN-1018 관련 Document를 참조할 수 있다.




1.00 Introduction
 ARM은 수 년 동안 Cortex라고 불리는 새로운 아키텍처를 개발해 왔다. 개발하는 동안 , uC/OS-II는 디자인 측면의 어떤것을 유효하게 하기 위해 사용되었고, RTOS를 제공하도록 새로운 가능성을 생성하기 위한 아이디어의 source로서 사용되었다. 다시말해 uC/OS-II는 Cortex에  port된 첫번째 RTOS이다.

 이 어플리케이션 노트는 Cortex-M3 processor에 uC/OS-II를 위한  'official' Micrium port를 설명한다. Figure1-1은 당신의 application ,uC/OS-II, port code, BSP  사이의 관계를 보여주는 block diagram을 보여준다. 이 어플리케이션 노트의 관련된 sections은 그림에서 참조된다.

2.00 The ARM Cortex-M3 programmer’s model
ARM Cortex-M3 processor에서 사용할 수 있는 레지스터는 Figure 2-1에 보여진다. ARM Cortex-M3는 총 20개의 레지스터를 갖는다. 각 레지스터는 32 bits wide이다.

R0-R12
R0 ~ R12 는 general purpose register이다. 이 레지스터들은  pointer 뿐만 아니라 data도 hold 하도록 사용될 수 있다.

R13
R13은 일반적을 stack pointer(SP)로서 사용되지만  산술연산의 결과를 저장할 때도 사용될 수 있다. 실제로 2개의 stack pointer(SP_process, SP_main)가 있지만 단지 하나만이 주어진 시간에 보여지게 된다. SP_process는 task level code 를 위해 사용되고 SP_main은 exception processing을 위해 사용된다.

R14
R14는 Link Register(LR)로 불려지고 Branch와 Link(BL) 명령이 실행될 때 PC의 contents를 저장하기 위해 사용된다. LR은 호출할 곳으로 return하게 해준다.

R15
R15는 Program Counter(PC)로 사용되고 수행되고 있는 현재 명령을 가리키고 있다. 명령이 실행될 때, PC는 명령에 따라 2 나 4 씩 증가하게 된다.

xPSR
CPU의 상태를 hold하기 위해 3개의 독립적인 레지스터가 있다. :  APSR, IPSR, EPSR

APSR은 그림 2-2에서 보여지는 것처럼 application의 상태를 포함한다.

N
비트 31dms 'negative' 비트이다. 최근 ALU 연산이 negative 결과일 때 set된다.
(i.e. the top bit of a 32-bit result was a one).

Z
비트 30은 'zero' 비트이다. 최근 ALU 연산이 zero 결과가 되었을 때, set된다.
(every bit of the 32-bit result was zero).

C
비트 29는 'carry' 비트이다. 최근 ALU 연산이 carry-out을 발생했을 때 set된다.  
ALU에서 산술 연산의 결과로서 또는 시프터로부터 carry-out이 발생했을 때 set된다.

V
비트 28은 'overflow' 비트이다. 최근 산술 ALU 연산이 sign 비트로 overflow를 발생했을 때, set 된다.

Q
비트 27은 sticky saturation flag이다.

Interrupt PSR(iPSR)은 현재 exception  동작 중인 ISR 번호를 포함한다. 그림 2-3에서 보여지고 있다.

Execution PSR(EPSR)은 두 개으 overlapping fields를 포함한다 :
- interrupted load multiple 과 store multiple 명령을 위한 Interruptible-Continuable Instruction(ICI) filed
- If-Then(IT) 명령과 T-bit(Thumb state bit)를 위한 execution state field

exception에 들어갈 때, 프로세서는 3개의 상태 레지스터로부터 stack으로 결합된 정보를 저장한다.


3.00 μC/OS-II Port for the ARM Cortex-M3 processors
우리는 port test를 위해 IAR EWARM V4.40A를 사용했다. EWARM은 editer, C/EC++ 컴파일러, 어셈블러, linker/locator,C-spy 디버거를 포함한다. C-Spy 디버거는 실제로 ARM Cotrex-M3 시뮬레이터를 포함한다.. 그것은 실제 하드웨어에서 run하기 전에 code를 테스트 할 수 있도록 해준다. 우리는 그림 3-1에 보여지는 Luminary Micro DK-LM3Sxxx 개발 보드에서 ARM Cortex-M3 port를 테스트했다.

당신은 다른 컴파일러 기반의 ARM Cortex-M3 에 이 application note에서 제공하는  port를 적용할 수 있다. 명령(i.e. the code)은 동일하고 당신이 해야만 하는 모든 것은 컴파일러 특색에 따라 port를 적용한다. 우리는 다른 파일의 내용을 cover할  때 이것 중 몇몇을 설명할 것이다.

port는 당신이 uC/OS-II V2.83이나 그보다 높은 버전을 사용한다고 가정한다.


3.01 Directories and Files
이 application note을 동반하는 소프트웨어는 아래 디렉토리에 위치된다고 가정한다.
\Micrium\Software\uCOS-II\ARM-Cortex-M3\Generic\IAR

모든 uC/OS-II ports는 유사하게, port를 위한 소스 코드는  아래 파일에서 찾을 수 있다.

OS_CPU.H
            OS_CPU_C.C
            OS_CPU_A.ASM
            OS_DBG.C

테스트 코드와 환경 설정 파일은 적합한 디렉토리에서 찾게 된다.


3.02 OS_CPU.H
OS_CPU.H는 processor- 와 구현을 구체화시킨 #define 상수, macro , typedef을 포함하고 있다.

3.02.01 OS_CPU.H, macro for 'externals'
OS_CPU_GLOBALS와 OS_CPU_EXT는 이 port에 특정 전역 변수를 가능하게 한다.

Listing 3-1, OS_CPU.H, Globals and Externs
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif


3.02.02 OS_CPU_H, Data Types
Listing 3-2, OS_CPU.H, Data Types
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U;
typedef signed char INT8S;
typedef unsigned short INT16U;          // (1)
typedef signed short INT16S;
typedef unsigned int INT32U;
typedef signed int INT32S;
typedef float FP32;                           // (2)
typedef double FP64;
typedef unsigned int OS_STK;          // (3)
typedef unsigned int OS_CPU_SR;    // (4)

L3-2(1)
만약 당신이 IAR compiler documnetation을 문의한다면 short는 16비트이고 int는 32비트 인 것을 찾을 수 있다. 대부분의 ARM 컴파일러는 같은 정의를 가진다.

L3-2(2)
부동 소수점 데이터 타입은 uC/OS-II는 부동소수점을 사용하지 않는데도 포함되어 있다.

L3-2(3)
ARM 프로세서를 위한 stack entry는 항상 32bit-wide이다. 그래서 OS_STK는 그에 맞게 적절히 정의된다. 모든 task stack은 데이터 타입으로서 OS_STK를 사용하여 정의되어야만 한다.

L3-2(4)
ARM 프로세서에서 상태 레지스터(xPSR)은 32bit-wide이다. OS_CPU_SR 데이터 타입은 OS_CRITICAL_METHOD #3이 사용될 때 사용된다. 사실 이 port는 단지 OS_CRITICAL_METHOD #3 만을 제공한다. 그것은 uC/OS-II port를 위한 우선되는 방법이기 때문이다.

3.02.03 OS_CPU_H, Critical Sections
모든 real-time kernel 들이 그런 것처럼, uC/OS-II는 코드의 critical section에 접근하기 위해 interrupt를 disable 하고 완료되었을 때, re-enable 하는 것이 필요하다. uC/OS-II는 interrupt를 disable하고 enable 하기 위해 두 개의 macro를 정의한다. : OS_ENTER_CRITICAL()과 OS_EXIT_CRITICAL()이 그것이다. uC/OS-II는 interrupt를 disable하기 위해 3가지 방법을 제시하지만, 당신은 interrupt를 disabling 하고 enabling 하기 위해 3가지 방법 중 단지 한가지를 사용하는 것이 필요하다. book(MicroC/OS-II, The Real-Time Kernel)은 이 3가지 방법을 설명한다. 하나를 선택하는 것은 프로세서와 컴파일러에 의존한다. 대부분의 경우, 우선시 되는 방법은 OS_CRITICAL_METHOD #3이다.

OS_CRITICAL_METHOD #3는 변수에 CPU의 상태 레지스터를 저장할 함수를 작성함으로써 OS_ENTER_CRITICAL()을 실행한다. OS_EXIT_CRITICAL()은 변수로부터 상태 레지시트를 restore 하기 위해 다른 함수를 inoke 한다. 책에서 Mr.Labrosse는 당신이 OS_ENTER_CRITICAL()과 OS_EXIT_CRITICAL()에서 기대되는 함수를 호출하도록 요구한다. 바로 OS_CPU_SR_Save()와 OS_CPU_SR_Restore()이다. 이 두함수를 위한 코드는 OS_CPU_A.S에 선언되어 있다.

Listing 3-3, OS_CPU.H, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
#define OS_CRITICAL_METHOD 3
#define OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL()     {OS_CPU_SR_Restore(cpu_sr);}


만약 당신의 application code가 이 macro를 사용한다면, 당신은 'cpu_sr'이라고 불리는 지역변수를 할당하고 그것을 0으로 초기화 해야 한다. 아래 보여진다 :

OS_CPU_SR cpu_sr = 0;

3.02.04 OS_CPU.H, Stack growth
ARM Cortex-M3에서 stack은 high 메모리로부터 low 메모리로 성장한다. 따라서 OS_STK_GROWTH는 uC/OS-II에 이것을 나타내기 위해 1로 set된다.

Listing 3-4, OS_CPU.H, Stack Growth
#define OS_STK_GROWTH 1


3.02.05 OS_CPU_H, Task Level Context Switch
Task level context switch는 uC/OS-II가 macro OS_TASK_SW()를 invoke 할 때 수행된다. context switcing이 프로세서에 특성화 되어 있기 때문에, OS_TASK_SW()는 어셈블리 언어 함수를 실행하는 것이 필요하다. 이 경우, OSCtxSw()는 OS_CPU_A.ASM에서 선언된다.

Listing 3-5, OS_CPU.H, Task Level Context Switch
#define OS_TASK_SW() OSCtxSw()

3.02.06 OS_CPU.H, Function Prototypes
Listing 3-6에서 prototype은 OS_CRITICAL_METHOD #3를 사용하는 interrupt를 disable하고 re-enable 하기 위해 사용되는 함수를 위한 것이다. 당신은 이러한 prototype이 특별한 키워드인 __arm 으로 prefixed 되었음을 주의해야 한다. 이것은 이 함수들이 ARM 모드에서 동작할 것이라는 것을 나타내는 IAR 키워드 이다.  따라서 호출되었을 때 컴파일러는 적절한 명령을 발생시킬 것이다.

Listing 3-6, OS_CPU.H, Function Prototypes
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR OS_CPU_SR_Save(void);
void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif

V2.77에서 OSCtxSw(), OSIntCtxSw(), OSStartHighRdy()를 위한 prototype은 OS_CPU.H에 위치되는 것이 필요하다. 사실 그것은 이것들이 모두 port specific한 파일이므로 이것을 수행하는 것을 느낄 수 있게 된다.

Listing 3-7, OS_CPU.H, Function Prototypes
void OSCtxSw(void);
void OSIntCtxSw(void);
void OSStartHighRdy(void);
void OSPendSV(void);


3.03 OS_CPU_C.C
uC/OS-II port는 10개의 간단한 C 함수를 작성하는 것을 요구한다.

OSInitHookBegin()
OSInitHookEnd()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskIdleHook()
OSTaskStatHook()OSTaskStkInit()
OSTaskSwHook()
OSTCBInitHook()
OSTimeTickHook()

일반적으로, uC/OS-II는 단지 OSTaskStkInit()을 요구한다. 다른 함수들은 당신 자신의 함수를 통해 OS의 기능을 확장하도록 해준다.  보여지는 함수들은 이 section에서 설명할 것이다.

컴파일러에 이 파일에서 선언된 함수를 사용하는 것을 알려주기 위해 OS_CFG.H에서 #define 상수 OS_CPU_HOOKS_EN을 1로 설정하는 것이 필요하다.

3.03.01 OS_CPU_C.C, OSInitHookBegin()
이 함수는 OSInit()의 시작에서 uC/OS-II의 OSInit()에 의해 호출된다. 그것은 port에 추가적인 초기화 코드를 추가할 수 있도록 해준다. 여기에서는 , 우리는 전역변수(global to OS_CPU_C.C) OSTmrCtr(which is used by the OS_TMR.C module if OS_TMR_EN is set to 1)을 초기화한다.

Listing 3-8, OS_CPU_C.C, OSInitHookEnd()
void OSInitHookBegin (void)
{
#if OS_TMR_EN > 0 OSTmrCtr = 0;
#endif
}

3.03.02 OS_CPU_C.C, OSTaskCreateHook()
이 함수는 task가 생성될 때 , uC/OS-II의 OSTaskCreate(), OSTaskCreateExt()에 의해 호출된다. OSTaskCreateHook() 는 task가 생성될때, port에 특정 코드를 추가할 수 있도록 해준다. 우리의 경우, 우리는 uC/OS-View의 초기화 함수를 호출한다(an optional module available for μC/OS-II which performs task profiling at run-time, See www.micrium.com for details).
 
호출되는 OSView_TaskCreateHook()를 주의해라. uC/OS-View를 위한 target 임시 코드는 당신의 build의 한 부분으로서 included 되야 한다. 여기서는, 당신의 applicaiton의 OS_CFG.H에서 #define OS_VIEW_MODULE 1을 추가하는 것이 필요하다.

만약 OS_VEW_MODULE이 0이라면, 우리는 ptcb는 실제 사용되지 않고 컴파일러 warning을 피하도록 컴파일러에게 알려 주어야 하는것을 주의해라.

Listing 3-9, OS_CPU_C.C, OSInitHookEnd()
void OSTaskCreateHook (OS_TCB *ptcb)
{
#if OS_VIEW_MODULE > 0
        OSView_TaskCreateHook(ptcb);
#else
        (void)ptcb;
#endif
}

3.03.03 OS_CPU_C.C, OSTaskStkInit()
함수의 첫번째 argument를 R0 레지스터로 pass하는 것은 ARM 컴파일러에서는 일반적인 것이다. listing 3-10에서 보여지는 것처럼 task가 선언된 것을 Recall한다.

Listing 3-10, μC/OS-II Task
void MyTask (void *p_arg)
{
    /* Do something with ‘p_arg’, optional */
    while (1) {
        /* Task body */
    }
}

listing 3-11에서 코드는 생성되고 있는 task를 위해 stack  frame을 초기화한다. task는 선택적인 argument 'p_arg'를 수신했다. 그것은 task가 생성될 때 'p_arg'가 R0에서 pass되기 때문이다. 대부분의 CPU 레지스터의 초기값은 그렇게 중요하지 않다, 우리는 레지스터 번호와 연관된 번호로 그것들을 초기화하기로 결정했다. 이것은 RAM에서 stack을 디법깅하고 시험할 때 변하게 해준다. 초기값은 task가 처음 생성될 때 사용할 수 있지만, 물론  레지스터 값은 task code가 실행됨으로서 바뀌게 될 것이다

Listing 3-11, OS_CPU_C.C, OSTaskStkInit()
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *stk;

(void)opt;                                                        /* 'opt' is not used, prevent warning */
stk = ptos;                                                       /* Load stack pointer */ 

                                                                     /* Registers stacked as if saved on exception */
*(stk) = (INT32U)0x01000000L;                           /* xPSR */
*(--stk) = (INT32U)task;                                   /* Entry Point */
*(--stk) = (INT32U)0xFFFFFFFEL;                      /* R14 (LR) */
*(--stk) = (INT32U)0x12121212L;                        /* R12 */
*(--stk) = (INT32U)0x03030303L;                        /* R3 */
*(--stk) = (INT32U)0x02020202L;                        /* R2 */
*(--stk) = (INT32U)0x01010101L;                        /* R1 */
*(--stk) = (INT32U)p_arg;                                 /* R0 : argument */
 
                                                                     /* Remaining registers saved on process stack */
*(--stk) = (INT32U)0x11111111L;                        /* R11 */
*(--stk) = (INT32U)0x10101010L;                        /* R10 */
*(--stk) = (INT32U)0x09090909L;                        /* R9 */
*(--stk) = (INT32U)0x08080808L;                        /* R8 */
*(--stk) = (INT32U)0x07070707L;                        /* R7 */
*(--stk) = (INT32U)0x06060606L;                        /* R6 */
*(--stk) = (INT32U)0x05050505L;                        /* R5 */
*(--stk) = (INT32U)0x04040404L;                        /* R4 */

return (stk);
}

그림 3-2sms 각 task가 생성될 때 stack frame을  초기화하는 방법을 보여준다.


task가 생성될 때, stk의 마직막 값은 OSTaskStkInit()를 호출하는 uC/OS-II 함수에 의해 task의 OS_TCB에 위치하게 된다(i.e. OSTaskCreate() or OSTaskCreateExt()).
 

3.03.04 OS_CPU_C.C, OSTaskSwHook()
OSTaskSwHook()는 context switch가 발생했을 때 호출된다. 이 함수는 context switch가 발생했을 대, task의 실행 시간을 측정하거나, port pin으로 pulse를 출력하는 것과 같은 작업을 수행하고 확장되기 위한 port code를 가능하게 한다. 여기서는, 우리는 OSView_TaskSwHook()라고 불리는 uC/OS-View task switch hook을 호출한다. 이것은 당신이 build의 한 부분으로 uC/OS-View를 갖고  OS_CFG.H에서 OS_VIEW_MODULE을 1로 설정했다고 가정한다.

Listing 3-12, OS_CPU_C.C, OSTaskSwHook()
void OSTaskSwHook (void)
{
#if OS_VIEW_MODULE > 0
        OSView_TaskSwHook();
#endif
}

3.03.05 OS_CPU_C.C, OSTimeTickHook()
OSTimeTickHook()은 OSTimeTick()의 시작에서 호출된다. 이 함수는 확장되는 port code를 가능하게 한다, 우리의 경우, 우리는 uC/OS-View 함수 OSView_TickHook()을 호출한다. 이것은 uC/OS-View를 build의 한 부분으로 가지고, OS_CFG.H에서 OS_VIEW_MODULE을 1로 설정한다고 가정한다.

OSTimeTickHook()은 또한 uC/OS-II 타이머를 update하는 시간을 결정한다. 이것은 timer task를 signaling함으로써 완료된다.

Listing 3-13, OS_CPU_C.C, OSTimeTickHook()
void OSTimeTickHook (void)
{
#if OS_VIEW_MODULE > 0
    OSView_TickHook();
#endif

#if OS_TMR_EN > 0
    OSTmrCtr++;
    if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { 
        OSTmrCtr = 0;
        OSTmrSignal();
    }
#endif
}


3.04 OS_CPU_A.ASM
uC/OS-II port는 5개의 간단한 어셈블러 함수를 작성하는 것을 요구한다. 이 함수들은 C 함수로 부터 레지스터를 save/restore 할 수 없기 때문에 필요하게 된다. 이 다섯개의 함수는 :

    OS_CPU_SR_Save()
    OS_CPU_SR_Restore()
    OSStartHighRdy()
    OSCtxSw()
    OSIntCtxSw()

ARM Cortex-M3는context switch를 수행하기 위해 영리한 방법을 사용한다. 이것은 정의되는 것이 필요한 exception handler를 통해 수행된다. 이 handler는 :

    OSPendSV()

3.04.01 OS_CPU_A.ASM, OS_CPU_SR_Save()
listing 3-14에서 코드는 interrupt mask register를 saving하고 OS_CRITICAL_METHOD #3를 실행하기 위해 인터럽트를 disabling한다. 이 함수는 OS_ENTER_CRITICAL() macro에 의해 invoked된다.

이 함수가 return될 때, R0는 interrupt disabling에 앞서 global interrupt mask를  포함하고 있는 PRIMASK 레지스터의 상태를 저장하게 된다.

Listing 3-14, OS_CPU_SR_Save()
OS_CPU_SR_Save
        MRS R0, PRIMASK        ; set prio int mask to mask all (except faults)
        CPSID I
        BX LR

3.04.02 OS_CPU_A.ASM, OS_CPU_SR_Restore()
아래의 listing에서 코드는 OS_ENTER_CRITICAL()을 호출하기에 앞서 original 값으로 interrupt disable mask를 restore하기 위한 함수를 실행한다. 다시 말해, 만약 인터럽트가 OS_ENTER_CRITICAL() 을 호출하기에 앞서 disabled되었다면, 그것들은 OS_EXIT_CRITICAL()을 호출하기에 앞서 disabled(???) 될 것이다.

Listing 3-15, OS_CPU_SR_Restore()
OS_CPU_SR_Restore
        MSR PRIMASK,R0
        BX LR

3.04.03 OS_CPU_A.ASM, OSStartHighRdy()
OSStartHighRdy()는 OSStart()를 호출하기 전에 생성된  가장 높은 우선순위의 task를 running을 시작하기 위해 OSStart()에 의해 호출된다. OSStart()는 가장 높은 우선순위의 task의 OS_TCB를 가리키도록(point) OSTCBHighRdy를 설정한다.

Listing 3-16, OSStartHighRdy()

OSStartHighRdy
        LDR R4, =NVIC_SYSPRI2 ; (1) Set the PendSV exception priority 
        LDR R5, =NVIC_PENDSV_PRI 
        STR R5, [R4] 

        MOV R4, #0 ; (2) Set PSP to 0 for initial context switch call 
        MSR PSP, R4 

        LDR R4, __OS_Running ; (3) OSRunning = TRUE
        MOV R5, #1 
        STRB R5, [R4] 

        LDR R4, =NVIC_INT_CTRL ; (4) Trigger the PendSV exception 
        LDR R5, =NVIC_PENDSVSET 
        STR R5, [R4]

        CPSIE I ; (5) Enable interrupts at processor level

L3-16(1)
ARM Cortex-M3는 context switch 수행하기 위해 특별한 mechanism을 제공한다. 특히 ARM Cortex-M3는 PendSV라고 불리는 특별한 exception handler를 제공한다(Pend Service call). PendSV는 기본적으로 소프트웨어에 호출됨으로써 트리거되는 인터럽트되는 machanism이다.  인터럽트가 enabled될 때까지 인터럽트가 발생하지 않는 것을 제외하고는 소프트웨어 인터럽트와 유사하다. 이 단계는 PendSV 인터럽트의 우선순위를 설정한다. 일반적으로 하드웨어 인터럽트보다는 낮게 설정된다. PendSV는 un-interruptable하게 설정해서 PendSV 호출은 atomically하게 context switch를 수행할 수 있다.

L3-16(2)
여기서 우리는 첫번째 task이지만 PendSV handler에 의해 구동하는 SP_process stack를 설정한다. 이것은 task의 context를 저장하지 않는다고 PendSV Handler에 알려주기 위해 SP_process를 0으로 설정함으로써 완료된다(because there is no task to save the context for since it will be the first task to run).  그것은 OSTCBHighRdy가 시작하기 위해 task의 OS_TCB로 pointer를 포함하고 있다고 가정한다.

L3-16(3)
 여기서 우리는 OSRunning을 TRUE로 설정한다. 이것은 multitasking을 시작할 것이라는 것을 나타내기 위한 것이다.

L3-16(4)
우리는 첫번째 task를 시작하게 될 PendSV handler를 trigger하기 위해 준비를 한다. PendSV handler는 단지 interrupt를 enabled 되었을 때 run할 것이다.

L3-16(5)
인터럽트가 enabled 되었을 때 ARM Cortex-M3 processor는 PendSV handler로 branh할 것이다.

3.04.04 OS_CPU_A.ASM, OSCtxSw()
task가 CPU의 제어권을 포기할 때, OS_TASK_SW() macro는 invoked된다. 이것은 OSCtxSw()로 호출로 바뀌게 된다. 보통, OSCtxSw()는 task level의 context switch를 수행하지만, ARM Cotex-M3는 모든 context switching은 PendSV handler로 연기된다. OSCtxSw()는 그래서 간단하게 PendSV handler를 트리거하고 , 호출한 곳으로 return한다. PendSV handler는 즉시 실행하지는 않는다. 이유는 OS_TASK_SW()는 interrupt disabled되기 때문이다. PendSV handler는 오로지 인터럽트가 re-enabled되었을 때, 실행된다.

OS_TASK_SW()는 항상 OS_Sched()로부터 호출된다(see OS_CORE.C). OS_Sched()의 현재 버전은 Listing 3-17에서 보여진다.

Listing 3-17, OS_Sched()
void OS_Sched (void) {
#if OS_CRITICAL_METHOD == 3
        OS_CPU_SR cpu_sr = 0;
#endif

    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0) {
         if (OSLockNesting == 0) {
             OS_SchedNew();
             if (OSPrioHighRdy != OSPrioCur) {
                 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

#if OS_TASK_PROFILE_EN > 0
                 OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif 
                 OSCtxSwCtr++; 
                 OS_TASK_SW();  -> Tirgger the PendSV handler
            }
        }
    }
    OS_EXIT_CRITICAL();     -> PendSV handler will run when interrupts are re-enabled
}

OSCtxSw()를 위한 코드는 Lising 3-18에서 보여진다. 다시 말하면 ,여기서 하는 모든 것은 PendSV handler를 trigger한다. OS_Sched()는 우리가 switch하기 위한 task의 OS_TCB를 가리키기 위해(point) OSTCBHighRdy를 설정한다.

Listing 3-18, OSCtxSw()
OSCtxSw
        LDR R4, =NVIC_INT_CTRL ; trigger the PendSV exception
        LDR R5, =NVIC_PENDSVSET 
        STR R5, [R4]
        BX LR



3.04.05 OS_CPU_A.ASM, OSIntCtxSw()

ISR이 완료되었을 때, OSIntExit()는 interrupted task보다 더 중요한 task를 결정하기 위해 호출된다. 만약 이런 경우라면, OSIntExit()는 다음에 구동할 task르르 결정하고 OSIntCtxSw()를 호출한다. 그러나 실제로 OSIntCtxSw()가 context switch를 수행하는 다른 uC/OS-II port와 달리, ARM Cortex-M3를 위한 OSIntCtxSw()는 간단히 PendSV handler를 trigger하고 Listing 3-19에서 보여지는 것처럼 return 한다.

Listing 3-19, OSIntCtxSw()
OSCtxSw
        LDR R4, =NVIC_INT_CTRL ; trigger the PendSV exception
        LDR R5, =NVIC_PENDSVSET
        STR R5, [R4]
        BX LR

3.04.06 OS_CPU_A.ASM, OSPendSV()
OSPendSV()는 uC/OS-II를 위한 모든 context switch를 담당하는 PendSV handler이다. 이것은 ARM Cortex-M3를 가지고 Context switch를 수행하기 위한 요구되는 방법이다. 이것은 ARM Cortex-M3 가 any exception에서 processor context의 절반을 auto-save하고, exception으로부터 return시 동일한 레지스터를 restore하기 때문이다. PendSV handler는 단지 R4-R11을 저장하는 것이 필요하고 stack pointer는 고정되어 있다. PendSV exception을 사용하는 것은 그것이 task로부터 초기화되거나 또는 인터럽트나 exception 때문에 발생하더라도 context saving과 restoring이 동일한 방법을 사용한다는 것을 의미한다. 

exception vector table에서 vector location 14번에 OSPendSV()의 Pointer를 위치시켜야 한다(based of the vector table + 4 * 14 or, offset 56).
 
PendSV handler를 위한 pseudo-code는 다음과 같다.

Listing 3-20, OSPendSV()
OSPendSV:
        if (PSP != NULL) {                                              (1)
                Save R4-R11 onto task stack;                      (2)
                OSTCBCur->OSTCBStkPtr = SP;                 (3)
        }
        OSTaskSwHook();                                            (4)
        OSPrioCur = OSPrioHighRdy;                             (5)
        OSTCBCur = OSTCBHighRdy;                           (6)
        PSP = OSTCBHighRdy->OSTCBStkPtr;              (7)
        Restore R4-R11 from new task stack;                (8)
        Return from exception;                                    (9)



L3-20(0)
OSPendSV()가 CPU에 의해 시작될 때, CPU는 자동으로 xPSR, PC, LR, R12, R0-R3레지스터를 task stack으로 저장한다. CPU 레지스터의 절반을 task stack에 저장한 후에, CPU는 handler의 나머지를 처리하기 위해, SP_main을 사용하도록 stack pointer를 switch 한다.

L3-20(1)
여기에서 우리는 만약 이것이 SP_process라면 stack pointer가 NULL 설정되었는지 그렇지 않은지 확인하기 위해 check 한다. OSStartHighRdy()가 task가 처음 시작할 때 task의 context를 저장하는 것을 피하기 위해 SP_process를 NULL로 설정하는 것을 재호출한다.

L3-20(2)
만약 OSPendSV()는 실제로 full task switch를 수행하도록 트리거되면, 그때 우리는 단순히 남아있는 레지스터(R4-R11)를 저장한다.

L3-20(3)
switched out 되고 있는 task의 context가 saved되었을 때, dnflsms ekstnsgl task의 OS_TCB로 task stack pointer(SP_process)를 저장한다.

L3-20(4)
우리는 uC/OS-II context switch hook을 호출한다(see OS_CPU_C.C).

L3-20(5)
모드 uC/OS-II ports에서, 우리는 current priority로 새로운 high priority를 복사하는 것이 필요하다.

L3-20(6)
유사하게 우리는 OSTCBCur로 OSTCBHighRdy를 복사하는 것이 필요하다.

L3-20(7)
우리는 우리가 지금 switch하기 원하는 task의 current top-of-stack pointer를 되찾는다.  top-of-stack pointer가 OSTCBHigRdy->OSTCBStkPtr에서 저장되도록 재호출한다. 편의를 위해, uC/OS-II는 항상 OS_TCB의 시작에 OSTCBStkPrt을 위치시킨다. 그리고 store SP의 offset가 무엇인지 찾을 필요가 없이, 항상 offset은 0이다.

L3-20(8)
우리는 task의 stack frame으로부터 실행하기 위해 task의 context를 restore한다.

L3-20(9)
우리는 exception으로부터 return을 수행한다. 이것은 ARM Cortex-M3을 R3-R0, R12, LR, PC, xPSR레지스터를 task의 stack frame로부터 restore하도록 한다. 이 시점에 우리는 새로운 task를 run한다.


OSPendSV() handler를 위한 실제 코드는 Listing 3-21에서 보여진다. comment에서 참조 번호는 Listing 3-20의 pseudo-code에서 동일 요소와 연관되어 있다 .

그림 3-3는 context switch를 graphically하게 보여준다(again with the corresponding references).

PendSV handler는 context switch가 atomically하게 수행하는 것을 보장하기 위해 non-preemptable하고 non-interruptable해야 한다는 것에 주의해야 한다. 만약 인터럽트가 context-switch가 수행될 때 발생한다면, 그것은 새로운 task가 restored 될 때 서비스될 것이다.

Listing 3-21, OSPendSV()
OSPendSV                                               ; (0) CPU saved xPSR, PC, LR, R12, R0-R3
        MRS R0, PSP                                   ; (1) PSP is process stack pointer
        CBZ R0, OSPendSV_nosave              ; skip register save the first time

        SUB R0, R0, #0x20                            ; (2) save remaining regs r4-11 on process stack
        STM R0, {R4-R11} 

        LDR R4, __OS_TCBCur                      ; (3) OSTCBCur->OSTCBStkPtr = SP; 
        LDR R4, [R4]
        STR R0, [R4]                                   ; R0 is SP of process being switched out

OSPendSV_nosave
        PUSH {R14}                                     ; (4) OSTaskSwHook();
        LDR R0, __OS_TaskSwHook
        BLX R0
        POP {R14}

        LDR R4, __OS_PrioCur                      ; (5) OSPrioCur = OSPrioHighRdy
        LDR R5, __OS_PrioHighRdy
        LDRB R6, [R5]
        STRB R6, [R4] 
       
        LDR R4, __OS_TCBCur                     ; (6) OSTCBCur = OSTCBHighRdy;
        LDR R6, __OS_TCBHighRdy
        LDR R6, [R6]
        STR R6, [R4]

        LDR R0, [R6]                                  ; (7) R0 is new task SP
                                                             ; SP = OSTCBHighRdy->OSTCBStkPtr;

        LDM R0, {R4-R11}                           ; (8) restore R4-R11 from new task stack
        ADD R0, R0, #0x20
        MSR PSP, R0                                  ; load PSP with new task SP
        ORR LR, LR, #0x04                          ; ensure exception return uses process stack
        BX LR                                            ; (9) exception return



3.05 OS_DBG.C
OS_DBG.C는 uC/OS-II와 그것의 환경 설정에 대한 정보를 뽑아내도록 Kernel Aware debugger를 제공하기 위해 V2.62에서 추가된 파일이다. 특기 OS_DGB.C는 debugger가 읽고 표시할 수 있는 ROM 공간에 위치한 여러개의 상수를 포함하고 있다. 이 파일이 필요한 debugger를 사용하지 않을 수도 있기 때문에 build시 제외할 수 도 있다.

IAR의 C-Spy debugger를 위해, Micrium은 이 파일을 사용하게 하는 Windows-based 'Plug-In' module을 소개해왔다. 그래서 C-Spy를 사용한다면 included 하는 것이 필요하다.

4.00 Exception Vector Table
ARM Cortex-M3는 0x00000000번지에서 시작하는 exception vector table(also called the interrupt vector table)을 포함하고 있다. 테이블은 256개의 entry를 포함할 수 있다(can be up to 1 Kbytes since each entry is a 32-bit pointer). 각 entry는 관련 exception 또는 interrupt를 가리키는 pointer이다.

일반적으로 이 테이블에 위치된 명령어는 signed 26-bit destination address를 갖는 branch 명령어이다. 다시말해 ARM은 vector위치로부터 +/- 0x0200000하게 address를 branch할 수 있다. branch하도록 하는 코드는 인터럽트 source를 결정해야 한다. 그것은 ARM이 interrupt할 수 있는 모든 device 중에 단지 하나의 address 만이 거기에 존재하기 때문이다.

ARM Cortex-M3의 exception vector table은 table 4-1에서 보여진다:


uC/OS-II는 context switching을 위해 PendSV handler를 사용하고 system tick을 처리하기 위해 SysTick handler를 사용한다.

PendSV handler는 un-interruptable되기 위해 OSStartHighRdy()에 의해 cofigured 된다. 그래서 PendSV handler는 atomically하게 실행할 수 있다.

ARM Cortex-M3는 RTOS 사용을 위해 특별히 디자인된 built-in 타이머를 가지고 있다. 이 타이머는 any tick rate로 동작할 수 있게 configured 될 수 있다. 어플리케이션의 BSP는 OS_TICKS_PER_SEC로이 타이머를 설정해야만 한다.

어플리케이션 코드가 Exception Vector Table을 setup 할 수 있다. 이 작업을 돕기 위해 APP_VECT.C라고 불리는 파일을 생성했다. 그것은 각각의 프로젝트에서 편집가능하다.


4.01 Exception / Interrupt Handling Sequence
CPU가 exception 또는 interrupt handler를 invoke할 때,  CPU는 자동으로 xPSR, PC, LR, R12, R0-R3 레지스터를 SP_process stack으로 push한다.

그 다음 CPU는 exception/interrupt handler의 address를 뽑아오기 위해 vector table을 읽고 그 address로 PC를 업데이트 한다. old  PC는 original code로 return하기위해 LR에 위치된다.  그 다음 CPU는 SP_main stack pointer를 사용하기 위해 switch한다.

4.02 Interrupt Controllers
ARM Cortex-M3는 또한 integrated Nestable Vectored Interrupt Controller(NVIC)를 가지고 있다.

4.03 Interrupt Service Routines
uC/OS-II 서비스를 사용하기 위해 필요한 ISR은 ARM Cortex-M3를 위해 Listing 4-1처럼 작성되야 한다.

Listing 4-1, Interrupt Service Routines using μC/OS-II services.
void OS_CPU_IRQ_ISR_Handler (void)
{
        OS_CPU_SR cpu_sr = 0;
       
        OS_ENTER_CRITICAL();         /* Tell uC/OS-II that we are starting an ISR */
        OSIntNesting++;
        OS_EXIT_CRITICAL();

        /* Handle the Interrupt … don’t forget to clear the interrupt source */

        OSIntExit();                          /* Tell uC/OS-II that we are leaving the ISR */
}

연산이 atomically하게 수행되는 것을 보장하도록 OSIntNesting을 증가시키기 위해 인터럽트를 disable해야만 한다. 우리는 OS_ENTER_CRITICAL()과 OS_EXIT_CRITICAL() macro를 호출함으로써 이것을 수행한다.

몇몇 ISR은 task에 signal을  줄 필요가 없이 동작하는 것이 가능하다. 이런 경우, ISR은 OSIntNesting을 증가시키고 OSIntExit()를 호출하는 것이 필요하지 않을 것이다.


5.00 Application Code
당신의 어플리케이션 코드는 이 섹션에서 설명하는 것처럼 이 어플르케이션 노트에서 표현된 port를 사용할 수 있다. 그림 5-1은 어플리케이션, uC/OS-II, uC/OS-II port, BSP, ARM Cotrex-M3 CPU, target 하드웨어  사이의 관계를 block diagram으로 보여주고 있다.


5.01 APP.C, APP.H and APP_CFG.H
토론을 위해, 어플리케이션은 APP.C, APP_H, APP_CFG.H라고 불리는 파일들에 위치된다. 물론 어플리케이션은 더 많은 파일을 포함할 수 있다.

APP.C는 main()이 위치되어 있을 것이다. , 물론 어느 곳에 위치하든 상관없다.

APP_VECT.C는 어플리케이션을 위한 exception/interrupt vector table을 포함하고 있다. 당신은 자신만의 인터럽트 handler를 추가하기 위해 이 파일을 편집할 수 있다(or at least pointers to them). vector 14번은 OSPendSV()를 가리키는 포인터가 필요하고(see OS_CPU_A.ASM), vector 15번은 Tmr_TickISR_Handler()를 가리키는 포인터를 위해 필요하다(see BSP.C).

APP_CFG.C는 어플리케이션을 configure하기 위한 #define 상수를 포함하고 있다. 우리는 task stack size, task 우선순위, 다른 #define 들을 이 파일에 위치시켰다. 이것은 한 곳에서 task의 우선순위와 size를 알 수 있게 해준다.

APP.C는 uC/OS-II 예제를 위한 standard test file이다. 두 개의 중요한 함수는 main()과 AppStartTask()이다.


Listing 6-1, main()
void main (void)
{
#if OS_TASK_NAME_SIZE > 13
        INT8U err;
#endif

        BSP_IntDisAll();                                                                                                     (1)
        OSInit();                                                                                                               (2)
        OSTaskCreateExt(AppStartTask,                                                                             (3)
                                  (void *)0,
                                  (OS_STK *)&AppStartTaskStk[APP_TASK_START_STK_SIZE-1],
                                  APP_TASK_START_PRIO,
                                  APP_TASK_START_PRIO,
                                  (OS_STK *)&AppStartTaskStk[0],
                                  APP_TASK_START_STK_SIZE,
                                  (void *)0,
                                  OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

#if OS_TASK_NAME_SIZE > 11
        OSTaskNameSet(APP_TASK_START_PRIO, "Start Task", &err);                                  (4)
#endif

        OSStart();                                                                                                             (5)
}

L5-1(1)
초기화 과정이 완료될 때까지 인터럽트를 받지 않는 것을 보장하기 위해 인터럽트를 disable하는 것이 필요하다.

L5-1(2)
어플리케이션 기반의 모든 uC/OS-II는 OSInit()를 호출함으로써 uC/OS-II를 호출하는 것이 필요하다.

L5-1(3)
 적어도 하나의 task를 생성하는 것이 필요하다. 이 경우에서 우리는 extended task create call을 사용해서 task를 생성했다. 이것은 uC/OS-II가 task에 대해 더 많은 정보를 갖도록 해준다. 특히 IAR toolchain에서 여분의 정보는 uC/OS-II Kernel Awareness Plug-in을 사용하 때 , C-Spy debugger가 stack 사용 정보를 표시하도록 해준다.

L5-1(4)
우리는 지금 task에게 이름을 줄 수 가 있고 IAR의 C-Spy와 같은 Kernel Aware debugger에 의해 표시될 수 있다.

L5-1(5)
multitasking을 시작하기 위해, OSStart()를 호출하는 것이 필요하다. OSStart()는 이 호출로부터 return하지 않을 것이다.

Listing 5-2, AppStartTask()
static void AppStartTask (void *p_arg)
{
        (void)p_arg;

        BSP_Init();                                                               (1)

#if OS_TASK_STAT_EN > 0
        OSStatInit();                                                             (2)
#endif

#if OS_VIEW_MODULE > 0
        OSView_Init(38400);                                                  (3)
        OSView_TerminalRxSetCallback(AppTerminalRx);
#endif

        AppTaskCreate();                                                     (4)
        while (TRUE) {
                /* Do something ‘useful’ in this task */               (5)
               LED_Toggle(1);                                                 (6)
               OSTimeDly(OS_TICKS_PER_SEC / 20);
        }
}

L5-2(1)
target boart를 위해 BSP를 실핼하기로 결정했다면, 여기에서 그것을 초기화할 것이다.

L5-2(2)
OS_CFG.H에서 OS_TASK_STAT_EN을 1로 셋팅함으로써 startinit task를 enabled 하였다면, 그 때 여기서 그것을 호출하는 것이 필요하다. OSStartInit()가 clock tick이 있다고 가정하기 때문에 uC/OS-II clock tick을 초기화했고 enabled 했다고 확신하는 것이 필요하다. 다시 말해, 만약 tick ISR이 OSStartInit()를 호출했을 때 active되지 않았다면, 어플리케이션은 uC/OS-II의 idel task에서 종료되고, 다른 task를 run하지 못할 것이다.

L5-2(3)
uC/OS-View를 구매했다면, 여기서 그것을 초기화 할 수 있을 것이다. 이것을 발생시키기 위해, uC/OS-View target 임시 파일을 build에 include하는 것이 필요하다.

L5-2(4)
이 시점에, 추가적인 task를 생성할 수 있다. 우리는 AppTaskCreate()라고 불리는 하나의 함수에 모든 task 초기화를 위치시키기로 결정했다.  그러나 당신은  다른 기술을 사용하기를 바란다.

L5-2(5)
이 task를 위해 당신이 원하는 추가적인 함수가 무엇이든지 지금 수행 할 수 있다.

L5-2(6)
우리는 이 task가 running할 때 , 20Hz를 주기로 LED를 토글하기로 결정했다.


5.02 INCLUDES.H
INCLUDE.H는 master include file이고 모든 .C 파일의 맨 위에 위치한다. INCLUDE.H는 header file이 실제 필요한 것에 신경쓰지 않고 작성되도록 당신의 프로젝트에서 모든 .C 파일을 접근할 수 있게 해준다. 단지 master include file이 가지는 약점은 INCLUDE.H가 컴파일된 실제 .C 파일과 관련없는 header file을 include 할수도 있다는 것과 컴파일 과정이 더 길어질 지도 모른다는 것이다. 이러한 불편함은 code의 유동성에 의해 offset 된다. 당신은 자신만의 header file을 추가하기 위해 INCLUDE.H를 편집할 수 있다. 하지만 header file은 list의 끝에 추가되어야만 한다.


6.00 BSP (Board Support Package)

BSP를 생성하는 것은 target 하드웨어를 위해 편리하다. BSP는 아래의 기능들으 encapsulate 할수 있게 해준다.

        Timer initialization
        ISR Handlers
        LED control functions
        Reading switches
        Setting up the interrupt controller
        Setting up communication channels
        Etc.

Micrium BSP는 적어도 2개의 파일로 구성된다. : BSP.C와 BSP.H이다.

각 BSP는 BSP 초기화 함수를 포함하고 있어야만 한다. 우리는 BSP_Init()를 호출했고 어플리케이션 코드에 의해 호출되어야만 한다.


6.01 BSP (Board Support Package) – LED Management
여러개의 evaluation board는 LED를 장착하고 있다. 우리는 아래와 같은 LED control 함수를 생성하기로 결정했다.

        void LED_Init(void);
        void LED_On(CPU_INT08U led_id);
        void LED_Off(CPU_INT08U led_id);
        void LED_Toggle(CPU_INT08U led_id);

이 경우에, LED는 'physically' 대신에 'logically'으로 참조된다. BSP를 작성할 때 , LED가 LED #1인지 LED #2인지 결정한다. LED #1을 켜기를 원할 때 단순히 LED_On(1)을 호출한다. LED #2를 토글하기를 원한다면, LED_Toggle(2)를 호출한다. 사실 #define을 사용해서 LED의 이름을 정의할 수 있다. 그래서 LED_OFF(LED_PM) 같이 명시할 수 있다. 

 
6.02 BSP (Board Support Package) – Clock Tick
우리는 다른 uC/OS-II port와 일관성을 위해 BSP에서 uC/OS-II clock tick handler를 encapsulate 하기로 결정했다. ARM Cortex-M3를 위해 clock tick handler는 uC/OS-II port의 한 부분이 될 수 있어왔다. 모든 ARM Cotex-M3 실행이 Systick를 포함할 것이기 때문이다. clock tick ISR handler는 BSP.C에서 찾게 되고, Tmr_TickISR_Handler()라고 불리게 된다.  clock tick handler의 예시는 Listing 6-1에서 보여진다. ARM Cortex-M3에서는 어셈블리어로 ISR code를 작성할 필요가 없다. ISR은 다른 C 함수이다.

Listing 6-1, Tmr_TickISR_Handler()
void Tmr_TickISR_Handler (void)
{
        OS_CPU_SR cpu_sr;

        OS_ENTER_CRITICAL();         /* Tell uC/OS-II that we are starting an ISR */
        OSIntNesting++;
        OS_EXIT_CRITICAL();

        OSTimeTick();                     /* Call uC/OS-II's OSTimeTick() */

        OSIntExit();                         /* Tell uC/OS-II that we are leaving the ISR */
}

7.00 Conclusion
이 어플리케이션 노트는 ARM Cortex-M3 프로세서를 위한 'generic' port를 설명했다. port는 쉽게 다른 컴파일러에 적용되어야만 한다. 물론 uC/OS-II를 사용하고 실제 하드웨어에 port를 사용한다면, 초기화가 필요할 것이고, 하드웨어 interrupt를 다루는 것이 필요할 것이다.




'[D-03] uC/OS-II' 카테고리의 다른 글

Flow-chart를 통해 분석한 µC/OS-II  (0) 2009.12.04
RTOS, ARM Architecture 개인 사이트  (0) 2009.11.25
uCOS-II_뛰어넘기  (0) 2009.11.25
Posted by eoseontaek

LM3S8962의 I2C 인터페이스에 대하여 알아본다.

우선 Luminary 홈페이지에서 LM3S8962 Datasheet를 다운 받는다.
Link : http://www.luminarymicro.com/products/LM3S8962.html#Datasheet

위의 링크에서 datasheet 및 각종 App Note, Software tool 등을 다운 받을 수 있다.

Datasheet를 토대로 LM3S8962 I2C 인터페이스에 대하여 분석해 보도록 한다.



Inter-Integrated Circuit (I2C) Interface
I2C 버스는 two-wire를 통해 양방향 데이터 통신을 제공하고 serial memory, networking devices, LCDs, tone generators 등과 같은 외부 디바이스와 interface 된다. i2C 버스는 또한 system testing과 제품 개발과 제조를 위한 diagnostic 목적으로 사용된다. LM3S8962 마이크로컨트롤러는 하나의 I2C 모듈을 가지고 있고 버스에서 다른 I2C 내부 동작을 가능하게 된다.

Stellaris I2C 인터페이스는 다음과 특징을 가지고 있다.

I2C 버스에서 Device는 master 나 slave로 지정된다.
    - master나 slave로서 데이터 송수신을 제공한다. 
    - master와 slave 동작은 동시에 동작한다
4개의 I2C 모드
    - Master transmit
    - Master receive
    - Slave transmit
    - Slave receive
■ 두개의 전송 속도 : Standard(100 Kbps), Fast(400 Kbps)
Master와 Slave interrupt generation
   - Master는 transmit 또는 receive 동작 완료할 때 interrupt를 발생한다. 
   - Slave는 master에 의해 데이터가 보내졌거나 요청되었을 때 인터럽트가 발생한다.
Master with arbitration and clock synchronization, multimaster support, and 7-bit addressing mode


1. Block Diagram



2. Functional Description
I2C 모듈은 독립된 peripherals로 동작하는 master와 slave로 구성된다. SDA와 SCL 핀은 양방햔 open-drain pads와 연결되어야만 한다. 전형적인 I2C 버스 configuration 은 아래 그림과 같다.

2.1 I2C Bus Functional Overview
I2C 버스는 단지 2개의 신호 SDA, SCL 만을 사용한다. Stellaris microcontroller에서는 I2CSDA, I2CSCL이라고 불린다.
SDA는 양방향 시리얼 데이터 라인이고 SCL은 양방향 시리얼 클럭라인이다. 버스는 두 신호 모두 High일때 idle 상태이다.

I2C 머스에서  모든 transaction은 9비트이다. 8비트의 데이터과 단일 응답 비트로 구성된다. 전송마다 byte의 수는 제한이 없지만, 각 byte는 응답비트가 따라와야 하며, 데이터는 MSB부터 전송되어야 한다. receiver가 another complete byte를 수신할 수 없을 때, receiver는 SCL 라인을 low 상태로 만들고, transmitter를 강제로 wati state 로 만든다.  receiver가 clock SCL을 방출할 때 데이터 전송은 계속된다.

2.1.1 START and STOP Conditions
I2C 버스의 프로토콜은 transaction을 start하고 end하기 위한 두가지 상태를 정의한다. : START와 STOP이다. SCL이 High인 동안 SDA 라인이 High에서 Low로 바뀌면 START 조건으로 정의 된다. 그리고 SCL 이 High인 동안 SDA 라인에서 Low에서 High로 바뀌면 STOP 조건으로 정의된다. 버스는 START 조건 후에 busy가 되고, STOP 조건 후에는 free가 된다.

2.1.2 Data Format with 7-Bit Address
데이터 전송은 아래 그림에서 보여지는 format을 따른다. START 조건 후에, slave address는 보내진다. 이 address는 7-bit의 길이 다음에 data의 방향을 비트인 여덟번째 비트가 따라온다(R/S bit in the I2CMSA register). zero는 전송동작(send)를 나타내고, 1은 데이타를 위한 요청(receive)을 나타낸다. 데이터 전송은 항상 master에 의해 발생하는 STOP 조건으로 종료된다.  그러나 master는 repeated START 조건을 발생함으로써 버스에서 다른 device와 같이 통신을 초기화 할 수 있다. STOP 조건의 발생하지 않고도 다른 slave를 addressing 할 수도 있다. 송/수신 format의 여러 조합은 단일 전송안에 가능하게 한다.

처음 byte의 첫 7 비트는 slave address를 구성한다. 여덟번째 비트는 message의 방향을 결정한다. 첫번째 byte의 R/S position에서 0은 master가 선택된 slave에 데이터를 write(send)할 것을 의미한다. 1은 master가 slave로부터 데이터를 수신할 것이라는 것을 의미한다.

2.1.3 Data Validity
SDA 라인에서의 데이터는 clock의 high 주기 동안 안정적이어야만 한다. 그리고 데이터 라인은 오로지 SCL이 Low일 때만 변하게 된다.

2.1.4 Acknowledge
모든 bus transaction은 master에서 발생되는 요구된 응답 클럭 사이클을 가지고 있다. 응답 사이클 동안 전송하는 쪽(which can be the master or slave)은 SDA line을 내본낸다. transaction을 응답하기 위해 수신하는 쪽은 응답 클럭 사이클 동안 SDA를 pull down해야 한다. 응답 사이클 동안 수신하는 쪽에 의해 보내지는 데이터는 data validity 요구사항을 따라야만 한다.

slave receiver가 slave address를 응답하지 못할 때, SDA는 slave에 의해 High로 남아 있어야만 한다. 그래야 master는 STOP 조건을 발생할 수있고 현재 전송을 취소할 수 있다. 만약 master device가 전송하는 동안 receiver로서 동작하고 있다면, 그것은 slave에 의해 만들어진 각각의 전송에 응답하기 위한 책임을 가질 수 있다. master가 전송에서 byte 수를 제어하기 때문에, 그것은 마지막 data byte에서 응답을 발생하지 않음으로서 slave transmitter에게 데이터의 끝이라는 신호를 준다. slave transmitter는 그때 master에게 STOP 또는  repeated START 조건을 발생하도록 허락하기 위해 SDA를 release해야 한다.

2.1.5 Arbitration
master는 bus가 idle상태라면 전송을 시작할 수 도 있다. START 조건의 최소 hold time을 가지고 START 조건을 발생시키는 것을 두 개 이상의 master에서 가능하다. 이 경우에 arbitration scheme은 SCL이 High인 동안 SDA 라인에서 이루어진다. arbitration 동안, 다른 master가 0을 전송하는 동안 SDA에서 '1'이 되도록 경쟁하는 master device 중 첫번째는 데이터의 출력 상태를 switch off 할 것이고 bus가 다시 idle 상태가 될때 까지 물러나 있을 것이다.

Arbitration은 여러개의 비트를 발생할 수 있다. 그것의 첫번째 stage는 address 비트의 비교이다, 만약 양쪽 master 모두 같은 device를 접근하려고 시도하면, arbitration은 data bit의 비교를 계속한다.



2.2 Available Speed Modes
I2C clock rate는 CLK_PRD, TIMER_PRD, SCL_LP, SCL_HP parameter에 의해 결정된다.

여기서 :
CLK_PRD : system clock period
SCL_LP : SCL의 low phase(fixed at 6)
SCL_LP : SCL의 high phase(fixed at 4)
TIMER_PRD : I2C Master Timer Period (I2CMTPR) register에서 프로그램된 값

I2C clock 주기는 다음 식으로 계산된다.
SCL_PERIOD = 2*(1 + TIMER_PRD)*(SCL_LP + SCL_HP)*CLK_PRD

예를들어,
CLK_PRD = 50 ns
TIMER_PRD = 2
SCL_LP=6
SCL_HP=4
yields a SCL frequency of:
1/T = 333 Khz

아래 테이블은 타이머 주기, 시스템 클럭, 스피드 모드의 예시를 보여준다. (Standard or Fast).



2.3 Interrupts
아래 조건들이 관찰되었을 때 I2C는 인터럽트를 발생할 수 있다.

■ Master transaction completed
■ Master transaction error
■ Slave transaction received
■ Slave transaction requested

I2C master와 I2C slave 모듈은 분리된 interrupt signal을 가지고 있다. 양 쪽 모듈이 여러개의 조건에 의한 인터럽트를 발생할 수 있는 동안 단지 하나의 인터럽트 신호가 interrupt controller로 보내진다.

2.3.1 I2C Master Interrupts
I2C master 모듈은 transaction이 완료되거나, error가 transaction 동안 발생했을 때, 인터럽트를 발생한다. I2C master 인터럽트를 enable하기 위해, 소프트웨어는 I2C Master Interrupt Mask (I2CMIMR) register에 '1'을 write해야 한다. 인터럽트 조건이 발생했을 때, 소프트웨어는 I2C Master Control/Status (I2CMCS) register에서 ERROR 비트를 확인해야 한다. 이것은 error가 마지막 transaction 동안 발생하지 않았다는 것을 증명하기 위해서이다. error 조건은 마지막 transaction이 slave에 의해 응답하지 않았다면 asserted 된다. 또한 master가 다른 master로 arbitration을 잃었기 때문에 bus의 ownership을 포기하도록 강제되었을 경우에도 error 조건은 asserted 된다.  error가 감지되지 않았다면, application은 전송을 게속할 수 있다. 인터럽트는 I2C Master Interrupt Clear (I2CMICR) register에 '1'을write 함으로써 clear 된다.
applicaiton이 인터럽트의 사용을 요구하지 않는다면, raw interurpt status는 항상 I2C Master Raw Interrupt Status (I2CMRIS) register를 통해 확인할 수 있다

2.3.2 I2C Slave Interrupts
slave 모듈은 데이터가 수신되었거나 요청되었을 때 인터럽트를 발생할 수 있다. 이 인터럽트는 I2C Slave Interrupt Mask (I2CSIMR) register에서 DATAIM 비트에 '1'을 write함으로서 enable 된다. 소프트웨어는 모듈이 I2C Slave Data (I2CSDR) register로부터 데이터를 write(transmit) 또는 read(receive) 해야만 하는지를 결정한다. 이것은 I2C Slave Control/Status (I2CSCSR) register의 RREQ, TREQ 비트를 확인함으로써 이루어진다. 만약 slave 모듈이 receive 모드에 있고 전송의 첫번째 byte가 수신되었다면, FBR 비트는 RREQ와 함께 set 된다. 인터럽트는 I2C Slave Interrupt Clear (I2CSICR) register에서 DATAIC 비트에 1dmf write함으로써 clear된다.

만약 application에서 인터럽트의 사용을 요구하지 않는다면, raw interrupt status는 항상 I2C Slave Raw Interrupt Status (I2CSRIS) register를 통해 확인할 수 있다.

2.4 Loopback Operation
I2C 모듈은 진단 및 debug 작업을 위해 내부 loopback 모드로 바뀔 수 있다. 이것은 I2C Master Configuration I2CMCR) register에서 LPBK 비트를 셋팅함으로써 이루어진다. loopback 모드에서 SDA, SCL 신호는 함께 묶인다.

2.5 Command Sequence Flow Charts
이 setcion은 master나 slave 모두 양쪽에서 여러개의 I2C 전송 타입을 수행하기 위해 요구되는 단계를 자세히 설명한다.

2.5.1 I2C Master Command Sequences
아래의 그림은 I2C master에서 사용할 수 있는 command sequence를 나타낸다.






2.5.2 I2C Slave Command Sequences
아래 그림은 I2C slave에서 사용할 수 있는 command sequence를 나타낸다.



3. Initialization and Configuration
아래의 예시는 master에서 단일 byte를 전송하기 위해 I2C module을 configure하는 방법을 보여준다.
이것은 system clock이 20MHZ라고 가정한다.

(1) System Control 모듈에서 RCGC1 레지스터에 0x0000.1000의 값을 writing함으로써 I2C clock을 enable한다.

(2) System Control 모듈에서 RCGC2 레지스터를 통해 적절한 GPIO의 clock을 enable 한다.

(3) GPIO 모듈에서, GPIOAFSEL 레지스터를 사용함으로써 alternate function을 위한 적절한 pin을 enable 한다.

(4) I2CMCR 레지스터에 0x0000.0020의 값을 writing함으로써 I2C Master를 초기화 한다.

(5) 정확한 값을 I2CMTPR 레지스터에 writing함으로써 희망하는 SCL clock speed를 100 Kbps로 설정한다. 
     I2CMTPR 레지스터에 쓰여진 값은 하나의 SCL clock 주기에서 시스템 클럭 주기의 수를 나타낸다. TPR 값은 다음
    수식에 의해 결정된다.

    TPR = (System Clock / (2 * (SCL_LP + SCL_HP) * SCL_CLK)) - 1;
    TPR = (20MHz / (2 * (6 + 4) * 100000)) - 1;
    TPR = 9
 
    I2CMTPR 레지스터에 0x0000.0009의값을 write 한다. 

(6) master의 slave address를 명시하고 다음 동작은 I2CMSA 레지스터에 0x0000.0076의 값을 write함으로써 Send 될
    것이라고 명시한다.   이것은 0x3B로 slave address를 설정한다.

(7) 희망하는 데이터를 I2CMDR에 writing함으로써 데이터 레지스터에서 보내지기 위한 데이터를 위치시킨다.

(8) I2CMCS 레지스터에 0x0000.0007 의 값을 writing함으로써 Master로부터 Slave로 데이터의 단일 byte 전송을
    초기화
한다.

(9) I2CMCS 레지스터의 BUSBSY비트가 clear 될때까지 polling함으로써 전송이 완료될 때까지 기다린다.


4. Register Map
아래의 테이블은 I2C 레지스트터를 list한다. 모든 address는 I2C base address와 관련되어 주어진다.

■ I2C Master 0: 0x4002.0000
■ I2C Slave 0: 0x4002.0800




5. API Functions



I2CMasterInitExpClk - I2C Master Block을 초기화한다.
master를 위한 bus speed를 설정하고, I2C Master block을 enable 한다.
        bFast : true -> transfer data at 400kbps                                            
        bFast : otherwise -> transfer data at 100kbps


I2CMasterEnable - I2C Master block를 enable한다.

I2CMasterDisable - I2C master  block를 disable 한다.

I2CMasterSlaveAddrSet - transction을 초기화할 때 bus에서 I2C master를 위치시킬 address를 설정한다.
        bReceive : true -> I2C Master가 slave로부터 read하도록 초기화 
        bReceive : otherwise -> I2C Master가 slave로 write하도록 초기화

I2CMasterDataPut - I2C Master로부터 1 byte를 전송한다.
이 함수는 I2C Master Data Register로 제공된 데이터를 넣게된다.

I2CMasterDataGet - I2C Master로 보내진 1 byte를 수신한다.
이 함수는 I2C Master Data Register로부터 1byte data를 read한다.

I2CMasterControl - I2C Master module의 상태를 제어한다.
이 함수는 Master module send/receive 동작의 상태를 제어하기 위해 사용된다.

I2CMasterBusy - I2C Master가 busy인지 아닌지를 나타낸다.
이 함수는 I2C Master가 data를 전송/수신 중 인지 여부를 나타낸다.

I2CMasterBusy - I2C bus 가  busy인지 아닌지를 나타낸다.
이 함수는  I2C bus의  busy여부를 return한다. multi-master 환경에서 다른 master 가 현재 bus에서 사용되는지를 결정하기 위해 사용된다.

I2CMasterErr - I2C Master module의 errt 상태를 얻어온다.
이 함수는 Master module send/receive 동작의 error 상태를 얻어오는 데 사용한다.

I2CMasterIntEnable - I2C Master interrupt suorce를  enable한다.

I2CMasterIntDisable - I2C Master interrupt source를 disable 한다.

I2CMasterIntStatus - 현재 I2C Master interrupt 상태를 얻어온다.
processor를 반영하도록 허락된 raw interrupt 상태나 interrupt 상태가 return 될 수 있다.
        bMasked : false -> raw interrupt status가 요청됨.
        bMasteed : true -> interrupt status가 요청됨.

I2CMasterIntClear - I2C Master interrupt source를 clear한다.
I2C Master interrupt source가 clear되고 더이상 assert 되지 않는다. 이것은 exit 후에 즉시 다시 호출되도록 하기위해 interrupt handler 내에서 수행되어야 한다.



I2CSlaveInit - I2C slave block을 초기화한다.
I2C block을 성공적으로 초기화하면, 이 함수는 slave address를 설정하고, I2C slave block을 enable하게 된다.
ucSlaveAddr은 I2C master에 의해 보내진 slave address와 비교될 값이다.

I2CSlaveEnable - I2C Slave block 을 enable 한다.

I2CSlaveDisable - I2C Slave block을 disable 한다.

I2CSlaveStatus - I2C Slave module 상태를 가져온다.
이 함수는 master 로부터 요청된 동작을 return 한다.
    I2C_SLAVE_ACT_NONE : I2C Slave modue 요청된 어떤 동작도 없다.
    I2C_SLAVE_ACT_RREQ : I2C master가 I2C Slave module로 데이터를 보냈다.
    I2C_SLAVE_ACT_TREQ : I2C master가 I2C Slave module이 data를 보내도록 요청했다.
    I2C_SLAVE_ACT_RREQ_FBR : I2C master가 I2C slave에게 data를 보내고, slave 자신의 address를 따라 첫번째 
                                                byte가 수신되었다. 

I2CSlaveDataGet - I2C slave로 보내진 1 byte를 수신한다.
이 함수는 I2C Slave Data Register로부터 1 byte의 data를 읽는다.

I2CSlaveDataPut - I2C Slave로부터 1 byte을 전송한다.
이 함수는 I2C Slave Data Register로 제공된 data를 넣는다.


I2CSlaveIntEnable - I2C Slave interrupt source를 enable한다.

I2CSlaveIntDisable - I2C Salve interrupt source를 disable한다.

I2CSlaveIntStatus - 현재 I2C Slave interrupt 상태를 얻어온다.
processor를 반영하도록 허락된 raw interrupt 상태 또는 interrupt 상태가 return될 수 있다.
        bMasked : false -> raw interrupt 상태가 요청됨.
        bMasked : true -> interrupt 상태가 요청됨.

I2CSlaveIntClear - I2C Slave interrupt source를 clear한다.
I2C Slave interrupt source는 clear되고 더이상 assert되지 않는다. 이것은 exit 후에 즉시 다시 호출되게 하기 위해 interrupt handler 내에서 수행되어야 한다.

I2CIntRegister - I2C module을 위해 interrupt handler를 등록한다.
이것은 I2C 인터럽트가 발생했을 때 호출될 handler를 설정한다.

I2CIntUnregister - I2C module을 위한 interrupt handler를 등록해제한다.
이 함수는 I2C 인터럽트가 발생했을 때 호출될 handler를 clear할 것이다. interrupt handler에서 interrupt를 mask off하므로 더이상 호출되지 않을 것이다.






Posted by eoseontaek

LM3S8962의 Timer에 대해서 알아본다.

우선 예제코드를 다운 받는다.
Link  : http://www.zlgmcu.com/luminary/exploitation_guide.asp


위의 링크된 사이트에서 timer 관련 파일을 모두 다운 받는다.
timer 관련 문서
LM3SLib_Timer.pdf

timer 관련 예제 코드
LM3SLib_Timer_16_CapCount.zip
LM3SLib_Timer_16_CapTime.zip
LM3SLib_Timer_16_OneShot.zip
LM3SLib_Timer_16_Periodic.zip
LM3SLib_Timer_16_PWM.zip
LM3SLib_Timer_32_OneShot.zip
LM3SLib_Timer_32_Periodic.zip
LM3SLib_Timer_32_RTC.zip
LM3SLib_Timer_APP_Buzzer.zip
LM3SLib_Timer_APP_Music.zip

제1장 General-Purpose Timers



1.1 Timer의 일반적인 특성
 Programmable timers는 Timer input pins으로 drive 하는 외부 이베트를 count하고 시간을 재기위해 사용할 수 있다. Stellaris General-Purpose Timer Module(GPTM)은 4개의 GPTM Block(Timer0, Timer1, Timer2, Timer3)을 가지고 있다. 각 GPTM block은 독립적으로 타이머와 이벤트 카운터로 동작하도록 설정하거나,  하나의 32비트 타이머와 하나의 32비트 Real-Time Clock(RTC)로 동작하도록 설정할 수  있는 2개의 16비트 타이머/카운터(TimerA, TimerB)를 제공한다. 

게다가 타이머는 analog-to-digital conversion(ADC)로 사용할 수 있다. 

GPT Module은 Stellaris microcontroller에서 하나의 timing resource 를 사용할 수 있다. 다른 timer resource는 System Timer(SysTick)과 PWM Module에서 PWM timer를 가지고 있다.

GPTM은 다음과 같은 특징을 가지고 있다.

4개의 GPTM은 두개의 16비트 타이머를 제공한다. 각각은 독립적으로 동작을 설정할 수 있다.
    – As a single 32-bit timer
    – As one 32-bit Real-Time Clock (RTC) to event capture
    – For Pulse Width Modulation (PWM)
    – To trigger analog-to-digital conversions

32비트 타이머 모드
    – Programmable one-shot timer
    – Programmable periodic timer
    – Real-Time Clock when using an external 32.768-KHz clock as the input
    – Software-controlled event stalling (excluding RTC mode)
    – ADC event trigger

16비트 타이머 모드
    – General-purpose timer function with an 8-bit prescaler (for one-shot and periodic modes only)
    – Programmable one-shot timer
    – Programmable periodic timer
    – User-enabled stalling when the controller asserts CPU Halt flag during debug
    – ADC event trigger

16비트 입력 캡쳐 모드
    – Input edge count capture
    – Input edge time capture

16비트 PWM 모드
    – Simple PWM mode with software-programmable output inversion of the PWM signal


Block Diagram
Note : 사용가능한 CCP 핀은 Stellaris device에 의존적이다.


사용가능한 CCP 핀은 다음과 같다.



1.2 Timer 기능 설명
각 GPTM block의 main component는 두개의 free-running 16비트 up/down 카운터, 두개의 16비트 match 레지스터, 두개의 prescaler match 레지스터, 두개의 16비트 load/initialization 레지스터, 그리고 관련 control function이다. 각 GPTM의 정확한 기능은 소프트웨어로 제어되고 레지스터 인터페이스를 통해 설정된다.

소프트웨어는 GPTM Configuration (GPTMCFG) register, GPTM TimerA Mode (GPTMTAMR) register, GPTM TimerB Mode (GPTMTBMR)를 사용하여 GPTM을 설정한다. 32비트 모드에서, 타이머는 오로지 32비트 타이머로만 동작할 수 있다. 하지만 16비트 모드에서는, GPTM은 16비트 모드의 조합을 통해 설정된 두개의 16비트 타이머로 동작할 수 있다. 

GPTM Reset Conditions
GPTM 모듈이 reset 된 후에, 모듈은 inactive 상태이고 모든 control 레지스터는 cleared 되거나 그들의 default 상태가 된다. 
Counters TimerA and TimerB는 0xFFFF로 초괴화 된다. 
    the GPTM TimerA Interval Load (GPTMTAILR) register 
    the GPTM TimerB Interval Load (GPTMTBILR) register
prescale  counter는 0x00으로 초괴화된다.
    the GPTM TimerA Prescale (GPTMTAPR) register
    the GPTM TimerB Prescale (GPTMTBPR) register

32-Bit Timer Operating Modes
GPTM은 GPTM Configuration(GPTMCFG) 레지스터에 0(One-Shot/Periodic 32-bit timer mode) 또는 1(RTC mode)을 Writing 함으로써 동작한다. 어느쪽 설정이든 정확한 GPTM 레지스터들은 pseudo 32-bit 레지스터를 형성하기 위해 연결된다. 이 레지스터드들은 다음과 같다.

    ■ GPTM TimerA Interval Load (GPTMTAILR) register [15:0]
    ■ GPTM TimerB Interval Load (GPTMTBILR) register [15:0]
    ■ GPTM TimerA (GPTMTAR) register [15:0]
    ■ GPTM TimerB (GPTMTBR) register [15:0]

32비트 모드에서, GPTM은 GPTMTAILR에 32비트 wrtie access 하는 것은  GPTMTAILR과 GPTMTBILR 양쪽으로 write access하는 것으로 바뀌게 된다. 이러한 write 동작을 위한 결과적인 word ordering 은 다음과 같다.
    GPTMTBILR[15:0]:GPTMTAILR[15:0]
GPTMTAR에 read access 하는 것도 유사하다, 리턴 값은 다음과 같다.
    GPTMTBR[15:0]:GPTMTAR[15:0]


[32-Bit One-Shot/Periodic Timer Mode]
  - TimerA와 TimerB 레지스터에 연결된 버전은 32비트 down-counter로서 설정된다. 
  - one-shot과 periodic 모드의 선택은 GPTM TimerA Mode(GPTMTAMR) 레지스터의 TAMR field에 쓰여지는
     값으로 결정된다.
  - GPTM TimerB Mode (GPTMTBMR) register에 wrtie 할 필요는 없다.
  - 소프트웨어에서 GPTM Control(GPTMCTL) 레지스터의 TAEN 비트를 write할때, 타이머는 preloaded value로부터
     counting down 한다. 
  - 0x0000.0000 상태가 되었을때, 타이머는 다음 cycle에 연결된 GPTMTAILR로부터 start value를 reload 한다.
  - One-shot 타이머로 설정되어 있다면, 타이머는 counting을 멈추고 GPTMCTL레지스터의 TAEN 비트를 clear한다.
  - periodic 타이머고 설정되어 있다면, counting을 계속한다.

  - 카운트 값을 reloading 하는 것 외에 GPTM은 0x0000.0000 상태가 되었을 때 interrupt와 trigger를 발생한다. 
  - GPTM은 GPTM Raw Interrupt Status(GPTMRIS) 레지스터의 TATORIS bit를 set하고 GPTM Interrupt Clear
    (GPTMICR) 레지스터를 writing함으로써 clear 할때까지 hold 한다.
  - GPTM Interrupt Mask(GPTIMR)레지스터에서 time-out interrupt가 enable되면 GPTM은GPTM Masked Interrupt
    Status(GPTMMIS)레지스터에서 TATOMIS비트를 set 한다.
  - ADC trigger는 GPTMCTL에서 TAOTE 비트를 setting 함으로써 enable 된다.

  - counter가 running 하는 동안 소프트웨어가 GPTMTAILR 레지스터를 reload 하면, counter는 다음 clock cycle에
    새로운 value을 load 한고 새로운 value로부터 conuting을 계속한다.

  - GPTMCTL 레지스터의  TASTALL비트가 asserted 되면 타이머는 signal이 deasserted 될때까지 freeze 된다.

[32-Bit Real-Time Clock Timer Mode]
  - RTC 모드에서 TimerA와 TimerB  레지스터에 연결된 버전은 32-bit up-counter로서 설정된다.
  - RTC 모드가 처음으로 선택되었을 때, 카운터는 0x0000.0001 값으로 load된다. 이후의 load value는 controller에
    의해 GPTM TimerA Match(GPTMTAMATCHR) 레지스터에 write 되어야만 한다. 
 
  - CCP0, CCP2, CCP4 핀의 input clock은 RTC  모드에서 32.768KHz가 요구된다.
  - clock signal은 1Hz 아래로 나누어지며 32비트 counter의 입력으로 전달된다.

  - 소프트웨어가 GPTMCTL 레지스터의 TAEN 비트를  write 할 때, counter는 0x0000.0001의 preload 값으로부터
    counting up을 시작한다.
  - 현재 count value가 GPTMMATCHR 레지스터에서 preloaded value로 match 되었을 때 , 0x0000.0000으로 
    roll over 히고 hardware reset이 되거나 소프트웨어에 의해 clear 될때까지 counting을 계속한다.
  - match 되었을 때 GPTM은 GPTMRIS의 RTCIS 비트를 assert 한다. GPTIMR에서 RTC  인터럽트가 enable 되었을
   때, GPTMISR의 RTCMIS 비트를 set하고 controller interrupt가 발생한다.
  - 상태 플래그는 GPTMICR에서 RTCCINT 비트를 writing 함으로써 clear 된다.
 


16-Bit Timer Operating Modes
GPTM은 GPTM Configuration(GPTMCFG) 레지스터에 0x4를 writing 함으로써 global 16-bit 모드가 된다.  TimerA와 TimerB는 동일하게 동작한다.

[16-Bit One-Shot/Periodic Timer Mode]
  - 16비트 one-shot와 periodic timer 모드에서, 타이머는 24비트로 카운트 범위를 확장하기 위한 선택적인 8비트
    prescaler를 갖는 16비트 down-counter로 설정된다.  
  - one-shot과 periodic 모드의 선택은 GPTMTnMR 레지스터의 TnMR field에 written 하므로서 결정된다. 
  - 선택가능한 prescaler는 GPTM Timern Prescale(GPTMTnPR) 레지스터로 load된다.
  
  - 아래 Table은 prescaler를 사용할 때, 16비트 free-running 타이머를 위한 여러 설정을 보여준다. 모든 값은
    Tc=20ns의 clock period를 갖는 50MHz에서 동작한다고 가정한다.


[16-Bit Input Edge Count Mode]
Note
: rising-edge detection을 위해, input signal은 rising-edge가 발생한 다음 적어도 두개의 systel clock periods
         동안 High 상태를 유지해야 만 한다. 유사하게 falling-edge detection을 위해, input signal은 falling-edge
         으로 적어도 두개의 system clock periods 동안 Low 상태를 유지해야 한다. 이런 이유로 edeg-detection을 위한
          maximum input frequencysms system frequency의 1/4 이 된다.

Note : Prescaler는 16-Bit Input Edge Count 모드에서 사용할 수 없다.
 
  - Edge Count 모드에서 타이머는 riding edge, falling edge, both 이렇게 3개의 이벤트 type을 captureing 할 수 있는 
    down-counter로서 설정된다.
  - Edge count 모드에서 타이머를 사용하기 위해, GPTMRnMR 레지스터의 TnCMR비트는 0으로 set 되어야 한다.
  - 타이머 카운터의 edge type은 GPTMCTL 레지스터의 TnEVENT fields에 의해 결정된다.
  - 초기화 동안, GPTM Timern Match(GPTMTnMATCHR) 레지스터는 GPTMTnILR 레지스터의 값과
    GPTMTnMATCHR 레지스터의 차이가 카운트 되어야만 edge event의 수가 같아질 수 있게 설정된다. 
 
  - 소프트웨어가 GPTM Control(GPTMCTL) 레지스터의 TnEN 비트를 write 할 때, 타이머는 envent capture로
    enable 된다.
  - CCP 핀에서 각 input event는  event count가 GPTMTnMATCHR과 match 될때까지 1씩 감소한다.
  - count가 match 될 때 GPTM은 GPTMRIS 레지스터의 CnRIS bit를 assert 한다.
  - 카운터는 GPTMTnILR에서 value를 이용해 reload 되고, GPTMCTL 레지스터의 TnEN 비트를 자동으로
    clear 함으로써 stop 한다.
  - event count가 완료되었을 때 모든 event는 TnEN이 소프트웨어적으로 re-enabled 될 때 까지 무시된다.
 



[16-Bit Input Edge Time Mode]
Note : rising-edge detection을 위해, input signal은 rising-edge가 발생한 다음 적어도 두개의 systel clock periods
         동안 High 상태를 유지해야 만 한다. 유사하게 falling-edge detection을 위해, input signal은 falling-edge
         으로 적어도 두개의 system clock periods 동안 Low 상태를 유지해야 한다. 이런 이유로 edeg-detection을 위한
          maximum input frequencysms system frequency의 1/4 이 된다.

Note : Prescaler는 16-Bit Input Edge Time 모드에서 사용할 수 없다.
 
  - Edge Time 모드에서 타이머는 GPTMTnILR 레지스터에서 loaded 된 값은 초기값으로 갖는 free-running
    down-counter로서 설정된다.
  - 이 모드는 rising edge, falling edge event capture 로 동작하지만 both로는 동작하지 않는다.
  - GPTMTnMR 레지스터의 TnCMR 비트를 setting함으로써 Edge Time  모드로 설정되고, event type은
    GPTMCnTL 레지스터의 TnEVENT field에 의해 결정된다.

  - 소프트웨어가 GPTMCTL 레지스터의 TnEN 비트를 write 할 때, 타이머는 event capture로 동작한다.
  - 선택된 input event가 detect되었을 때, 현재 Tn counter 값은 GPTMTnR 레지스터에서 capture 되고, controller에
    의해 read되어 사용할 수 있게 된다.
  - 그때 GPTM은 CnERIS 비트를 assert 한다 

  - event가 capture 된 후에 타이머는 counting을 stop 하지 않는다.
  - TnEN 비트가 clear될때 까지 count를 계속한다.
  - 타이머가 0x0000 상태가 되었을 때, GPTMnILR 레지스터로부터 값을 reloaded 한다.



[16-Bit PWM Mode]
Note
: Prescaler는 16-Bit PWM 모드에서 사용할 수 없다.

  - GPTM은 간단한 PWM generation 모드를 제공한다.
  - PWM 모드에서, 타이머는 GPTMTnILR에 의해 정의돈 start value를 갖는 down-counter로서 설정된다.
  - PWM 모드는 GPTMTnMR 레지스터의 TnAMS bit를 0x01, TnCMR bit를 0x0, TnMR field를 0x2로 setting
    함으로써  enable 된다.
 
  - 소프트웨어가 GPTMCTL 레지스터의 TnEN 비트를 write 할 때, 카운터는 0x0000이 될 때까지 counting down을
     시작한다.
  - 다음 counter cycle에서, 카운터는 GPTMTnILR로부터 start value를 reload하고 GPTMCTL레지스터의 TnEN
    비트를 소프트웨어 clear 함으로써 disable 될때까지 counting을 계속한다.
  - 어떤 인터럽트나 상태 비트도 PWM 모드에서는 assert 될 수 없다.

  - output PWM signal은 카운터가 GPTMTnILR 레지스트의 값일 때 assert 하고, 카운터가 GPTM Timern Match
     Register(GPTMnMATCHR)과 값이 같은 때 deassert 된다.
  - 소프트웨어는 GPTMCTL 레지스터의 TnPWML 비트를 setting 함으로써 output PWN signal을 반전 할 수 있다.




1.3 Timer 라이브러리 함수
Timer 모듈을 사용하기 위해서는 먼저 timer를 Enable 해야 한다. Enable 방법은 다음과 같다.

#define     SysCtlPeriEnable     SysCtlPeripheralEnable

SysCtlPeriEnable(SYSCTL_PERIPH_TIMERn);  
                              // 末尾的n取0、1、2或3

RTC, Input Edge Count, Input Edge Time, PWM 함수를 사용하기 위해서는  CCP의 입력 또는 출력 신호에 해당하는 핀을 사용해야 한다. 따라서 CCP에 해당하는 GPIO  포트를 구성해야 한다.

#define   CCP2_PERIPH   SYSCTL_PERIPH_GPIOD
#define   CCP2_PORT     GPIO_PORTD_BASE
#define   CCP2_PIN        GPIO_PIN_5

SysCtlPeripheralEnable(CCP2_PERIPH);           // 使能CCP2管脚所在的GPIOD
GPIOPinTypeTimer(CCP2_PORT, CCP2_PIN);   // 配置CCP2管脚为Timer功能




Configure & Control

TimerConfigure() - 타이머의 동작 모드를 설정한다.

TimerControlStall( ) - 명시된 timer를 위한 stall response를 제어한다.

TimerControlTrigger( ) - 명시된 타이머를 위한 trigger output을 제어한다.

TimerControlEvent( ) - capture mode일때 타이머를 trigger할 signal edge를 set한다.

TimerControlLevel( ) - 명시된 타이머를 위한  PWM output level을 set 한다.



Load & Value Get

TimerLoadSet( ) - 타이머 load value를 set한다.

TimerLoadGet( ) - 명시된 타이머에서 현재 프로그램된 interval load value 를 가져온다.

TimerValueGet( ) - 명시된 타이머의 현재값을 읽어온다.



Mode Enable/Disable

TimerEnable( ) - timer module의 동작을 enable 한다.

TimerDisable() - timer module의 동작을 disable 한다.

TimerRTCEnable( ) - RTC mode에서 타이머로 하여금 counting을 시작하도록 한다.

TimerRTCDisable( ) - RTC 모드에서 타이머로 하여금 counting을 멈추게 한다.

TimerQuiesce( ) -  타이머를 초기화 상태로 바꾼다


Match &  Prescaler

TimerMatchSet( ) - 타이머를 위한 match value를 set 한다.

TimerMatchGet( ) - 명시된 타이머에서 match value를 가져온다.

TimerPrescaleSet( ) - input clock prescaler의 값을 set 한다.

TimerPrescaleGet( ) - input clock prescaler의 값을 가져온다.




Interrupt Control

TimerIntEnable( ) - 타이머 인터럽트 source를 enable 한다.

TimerIntDisable( ) - 타이머 인터럽트 source를 Disable한다.

TimerIntClear( ) - 명시된 timer interrupt source가 clear 된다.

TimerIntStatus( ) - timer module의 인터럽트 상태를 return한다.

TimerIntRegister( ) - 타이머 인터럽트가 발생했을 때 호출될 handler를 set 한다.

TimerIntUnregister( ) - 타이머 인터럽트가 발생했을 때 호출될 handler를 clear 한다.

Posted by eoseontaek

LM3S8962  Interrupt 예제에 대하여 분석해 보았다.

우선 예제코드를 다운받는다.
Link : http://www.zlgmcu.com/luminary/exploitation_guide.asp


위의 링크된 사이트에 가서 3개의 파일 모두를 받는다.
맨 위의 pdf 문서는 interrupt libary를 설명한 문서이고, 아래의 두개의 zip 파일은 예제코드이다.

제1장. 인터럽트 제어
LM3SLib_Interrupt.pdf 문서의 초반부에 함수의 prototype에 대하여 설명하고 있다.


1.1 인터럽트 기본 프로그래밍 방법

Stellaris는 인터럽트를 위해 다음과 같은 Periperal Driver library가지고 있다.

1. Periperal 활성화
관련 인터럽트를 사용하기 위해서는 <sysctl.h>에 정의되어 있는 헤더 파일을 이용하여 SysCtlPeriperalEnable() 함수를 호출한다.

2. 인터럽트 type 설정
인터럽트를 활성화하기 전에 인터럽트 type을 정확히 설정한다.

3. 인터럽트 활성화
ARM core의 Stellaris 제품군은 3단계의 인터럽트를 활성화 순서를 거친다.
    ● 특정 핀 인터럽트 활성화
    ● 특정 전체 인터럽트 활성화 ( IntEnable() )
    ● 전체 프로세스 인터럽트 활성화 ( IntMasterEnable() )

4. 인터럽트 서비스 루틴
인터럽트 서비스 함수 이름 GCC 컴파일러는 인터럽트 서비스 함수의 이름을 사전에 예약해 놓고 있다. 인터럽트 서비스 함수는 "LM3S_Startup.s"에서 확인할 수 있다. 예를 들어 GPIOB 포트 인터럽트 함수의 이름은 GPIOB_Port_B_ISR이며, parameter와 return value는 void 형이어야 한다. void GPIO_Port_B_ISR(void) 
KEIL 또는 IAR 개발환경에서는 인터럽트 서비스 함수 이름은 프로그래머가 자체적으로 지정할 수 있다. 하지만 GCC의 표준을 따르기를 권장하고 있다.

인터럽트 상태 확인 하나의 PIN은 몇가지 인터럽트 소스를 갖는 Periperal 이지만 인터럽트 vector는 공유할 수 있다. 예를 들어 GPIOA는 8가지의 기능을 갖지만 Vector number는 16번으로 인터럽트 vector를 공유한다. 각 인터럽트 소스를 정확히 구분하기 위한 쿼리 함수를 통해 인터럽트의 상태를 읽오 온다. 예를들어 GPIO의 상태 쿼리 함수로 GPIOPinIntStatus()를 사용한다.

인터럽트 허가 ARM 코어의 Stellaris 제품군의 모든 periperal interrupt는 인터럽트 상태를 자동으로 clear하지 않는다. 따라서 소프트웨어적으로 clear 시켜주어야 한다. (Periperal에 속하지 않는 Cortex-M3 코어 Exception 은 자동 clear한다.). 만약 clear 시키지 않으면 인터럽트 서비스가 종료되는 즉시 다시 인터럽트가 발생한게 된다. clear를 통해 인터럽트 상태를 clear한다. 예를 들어 GPIO의 인터럽트 상태 clear 함수는 GPIOPinIntClear()이다.

5. 인터럽스 서비스 등록
인터럽트 서비스를 등록하는 방법에는 두가지가 있다. 첫번째는 인터럽트 서비스 함수를 직접 등록하는 것이다. 구현이 간단하다는 장점이 있는 반면에 SRAM에 매번 인터럽트 vector를 등록해 줘야하기 때문에 효율성이 감소되는 단점이 있다. 다른 방법은 시작파일을 수정하는 방법인데 구현이 효율적인 반면에 이동성이 없다는 단점이 있다.

개발환경마다 인터럽트 서비스 함수를 등록하는 방법에는 차이가 있다.
GCC GCC 컴파일러에서는 "LM3S_Startup.s" 파일안에 표준 함수들이 등록되어 있어서 수정없이 바로 사용할 수 있다.
Keil Keil 개발환경에서는 "Startup.s"  어셈블러 파일을 활용한다. 예를들어 "void I2C_ISR(void)" 인터럽트 핸들러를  Vector Table 등록하려면 "IntDefaultHandler"을 "I2C_ISR"로 바꾸어 주고, "EXTERN I2C_ISR"로 선언해 주면 된다.
IAR IAR 개발환경에서는 "startup_ewarm.c" 파일을 사용한다. 예를 들어 "void I2C_ISR(void)" 인터럽트 핸들러를 선언하고 인터럽트 vector table에 해당 "IntDefaultHandler"를 "I2C_ISR"로 교체해준다.

위의 단계를 완료하면 이벤트 발생시 프로그램이 자동적으로 해당 인터럽트 서비스 함수로 분기하여 처리하게 된다.

아래는 GCC 컴파일러의 인터럽스 서비스 함수를 나타낸다.


1.2 인터럽트 라이브러리 함수

1.인터럽트 Enable & Disable
전체인터럽트 Enable : IntMasterEnable()
전체인터럽트 Disable : IntMasterDisable()
    (예외 : Reset ISR, NMI ISR, Fault ISR - 언제든지 발생할 수 있으므로 소프트웨어적으로 Disable되지 않을 수 있다)

반면 IntEnable(), IntDisable() 라이브러리 함수는 칩 전체의 인터럽트 설정을 제어한다.
인터럽트는 두가지 범주로 구분이 되는데, 그 중 하나는  NMI, SysTick 과 같은 ARM Cortex-M3 프로세서 내부에서 발생하는 인터럽트 vector가 15이하인 인터럽트를 나타내며, 다른 하나는 GPIO, UART, PWM 과 같은 Vector 번호가 16 이상인 Stellaris 제품군에 의존적인 인터럽트이다.


IntMasterEnable() - 프로세스 인터럽트 Enable한다.


IntMasterDisable() - 프로세스 인터럽트 Disable한다.


IntDisable() - 명시된 인터럽트를 Disable한다.


IntEnable() - 명시된 인터럽트를 Enable한다.



Stellaris 제품군의 ARM 인터럽트 소스는 다음과 같다.


2. 인터럽트 우선순위

ARM Cortex-M3는 256개까지 인터럽트 우선순위 레벨을 조절할 수 있다. 하지만 Stellaris 제품군은 8개의 우선순위 레벨을 지원한다. 인터럽트 우선순위를 설정하는 것은 복잡한 제어시스템에서 매우 중요한 요소이다.

우선순위를 설정하기 위해 IntPrioritySet(), IntPriorityGet() 함수를 사용한다. 하나 이상의 인터럽트가 발생할 경우 가장 높은 우선순위를 갖는 인터럽트의 순서대로 먼저 처리하며, 동일한 시간에 생성된 인터럽트의 경우 우선순위가 높은 인터럽트를 먼저 처리한다. 낮은 우선순위의 인터럽트가 처리되는 동안 우선순위가 높은 인터럽트가 발생하면 프로세서는 즉시 높은 인터럽트 처리 루틴으로 전환한다.

IntPriorityGroupingSet(), IntPriorityGroupingGet()함수는 preemptable priority 레벨과 subpriority레벨의 그룹화 설정을 관리하는데 사용한다.

IntPrioritySet() - 인터럽트의 priority를 설정한다.


IntPriorityGet() - 인터럽트의 priority를 가져온다.



IntPriorityGroupingSet() - 인터럽트 컨트롤러의 Priority grouping을 설정한다.


IntPriorityGroupingGet() - 인터럽트 컨트롤러의 Priority grouping을 가져온다.



3. 인터럽트 서비스 함수 등록 및 취소

IntRegister() - 인터럽트가 발생했을 경우 호출될 함수를 등록한다.


IntUnregister() - 인터럽트가 발생했을 경우 호출될 함수를 등록해지한다.


Posted by eoseontaek


"C:\StellarisWare\boards\ek-lm3s8962\qs_ek-lm3s8962"에 있는 "qs_ek-lm3s8962.icf"를 분석해 보았다.

//*****************************************************************************
//
// qs_ek-lm3s8962.icf - Linker configuration file for qs_ek-lm3s8962.
//
// Copyright (c) 2007-2009 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 5450 of the EK-LM3S8962 Firmware Package.
//
//*****************************************************************************

//
// Define a memory region that covers the entire 4 GB addressible space of the
// processor.
//
define memory mem with size = 4G; 
// 전체 메모리 영역의 크기 정의 :: 4G
define memory mem with size = 4G;

//
// Define a region for the on-chip flash.
//
define region FLASH = mem:[from 0x00000000 to 0x0003ffff];
// on-chip flash 영역의 크기 지정
define region FLASH = mem:[from 0x00000000 to 0x0003ffff];


LM3S8962 메모리 맵에서 On-chip Flash 영역은 0x0000 0000 ~ 0x0003 FFFF (256KB) 인 것을 확인 할 수 있다.


//
// Define a region for the on-chip SRAM.
//
define region SRAM = mem:[from 0x20000000 to 0x2000ffff];
// on-chip SRAM영역의 크기 지정
define region SRAM = mem:[from 0x20000000 to 0x2000ffff];


LM3S8962 메모리 맵에서 Bit-banede on-chip SRAM 영역은 0x2000 0000 ~ 0x2000 FFFF (64KB) 인 것을 확인 할 수 있다.



//
// Define a block for the heap.  The size should be set to something other
// than zero if things in the C library that require the heap are used.
//
define block HEAP with alignment = 8, size = 0x00000000 { };

// Heap을 위한 block 영역을 정의
// Heap 이 사용되도록 하는  C 라이브러리가 있다면 heap의 size는 0보다 크게 설정해야 한다.
define block HEAP with alignment = 8, size = 0x00000000 { };

여기서는 Heap영역을 사용하지 않는다.


//
// Indicate that the read/write values should be initialized by copying from
// flash.
//
initialize by copy { readwrite };
// read/write value는 flash로부터 복사됨에 의해 초기화 되어야만 하는 것을 나타냄.
initialize by copy { readwrite };


//
// Indicate that the noinit values should be left alone.  This includes the
// stack, which if initialized will destroy the return address from the
// initialization code, causing the processor to branch to zero and fault.
//
do not initialize { section .noinit };
//noinit values 는 홀로 남아있어야만 함을 나타냄(초기화 되지 말야야 함). 이것은 stack을 포함하고, 만약 초기화되면 initialization code로부터 return address를 파괴하고 processor를 zero나 fault로 분기시키는 원인이 됨.
do not initialize { section .noinit };


//
// Place the interrupt vectors at the start of flash.
//
place at start of FLASH { readonly section .intvec };
// Flash의 시작에 interrupt vectors를 위치시킴.
place at start of FLASH { readonly section .intvec };


//
// Place the remainder of the read-only items into flash.
//
place in FLASH { readonly };
// read-only items의 나머지를 Flash로 위치시킴.
place in FLASH { readonly };


//
// Place the RAM vector table at the start of SRAM.
//
place at start of SRAM { section VTABLE };
// SRAM의 시작에 RAM vector table을 위치시킴.
place at start of SRAM { section VTABLE };


* 런타임시 인터럽트 벡터를 바꾸기 위해 SRAM 영역 사용.
* 어플에서 벡터테이블 위치를 바꾸게 하기 위해 사용.



//
// Place all read/write items into SRAM.
//
place in SRAM { readwrite, block HEAP };
// SRAM으로 모든 read/write items를 위치시킴.
place in SRAM { readwrite, block HEAP };


Posted by eoseontaek

1. IAR EWARM을 시작하고 File 메뉴에서 "New -> Workspace"를 클릭하여 새로운 Workspace를 생성한다.

2. Project 메뉴에서 "Add Existing Project..."를 선택하고, "C:\StellarisWare\driverlib"에서 "driverlib.ewp" 프로젝트 파일을 추가한다. 정상적으로 등록되면 아래 처럼 등록된다.

3. "C:\StellarisWare\driverlib"에 "LM3S_DriverLib.eww" 로 Worksapce를 저장한다.

4. "driverlib - Debug"에 오른쪽 마우스를 클릭하여 "Options..."를 선택하고, 필요한 옵션을 지정한다.

    ● "Generral Options" Category에서 "Target" 탭을 선택하고 "Device"를 "Luminary LM3Sx9xx"를 선택한다.

    ● "Generral Options" Category에서 "Output" 탭을 선택하고 "Library"를 선택한다.


    ● "C/C++ Complier" Category에서 "Optimizations" 탭을 선택하고 최적화 level을 "None"을 선택한다.
         이후에 온라인 시뮬레이션 및 디버깅을 수행할 수 있다.



     ● "Library Builder" Category에서 "Output" 탭을 선택하고 "Override default"를 체크후, 라이브러리 파일의 출력
        path를 설정한다.
        여기서는 "C:\StellarisWare\driverlib\ewarm\Exe\driverlib.a"에 driverlib.a 파일이 위치한다.


5. Project를 "Make"한다.
    "C:\StellarisWare\driverlib\ewarm\Exe"에 driverlib.a 파일이 위치하는 것을 확인 한다.


Posted by eoseontaek



[1] Luminary 공식 웹사이트(http://www.luminarymicro.com/) 에서 최신 드라이버 라이브러리를 다운로드 한다.
 StellarisWare complete Firmware Development Package(SW-LM3S-5450)을 다운로드한다.
 



[2] 기본 설정대로 install 한다.
C:\StellarisWare 에 기본으로 install된다.


Posted by eoseontaek
Posted by eoseontaek

Link : http://blog.naver.com/gaping2?Redirect=Log&logNo=20089851428


[국내]
    - 인텔레인(주) : http://www.intellane.com/
    - Air Gate : http://www.air-gate.co.kr/
    - 마이크로인피니티 : http://www.cruizcore.com/k_index.html


[국외]
    - XSENS : http://www.xsens.com/







Posted by eoseontaek
O 커널 소스 구하기
    - 공식 배포 사이트 : http://www.kernel.org/


O 커널 컴파일 하기
   커널 버전 확인 
   #uname -a

    커널 소스 다운로드 => http://www.kernel.org에 접속하여 최신 커널을 다운로드 한다.
    #wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.30.tar.bz2

    다운로드한 커널을 압축 해제한다.
    #tar -xvjf linux-2.6.30.tar.bz2

    생성된 디렉토리를 링크파일로 링크
    #ln -s linux-2.6.30 linux

    커널 설정값 초기화
    #make menuconfig

    커널 이미지 생성
    #make bzImage

    커널 모듈 생성
    #make modules

    생성된 object 파일들을 /lib/modules/커널버전 디렉토리로 복사
    #make modules_install

    모듈들이 정상적으로 설치되었는지 확인
    #ls -l /lib/modules/2.6.30/

    #ls -l /lib/modules/2.6.30/kernel/

    커널관련 파일 복사
    #make install

    /boot 디렉토리에 정상적으로 복사되었는지 확인
    #ls -l /boot

    /boot/grub/grub.conf 파일에 새로운 커널에 맞는 부팅 메뉴가 추가되었는지 확인
    #vi /boot/grub/grub.conf

    재부팅
    #reboot
 
    커널버전확인
    #uname -r   


Posted by eoseontaek
O 시스템 준비
    - 가급적 많이 사용하는 기종을 선택
    - 최신 기종보다는 한 단계 낮은 시스템을 선택

O 리눅스 배포판의 설치와 환경 설정
배포판 설치시 주의사항
    - 초보자는 가급적 전체 패키지 설치 권장
    - 부트로더 : 사용법이 간단하고 멀티부티을 지원하는 부트로더 선택

부팅디스크 확인
    - 부팅디스크 만드는 명령의 사용법
        #man mkbootdik 

커널버전 확인
    - 리눅스 커널에서 모듈이라는 방식을 지원하면서 부터 커널버전의 확인이 필요해짐.
    - 디바이스 드라이버를 컴파일하기 위해 참조하는 커널소스와 실제로 시스템에서 동작하는 커널의 버전이 같은지 확인.
    - 시스템에 설치된 커널버전 확인 명령
        #cat /proc/version
    - 디바이스 드라이버가 참조하는 커널소스 버전 - 커널소스가 있는 최상위 디렉토리의 Makefile에 기술되어 있음.
        #head /usr/src/linux/Makefile
    - 일치하지 않을 경우, 커널소스를 재컴파일하여 설치.

루트권한 설정
    - 단독시스템을 이용해서 가급적 root 권한으로 개발하는 것이 편리
    - root 사용자 권한에는 제한이 없기 때문에 삭제나 포멧같은 명령 사용시 주의해야 함.

    







Posted by eoseontaek

<이충무공전서>에 수록된 행장록의 유명한 장계 일부분입니다.


今臣戰船尙有十二 出死力拒戰則猶可爲也,
지금 신에게 아직 12척의 전선이 있으니,
죽을 힘을 다하여 막아 싸운다면 능히 대적할 방책이 있사옵니다.

戰船雖寡 微臣不死則不敢侮我矣.
전선이 비록 적다고 하더라도 미천한 신이 죽지 아니한 즉,
적이 감히 우리를 가볍게 여기지 못할 것이옵니다.

'[Z-01] 참고 ' 카테고리의 다른 글

Embedded Linux study 목표  (0) 2010.03.26
Embedded Linux 공부에 대해서  (0) 2010.03.26
__attribute__((packed))  (0) 2009.12.28
[UTIL] FileZilla  (0) 2009.12.21
[UTIL] EASEUS Partition  (0) 2009.12.21
Posted by eoseontaek
Link : http://sw-programming.blogspot.com/2006/06/attributepacked.html

프로그래밍중 가끔 실수하는것이 구조체의 바이트 정렬이다.
보통 시스템이 32비트이므로 4바이트로 정렬이 된다. 같은 머신에서 돌아가는 소프트웨어일 경우는 문제가 생기지 않으나 다른 머신과 통신하는 프로그램일 경우 문제가 발생한다.

typedef struct {
struct color{
uchar blue;
uchar read;
uchar black;
}
int made_in;
} apple;


위 구조체의 경우 __attribute__((packed))을 사용하지 않았으므로 8바이트가 할당된다.
color구조체는 3바이트만 사용했지만 바이트 정렬문제로 4바이트가 되서 총 8바이트다. 이런 문제를 사전에 방지하기 위해 __attribute__((packed))를 사용해야 한다.

typedef struct {
struct color{
uchar blue;
uchar read;
uchar black;
}
int made_in;
}__attribute__((packed)) apple;


윈도우의 비주얼씨에서는 #pragma pack(1)을 선언한다.

'[Z-01] 참고 ' 카테고리의 다른 글

Embedded Linux 공부에 대해서  (0) 2010.03.26
今臣戰船尙有十二  (0) 2009.12.28
[UTIL] FileZilla  (0) 2009.12.21
[UTIL] EASEUS Partition  (0) 2009.12.21
SAMPLE 전자에서 판매되는 각종 센서 모음 사이트  (0) 2009.12.08
Posted by eoseontaek

1.Host IP 주소를 입력한다.



2. Charater set translation on received data를 UTF-8로 설정한다.
 


3. Open을 누르면 아래와 같은 터미널 창이 나온다.
    login ID와 password를 입력 후, Host에 접속한다.
   




PyTTy 다운로드
Link : http://www.putty.nl/




Posted by eoseontaek


#man mkbootdisk    - mkbootdisk의 사용법







Posted by eoseontaek

'[B-01] Quad-rotor' 카테고리의 다른 글

Headholding  (0) 2009.12.22
Tilt-camera  (0) 2009.12.22
Outdoor flying  (0) 2009.12.22
Indoor flying  (0) 2009.12.22
GPS용 지도 만들기 입문  (0) 2009.12.04
Posted by eoseontaek
2009. 12. 22. 14:36




'[B-01] Quad-rotor' 카테고리의 다른 글

ZigBee Transmitter  (0) 2009.12.22
Tilt-camera  (0) 2009.12.22
Outdoor flying  (0) 2009.12.22
Indoor flying  (0) 2009.12.22
GPS용 지도 만들기 입문  (0) 2009.12.04
Posted by eoseontaek
2009. 12. 22. 14:26

'[B-01] Quad-rotor' 카테고리의 다른 글

ZigBee Transmitter  (0) 2009.12.22
Headholding  (0) 2009.12.22
Outdoor flying  (0) 2009.12.22
Indoor flying  (0) 2009.12.22
GPS용 지도 만들기 입문  (0) 2009.12.04
Posted by eoseontaek