반응형
#include "timer.h"


static volatile unsigned int uiTic; // Timer_Handler 함수 호출을 카운트, 1m초


 

void Timer0_Init(void)

{

PMC_PCER = 1 << TC0; // PMC_PCER(Peripheral Clock Enable Register)에 타이머카운터 장치 활성화, P204, P33

// TC0(타이머카운터 0)에 클럭이 공급된다.


// 1. 시작 : 타이머 클럭 비활성화 ------------------

TC0_CCR = 1 << CLKDIS; //카운터 클럭 비활성화 명령(CLKDIS)을 Enable


// 2. 시작 : 타이머 인터럽트 비활성화 -------------

TC0_IDR = (1 << COVFS)|(1 << LOVRS)|(1 << CPAS)|(1 << CPBS)

|(1 << CPCS)|(1 << LDRAS)|(1 << LDRBS)|(1 << ETRGS); // 타이머 인터럽트 비활성화(TC_IDR 설정)

TC0_SR;// 타이머카운터 상태 레지스터 초기화(TC_SR 읽기)


TC0_CMR = (TIMER_CLOCK4 << TCCLKS) | (1 << CPCTRG); /*TC0_CMR(채널 모드 레지스터)에서

TCCLKS(Clock Selection)에 3을 넣어 분주비 128(TIMER_CLOCK4) 설정 | RC 비교방식 트리거 활성화*/


TC0_RC = 375; // MCK divided by 128 => 375000Hz, 1CK = (about)2.67us [TC_RC(Register C)설정]

// 한마디로 1ms에 인터럽터를 발생시키기 위해 375로 설정


// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------

AIC_IDCR = 1 << TC0; // 인터럽트 비활성화(AIC_IDCR) = Enable(1) << 타이머 카운터 0(TC0)


AIC_SVR[TC0] = (volatile unsigned int)Timer_Handler;

/*AIC_Source Vector Register = 타이머 카운터 0 인터럽트 핸들러 등록

여기서 Vector 레지스터는 인터럽트가 발생하면 점프하게 될 함수(ISR:인터럽트 서비스 루틴) 주소만을 저장할 수 있다.

함수 전체를 저장할 수 있으면 좋겠지만, 그러기엔 ARM 레지스터의 용량이 너무 작다.


Vector 가 뭔지 궁금해 하시는 분들을 위해

- 우리의 ARM은 폴링형 인터럽트와 vector형 인터럽트 등 인터럽트 처리방법 중에 vector형 인터럽트 처리 방식을 사용한다.

1. Polling 형 인터럽트

- 폴링은 투표, 개표 라는 뜻이다. 즉 CPU가 소프트웨어적으로 보드에 인터럽트를 낼수있는 하드웨어들을 차례대로

검사하는 방식이다. 하드웨어가 간단하고 저렴하지만, 인터럽트를 낼수있는 하드웨어 갯수 증가에 따라 속도가 느려진다.

이후 인터럽트가 검출된 장치를 처리한다. 여기서 "처리한다" ISR(Interrupt Service Rutine)이라고 한다.


2. vector 형 인터럽트

- cpu가 소프트웨어적으로 하드웨어들을 검사하는것이 아니라,

인터럽트를 발생시킨 장치가 cpu에 ISR(우리가 만든 핸들러 함수)의

시작 번지를 제공하면 cpu가 이것을 먼저 처리하는 방식.

이 ISR들은 기본적으로 interrupt vector에 저장되어 있고 더 나아가

사용자가 ISR을 설정해주고 싶으면 Interrupt Handler를 작성/등록(AIC_SVR[TC0])해주면 된다.

하드웨어가 복잡하고 비싸지만, 빠르고, 장치 갯수에 상관없이 언제든지! 서비스를 제공한다.

AT91SAM7S256, atmega2560 등 에서는 이방식을 사용한다.


AIC_SMR[TC0] = (0 << PRIOR)|(3 << SRCTYPE);

/* TC0 인터럽트 소스 모드 레지 = 우선순위레벨(Priority Level)을 0 |

여기서 만약, 인터럽트 두개가 동시에 발생하면 ?

polling 방식은 순차적으로 장치를 검사하기 때문에 그 순서대로 우선순위를 정하지만

vector 방식은 인터럽트 우선순위를 제어할 수 있는 레지스터(AIC_SMR)가 존재하여,

레지스터에 값을 집어넣어 우선순위를 정한다.

[출처] [AVR] Interrupt|작성자 태희로그

[출처] [AVR] Interrupt|작성자 태희로그


Interrupt Source Type(SRCTYPE) High level Sensitive로 설정*/



AIC_ICCR = 1 << TC0; // 타이머 카운터 0 인터럽트 클리어(TC0)


TC0_IER = 1 << CPCS;

/* 타이머 카운터 인터럽트 활성화 레지스터 = RC 비교 인터럽트만 활성화*/


// 2. 끝 : 타이머 인터럽트 비활성화 ---------------


AIC_IECR = 1 << TC0; // 타이머 카운터 0 인터럽트 활성화(AIC_IECR, TC0)


// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------


TC0_CCR = 1 << CLKEN; // 타이머 클럭 활성화(TC_CCR, CLKEN)


// 1. 끝 : 타이머 클럭 비활성화 ------------------


TC0_CCR = 1 << SWTRG; // 타이머 시작(TC_CCR, SWTRG)


}


void Timer_Handler(void)

{

TC0_SR; //핸들러가 호출되면 현재 인터럽트가 발생된 상태이기 때문에

//다음 인터럽트가 발생할 수 있도록 상태 레지스터 초기화

++uiTic;

return;

}


void ms_Delay(unsigned int uims)

{

uiTic = 0;

while(uims > uiTic); //이 함수를 종료하려면 uims를 기다려야 한다

// uiTic은 1ms마다 증가하므로 uims에 1000을 넣으면

//약 1초를 기다려야 반복문이 종료된다.

}


 

반응형

+ Recent posts