2011년9월6일_ARM_AT91SAM7S256 타이머/카운터(TC)


                       개   요

● 채널 TC0 ~ TC2까지 총 3개의 16비트 타이머/카운터(Timer/Counter)를 가지고 있음.

● 이들 3개의 채널은 서로 독립적으로 동작하며, 아래의 기능들을 수행할 수 있다.
   ① 이벤트 카운트
   ② 주파수 측정
   ③ 시간 간격 측정
   ④ 시간 지연
   ⑤ 펄스 발생
   ⑥ PWM출력      

● 사용자가 타이머/카운터 채널을 사용하려면 해당 채널의 기능을 제어하는 I/O레지스터를 사용해야 함.
    TC_BCR(블록제어)와 TC_BMR(블록모드) 레지스터들은 3개의 채널에 공통으로 사용된다.

● 파형발생 모드에서는 타이머/카운터 입/출력 단자로 사용된다.
    이들 신호를 사용하려면 병렬 입출력 제어기(PIO)에서 Peripheral B로 설정해야 한다.

● 마스터클록을 분주(2, 8, 32, 128, 1024)한 신호를 입력할 수 있다.
    외부클록은 XC0~XC2로 입력한다.

● 타이머/카운터는 기본적으로 클록이 공급되지 않는 상태이므로 사용하려면,
   전력관리제어기(PMC)에서 클록을 공급하도록 설정해야 한다.



image

좌측 TIMER_CLOCK1 ~ 5는 각각 마스터 클록을 분주(2, 8, 32, 128, 1024)한 주파수 신호이다.
검은색사각형으로 화살표가 그려져 있는데 이 검은 사각형이 Timer Counter이고,
내부에는 3개의 채널별 TC모듈이 있다.
TC우측에 PIO가 있고 TC와 연결되어 외부로부터 TC로 클록을 입력할 수 있다.
각 핀 배치는 Datasheet p.36 PIO 제어기 A 멀티플렉싱 참조할 것.

image

Peripheral B모드를 사용하려면 PIOA관련 레지스터 PIOA_BSR의 해당 핀을 1로 세트함으로 사용할 수 있다.
외부핀을 마음대로 설정할 수 있는 듯 해보여 좋다고 생각했으나 역시 아니었다.

이론은 그만하고 TC를 초기화하는 코드를 작성해보자.




● 타이머/카운터 중 채널0인 TC0를 초기화하는 과정

① 전력 공급차단                                                  PMC_PCER 레지스터
② TC0 전체 클록 공급차단                                       TC0_CCR 레지스터
③ TC0 인터럽트 금지                                             TC0_IDR 레지스터
④ TC0의 상태를 읽어와 상태레지스터를 0으로 초기화       TC0_SR 레지스터
⑤ TC0 전체 인터럽트 금지                                       AIC_IDCR 레지스터
⑥ TC0 인터럽트 서비스 루틴을 지정                           AIC_SVR[] 레지스터
⑦ TC0 인터럽트 신호 검출 모드 설정                          AIC_SMR[] 레지스터
⑧ TC0 인터럽트 클리어 (에지 검출기 클리어)                 AIC_ICCR 레지스터
⑨ TC0 카운트모드 설정                                          TC0_CMR 레지스터
⑩ TC0 인터럽트 활성                                             TC0_IER 레지스터
⑪ TC0 전체 인터럽트 활성                                       AIC_IECR 레지스터

타이머하나 사용하는데 설정해야 하는 레지스터가 왜 이리 많누...
외부인터럽트도 그렇고...


