이로또

임베디드 리눅스 드라이버의 이해 4편: 인터럽트 처리의 원리 본문

임베디드

임베디드 리눅스 드라이버의 이해 4편: 인터럽트 처리의 원리

이로또 2025. 6. 4. 19:20

이 글에서는 리눅스 커널에서의 인터럽트가 무엇인지, 어떤 흐름으로 처리되는지, 그리고 우리가 만든 디바이스 드라이버에서 인터럽트를 어떻게 등록하고 사용하는지를 예제를 통해 정리합니다.
인터럽트는 외부 버튼이나 센서처럼 갑작스럽게 발생하는 이벤트에 반응하기 위한 핵심 개념입니다.


목차

  1. 인터럽트란?
  2. 인터럽트 처리 흐름 쉽게 이해하기
  3. 커널 내부 인터럽트 처리 과정
  4. 디바이스 드라이버에서 인터럽트 등록하기
  5. 실습 예제: 버튼 입력 처리
  6. 인터럽트 등록 확인하기 - /proc/interrupts
  7. request_irq 함수 자세히 보기
  8. 정리 요약

1. 인터럽트란?

인터럽트란? "갑자기 CPU한테 중요한 일이 생겼어요! 라고 알리는 것"

 

예를 들어:

  • 사람이 키보드를 누름 → 키보드 장치가 CPU에게 알림
  • 타이머가 종료됨 → CPU에게 알림

이렇게 장치에서 "지금 나를 처리해줘!"라고 CPU에 요청하는 것이 바로 인터럽트입니다.


2. 인터럽트 처리 흐름 쉽게 이해하기

  1. CPU는 프로그램을 실행 중
  2. 외부 장치에서 인터럽트 발생 (예: 버튼 누름)
  3. CPU는 잠시 작업을 멈추고, 인터럽트 처리 함수로 이동
  4. 인터럽트 핸들러(처리 함수) 실행
  5. 처리 끝나면 원래 하던 일로 복귀

즉, 인터럽트는 CPU가 외부의 신호에 빠르게 반응하도록 도와주는 메커니즘입니다.


3. 커널 내부 인터럽트 처리 과정

리눅스 커널 안에서는 아래와 같은 흐름으로 인터럽트를 처리합니다:

  1. asm_do_irq() → CPU 아키텍처 레벨에서 인터럽트 진입
  2. do_IRQ(n) → 인터럽트 번호 n을 받아서 처리
  3. irq_desc[n] → 해당 번호에 등록된 처리 함수 확인
  4. 등록된 핸들러 함수 실행 → 우리가 작성한 ISR (Interrupt Service Routine)

4. 디바이스 드라이버에서 인터럽트 등록하기

커널은 "어떤 인터럽트 번호에 어떤 함수를 실행할지" 미리 등록해두어야 합니다.
이를 위해 사용하는 함수가 request_irq()입니다.

 

예시:

request_irq(PIN_KEY1_irq, isr_func, IRQF_TRIGGER_RISING, "my_device", NULL);
  • PIN_KEY1_irq: IRQ 번호 (어떤 핀에 연결된 인터럽트인지)
  • isr_func: 실제 처리할 함수
  • IRQF_TRIGGER_RISING: 상승 에지(버튼이 눌렸을 때) 트리거
  • "my_device": 장치 이름
  • NULL: 장치 식별자 (필요 시 구조체 주소 등)

인터럽트가 더 이상 필요 없을 때는 free_irq()로 해제합니다.


5. 실습 예제: 버튼 입력 처리

1. GPIO 설정

gpio_request(PIN_KEY1, "PIN_KEY1");
gpio_direction_input(PIN_KEY1);
PIN_KEY1_irq = gpio_to_irq(PIN_KEY1);
  • 버튼이 연결된 GPIO를 입력 모드로 설정하고, IRQ 번호를 얻어옵니다.

2. 인터럽트 핸들러 작성

static irqreturn_t isr_func(int irq, void *dev_id, struct pt_regs *regs) {
    printk("(isr) Button pressed!\n");
    return IRQ_HANDLED;
}

3. 인터럽트 등록

request_irq(PIN_KEY1_irq, isr_func, IRQF_TRIGGER_RISING, "my_device", NULL);

4. 해제 시

free_irq(PIN_KEY1_irq, NULL);

6. 인터럽트 등록 확인 - /proc/interrupts

cat /proc/interrupts
  • IRQ 번호별로 인터럽트가 얼마나 발생했는지 확인 가능
  • 내가 등록한 "my_device" 이름이 있는지 확인 가능

7. request_irq() 함수 자세히 보기

int request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long flags,
                const char *name,
                void *dev);

 

인자 설명
irq IRQ 번호 (어느 핀에 연결된 인터럽트인지)
handler 처리할 함수 (ISR)
flags 언제 인터럽트를 감지할지: 상승 에지, 하강 에지 등
name 장치 이름 (/proc/interrupts에 나옴)
dev 장치 구분자 (여러 장치가 같은 IRQ 쓸 때 사용)

8. 정리 요약

개념 설명
인터럽트 외부 이벤트에 CPU가 즉시 반응하는 시스템
ISR 인터럽트가 발생했을 때 실행되는 함수
request_irq() 인터럽트와 ISR을 등록하는 함수
free_irq() 등록 해제하는 함수
/proc/interrupts 등록된 인터럽트와 발생 횟수 확인