임베디드 스터디 - IO 인터페이스
임베디드 스터디 - IO 인터페이스
IO 접근 전략 : MMIO vs PMIO
- MMIO(Memory-Mapped I/O) : CPU 주소 공간에 RAM, Peripheral 영역을 나누고, Peripheral도 메모리 주소처럼 접근하는 방법
- PMIO(Port-Mapped I/O) : CPU 주소 공간은 오로지 RAM만, Perpheral 접근은 별도의 ISA로 구성
| 항목 | MMIO | PMIO |
|---|---|---|
| 접근 명령어 | 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 설정 필요 |
| 적합한 상황 | 응답 시간이 매우 짧고 예측 가능한 경우 | 이벤트 발생 시점이 불규칙한 경우 |
- 인터럽트 동작 순서
- 현재 컨텍스트 저장 : PC, 레지스터 정보를 스택에 푸시
- ISR 실행 : 인터럽트 처리 함수(Interrupt Service Routine) 실행
- 컨텍스트 복원 : 스택에서 기존 기능 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의 인터럽트 기반 동작을 수행함
- Linux의
| 하드웨어 폴링 | 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 라이센스를 따릅니다.