Arm 프로세서의 인터럽트와 익셉션
인터럽트와 익셉션(exception)은 비슷한 용어지만 두 용어 사이에는 약간의 차이점이 있습니다.
일반적인 의미로는, 인터럽트는 주로 CPU 외부 이벤트에 의해서 발생하는 것으로 보는 경우가 많다. 즉, 인터럽트는 외부 주변 장치나 외부 신호에 의해서 발생하는 이벤트라고 볼 수 있다.
반면, 익셉션은 단어의 뜻이 의미하는 바와 같이 예외적인 상황에서 발생하는 이벤트로 보는 것이 일반적이다. 따라서, 익셉션은 주로 CPU 내부에서 발생하는 예외적인 상황에 발생하는 이벤트로서, 예를 들면 나눗셈을 실행할 때 0으로 나누는 상황에서 발생하는 이벤트 등이다.
좀 더 쉽게 풀이하자면,
Exception이라는 건 Interrupt를 포함한 더 큰 사건을 의미합니다. 그러니까 외부 요청 이라던가 오류에 관련된 사건인 것이죠. Interrupt는 Exception의 한 종류에요.
Arm 프로세서에 관한 문서에서는, 인터럽트를 익셉션의 한 종류로 분류를 합니다.
즉, 익셉션은 인터럽트를 포함한 의미로 사용되며, 인터럽트는 외부 주변 장치나 외부 신호에 의해서 발생하는 익셉션의 한 종류를 의미한다.
그러나, 위에서 언급했듯이, 이런 용어의 차이점은 문맥상으로 파악이 가능하므로 문제가 되는 경우는 적을 수 있습니다.
인터럽트 벡터 테이블(Interrupt Vector Table)
인터럽트가 발생하면 CPU는 현재 실행 중인 프로그램을 잠시 중단하고 인터럽트 서비스 루틴으로 점프한다. 이때, CPU는 인터럽트 서비스 루틴의 시작 주소를 알 수 있어야 하므로, 인터럽트 서비스 루틴의 시작 주소를 저장하기 위한 저장소가 필요하다. 인터럽트 서비스 루틴의 시작 주소를 인터럽트 벡터(interrupt vector)라고 부르며, 인터럽트 벡터를 저장하는 장소를 인터럽트 벡터 테이블이라고 부른다. 앞에서 언급한 바와 같이, Arm 프로세서 관련 문서에서는 익셉션이 인터럽트를 포함하므로, 익셉션 벡터 테이블(exception vector table) 혹은 벡터 테이블로 부른다. 마이크로컨트롤러에서 인터럽트의 종류는 여러 가지가 있을 수 있으므로, 인터럽트 벡터 테이블은 인터럽트 벡터를 여러 개 저장하고 있다. 일반적으로, 인터럽트 혹은 익셉션 벡터 테이블은 프로그램 메모리의 첫 부분에 저장한다. 표 6.1은 Arm Cortex-M 프로세서의 익셉션의 종류와 벡터 테이블의 메모리 주소를 보여준다. 인터럽트 혹은 익셉션 벡터는 32비트의 주소 이므로 메모리에 저장하기 위해서는 4바이트의 메모리가 필요하다. 메모리의 한 주소당 1바이트를 저장할 수 있으므로, 표 6.1에서 볼 수 있듯이, 각 벡터에 대해서 4바이트의 메모리 주소가 배정된 것을 볼 수 있다.
표 Arm Cortex-M 프로세서의 익셉션의 종류와 벡터 테이블의 주소
Exception NumberExceptionMemory Address
1 | Reset | 0x00000004 |
2 | NMI | 0x00000008 |
3 | Hard Fault | 0x0000000C |
4 | Memory Management Fault | 0x00000010 |
5 | Bus Fault | 0x00000014 |
6 | Usage Fault | 0x00000018 |
7~10 | Reserved | |
11 | SVCall | 0x0000002C |
12 | Debug Monitor | 0x00000030 |
13 | Reserved | |
14 | PendSV | 0x00000038 |
15 | SysTick | 0x0000003C |
16 | IRQ(Interrupt Request) 0 | 0x00000040 |
17 | IRQ(Interrupt Request) 1 | 0x00000044 |
~ | ~ | ~ |
255 | IRQ(Interrupt Request) 239 | 0x000003FC |
표 에서 볼 수 있듯이 Arm Cortex-M 프로세서의 익셉션의 종류는 모두 255개이다. 이들 중에서 익셉션 번호 1에서 15까지는 CPU 내부에서 발생하는 예외 상황의 이벤트이며, 익셉션 번호 16~255는 외부 주변 장치에 의해서 발생하는 인터럽트이다. 반도체 제조 회사에서 Arm Cortex-M 코어에 대한 라이센스를 받아서 반도체를 설계 할 때, 익셉션 번호 1~15번에 대해서는 반도체 제조 회사가 변경할 수 없다.
그러나, 익셉션 번호 16~255의 인터럽트에 대해서는 반도체 회사에서 추가한 주변 장치들의 인터럽트를 배정할 수 있다. 따라서, 동일한 Cortex-M 코어를 사용하더라도 익셉션 번호 16~255의 인터럽트에 대해서 배정하는 주변 장치는 제조하는 반도체 회사에 따라서 다르다. 익셉션 번호 1~15의 익셉션에 대해서는 다소 복잡한 내용이 있으므로, 이들 중에서 기본적인 몇가지에 대해서만 설명을 한다.
- Reset: Reset은 마이크로컨트롤러의 동작을 처음 시작하는 신호이다. 마이크로컨트롤러가 어떤 기기에 내장이 되었을 때, 전원 버튼을 켜면 가장 먼저 발생하는 신호가 Reset 이다. Reset도 인터럽트 혹은 익셉션의 한 종류이며, Reset 신호가 발생하면 리셋 핸들러(reset handler)라고 하는 인터럽트 서비스 루틴이 실행된다. 즉, 리셋 핸들러는 마이크로컨트롤러에 전원 인가 후 최초로 실행하는 프로그램이다. 리셋 인터럽트가 반드시 전원 버튼을 켤 때 만 발생하는 것은 아니다. 기기에 따라서 전원 버튼과는 별도로 리셋 버튼이 있을 수도 있고, 또한 어떤 특정 상황에서 리셋 신호가 발생할 수 있다.
- NMI: NMI는 영어로 non-maskable interrupt의 약자이다. 일반적으로, 인터럽트는 프로그램에 의해서 활성화 하거나 비활성화 할 수 있으며, 이를 영어로 maskable 이라고 한다. Non-maskable 이라고 하면, 임의로 비활성화 할 수 없다는 의미이며, NMI는 그런 종류의 인터럽트를 말한다. NMI는 비활성화 되거나 무시될 수 없는 인터럽트에 사용된다.
- Fault: CPU가 정상적으로 처리할 수 없는 오류 상황을 말하며, 종류로는 Hard Fault, Memory Management Fault, Bus Fault, Usage Fault가 있다. 가장 이해하기 쉬운 예로서, Usage Fault의 경우인 0으로 나누는 나눗셈, 정의 되지 않은 명령어 등이 있다.
- SysTick: 이 책에서는 운영체제(operating system)가 사용되는 경우는 다루지 않지만, 마이크로컨트롤러와 같이 비교적 작은 CPU에도 운영체제를 적용할 수 있다. 운영체제가 적용될 경우에는 일정한 시간 간격으로 인터럽트를 발생시키는 타이머가 필요하다. Arm Cortex-M 에는 그런 용도로 사용될 수 있는 타이머가 있으며, 이 타이머가 발생하는 인터럽트를 SysTick 인터럽트라고 한다.
NVIC (Nested Vector Interrupt Controller)
Arm Cortex-M의 CPU는 주변장치로부터 여러 개의 인터럽트 신호를 받아들이게 된다. 따라서, 이러한 인터럽트 신호들 사이의 우선 순위 결정 등의 기능을 수행할 수 있는 인터럽트 제어기가 필요하며, 이를 NVIC (Nested Vector Interrupt Controller)라고 부른다. 그림 6.2와 같이 Arm Cortex-M 코어에는 CPU와 함께 NVIC가 포함되어 있어서, 동일한 Arm Cortex-M 코어를 가질 경우 서로 다른 반도체 제조사의 Arm 프로세서들 사이에도 인터럽트 제어에 관한 호환성을 유지할 수 있다.
모든 Arm 코어가 NVIC를 포함하고 있지는 않다. Cortex 모델 이전의 Arm 코어들은 NVIC를 가지고 있지 않으므로, 각 반도체 제조사들의 Arm 프로세서의 인터럽트 취급 방식은 표준화 되어있지 않았다. 현 시점에서, Cortex 시리즈 중에는 Cortex-M 코어만 NVIC를 포함하고, Cortex-A 코어와 Cortex-R 코어는 NVIC를 포함하지 않는다. 따라서, Cortex-M 시리즈를 제외한 Arm 코어의 인터럽트 처리 방식은 서로 상당히 다를 수 있다.
인터럽트 중첩 (Nested Interrupt)
인터럽트 서비스 루틴의 실행 중에 새로운 인터럽트가 발생할 경우, 새로 발생한 인터럽트를 처리하는 방식에는 두 가지가 있으며, 그림 6.3은 이 두 가지 방식을 보여준다.
그림 Interrupt1을 처리하기 위한 ISR1이 실행 중에, 우선 순위가 더 높은 Interrupt2가 발생했을 때 이를 처리하는 방법 두 가지를 보여준다. 그림 (a)에서는 ISR1의 실행 중에 Interrupt2 가 발생하면, Interrupt2에 대한 ISR2가 즉시 실행되지 않고, ISR1이 종료된 후에 ISR2가 실행이 된다. 반면, 그림 (b)에서는 ISR1을 잠시 중단하고, ISR2를 우선적으로 실행한 후, ISR2가 종료되었을 때 ISR1을 다시 시작해서 실행을 계속한다. 여기에서, 그림 (b)의 경우를 인터럽트 중첩(nested interrupt)이라고 부른다. 마이크로컨트롤러의 종류에 따라서 인터럽트 중첩 기능이 있는 경우도 있고 없는 경우도 있다. Arm Cortex-M의 경우에는 인터럽트 제어기의 이름인 NVIC에서 알 수 있듯이 인터럽트 중첩이 가능하다.