본문 바로가기
Programming/Embedded

[Arduino Due]-basic pin change interrupt code

by No Brainer 2022. 2. 18.

 

/* pin26(PD1)    SW1

 * pin27(PD2)    SW2

 * 

 * pio interrupt를 설정하는 방법을 학습할 수 있음

 * 아두이노 라이브러리의 attachinterrupt()를 사용하면 매우 고속으로 변화하는 

 * pin change에 대응하기 힘들다. 인터럽트 지연이 길기 때문.

 * 따라서 이 스케치에서는 attachinterrupt를 사용하지 않고 직접 PIO handler을 정의하기

 * 로 한다.(이렇게 직접 PIO HANDER를 정의하여 사용하려면 winterrupts.c에서 

 * 사용하고자 하는 pio handler을 weak선언 해주어야 함.(아두이노 라이브러리를 무효화

 * 시키는 작업) 현재 모든 pio handler에 weak선언을 해두었다.

 * 

 */

 

void configure_pio_interrupt();//함수 프로토타입 선언

 

void setup()

{

  Serial.begin(115200);

  

  configure_pio_interrupt();//pio and pio interrupt의 환경설정

}

 

 

void loop()//아무것도 안함

{}

 

//아두이노 듀의 모든 pio는 외부 인터럽터를 설정할 수 있음.

void configure_pio_interrupt()

{

  pmc_enable_periph_clk(ID_PIOD); //PIOD에 clock 공급하는 함수

 

  PIOD->PIO_AIMDR = PIO_PD1 | PIO_PD2;  ///PD1과 PD2의 인터럽트를 default(초기값)인 both edge detection으로 함.

  PIOD->PIO_IDR = PIO_PD1 | PIO_PD2;  ///pd1과 2의 외부인터럽트 기능을 disable시킴

  PIOD->PIO_PER = PIO_PD1 | PIO_PD2;  ///그리고 1과 2의 pio기능을 enable시킴

  PIOD->PIO_ODR = PIO_PD1 | PIO_PD2;  ///1과 2를 input 으로 설정함. 

  //일단 아래의 glitch filter에 관련한 코드를 설정하기 위해

  //해당 pio의 interrupt기능을 disable한 것 같음

  /*

  #if 0  //falling or rising 중 하나만 사용할 때

  PIOD->PIOD_AIMER = PIO_PD1 | PIO_PD2;

  PIOD->PIO_ESR = PIO_PD1 | PIO_PD2; //interrupt source is edge detection event. PIO_ELSR의 경우 해당하는 칸을 0으로 설정하면 EDGE detection 이고 1로 설정하면 level detection임.

  PIOD->PIO_REHLSR = PIO_PD1 | PIO_PD2; //interrupt source을 rising edge detection이나 high level detection으로 설정함.

  #endif

  */ 

 

  #if 0  //빠른 신호에 사용

  PIOD->PIO_SCIFSR = PIO_PD1 | PIO_PD2; 

  #endif

  

  #if 1 //느린 신호에 사용

  PIOD->PIO_DIFSR = PIO_PD1 | PIO_PD2; 

  PIOD->PIO_SCDR=10;  //clock division

  #endif

  PIOD->PIO_IFER = PIO_PD1 | PIO_PD2;//input glitch filter 기능을 enable함.

 

  

  //위에서 해제한PD1,PD2의 인터럽터기능을 복구시켜줌

  PIOD->PIO_IER = PIO_PD1 | PIO_PD2;  

 

//NVIC:Nesting(2개 이상 작동 가능한) Vectored Interrupt Controller. //interrupt의 우선순위를 정할 수 있다  

  NVIC_DisableIRQ(PIOD_IRQn);   //일단 interrupt를 disable시킴. 

  NVIC_ClearPendingIRQ(PIOD_IRQn);   //Clear IRQn pending status . pending: 인터럽트 발동 대기

  NVIC_SetPriority(PIOD_IRQn,1);   //NVIC의 priority번호를 설정. systick interrupt의 priority를 0으로 설정했으므로 그것보다 한단계 낮게 설정.

  NVIC_EnableIRQ(PIOD_IRQn); // interrupt를 enable시킴. 

}

//PIOD의 interrupt handler(인터럽트 신호의 처리를 위한 프로그램,함수). 

//여기서는 직접 PIOD의 INTERRUPT HANDLER을 가져다 쓴것임.

void PIOD_Handler(void)

{

  uint32_t status, PD_value;

 

  status =PIOD->PIO_ISR; //pin chanege가 있는지를 나타내는 레지스터. 만일 PD1에 핀변화가 있다면 레지스터의 P1에 1이 들어감.

  

  PD_value=PIOD->PIO_PDSR;//pin data status registor. I/O라인의 상태(0인지 1인지)를 읽음.

 

 

 

//PIO_PD1의 값은 0X00..0010으로, 헤더파일에 정의되어 있음.

  if(status & PIO_PD1) //

  {

    if(PD_value & PIO_PD1)  //현재 PD상태는 1인데, I/O라인에서 읽어온 정보또한 1임.

    {

      Serial.println("SW1 has just been released");

    }

    else  //falling 변화가 있었는데, 그결과 현재 PD1의 상태가 0임> 즉 falling edge임.

    {

      Serial.println("SW1 has just been pushed");

    }

  }

 

 

  

   if(status & PIO_PD2)

  {

    if(PD_value & PIO_PD2)

    {

      Serial.println("SW2 has just been released");

    }

    else

    {

      Serial.println("SW2 has just been pushed");

    }

  }

}