스타브로


[ 2 주차 : 1조 김 경 진] 인터럽트 간섭 실습 보고서


 

[ 2 주차 : 1조 김 경 진] 인터럽트 간섭 실습 보고서


* 실험 목표


1. cpu-timer0,1을 사용하여 LED점멸 실습을 해보자.

2. 두 개의 인터럽트가 동시에 걸렸을 때 인터럽트 간섭에 대해 알아보자.


* 실습 과정


1. cpu-timer0을 이용하여 1초간격의 LED점멸 구현

2. cpu-timer1을 이용하여 2초간격의 LED점멸 구현

3. 두 개의 인터럽트를 동시에 실행시켜 간섭을 관찰

4. 인터럽트의 간섭에 대한 고찰


* 실습 결과

기본적으로 tidoc에 있는 cpu-timer 예제를 조금 손봐 프로그램을 구현했다. 먼저 cpu-timer0번을 이용하여 1초 간격의 LED 점멸을 구현해 보자. LED 점멸에 관한 소스는 gpio-tlggle 예제에 자세한 설명이 나와 있기 때문에 상세한 설명은 넘어 가겠다. 일단 cpu-timer 예제의 매인 함수를 보면


EALLOW; 

PieVectTable.TINT0 = &cpu_timer0_isr;

EDIS;


을 찾을 수 있다. 여기에


GpioMuxRegs.GPFMUX.bit.SCITXDA_GPIOF4 = 0; // 일반 입, 출력 핀으로 사용

GpioMuxRegs.GPFDIR.bit.GPIOF14 = 1;           // OUT핀으로 사용


을 추가 시켜


EALLOW;

PieVectTable.TINT0 = &cpu_timer0_isr;

GpioMuxRegs.GPFMUX.bit.SCITXDA_GPIOF4 = 0;

GpioMuxRegs.GPFDIR.bit.GPIOF14 = 1;

EDIS;


와 같은 구문을 만들자 이로서 핀에 대한 기본적인 설정은 모두 끝났다.  그리고 아래 나와 있는 방법 등으로 딜레이 루프를 만들어 딜레이를 조정한다. 딜레이 확인방법은  프로파일러를 통해 가능하다.


void delay_loop(void)

{

    long      i;

    for (i = 0; i < 1000000; i++) {}

}


그리고 void cpu_timer0_isr(void)함수를 다음과 같이 고쳐 보자


interrupt void cpu_timer0_isr(void)

{

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 1;  //14번 핀에 1을 출력해서 점등

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 0; // 14번 핀에 0을 출력해서 소등

        

   // Acknowledge this interrupt to receive more interrupts from group 1

   PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // 1을 써줌으로서 같은 그룹의 인터럽

                                               // 트가 더 들어 올수 있게 해준다.

}


   일단 cpu-timer0번을 이용한 LED점멸은 상당히 간단하다. 특별히 설명할 것도 없는 듯하다. 그 이유는 이미 cpu-timer0에 대한 구조체 선언과 섹션 할당 등이 모두 끝나있기 때문이다. 지금 부터는 cpu-timer1을 이용한 LED 점멸을 해보면서 인터럽트의 설정과정을 하나씩 알아보자. 가장 먼저 DSP281x_CpuTimer.c 파일을 열어보자 파일을 살펴보면 cpu-timer0번에 대한 구조체는 모두 설정이 되어있지만. timer1,2에 대한 설정부분은 주석으로 처리되었다. 그 이유는 timer1,2는 DSP BIOS와 리얼타임 OS부분을 위해 사용되기 때문이라고 적혀있다. 실습을 하면서 느낀 점이지만 cpu-timer1,2를 이용하여 인터럽트를 거는 것은 바람직하지 않은 것 같다. 하지만 모든 구문이 주석으로 처리 되어 있어서 하나씩 따라가면서 실습을 하다 보면 인터럽트의 실행과정에 대한 공부를 하기는 참 좋은 것 같다.

//struct CPUTIMER_VARS CpuTimer1;

//struct CPUTIMER_VARS CpuTimer2;


