2011년9월1일_ARM_외부핀(PIOA)로 인터럽트를 받기. 확인은 LED



● 선생님 소스에 주석달아놓은 것

   1: /*********************************************************
   2: 
   3:     제    목: 외부핀(PA7) 인터럽트 받아 PA0번에 연결된,
   4:                 LED ON/OFF 토글하기
   5:     
   6: *********************************************************/
   7:  
   8: #include "PIOA.h"
   9:  
  10: /*********************************************************
  11:                     PMC (AT91SAM7S256)
  12: *********************************************************/
  13: #define PMC_PCER        (*(volatile unsigned int *)0xFFFFFC10)    //주변장치 클록 허용 Reg.
  14:  
  15: /*********************************************************
  16:                     AIC (AT91SAM7S256)
  17: *********************************************************/
  18: #define AIC_IECR        (*(volatile unsigned int *)0xFFFFF120)    //인터럽트 허용 명령
  19: #define AIC_IDCR        (*(volatile unsigned int *)0xFFFFF124)    //인터럽트 금지 명령
  20: #define AIC_ISCR        (*(volatile unsigned int *)0xFFFFF12C)    //인터럽트 세트 명령
  21: #define AIC_ICCR        (*(volatile unsigned int *)0xFFFFF128)    //인터럽트 클리어 명령
  22: #define AIC_SMR        ((volatile unsigned int *)0xFFFFF000)        //32개이니 시작주소 array
  23: #define AIC_SVR        ((volatile unsigned int *)0xFFFFF080)        //32개이니 시작주소 array
  24: #define AIC_EOICR        (*(volatile unsigned int*)0xFFFFF130)    //인터럽트 종료 명령 레지스터 
  25: #define    PIOA        2    //PIOA PID
  26: #define    INT_PIN        7    //7번핀으로 인터럽트를 받음. 이 MCU는 모든 핀으로 인터럽트를 받을 수 잇음.
  27: #define    SRCTYPE        5    //검출 모드 
  28: #define    PRIOR        0    //우선 순위
  29: #define    LED            0    //0번 핀에 LED연결
  30:  
  31: void Interrupt_INIT();     //9월 1일 추가
  32: void HANDLER();            //인터럽트 서비스 루틴
  33: void LED_INIT();        //LED가 연결된 포트 초기화
  34:  
  35: int main(void)
  36: {
  37:     LED_INIT();            //LED를 사용하겠다.
  38:     Interrupt_INIT();    //외부핀 인터럽트를 받겠다.
  39:  
  40:     while(1);            //return되면 안됨. 돌아갈 곳이 없어. 집이 없어. 
  41:  
  42:     return 0;
  43: }
  44:  
  45: void HANDLER(void)                    //인터럽트 신호 들어온 장치 ID 찾는 함수 
  46: {
  47:     static volatile unsigned int isr;    //여기서 값 대입하면 static변수라 한번만 사용하게 됨!!
  48:     volatile unsigned int cnt;
  49:  
  50:     isr=PIOA_ISR;    //신호 들오온 장치 번호 저장 
  51:                     //(한번 읽으면 레지스터내용은 지워지므로 변수에 저장)
  52:  
  53:     if(0 != ((1<<INT_PIN) & isr))            //7번 비트 &  읽어온 번호 , 7번에 들어오면  1  
  54:     {
  55:         if(0 != ((1 << LED) & PIOA_ODSR))    //LED가 꺼져 있으면
  56:         {                                    //LED를 킨다.
  57:             PIOA_CODR = (1 << LED);        
  58:         }
  59:         else                                //LED가 켜져 있으면
  60:         {                                    //LED를 끈다.
  61:             PIOA_SODR = (1 << LED);
  62:         }
  63:     }    
  64:     for(cnt=0;1000000>cnt;cnt++);            //약 0.5초의 딜레이
  65:     isr=PIOA_ISR;    //왜 또 저장하지? 인터럽트 상태를 지우기 위해?
  66:     
  67:     AIC_EOICR=0;    //인터럽트 서비스루틴이 종료하다고 적음.
  68:  
  69:     return ;
  70: }
  71:  
  72: void LED_INIT()
  73: {
  74:     PIOA_PER = (1 << LED);            //포트사용
  75:     PIOA_OER = (1 << LED);            //출력 활성
  76:     PIOA_PPUDR = (1 << LED);        //풀업 없앰
  77:     PIOA_SODR = (1 << LED);        //LED Off
  78:     
  79:     return ;
  80: }
  81:  
  82: void Interrupt_INIT()
  83: {
  84:     PMC_PCER = (1 << PIOA);            //PID2 = PIOA에 
  85:     PIOA_ODR = (1 << INT_PIN);            //7번핀 입력을 받기 위해 출력 비활성화
  86:     PIOA_PER = (1 << INT_PIN);            //7번핀 포트를 사용함.
  87:  
  88:     PIOA_IDR    = (1 << INT_PIN);        //PIOA 인터럽트 비활성.
  89:     AIC_IDCR = (1 << PIOA);            //인터럽트 설정하는 도중 인터럽트가 걸리면 안되.
  90:  
  91:     AIC_SVR[PIOA] = (unsigned int)HANDLER;        //SVR[] (배열의 값)은 unsigned int형
  92:     AIC_SMR[PIOA] = (2 << SRCTYPE) |(0 << PRIOR);    //상승에지, 우선순위 최하
  93:  
  94:     AIC_ICCR    = (1 << PIOA);            //에지 검출기 클리어
  95:     PIOA_IFER = (1 << INT_PIN);        //글리치 필터 적용.
  96:     AIC_ISCR = (1 << PIOA);            //에지 검출기를 세트한다.
  97:  
  98:     PIOA_IER = (1 << INT_PIN);            //인터럽트 허용.
  99:     AIC_IECR = (1 << PIOA);            //PIOA장치 인터럽트 허용.
 100:     
 101:     return ;
 102: }
 103:  



