Renesas Engineer School 내용을 기반으로 공부한 내용을 정리했습니다.
https://www.renesas.com/en/support/engineer-school/mcu-04-peripheral-circuitry-control
들어가며
C언어로 작성한 코드가 컴파일러를 거쳐 기계어로 변환되고, MCU에서 실행된다는 흐름을 정리했습니다. 그런데 한 가지 의문이 남습니다. 소프트웨어(프로그램)가 하드웨어(LED, 모터, 센서)를 어떻게 직접 제어하는 걸까요?
그 답이 SFR(Special Function Register) 입니다.
SFR: 소프트웨어와 하드웨어를 연결하는 다리
MCU 내부에는 일반적인 데이터 저장용 레지스터 외에, 주변장치를 제어하기 위한 특수 레지스터가 있습니다. 이것이 SFR입니다.
SFR의 각 비트는 특정 핀이나 주변장치의 상태와 직접 연결되어 있습니다. 프로그램이 SFR의 특정 비트에 0 또는 1을 쓰면, 그 값이 그대로 핀의 전압으로 나타납니다. 반대로 외부 핀의 전압 상태는 SFR 비트를 읽으면 알 수 있습니다. 쉽게 말해 SFR은 소프트웨어와 하드웨어 사이의 다리 역할을 합니다.

