04. CpuTimer 알아보기

안양진·2023년 2월 15일
0

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가 들어가 있다.

InitCpuTimers()

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;
}

차례대로 작성을하자면

  • 타이머 레지스터에 대한 포인터 초기화
  • 타이머 주기를 최대로 초기화 ->잘못쓰는것을 방지하기위해
  • 16bit CPU Timer/Counter Prescale Register 설정 -> 0 이므로 Prescale 사용 안함
  • 타이머를 중지시킨다.
  • TIMH:TIM가 PRDH:PRD값을 가져온다.그리고 Prescaler 카운터(PSCH:PSC)는 타이머 분할 다운 레지스터(TDDRH:TDDR)의 값으로 로드됩니다.
  • 인터럽트 카운터 초기화
  • 그 후 아래는 타이머 1/2의 초기화로 같은 내용이다.

ConfigCpuTimer()

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;
}
  • 전체 주기 = 주파수 x 프리스케일 주기
  • 전체 주기를 PRD에 입력 (Period Register에 입력)
  • No prescale (Precale Register)
    -> 이전에 PRD에 주기를 입력하여 프리스케일 사용 X
  • STOP Timer
  • Reload Timer
  • 프리러닝 모드
  • 타이머 인터럽트 허용

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번째 우선순위 이다

0개의 댓글