지난번에 STM32F103C8T6 칩으로 고추건조기를 만든 임베디드 프로젝트를 진행했다. STM32F103C8T6 칩은 Cortex-M3 코어에 Flash 64KB, SRAM 20KB짜리 칩이다. 그때 프로젝트를 진행하면서 가졌던 의문이 하나 있었다. "얘는 가상 메모리가 없는 것 같은데?"
데스크톱에서 돌아가는 프로그램은 가상 주소 공간 위에서 동작한다. 프로세스마다 같은 가상 주소가 서로 다른 물리 주소로 매핑되고, 그 변환을 하드웨어가 처리한다. 그런데 이 칩의 펌웨어에서는 그런 변환 계층이 보이지 않았다. 데이터시트의 메모리 맵에 적힌 주소가 코드에서 쓰는 주소와 그대로 같았다.
찾아보니 이 칩에 가상 메모리가 없는 것은 맞았다. 다만 "임베디드에는 가상 메모리가 없다"로 일반화하면 틀린다는 것도 알게 됐다. 같은 ARM 계열 안에서도 가상 메모리를 완전히 갖춘 칩이 있고, 의도적으로 빼버린 칩이 있다. 이 글은 그 경계가 어디서 갈리는지, 그리고 STM32F103이 그 안에서 어디에 위치하는지를 정리한다.
MMU와 MPU는 다른 장치다

가상 메모리를 이야기할 때 먼저 구분해야 할 두 하드웨어 블록이 있다.
MMU(Memory Management Unit)는 가상 주소를 물리 주소로 변환하는 장치다. 페이지 테이블을 참조해 가상 주소 공간을 물리 메모리에 매핑하고, 그 과정에서 페이지 단위 접근 권한도 함께 검사한다. 가상 메모리 시리즈 2편과 3편에서 다룬 페이지 테이블, TLB, 페이지 폴트가 모두 이 MMU를 전제로 한 메커니즘이다.
MPU(Memory Protection Unit)는 이름이 비슷하지만 하는 일이 다르다. MPU는 주소 변환을 하지 않는다. 미리 정의된 메모리 영역(region)별로 접근 권한과 속성만 설정한다. 예를 들어 특정 영역을 읽기 전용으로 지정하거나, 지정한 영역을 벗어난 접근에 폴트를 내도록 설정하는 식이다. 주소는 변환되지 않고 그대로 쓰이며, 위반이 발생하면 폴트를 일으킨다.
한 문장 요약
MMU는 "주소를 바꾸고 보호한다", MPU는 "주소는 그대로 두고 보호만 한다". 가상 메모리는 주소 변환에서 출발하므로 MPU만으로는 가상 메모리가 성립하지 않는다.
같은 ARM이라도 갈린다 — Cortex 프로파일