● PIOA.h (병렬 입출력 제어기관련 레지스터 정의)

   1: #ifndef __PIOA_H__
   2: #define __PIOA_H__
   3:  
   4: /*********************************************************
   5:                     PIO (AT91SAM7S256)
   6: *********************************************************/
   7: #define PIOA_PER    (*(volatile unsigned int *)0xFFFFF400)    //포트 활성
   8: #define PIOA_OER    (*(volatile unsigned int *)0xFFFFF410)    //포트 출력사용
   9: #define PIOA_ODR    (*(volatile unsigned int *)0xFFFFF414)    //포트 출력x
  10: #define PIOA_PPUDR    (*(volatile unsigned int *)0xFFFFF460)    //포트 풀업x
  11: #define PIOA_CODR    (*(volatile unsigned int *)0xFFFFF434)    //포트 클리어
  12: #define PIOA_SODR    (*(volatile unsigned int *)0xFFFFF430)    //포트 세트
  13: #define PIOA_IFER    (*(volatile unsigned int *)0xFFFFF420)    //글리치 필터
  14: #define PIOA_IER    (*(volatile unsigned int *)0xFFFFF440)    //인터럽트 허용 PIOA를 먼저 거친다.
  15: #define PIOA_IDR    (*(volatile unsigned int *)0xFFFFF444)    //인터럽트 금지 PIOA를 먼저 거친다.
  16: #define PIOA_ISR    (*(volatile unsigned int *)0xFFFFF44C)    //인터럽트 상태
  17: #define PIOA_ODSR    (*(volatile unsigned int *)0xFFFFF438)    //출력 데이터 상태
  18: #define PIOA_PDSR    (*(volatile unsigned int *)0xFFFFF43C)    //핀 데이터 상태
  19:  
  20: #endif    //__PIOA_H__

<실행결과>



