**인터럽트(Interrupt)**란, MCU가 프로그램을 실행하던 도중, 외부 또는 내부에서 발생한 사건에 반응하기 위해 기존의 흐름을 잠시 중단하고 특정 처리를 수행한 뒤 다시 원래 위치로 되돌아가는 메커니즘을 말한다.
while(true)로 감시(polling)하면 CPU 자원을 낭비하게 되므로 효율적인 이벤트 기반 시스템이 필요함| Polling 방식 | Interrupt 방식 |
|---|---|
| CPU가 지속적으로 상태 체크 | 이벤트 발생 시에만 응답 |
| CPU 시간 낭비 큼 | 효율적 |
예: if(sw_pressed) | 예: 인터럽트 발생 시 ISR() 실행 |
교수님 설명: “인터럽트는 코드가 실행 중일 때도 하드웨어가 끼어드는 방식이다. 이벤트 중심 시스템에서 반드시 필요한 구조이다.”
⏱ ISR은 매우 짧고 빠르게 실행되어야 하며, 중요한 작업은 되도록 메인 코드에 위임해야 한다.
| 종류 | 설명 | 예시 |
|---|---|---|
| 하드웨어 인터럽트 | 외부/내부 하드웨어 신호에 의해 발생 | 버튼, 센서, 타이머 |
| 소프트웨어 인터럽트 (Exception) | 명령어 실행 도중 발생 | Division by 0, HardFault |
| 마스크 가능 인터럽트 | PRIMASK 등에 의해 차단 가능 | 일반 외부 인터럽트 |
| 마스크 불가 인터럽트 | 언제든지 발생 처리됨 | NMI, Reset, HardFault 등 |
교수님 설명:
“ISR은 LED 제어가 아니라 변수 증가만 하고 빠르게 끝내야 한다.
색상 변경은 메인 루프에서 처리한다. 이것이 좋은 구조이다.”
InterruptIn 클래스 사용#include "mbed.h"
DigitalOut led(LED1);
InterruptIn button(USER_BUTTON);
void toggle_led() {
led = !led;
}
int main() {
button.fall(&toggle_led); // 버튼이 눌릴 때 인터럽트 발생
while (true) {
// 메인 루프에서 다른 작업 가능
}
}
| 메서드 | 설명 |
|---|---|
rise() | 상승 에지(버튼 뗐을 때) 발생 시 |
fall() | 하강 에지(버튼 눌렀을 때) 발생 시 |
mode() | PullUp, PullDown 설정 가능 |
Nested Vectored Interrupt Controller의 약자로, ARM Cortex-M에서 인터럽트의 우선순위 관리, 마스킹, 중첩 처리 등을 담당하는 하드웨어 모듈이다.
| 구성 요소 | 설명 |
|---|---|
| Enable Register | 인터럽트를 활성화 |
| Pending Register | 인터럽트 발생 대기 상태 |
| Priority Register | 인터럽트 우선순위 설정 |
| PRIMASK | 전체 인터럽트 마스크 (Enable/Disable All) |
NVIC_EnableIRQ(EXTI0_IRQn); // EXTI0 인터럽트 활성화
NVIC_SetPriority(EXTI0_IRQn, 1); // 우선순위 설정
NVIC_DisableIRQ(EXTI0_IRQn); // 비활성화
NVIC_ClearPendingIRQ(EXTI0_IRQn); // 펜딩 제거
CMSIS 사용 시 레지스터 접근 없이 인터럽트를 안전하게 제어할 수 있다.
| 주의사항 | 설명 |
|---|---|
| 빠르게 실행할 것 | ISR 안에서는 오래 처리하지 않는다 |
전역 변수 사용 시 volatile 키워드 사용 | 최적화로 인한 값 손실 방지 |
| 공유 자원 사용 시 주의 | race condition 발생 가능성 존재 |
| 인터럽트 재진입 가능 여부 고려 | nested interrupt 발생 가능성 분석 필요 |
volatile의 필요성volatile int count = 0;
void ISR() {
count++;
}
volatile을 붙이지 않으면 컴파일러가count값을 캐싱해서 ISR에서 바뀐 값을 메인 루프가 못 볼 수 있다.
| 예외 | 우선순위 |
|---|---|
| Reset | -3 |
| NMI | -2 |
| HardFault | -1 |
| 일반 인터럽트 | 0 ~ 255 설정 가능 |
예: UART 인터럽트보다 타이머 인터럽트를 더 빠르게 처리하려면 우선순위를 낮게 설정한다 (값 작게).
| 레지스터 | 기능 |
|---|---|
| PRIMASK | 모든 인터럽트 차단/허용 |
| BASEPRI | 특정 우선순위 이하만 차단 |
| FAULTMASK | HardFault 포함 모든 인터럽트 차단 |
__disable_irq(); // PRIMASK = 1
__enable_irq(); // PRIMASK = 0
MCU는 GPIO 신호를 클럭 기반으로 안정화하여 인식한다.
→ 이로 인해 인터럽트는 비동기처럼 보이지만, 클럭 동기 방식으로 처리된다.
교수님 설명:
“핀 신호는 진짜 실시간처럼 변하지만, MCU는 클럭으로 동작하기 때문에
그 신호를 ‘눈 깜짝할’ 틈에 정확히 인식하려면 내부에 flip-flop과 클럭이 필요하다.”
[외부 이벤트 발생]
↓
[인터럽트 트리거됨 (핀 or 장치)]
↓
[NVIC이 해당 인터럽트를 Pending으로 설정]
↓
[CPU가 현재 작업 중단 → 컨텍스트 저장]
↓
[ISR 실행 → 작업 수행]
↓
[ISR 종료 → 컨텍스트 복원]
↓
[메인 코드 재개]
| 항목 | 설명 |
|---|---|
| Interrupt | 이벤트 기반 코드 실행 구조, 하드웨어 트리거 |
| ISR | 인터럽트 발생 시 실행되는 서브루틴 |
| NVIC | 인터럽트 우선순위 및 마스크 제어 모듈 |
| PRIMASK 등 | 전역 인터럽트 차단 제어 |
| Mbed API | InterruptIn 클래스 사용해 고수준 제어 |
| CMSIS API | NVIC 관련 함수로 저수준 제어 가능 |
| volatile | ISR와 main 간 공유 변수에 필수 |
| 우선순위 | 숫자 작을수록 우선, 일부 고정 우선순위 존재 |
| 동기 클럭 기반 | 실제 인터럽트 처리는 클럭 동기화로 안전하게 진행됨 |