위에 나와 있는 구문을 시작으로 밑에 있는 모든 cpu-timer1,2에 관한 주석 표시를 제거하자. 이로서 cpu-timer 1,2관한 구조체가 선언됐다. 나중에 이 CpuTimer1,2에 대한 구조체는  하나의 과정을 더 거쳐서 링커 커맨드 파일에서 주소를 할당 받는다.


   그 다음으로는 DSP281x_Defautlsr.c 파일을 열어 보자.  파일을 보면 인터럽트가 걸렸을 때 기본적으로 실행되는 함수들이 나와 있다. 만약 cpu- timer 예제에서


EALLOW; 

PieVectTable.TINT0 = &cpu_timer0_isr;

EDIS;


부분이 없었다면 어떨까? 그렇다면 밑에 나와 있는 이 함수에 실행 구문을 적어야 한다. 이함수는 DSP281x_Defautlsr.c 파일에 있는 함수이다.

// INT1.7

interrupt void  TINT0_ISR(void)      // CPU-Timer 0

{

  // Insert ISR Code here


  // To receive more interrupts from this PIE group, acknowledge this interrupt

  // PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

 

  // Next two lines for debug only to halt the processor here

  // Remove after inserting ISR Code

     asm ("      ESTOP0");

     for(;;);

}

정말 실행이 되나 확인하기위해 Example_281xCpuTimer.c 파일과 DSP281x_Defautlsr.c 파일 모두에 함수를 적어 실행시켜 보았다. 역시 실행이 되었다. 물론 DSP281x_Defautlsr.c 파일의 함수에서 프로그램을 실행시키기 위해서는 PieVectTable.TINT0 = &cpu_timer0_isr; 구문은 빠져야 한다. 그럼 잠시 DSP281x_Defautlsr.c 파일에 대해 좀 더 알아보자. 매인 함수의 TINT1_ISR에 마우스를 가만히 가져다 되면 주소가 보인다. 그 주소는 0x003F817B 라는 주소 값이다. 이는 기본적으로 INT1.7이 걸리면 이 주소에 있는 함수가 실행이 된다는 뜻이다. 이를 매인함수서 PieVectTable.TINT0 = &cpu_timer0_isr; 곧 0x003F817B라는 주소에 cpu_timer0_isr의 주소를 넣어준 것이다. 그럼 어디서 INT1_ISR에 주소 값을 부여했는지 찾아보자. DSP281x-PieVect.c 파일을 열어 보면 PieVectTableInit라는 구조체가 보인다. 이 구조체를 따라 가다 보면  TINT0_ISR를 찾을  수 있다. 역시 마우스를 가져가 보면 같은 주소 값이 나오는 걸 확인할 수 있다. 곧 이 구조체를 선언하고 주소를 할당했다는 걸 알 수 있다.

 

   그 다음으로 DSP281x_GlonalVariablDef.c 파일을 열어보자. 이 파일에는 각각의 인터럽트들의 MMR을 구조체로 선언한 것들을 define하고 있다.


일단 다음과 같은 주석을 풀어 주자.


//#pragma DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile");

//volatile struct CPUTIMER_REGS CpuTimer1Regs;

//#pragma DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile");

//volatile struct CPUTIMER_REGS CpuTimer2Regs;


그리고 마지막에 다음과 같은 선언을 해주어야 한다.


#define CPUTimer1Regs CpuTimer1Regs

#define CPUTimer2Regs CpuTimer2Regs


이것을 설정하여 위에 나와 있는 DSP281x_CpuTimer.c에서 풀어준 주석들을 링커 커맨드 파일에서 주소를 할당해 줄 수 있는 것이다.


   그럼 잠시 링커 커맨드 파일을 살펴보자. spru078c의 표 3-14를 살펴보면 cpu-timer0,1,2번에 대한 MMR을 어디에 넣어 줘야 하는지 쉽게 알 수 있다. 그럼 하나하나 설정해보자. 일단 메모리 영역을 잡아준다.


   CPU_TIMER1  : origin = 0x000C08, length = 0x000008

   CPU_TIMER2  : origin = 0x000C10, length = 0x000008