GPIO 출력 제어 — LED를 켜고 끄는 원리
핀 A가 SFR-j의 bit-k에 연결되어 있다고 가정합니다.
- SFR-j의 bit-k에 0을 쓰면 → 핀 A가 LOW(0V)
- SFR-j의 bit-k에 1을 쓰면 → 핀 A가 HIGH(5V)
LED가 핀 A에 연결되어 있다면, 프로그램에서 SFR 비트 하나를 조작하는 것만으로 LED를 켜고 끌 수 있습니다.
// c langauge
// 의사 코드 예시
SFR_J.bit_k = 0; // LED ON (LOW 신호)
SFR_J.bit_k = 1; // LED OFF (HIGH 신호)
모터 ON/OFF 제어도 동일한 원리입니다. 단, 대부분의 MCU는 모터를 직접 구동할 만큼 충분한 전류를 출력하지 못하기 때문에, 실제로는 FET나 트랜지스터로 구성된 드라이브 회로를 사이에 끼워서 MCU 핀이 드라이브 회로를 제어하고, 드라이브 회로가 모터를 구동하는 방식을 씁니다.
GPIO 입력 읽기 — 스위치 상태를 감지하는 원리
출력과 반대로, 외부 장치의 상태를 읽을 때는 SFR 비트를 읽으면 됩니다.
- SFR-j의 bit-k에서 0을 읽으면 → 핀 A에 LOW 신호가 들어오고 있음
- SFR-j의 bit-k에서 1을 읽으면 → 핀 A에 HIGH 신호가 들어오고 있음
스위치가 핀 A에 연결되어 있다면:
- 스위치 OFF → 풀업 저항에 의해 핀 A가 HIGH → SFR 비트 = 1
- 스위치 ON → 핀 A가 GND와 연결되어 LOW → SFR 비트 = 0
프로그램은 이 비트 값을 읽어서 스위치가 눌렸는지 판단합니다.
// c language
// 의사 코드 예시
if (SFR_J.bit_k == 0) {
// 스위치가 눌린 상태
}
Renesas는 SFR이 MCU의 손발이자 오감이라고 표현합니다. 실제로 MCU가 외부 세계와 주고받는 모든 신호는 결국 SFR을 통해 이루어집니다.
인터럽트: 이벤트에 즉시 반응하는 방법
폴링의 한계
SFR을 읽어서 스위치 상태를 감지하는 방법은 이해했습니다. 그런데 실제로 구현하면 문제가 생깁니다. 스위치가 언제 눌릴지 모르기 때문에, CPU가 계속 반복해서 SFR을 읽어야 합니다.
// c language
while (1) {
if (SFR_J.bit_k == 0) {
// 스위치 처리
}
// 다른 작업...
}
이처럼 주기적으로 상태를 확인하는 방식을 폴링(Polling) 이라고 합니다. 폴링의 문제는 두 가지입니다. 첫 번째는 CPU 낭비입니다. 스위치가 눌리지 않는 동안에도 CPU는 계속 확인 작업을 반복합니다. 이 시간 동안 다른 유용한 연산을 할 수 없습니다. 두 번째는 반응 지연입니다. 폴링 루프 안에 다른 작업이 있으면, 스위치가 눌리는 순간과 MCU가 감지하는 순간 사이에 지연이 발생합니다. 폴링 주기가 길수록 지연도 길어집니다.
인터럽트 — 이벤트가 발생하면 CPU에게 직접 알린다
인터럽트는 폴링의 반대 개념입니다. CPU가 계속 확인하는 대신, 이벤트가 발생하는 순간 하드웨어가 CPU에게 신호를 보내는 방식입니다.
일상적인 비유로 설명하면 이렇습니다. 책을 읽으면서 택배를 기다린다고 할 때, 폴링은 주기적으로 현관문을 열어보는 방식이고, 인터럽트는 초인종이 울릴 때만 문을 여는 방식입니다. MCU에서 인터럽트가 발생하는 과정은 다음과 같습니다.
| 단계 | 설명 |
| 1 | 메인 프로그램이 실행 중이다 |
| 2 | 외부 이벤트 발생 (버튼 눌림, DMA 완료, Timer 만료 등) |
| 3 | 인터럽트 신호가 인터럽트 컨트롤러에 전달된다 |
| 4 | CPU가 현재 실행 상태(레지스터 값, PC 등)를 저장한다 |
| 5 | 해당 인터럽트에 대응하는 ISR(Interrupt Service Routine)을 실행한다 |
| 6 | ISR이 끝나면 저장해둔 실행 상태를 복원한다 |
| 7 | 메인 프로그램이 중단된 지점부터 재개된다 |
ISR은 인터럽트가 발생했을 때 실행할 코드를 미리 작성해둔 함수입니다. "버튼이 눌리면 이 함수를 실행해라"는 식으로 등록해두면, 이벤트 발생 시 CPU가 자동으로 해당 함수를 호출합니다.
인터럽트 컨트롤러의 역할
여러 이벤트가 동시에 발생하면 어떻게 될까요? 예를 들어 버튼 인터럽트와 DMA 완료 인터럽트가 동시에 들어오면, 인터럽트 컨트롤러가 우선순위를 판단해서 CPU에 순서대로 전달합니다. 우선순위가 높은 인터럽트가 먼저 처리됩니다. 인터럽트 컨트롤러는 특정 인터럽트를 무시하도록 마스킹(Masking) 하는 기능도 제공합니다. 처리하고 싶지 않은 인터럽트를 임시로 차단할 수 있습니다.
인터럽트 vs 폴링 — 무엇을 쓸 것인가?
| 구분 | 폴링 | 인터럽트 |
| 구현 난이도 | 단순 | 상대적으로 복잡 |
| CPU 효율 | 낮음 (계속 확인) | 높음 (이벤트 때만 처리) |
| 반응 속도 | 폴링 주기에 의존 | 즉시 |
| 적합한 상황 | 이벤트가 매우 자주 발생할 때 | 이벤트가 불규칙하게 발생할 때 |
이벤트가 매우 자주 발생하는 경우엔 오히려 폴링이 유리할 때도 있습니다. 인터럽트는 상태를 저장하고 복원하는 오버헤드가 있기 때문입니다. 하지만 대부분의 임베디드 시스템에서는 인터럽트가 기본입니다.
💡 AI를 MCU에서 돌리면 — SFR·인터럽트 관점
문제
음성 AI 파이프라인에서 인터럽트 설계는 시스템 전체 성능을 좌우합니다. 마이크에서 16kHz로 오디오를 샘플링하면 1ms마다 16개의 샘플이 생깁니다. 이걸 폴링으로 처리하면 CPU가 1ms마다 ADC/I2S SFR을 읽는 작업에 묶여 있어야 합니다. AI 추론은 그 틈에 끼워 넣어야 하는데, 추론이 길어지면 샘플이 누락됩니다.
해결 방향
현실적인 구조는 DMA + 인터럽트 조합입니다. DMA가 마이크 데이터를 자동으로 메모리 버퍼에 채우고, 버퍼가 가득 차면 DMA 완료 인터럽트가 발생합니다. CPU는 이 인터럽트를 받아서 ISR에서 FFT와 AI 추론을 시작합니다. 오디오 수신은 DMA가, 연산은 CPU가 담당하는 병렬 구조입니다.
인터럽트 우선순위 설계도 중요합니다. DMA 완료 인터럽트는 높은 우선순위로, AI 추론 관련 처리는 낮은 우선순위로 설정해서, 오디오 버퍼 오버런이 발생하지 않도록 합니다.
더 나아가 이중 버퍼(Double Buffering) 를 씁니다. 버퍼를 두 개 준비해서, DMA가 버퍼 A를 채우는 동안 CPU는 버퍼 B를 처리합니다. DMA가 버퍼 A를 다 채우면 버퍼 B로 전환하고, CPU는 이제 버퍼 A를 처리합니다. 데이터 수신과 처리가 끊김 없이 교대로 진행됩니다.
정리
- SFR은 소프트웨어와 하드웨어를 연결하는 다리입니다. SFR 비트를 쓰거나 읽는 것만으로 핀의 전압을 제어하고 외부 상태를 감지할 수 있습니다.
- GPIO 출력은 SFR 비트에 0/1을 써서 핀 전압을 LOW/HIGH로 제어합니다.
- GPIO 입력은 SFR 비트를 읽어서 핀에 들어오는 전압 상태를 파악합니다.
- 폴링은 CPU가 계속 상태를 확인하는 방식이고, 인터럽트는 이벤트 발생 시 하드웨어가 CPU에 알리는 방식입니다.
- 인터럽트는 CPU 효율이 높고 반응이 빠르지만 구현이 복잡합니다. 대부분의 임베디드 시스템에서 기본으로 사용합니다.
- AI 추론 파이프라인에서는 DMA + 인터럽트 + 이중 버퍼 조합으로 오디오 수신과 연산을 병렬화하는 것이 핵심입니다.
'Model Lightening > MCU' 카테고리의 다른 글
| MCU 입문 [3] - MCU에게 일을 시키는 방법: 프로그래밍 언어와 개발 환경 (0) | 2026.03.02 |
|---|---|
| MCU 입문 [2] - MCU를 작동시키는 주변 하드웨어(전원, 클럭, 리셋) (0) | 2026.03.02 |
| MCU 입문 [1] - MCU란 무엇인가? (0) | 2026.02.27 |