<소스분석>

  35: int main(void)
  36: {
  37:     LED_INIT();            //LED를 사용하겠다.
  38:     Interrupt_INIT();    //외부핀 인터럽트를 받겠다.
  40:     while(1);            //return되면 안됨. 돌아갈 곳이 없어. 집이 없어. 

ARM이 리셋되어 시작하면 startup코드들을 실행하고 main()로 분기한다.
main()에서는 LED_INIT()과 Interrupt_INIT()를 호출하여 LED가 연결된 포트와 인터럽트를 활성시킨 후 무한 대기한다.
즉, 초기화 후에는 아무 일도 하지 않는다.

  29: #define    LED            0    //0번 핀에 LED연결
  74:     PIOA_PER = (1 << LED);            //포트사용
  75:     PIOA_OER = (1 << LED);            //출력 활성
  76:     PIOA_PPUDR = (1 << LED);        //풀업 없앰
  77:     PIOA_SODR = (1 << LED);        //LED Off

LED_INIT()에서는 PA0를 사용하기 위해 PIOA관련 레지스터의 최하위비트 0번비트에 1을 써서 PA0설정을 한다.
PER은 포트활성으로 포트를 사용하겠다는 말이고,
OER은 출력활성으로 포트에 있는 출력버퍼를 Hi-Z상태가 아닌 정상적인 상태(ON/OFF)로 만듬.
         출력버퍼가 Hi-Z상태이면 입력을 받을 수 있음.
PPUDR은 책에 PUDR로 적혀있고 핀에 풀업 저항을 비활성화 시키는 레지스터로 PA0에 달린 풀업저항을 쓰지 않겠다는 말이다.
SODR은 출력을 1 (High Level)로 만드는 레지스터로 PA0을 High Level로 초기화한다.
          이렇게 되면 PA0에는 MCU VDDIO핀에 공급되는 +3.3V가 출력된다.
          VDDIO핀은 외부장치와 연결에 사용되는 전압으로 core는 1.8V로 낮고 주변장치는 높으니 전압레벨을 맞추기 위해 존재.

  25: #define    PIOA        2    //PIOA PID
  84:     PMC_PCER = (1 << PIOA);            //PID2 = PIOA에 
  85:     PIOA_ODR = (1 << INT_PIN);            //7번핀 입력을 받기 위해 출력 비활성화
  86:     PIOA_PER = (1 << INT_PIN);            //7번핀 포트를 사용함.
  88:     PIOA_IDR    = (1 << INT_PIN);        //PIOA 인터럽트 비활성.

PMC_PCER은 주변장치에 클럭을 공급하여 주변장치를 동작시킬 수 있도록 설정할 수 있는 레지스터로,
(1 << PIOA) => (1 << 2)  2번 비트를 1로 세트하여 PIOA장치를 켠다.
왜 그런지 아래의 표와 그림을 보고 알아보자.
 

image

주변장치 ID표를 보면 PIOA장치에 클록을 공급하여 동작을 시키려고 하니 PIOA의 ID가 2번이다.
다시 레지스터를 보면,

image 

주변장치ID 2번은 2번 비트에 있다. 앞으로 나올 대부분의 레지스터가 PIOA관련레지스터와 같이 32개의 비트에 각각 1:1 대응되어 있다.
쉽게 설명하자면 PA0는 0번 비트, PA31은 31번 비트, PID31은 31번 비트...어때 쉽지 않아?
밑에 주의사항은 주변장치표를 참고하고 구현되지 않은(회로가 없는)장치의 ID를 건들여도 아무런 효과가 없다는 말이다.


image

이렇게 PMC_PCER


  89:     AIC_IDCR = (1 << PIOA);            //인터럽트 설정하는 도중 인터럽트가 걸리면 안되.
  91:     AIC_SVR[PIOA] = (unsigned int)HANDLER;        //SVR[] (배열의 값)은 unsigned int형
  92:     AIC_SMR[PIOA] = (2 << SRCTYPE) |(0 << PRIOR);    //상승에지, 우선순위 최하
  94:     AIC_ICCR    = (1 << PIOA);            //에지 검출기 클리어
  95:     PIOA_IFER = (1 << INT_PIN);        //글리치 필터 적용.
  96:     AIC_ISCR = (1 << PIOA);            //에지 검출기를 세트한다.
  98:     PIOA_IER = (1 << INT_PIN);            //인터럽트 허용.
  99:     AIC_IECR = (1 << PIOA);            //PIOA장치 인터럽트 허용.