위와 같이 설정이 끝났다면  섹션으로 내려가서 위에서 define한 CpuTimer1Regs, CpuTimer2Regs를 다음과 같이 넣어주자.


   CpuTimer1RegsFile : > CPU_TIMER1,  PAGE = 1

   CpuTimer2RegsFile : > CPU_TIMER2,  PAGE = 1 


   이것으로 Sourec폴더에 있는 모든 설정이 끝났다. 그럼 해더 파일로 넘어가 보자 해더 파일에서는 DSP281x-CpuTimer.h 파일만 고쳐주면 된다. 이 파일에 있는 주석을 제거함으로서 매인 함수에 ConfigCpuTimer(&CpuTimer1, 100, 2000000), StartCpuTimer1(); 등의 함수를 사용할 수 있게 된다. 이런 함수가 모두 해더 파일에서 정의 되어 있기 때문이다.


   위 과정이 모두 끝났다면 매인 함수 부분은 아주 간단하다. DSP281x_Defaultlsr.c 파일에 함수를 넣어 줘도 되고 cpu-timr0번과 같이 Example_281x.c 파일에서  PieVectTable.XINT13 = &cpu_timer1_isr;와 같이 주소를 할당받아 사용해도 된다. 두 가지 방법 모두 실행 시켜 보았지만, Example_281x.c 파일에서 실행시키는 것이 좀 더 편한 느낌이었다. 하지만 인터럽트가 늘어나게 된다면 DSP281x_Defaultlsr.c파일을 이용하는 편이 좀 더 편할 듯하다. cpu-timer0에 관한 부분은 잠시 주석으로 만들어 버리자. 그리고 INT13은 PIE를 통하지 않게 때문에 PieCtrlRegs.PIEIER1.bit.INTx7 = 1;이나,  PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; 과 같은 구문은 필요하지 않다. 인터럽트가 걸렸을 때 2초에 2번 점멸하는 프로그램은 적지 않겠다.


   그럼 두 개의 인터럽트를 동시에 실행시켜 LED 점멸을 관찰해 보자 

위에서 잠시 주석으로 만들었던 것들을 모두 풀어주면 간단하게 해결된다. 과제물으 인터럽트 구조와 MMR에서도 설명 했지만, 기본적으로 인터럽트 간섭은 일어나지 않는 것 같다. 모든 인터럽트들은 우선순위를  갖고 있기 때문에 우선순위에 따라 IMT1.7번의 timer0번이 INT13의 timer1보다 먼저 일어나게 된고 우선 순위가 낮다면 대기하기 된다. 만약 밑에 나와 있는 식으로 무한 for문을 넣어 버리면 INT1 한 번 실행 후 INT13은 한 번도 실행되지 않는다.


interrupt void cpu_timer0_isr(void)

{

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 1;

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 0;

   for(;;){}                                     /////인터럽트 함수가 끝나

                                                 //// 지 않는다.

        

   // Acknowledge this interrupt to receive more interrupts from group 1

   PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

}


 마찬 가지로


interrupt void cpu_timer1_isr(void)

{


   GpioDataRegs.GPFDAT.bit.GPIOF14 = 1;

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 0;

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 1;

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 0;

   for(;;){}                                   ////////무한 for문

}


같이 프로그램을 짜도 INT1 한 번 실행후 INT13인 한 번 실행되고, 더 이상의 인터럽터는 거리지 않는다.

 

   참고로 다음과 같이 프로그램을 짜다면 어떨까?


interrupt void cpu_timer0_isr(void)

{

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 1;

   delay_loop();

   GpioDataRegs.GPFDAT.bit.GPIOF14 = 0;       

   // Acknowledge this interrupt to receive more interrupts from group 1

  // PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;  이 부분을 주석처리

}

INT1이 한 번 실행된 후 계속해서 INT13만 실행된다. 


감알 마제스 삶의 향기 근검절약 견지와 여행 독백들의 공간. 깜장마녀 하우스 나무 친구들 adsl 도나코
2009/06/22 13:10 2009/06/22 13:10
top

Leave a comment..