본문 바로가기
Programming/Embedded

[Arduino Due]-basic timer interrupt code

by No Brainer 2022. 2. 18.

//타이머인터럽트를 이용하면 주기적인 연산(일정한 sampling time이 필요할 때)을 처리할 때 편하다.

//이 스케치에서는 dt주기로 타이머 인터럽트를 설정하고 그때마다 led를 on off제어 한다. 

//출력은 PB27번, DUE보드의 13번 핀이다.

 

float dt =0.2;  //sampling time. 이것이 인터럽트 발생의 주기가 됨.

 

 

//함수 프로토타입 선언

void confugure_pio();

void configure_timer_counter();

 

 

 

void confugure_pio()//pio의 환경설정

  pmc_enable_periph_clk(ID_PIOB);//PIOB를 사용하려면 PIOB로 가는 CLOCK을 활성화해야함.

 

  PIOB->PIO_PER = PIO_PB27;//PB27의 PIO기능을 ENABLE함

  PIOB->PIO_IDR = PIO_PB27;//PB27의 INTERRUPT DISABLE

  PIOB->PIO_OER = PIO_PB27;//PB27을 I/O라인의 OUTPUT으로 설정함.

 

}

 

 

//TC0을 사용하자. 타이머카운터 0번의 0번 채널

//타이머 인터럽트를 사용하도록 설정하자.

//타이머 인터럽트의 주기는 dt에 정의하면 매 dt의 시간마다 led를 on off하게 한다. 

//dt가 0.1이므로 인터럽트의 주기가 0.1초이며 10hz이다.

void configure_timer_counter()타이머 카운터의 환경설정

{

  pmc_set_writeprotect(false);//write protection기능을 꺼둠

  pmc_enable_periph_clk(ID_TC3);//peripheral clock을 enable시킴.

  

//TC_CMR를 환경설정하자.

//wavemode, upmode with automatic trigger on RC compare, TIMER CLOCK 1(MCK/2)로 환경설정됨.

  TC1->TC_CHANNEL[0].TC_CMR=(TC_CMR_WAVE) | (TC_CMR_WAVSEL_UP_RC) | (TC_CMR_TCCLKS_TIMER_CLOCK1);

  //CMR : Channel Mode Register  // 15th bit | 14th bit | 0th bit

  //14번 비트는 CPCTRG로, 1로 SET될 경우, RC compare resets the counter and starts the counter clock

 

 

//Register C(RC) is set to the maximum count  specified by the clock frequency divided by the desired frequency.

//RC contains the Register C value in real time.

  uint32_t rc = (uint32_t)((VARIANT_MCK/2)*dt);

  

  TC1->TC_CHANNEL[0].TC_RC = rc-1;  // TOP값=registor RC설정(그냥 TC_RC=rc라고 해줘도 된다)

  TC1->TC_CHANNEL[0].TC_RA = rc/2;  // Middle값=registor RA설정

 

  TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;  //RC compare interrupter을 활성화시킴

  //TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPAS;  

  TC1->TC_CHANNEL[0].TC_IDR = ~TC_IER_CPCS;  //RC compare interrupter을 제외한 interrupter을 disable시킨다. 근데 도대체 위에서 RA설정해 놓고 왜 다시 DISABLE시키는거지?

//TC1->TC_CHANNEL[0].TC_IDR = ~(TC_IER_CPCS | TC_IER_CPAS);

 

//And tell the Nested vector Interrupt Controller to enable our IRQ(interrupt requenst).//

//NVIC는 간단히 설명하면 INTERRUPT가 발생하여 MCU로 알려주면 CORE에서 INTERRUPT HANDLER를

//호출할지 , 무시할지, 혹은 어떤 순서로 호출할지 등을 결정하는 역할을 한다.

//흔히 우선순위가 높은 인터럽트를 호출하는 역할을 함.

  NVIC_EnableIRQ(TC3_IRQn);

 

//counter을 reset하고(SWRG), Counter clock을 enable함(CLKEN)

  TC1->TC_CHANNEL[0].TC_CCR=TC_CCR_CLKEN | TC_CCR_SWTRG;  //counter 을 리셋 한 후 counter clock을 enable한다

}

 

 

void setup() 

{

  Serial.begin(115200);

  void confugure_pio();  //PIO confuguration

  configure_timer_counter();  //tiemr/counter confuguration

}

 

 

 

void loop() 

{

  }// do nothing

 

 

void TC3_Handler()//timer counter 의 service routine. TC1의 CHANNEL 0에 해당하는 TIEMR COUNTER INTERRUPT

{

  static int flag=0;

  unsigned int status;

  

  status =TC1->TC_CHANNEL[0].TC_SR;// status 정보를 읽어 TC_SR을 0으로 CLEAR함.

  

  if(flag==0)

  {

    PIOB->PIO_SODR=PIO_PB27;// LED ON

    flag=1;

  }

  else

  {

    PIOB->PIO_CODR=PIO_PB27;//LED OFF

    flag=0;

  }

 

 

 

}