▷ Timer.h

   1: #ifndef __TIMER_H__        // 9월 6일추가 분할컴파일.
   2: #define __TIMER_H__
   3:  
   4: #include "PMC.h"        //다른 헤더파일은 헤더파일에서 include
   5: #include "AIC.h"
   6:  
   7: /*********************************************************
   8:                     TC (AT91SAM7S256)
   9: *********************************************************/
  10: #define TC0_CCR        (*(volatile unsigned int *)0xFFFA0000)        //TC0 채널 제어
  11: #define TC0_CMR        (*(volatile unsigned int *)0xFFFA0004)        //TC0 채널 모드
  12: #define TC0_SR        (*(volatile unsigned int *)0xFFFA0020)        //TC0 상태 
  13: #define TC0_IER        (*(volatile unsigned int *)0xFFFA0024)        //TC0 인터럽트 활성.
  14: #define TC0_IDR        (*(volatile unsigned int *)0xFFFA0028)        //TC0 인터럽트 비활성.
  15:  
  16:  
  17: #define    TC0            12    //TC의 PID
  18: #define    CLKDIS        1    //카운터 클록 비활성.
  19: #define    TCCLKS        0    //분주비 선택. 
  20: #define    CPCTRG        14    //RC비교 트리거 활성비트
  21: #define    CPCS        4    //RC비교 인터럽트 활성비트
  22:  
  23:  
  24: void Timer_INIT(void);
  25: void MyCounter(void);
  26:  
  27: #endif    //__TIMER_H__
  28:  


▷ Timer.c

   1: #include "Timer.h"
   2:  
   3:  
   4: void Timer_INIT(void)
   5: {
   6:     PMC_PCER = (1 << TC0);        //타이머/카운터0에 전력공급. (clock)
   7:     TC0_CCR = (1 << CLKDIS);        //TC0에 클록이 공급되지 않도록.
   8:     TC0_IDR = 0xFFFFFFFF;        //TC0인터럽트 금지.
   9:     TC0_SR;                        //TC0상태레지스터를 읽어 오기만 함. (임베디드에서 많이 사용)
  10:     AIC_IDCR = (1 << TC0);        //타이머/카운터장치 전체 인터럽트 비활성.
  11:     AIC_SVR[TC0] = (unsigned int)MyCounter;        //인터럽트 서비스 루틴의 주소값 저장. SVR[] (배열의 값)은 unsigned int형
  12:     AIC_SMR[TC0] = (2 << SRCTYPE) |(0 << PRIOR);    //High레벨 검출, 우선순위 최하
  13:     AIC_ICCR = (1 << TC0);        //엣지 검출기 클리어.
  14:     TC0_CMR = (1 << CPCTRG) | (0 << TCCLKS);        //compare모드, 분주비 1/2
  15:     //여기서까지 선생님 코드 
  16:     TC0_IER = (1 << CPCS);        //RC 비교 인터럽트 활성.
  17:     AIC_IECR = (1 << TC0);        //TC0 전체 인터럽트 활성.
  18:     
  19:     return ;
  20: }
  21:  
  22: void MyCounter(void)
  23: {
  24:     return ;
  25: }
  26:  


<소스분석>

  14:     TC0_CMR = (1 << CPCTRG) | (0 << TCCLKS);        //compare모드, 분주비 1/2

타이머동작모드를 compare모드로 하고 분주비는 2로 하고 싶다.

image 

TC0_CMR레지스터인데 상기의 스크린샷에는 TC_CMR0로 되어 있다. (x는 채널번호)
0~2번 비트 TCCLKS와 14번 비트 CPCTRG를 설정해야 한다.

image 

우선 비교매치인터럽트를 14번 비트 CPCTRG를 1로 세트한다.
RC비교가 카운터를 리셋하고 클록을 공급하기 시작한다.


image

상기의 클록선택표에서,
내부클록 MCK를 사용하고 분주비는 2로 하기 위해서 TIMER_CLOCK1을 선택한다.
TCCLKS 비트들은 모두 0이 되면 된다.




● 타이머 인터럽트 동작방식

image

오버플로 인터럽트방식은 타이머값을 초기에 주고 타이머가 작동한 뒤에 16bit의 최대값인 65535에서 +1되어 0이 될 때,
발생하므로 주기적으로 반복되는 일이 이 신호를 받아 동작한다면,
ISR(인터럽트 서비스 루틴)내에 타이머값 초기화 코드를 넣어야 하므로 시간이 정확히 맞지 않고 느리다.

비교매치 인터럽트방식은 타이머값이 초기에 0으로 시작해,
비교대상이 되는 값과 비교하여 맞으면 타이머값은 자동으로 0이 되고 인터럽트가 발생한다.
한 번 비교대상의 값을 기입하면 되므로 오버플로모드에 비해 속도가 빠르고 정확하다.