ARM Cortex는 단일 제품군이 아니라 세 개의 아키텍처 프로파일로 나뉜다. 마케팅 분류가 아니라 ARM Architecture Reference Manual에 규정된 서로 다른 아키텍처이며, 명령어 집합·예외 모델·메모리 모델이 각각 다르다.
- Cortex-A (Application): MMU를 갖추고 완전한 가상 메모리를 지원한다. 리눅스, 안드로이드, Windows on Arm 같은 풀 기능 OS를 돌리기 위한 프로파일이다. 스마트폰의 메인 CPU, 라즈베리파이, 차량 인포테인먼트가 여기에 속한다.
- Cortex-R (Real-Time): 실시간 처리용 프로파일. MMU 대신 MPU를 쓴다. 자동차·산업 제어처럼 마감 시한을 놓치면 실패로 간주되는 영역을 겨냥한다.
- Cortex-M (Microcontroller): 저전력 마이크로컨트롤러용. MMU가 없다. 일부 모델(M7, M33, M55 등)에 MPU 옵션이 있을 뿐이다.
STM32F103은 이 중 Cortex-M 코어, 그중에서도 M3를 쓴다.
"임베디드"라는 단어 안의 두 부류
여기서 "임베디드에는 가상 메모리가 없다"는 일반화가 왜 틀리는지가 드러난다. 임베디드라는 단어는 성격이 다른 두 부류를 한데 묶는다.
한쪽은 MCU(Microcontroller Unit)다. STM32, ATmega, ESP32, RP2040이 여기 속한다. MMU가 없고, OS 없이 또는 RTOS(Real-Time Operating System) 위에서 펌웨어가 직접 돈다.
다른 한쪽은 AP/SoC(Application Processor / System on Chip)다. 라즈베리파이의 Cortex-A 코어, 안드로이드 기기, 차량 인포테인먼트 시스템이 여기 속한다. MMU를 완전히 갖추고 리눅스나 안드로이드 같은 OS 위에서 여러 프로세스를 돌린다.
둘 다 "임베디드"로 불리지만 가상 메모리 유무는 정반대다. 그래서 기준은 칩의 크기나 용도가 아니라 하나의 질문으로 좁혀진다 — OS 위에서 여러 프로세스를 격리해 돌릴 것인가. ARM의 칩 선택 가이드도 같은 기준을 제시한다. 리눅스·안드로이드처럼 MMU와 가상 메모리가 필요한 OS를 요구하면 Cortex-A를 쓰라는 것이다.
MCU가 가상 메모리를 안 쓰는 이유
MCU에 가상 메모리가 없는 것을 "메모리가 작아서"로만 설명하는 경우가 많지만, 메모리 크기는 결과적 이유에 가깝다. 더 근본적인 이유가 셋 더 있다.
하드웨어 비용
MMU는 추가 게이트와 전력을 요구하는 블록이다. 페이지 테이블 워크 로직, TLB, 권한 검사 회로가 모두 실리콘 면적과 소비 전력으로 이어진다. 수십 센트 단가에 마이크로암페어급 소비 전력을 다투는 MCU 시장에서 이 비용은 그대로 부담이 된다.
결정론(determinism)
이것이 실시간 시스템에서 가장 중요한 이유다. 가상 메모리는 본질적으로 지연을 예측 불가능하게 만든다. 페이지 폴트가 발생하면 폴트가 난 프로세스는 디스크에서 페이지를 읽어 올 때까지 블록되고, 그동안 다른 프로세스가 CPU를 쓴다. 문제는 그 비용의 크기다. 메모리와 디스크의 속도 차는 대략 10⁴~10⁵배에 이르고, 데스크톱에서는 이런 지연이 가끔 생겨도 전체 성능에 묻혀 티가 나지 않는다. 하지만 응답 시간이 마이크로초 단위로 정해진 실시간 제어에서는 폴트 한 번이 곧 데드라인 위반으로 이어진다. 페이지 폴트의 블록 동작과 메모리·디스크 속도 차는 가상 메모리 시리즈 3편에서 다뤘다.
결정론과 가상 메모리
실시간 시스템에서 "평균이 빠른 것"보다 "최악이 예측 가능한 것"이 중요하다. 가상 메모리는 평균을 개선하는 대신 최악 지연의 예측 가능성을 떨어뜨린다. 그래서 실시간 영역에서는 의도적으로 배제된다.
메모리 모델의 단순성
MCU는 단일 물리 주소 공간을 그대로 쓴다. Flash, SRAM, 그리고 주변장치 레지스터가 모두 하나의 주소 공간에 배치된다. 주변장치를 메모리처럼 주소로 접근하는 이 방식을 MMIO(Memory-Mapped I/O)라 한다. 주소 변환 계층이 없으니 포인터 주소가 곧 물리 주소이고, 데이터시트의 메모리 맵이 그대로 코드의 주소가 된다. 펌웨어 입장에서는 이 단순함이 오히려 장점이다.
여기서 짚어둘 점이 있다. MMU를 갖춘 코어에서 단순히 MMU를 끄는 것은 MCU의 단순함을 얻는 방법이 못 된다. MMU를 갖춘 코어에서 단순히 MMU를 끈다고 MCU처럼 단순해지는 것은 아니다. ARM 아키텍처에서 캐시 가능성(cacheability) 같은 메모리 속성은 페이지 테이블 안에 기록되기 때문에, MMU를 끄면 그 속성도 함께 사라진다. Armv8-A에서는 MMU가 꺼지면 모든 접근이 Device 메모리로 취급되어 캐시가 동작하지 않는다. MMU가 없는 단순함과 MMU를 끈 상태는 같지 않다 — MCU는 애초에 MMU 없이 설계되어 이 문제 자체가 없다.
메모리 크기

