LM3S8962  Interrupt 예제에 대하여 분석해 보았다.

우선 예제코드를 다운받는다.
Link : http://www.zlgmcu.com/luminary/exploitation_guide.asp


위의 링크된 사이트에 가서 3개의 파일 모두를 받는다.
맨 위의 pdf 문서는 interrupt libary를 설명한 문서이고, 아래의 두개의 zip 파일은 예제코드이다.

제1장. 인터럽트 제어
LM3SLib_Interrupt.pdf 문서의 초반부에 함수의 prototype에 대하여 설명하고 있다.


1.1 인터럽트 기본 프로그래밍 방법

Stellaris는 인터럽트를 위해 다음과 같은 Periperal Driver library가지고 있다.

1. Periperal 활성화
관련 인터럽트를 사용하기 위해서는 <sysctl.h>에 정의되어 있는 헤더 파일을 이용하여 SysCtlPeriperalEnable() 함수를 호출한다.

2. 인터럽트 type 설정
인터럽트를 활성화하기 전에 인터럽트 type을 정확히 설정한다.

3. 인터럽트 활성화
ARM core의 Stellaris 제품군은 3단계의 인터럽트를 활성화 순서를 거친다.
    ● 특정 핀 인터럽트 활성화
    ● 특정 전체 인터럽트 활성화 ( IntEnable() )
    ● 전체 프로세스 인터럽트 활성화 ( IntMasterEnable() )

4. 인터럽트 서비스 루틴
인터럽트 서비스 함수 이름 GCC 컴파일러는 인터럽트 서비스 함수의 이름을 사전에 예약해 놓고 있다. 인터럽트 서비스 함수는 "LM3S_Startup.s"에서 확인할 수 있다. 예를 들어 GPIOB 포트 인터럽트 함수의 이름은 GPIOB_Port_B_ISR이며, parameter와 return value는 void 형이어야 한다. void GPIO_Port_B_ISR(void) 
KEIL 또는 IAR 개발환경에서는 인터럽트 서비스 함수 이름은 프로그래머가 자체적으로 지정할 수 있다. 하지만 GCC의 표준을 따르기를 권장하고 있다.

인터럽트 상태 확인 하나의 PIN은 몇가지 인터럽트 소스를 갖는 Periperal 이지만 인터럽트 vector는 공유할 수 있다. 예를 들어 GPIOA는 8가지의 기능을 갖지만 Vector number는 16번으로 인터럽트 vector를 공유한다. 각 인터럽트 소스를 정확히 구분하기 위한 쿼리 함수를 통해 인터럽트의 상태를 읽오 온다. 예를들어 GPIO의 상태 쿼리 함수로 GPIOPinIntStatus()를 사용한다.

인터럽트 허가 ARM 코어의 Stellaris 제품군의 모든 periperal interrupt는 인터럽트 상태를 자동으로 clear하지 않는다. 따라서 소프트웨어적으로 clear 시켜주어야 한다. (Periperal에 속하지 않는 Cortex-M3 코어 Exception 은 자동 clear한다.). 만약 clear 시키지 않으면 인터럽트 서비스가 종료되는 즉시 다시 인터럽트가 발생한게 된다. clear를 통해 인터럽트 상태를 clear한다. 예를 들어 GPIO의 인터럽트 상태 clear 함수는 GPIOPinIntClear()이다.

5. 인터럽스 서비스 등록
인터럽트 서비스를 등록하는 방법에는 두가지가 있다. 첫번째는 인터럽트 서비스 함수를 직접 등록하는 것이다. 구현이 간단하다는 장점이 있는 반면에 SRAM에 매번 인터럽트 vector를 등록해 줘야하기 때문에 효율성이 감소되는 단점이 있다. 다른 방법은 시작파일을 수정하는 방법인데 구현이 효율적인 반면에 이동성이 없다는 단점이 있다.

