Timer : 시간의 주기를 정하는 것 (constant)
Counter : 0 ~ 정해진 주기값까지 변화를 저장하는 값 (variable)
28335 모데에서는 3개의 CPU Timer가 있다(0, 1, 3)
0과 1은 사용자가 사용이 가능하며,
2는 DSP/BIOS용으로 사용될 경우 BIOS 스케쥴링에 사용되지만, 사용하고 있지 않은경우
사용이 가능하다.
CPU 타이머는 PLL을 거친 SYSCLKOUT을 공급받아 작동한다.
TDDRH:TDDR(16bit:16bit)와 PRDH:PRD는 AVR의 프리스케일러와 같다.
타이머가 작동시 "PSCH:PSC" 는 TDDRH:TDDR의 값을 복사해온다.
그후 SYSCLKOUT의 한 클럭당 1씩 Down-counting을 하게된다.
이후 값이 0에서 -1이 되는 순간 "TIMH:TIM"에 1클럭의 신호를 보내게된다.
TIMH:TIM 또한 마찬가지로 PRDH:PRD의 값을 복사해와 대기중이다가 PSCH로부터 -1에 대한 신호를 받게되면 1클럭당 값을 1씩 Down-counting을 하게되고, 마찬가지로 0에서 -1이 되는 순간
TINT신호를 보내 인터럽트가 발생하게 된다.
따라서 인터럽트의 주기는 (1/SYSCLKOUT)x(TDDRH:TDDR+1)x(PRDH:PRD+1)이라고 볼수 있다.
28335의 SYSCLKOUT는 150MHz를 사용한다.
좀더 간략하게 정리하자면
16bit 카운터의 값이 SYSCLK과 만나 1씩 감소하며, 0에서 -1이 될때 인터럽트 발생
->이때 32bit 카운터의 값이 1씩 감소(똑같이 0에서 -1이 될때 비로소 Timer Interrupt 발생)
TDDR : Prescale의 값을 저장하는 곳
PSC : Prescale의 값이 로드된 후 SYSCLKOUT 1클럭 마다 -1씩 감소 0이되면 신호 발상
PRD : 주기 값을 저장하는 곳
TIM : 주기값을 로드 후 PSC신호 1클럭마다 -1씩 감소 0이 되면 비로소 인터럽트 발생
16bit T/C와 32bit T/C는 직렬로 연결되어 있어 48bit T/C로도 사용 가능
16bit는 Precsale 용 T/C
32bit는 CPU T/C로 사용
Timer 0/1/2는 각각 PIE Interrupt에 들어있다. (각각 1, 13, 14)
1/2는 우선순위가 낮아 PWM이나 ADC등보다 우선순위를 양보
CPU_Timer2 는 DSP에서 따로 사용하도록 할당되어 있기 때문에 사용 X
다음 레지스터 구성을 보자면
16bit 타이머는 아래와 같이 Prescale Register가 들어가 있다.
void InitCpuTimers(void)
{
// CPU Timer 0 - Initialize address pointers to respective timer registers
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT)
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters
CpuTimer0.InterruptCount = 0;
// CpuTimer2 is reserved for DSP BIOS & other RTOS
// Do not use this timer if you ever plan on integrating
// DSP-BIOS or another realtime OS.
// Initialize address pointers to respective timer registers
CpuTimer1.RegsAddr = &CpuTimer1Regs;
CpuTimer2.RegsAddr = &CpuTimer2Regs;
// Initialize timer period to maximum
CpuTimer1Regs.PRD.all = 0xFFFFFFFF;
CpuTimer2Regs.PRD.all = 0xFFFFFFFF;
// Make sure timers are stopped
CpuTimer1Regs.TCR.bit.TSS = 1;
CpuTimer2Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value
CpuTimer1Regs.TCR.bit.TRB = 1;
CpuTimer2Regs.TCR.bit.TRB = 1;
// Reset interrupt counters
CpuTimer1.InterruptCount = 0;
CpuTimer2.InterruptCount = 0;
}
차례대로 작성을하자면
void
ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
{
Uint32 temp;
//
// Initialize timer period
//
Timer->CPUFreqInMHz = Freq;
Timer->PeriodInUSec = Period;
temp = (long) (Freq * Period);
Timer->RegsAddr->PRD.all = temp;
//
// Set pre-scale counter to divide by 1 (SYSCLKOUT)
//
Timer->RegsAddr->TPR.all = 0;
Timer->RegsAddr->TPRH.all = 0;
//
// Initialize timer control register
//
//
// 1 = Stop timer, 0 = Start/Restart Timer
//
Timer->RegsAddr->TCR.bit.TSS = 1;
Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer
Timer->RegsAddr->TCR.bit.SOFT = 1;
Timer->RegsAddr->TCR.bit.FREE = 1; // Timer Free Run
//
// 0 = Disable/ 1 = Enable Timer Interrupt
//
Timer->RegsAddr->TCR.bit.TIE = 1;
//
// Reset interrupt counter
//
Timer->InterruptCount = 0;
}
Cpu Timer 예제에는 다음과 같이 작성되어있다.
ConfigCpuTimer(&CpuTimer0, 150, 1000000);
28335의 경우 150MHz로 작동된다.
따라서 정리하면
150MHz=> 1/150MHz =6.667nsec
6.667nsec x 150 =1usec
1usec * 1000000 =1 1sed 이므로 1/1sec = 1Hz 마다 도는 Interrupt 주기
Timer0의 경우는 약 7번째 우선순위 이다