위 세 가지의 결과로, MCU는 애초에 페이지 단위로 관리할 만큼 큰 메모리를 갖지 않는다. 수십 KB에서 수 MB 규모의 SRAM에 가상 메모리의 페이지 관리 오버헤드를 얹는 것은 이득이 없다. 그래서 메모리가 작은 것은 가상 메모리가 없는 원인이 아니다. 순서가 반대다 — 가상 메모리가 필요 없게 설계했기 때문에 메모리도 그만큼 작은 것이다.
중간 지대 — MMU 없이 보호만 하는 영역
메모리 보호 방식은 MMU 있음과 없음으로 딱 갈리는 것처럼 보이지만, 실제로는 그 사이에 보호 메커니즘만 두는 중간 지대가 있다.
Cortex-R은 자동차·산업 실시간 영역을 위한 프로파일로, MMU 없이 MPU로 영역 단위 보호를 제공한다. 주소 변환의 불확정성은 피하면서 메모리 보호는 확보하는 절충이다.
Cortex-M + MPU + RTOS 조합에서는 MPU로 RTOS 태스크 간 메모리를 격리할 수 있다. FreeRTOS나 Zephyr 같은 RTOS는 이 MPU를 활용해 사용자 스레드와 커널 스레드를 분리한다. 가상 메모리는 없지만 "태스크가 남의 메모리를 건드리면 폴트"라는 보호는 가능하다.
TrustZone은 또 다른 격리 방식이다. 여기서 주의할 점이 있는데, TrustZone은 페이지 테이블 기반이 아니다. Cortex-M의 TrustZone-M은 SAU(Security Attribution Unit) 설정으로 메모리를 secure/non-secure 영역으로 나누고, 그 상태를 버스 인터커넥트까지 전파해 하드웨어 수준에서 격리한다. 가상 메모리의 주소 변환과는 완전히 다른 메커니즘으로, 보안 격리를 별도 하드웨어로 구현한 것이다.
그렇다면 처음의 STM32F103C8T6은 이 구분에서 어디에 속하나. MPU는 Cortex-M에서도 선택적 컴포넌트라 같은 M3 코어여도 부품마다 탑재 여부가 갈린다. 그런데 이 칩의 데이터시트(STM32F103x8/xB) Features 목록에는 MPU가 없다.

즉 그 프로젝트의 칩은 MMU도 MPU도 없는, 보호 계층이 전혀 없는 단일 주소 공간이었다. 포인터 주소가 곧 물리 주소로 보였던 것은 변환 계층이 없어서였고, 잘못된 주소에 써도 막아줄 영역 보호조차 없었다는 뜻이다.
정리
"임베디드 = 가상 메모리 없음"은 틀린 일반화다. 정확한 기준은 메모리 크기도 칩 용도도 아니라 "OS 위에서 여러 프로세스를 격리해 돌릴 것인가"이다. 그 답이 예라면 MMU를 갖춘 Cortex-A로 가고, 아니라면 MMU 없는 Cortex-M으로 충분하다. STM32F103에 가상 메모리가 없던 것은 결함이 아니라, 실시간성과 단순성과 비용을 위해 의도적으로 선택된 설계였다.
'Embedded' 카테고리의 다른 글
| [오제이 튜브 임베디드 강의] 외전. 최신 DS18B20 라이브러리로 고추건조기 리팩토링하기 (1) | 2026.05.06 |
|---|---|
| [오제이 튜브 임베디드 강의] 40. 클라스가 다른 ADC 강의 (1) | 2026.05.06 |
| [오제이 튜브 임베디드 강의] 39. 너무나도 중요한 ADC (0) | 2026.05.06 |
| [오제이 튜브 임베디드 강의] 38. 고추건조기 보드완성 (0) | 2026.05.06 |
| [오제이 튜브 임베디드 강의] 37. 보드 완성까지 두번 남았다 (0) | 2026.05.06 |