포스트

임베디드 스터디 - IO 인터페이스

임베디드 스터디 - IO 인터페이스

IO 접근 전략 : MMIO vs PMIO

  • MMIO(Memory-Mapped I/O) : CPU 주소 공간에 RAM, Peripheral 영역을 나누고, Peripheral도 메모리 주소처럼 접근하는 방법
  • PMIO(Port-Mapped I/O) : CPU 주소 공간은 오로지 RAM만, Perpheral 접근은 별도의 ISA로 구성
항목MMIOPMIO
접근 명령어LDR/STR, MOV (일반 메모리 명령)IN/OUT (전용 명령어)
주소 공간RAM과 동일 공간, 구역 분리별도 I/O 주소 공간
CPU 설계단순 (추가 ISA 불필요)복잡 (전용 명령어 필요)
C 코드 접근volatile 포인터로 직접 접근inb()/outb() 같은 전용 함수
채택 아키텍처ARM (전용), x86 병행x86 (역사적 유산)
임베디드 적합성✅ 높음❌ 낮음 (MCU에서 사실상 미사용)

폴링 vs 인터럽트

  • 폴링(Polling) : 특정 데이터가 들어왔는지 지속적으로 확인
  • 인터럽트(Interrupt) : 기능 동작 중 특정 신호가 발생하면 현재 동작을 일시정지하고 신호에 해당하는 동작을 우선 처리
항목폴링인터럽트
CPU 효율❌ Busy-wait✅ 다른 작업 가능
응답 지연폴링 주기에 종속하드웨어 즉시 통보
구현 복잡도단순ISR, NVIC 설정 필요
적합한 상황응답 시간이 매우 짧고 예측 가능한 경우이벤트 발생 시점이 불규칙한 경우
  • 인터럽트 동작 순서
    1. 현재 컨텍스트 저장 : PC, 레지스터 정보를 스택에 푸시
    2. ISR 실행 : 인터럽트 처리 함수(Interrupt Service Routine) 실행
    3. 컨텍스트 복원 : 스택에서 기존 기능 Pop 후 다시 재개

인터럽트 벡터 테이블 (IVT, Interrupt Vector Table)

  • 인터럽트 소스 테이블마다 대응하는 ISR 주소를 저장하는 테이블
    • Flash에 저장
  • Cortex-M에서 0x0000_0000부터 테이블 시작
    • 단, 엔트리는 초기 스택 포인터 값
1
2
3
4
5
6
7
8
0x0000_0000  Initial Stack Pointer
0x0000_0004  Reset_Handler
0x0000_0008  NMI_Handler
0x0000_000C  HardFault_Handler
...
0x0000_0040  EXTI0_IRQHandler   ← 외부 인터럽트 0
0x0000_0044  UART1_IRQHandler
...

NVIC (Nested Vectored Interrupt Controller)

  • 하드웨어 계층에서 ISR을 관리하는 모듈
    • Nested — 인터럽트 중에 더 높은 우선순위 인터럽트가 오면 중첩 처리 가능
    • Vectored — 인터럽트 소스마다 벡터(ISR 주소)가 대응되어 자동 점프
    • Interrupt Controller — 모든 인터럽트 소스를 중앙에서 관리
  • NVIC의 역할
    • 우선순위 설정 : 각 IRQ에 0~255 우선순위 부여 (숫자 낮을수록 높은 우선순위)
    • Enable/Disable : 특정 인터럽트 소스를 개별적으로 on/off
    • Pending 관리 : 인터럽트 발생 시 pending 플래그 세트, 처리 후 클리어
    • Nesting : 높은 우선순위 인터럽트가 낮은 우선순위 ISR을 선점(preempt)
  • Nesting의 동작 순서
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[스택 성장 방향 ↓]

메인 코드 실행
  → UART ISR 진입 시: [메인 컨텍스트] 푸시
      → Timer ISR 진입 시: [UART ISR 컨텍스트] 푸시

        Timer ISR 실행 중 스택 상태:
        ┌─────────────────────┐ ← SP
        │  UART ISR 컨텍스트  │  (Timer 끝나면 팝)
        ├─────────────────────┤
        │  메인 컨텍스트      │  (UART 끝나면 팝)
        └─────────────────────┘

      ← Timer ISR 완료: [UART ISR 컨텍스트] 팝 → UART ISR 재개
  ← UART ISR 완료: [메인 컨텍스트] 팝 → 메인 코드 재개

Linux poll/epoll/fd 운용과 HW Polling

  • 컨셉은 유사하지만 운용하는 계층이 다르다
    • Linux의 poll, epoll 모두 HW의 인터럽트 기반 동작을 수행함
 하드웨어 폴링poll()/epoll()
확인 대상주변장치 레지스터 상태파일 디스크립터(fd) 상태
확인 방식CPU가 레지스터를 직접 읽음커널에 “이 fd들 준비되면 알려줘” 요청
Busy-wait✅ (CPU 낭비)❌ (커널이 블로킹, CPU 양보)
1
2
3
4
5
6
7
[ 유저 앱 ]   poll() / epoll()  ← 여기서 사용
     ↓
[ 커널 ]      VFS / 소켓 레이어
     ↓
[ 드라이버 ]  실제로는 인터럽트 기반으로 동작  ← 하드웨어 인터럽트
     ↓
[ 하드웨어 ]  UART/GPIO/Network HW
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.