개발환경마다 인터럽트 서비스 함수를 등록하는 방법에는 차이가 있다.
GCC GCC 컴파일러에서는 "LM3S_Startup.s" 파일안에 표준 함수들이 등록되어 있어서 수정없이 바로 사용할 수 있다.
Keil Keil 개발환경에서는 "Startup.s"  어셈블러 파일을 활용한다. 예를들어 "void I2C_ISR(void)" 인터럽트 핸들러를  Vector Table 등록하려면 "IntDefaultHandler"을 "I2C_ISR"로 바꾸어 주고, "EXTERN I2C_ISR"로 선언해 주면 된다.
IAR IAR 개발환경에서는 "startup_ewarm.c" 파일을 사용한다. 예를 들어 "void I2C_ISR(void)" 인터럽트 핸들러를 선언하고 인터럽트 vector table에 해당 "IntDefaultHandler"를 "I2C_ISR"로 교체해준다.

위의 단계를 완료하면 이벤트 발생시 프로그램이 자동적으로 해당 인터럽트 서비스 함수로 분기하여 처리하게 된다.

아래는 GCC 컴파일러의 인터럽스 서비스 함수를 나타낸다.


1.2 인터럽트 라이브러리 함수

1.인터럽트 Enable & Disable
전체인터럽트 Enable : IntMasterEnable()
전체인터럽트 Disable : IntMasterDisable()
    (예외 : Reset ISR, NMI ISR, Fault ISR - 언제든지 발생할 수 있으므로 소프트웨어적으로 Disable되지 않을 수 있다)

반면 IntEnable(), IntDisable() 라이브러리 함수는 칩 전체의 인터럽트 설정을 제어한다.
인터럽트는 두가지 범주로 구분이 되는데, 그 중 하나는  NMI, SysTick 과 같은 ARM Cortex-M3 프로세서 내부에서 발생하는 인터럽트 vector가 15이하인 인터럽트를 나타내며, 다른 하나는 GPIO, UART, PWM 과 같은 Vector 번호가 16 이상인 Stellaris 제품군에 의존적인 인터럽트이다.


IntMasterEnable() - 프로세스 인터럽트 Enable한다.


IntMasterDisable() - 프로세스 인터럽트 Disable한다.


IntDisable() - 명시된 인터럽트를 Disable한다.


IntEnable() - 명시된 인터럽트를 Enable한다.



Stellaris 제품군의 ARM 인터럽트 소스는 다음과 같다.


2. 인터럽트 우선순위

ARM Cortex-M3는 256개까지 인터럽트 우선순위 레벨을 조절할 수 있다. 하지만 Stellaris 제품군은 8개의 우선순위 레벨을 지원한다. 인터럽트 우선순위를 설정하는 것은 복잡한 제어시스템에서 매우 중요한 요소이다.

우선순위를 설정하기 위해 IntPrioritySet(), IntPriorityGet() 함수를 사용한다. 하나 이상의 인터럽트가 발생할 경우 가장 높은 우선순위를 갖는 인터럽트의 순서대로 먼저 처리하며, 동일한 시간에 생성된 인터럽트의 경우 우선순위가 높은 인터럽트를 먼저 처리한다. 낮은 우선순위의 인터럽트가 처리되는 동안 우선순위가 높은 인터럽트가 발생하면 프로세서는 즉시 높은 인터럽트 처리 루틴으로 전환한다.

IntPriorityGroupingSet(), IntPriorityGroupingGet()함수는 preemptable priority 레벨과 subpriority레벨의 그룹화 설정을 관리하는데 사용한다.

IntPrioritySet() - 인터럽트의 priority를 설정한다.


IntPriorityGet() - 인터럽트의 priority를 가져온다.



IntPriorityGroupingSet() - 인터럽트 컨트롤러의 Priority grouping을 설정한다.


IntPriorityGroupingGet() - 인터럽트 컨트롤러의 Priority grouping을 가져온다.



3. 인터럽트 서비스 함수 등록 및 취소

IntRegister() - 인터럽트가 발생했을 경우 호출될 함수를 등록한다.


IntUnregister() - 인터럽트가 발생했을 경우 호출될 함수를 등록해지한다.


Posted by eoseontaek