ARM이 설계한 마이크로컨트롤러용 프로세서 코어 계열. STM32, nRF, RP2040 등 대부분의 32비트 MCU가 이 코어를 쓴다.
계열 비교
| 아키텍처 | 명령어 | 특징 | |
|---|---|---|---|
| M0 / M0+ | ARMv6-M | Thumb 일부 | 가장 작고 저전력. 정렬 안 된 접근 불가 |
| M3 | ARMv7-M | Thumb-2 | 범용. 비트 밴딩, 하드웨어 나눗셈 |
| M4 | ARMv7E-M | + DSP | DSP 명령, 선택적 FPU |
| M7 | ARMv7E-M | + DSP | 캐시, 슈퍼스칼라, 고성능 |
| M23 / M33 | ARMv8-M | + TrustZone | 보안 분리 |
M4와 M7의 차이가 실무에서 중요하다 — M7에는 L1 캐시가 있어 DMA와 함께 쓸 때 캐시 관리가 필요해진다. M4 코드를 M7로 포팅하면 멀쩡하던 DMA가 깨지는 이유다.
Thumb-2 — 코드 밀도가 핵심
- ARM 명령어 — : 전부 32비트. 빠르지만 코드가 크다
- Thumb — : 전부 16비트. 작지만 표현력이 제한적
- Thumb-2 — : 16비트와 32비트를 섞어 쓴다 ← Cortex-M은 이것만 지원
플래시 용량이 곧 원가인 MCU에서 코드 크기는 성능만큼 중요하다. Thumb-2는 ARM 대비 약 30% 작은 코드로 비슷한 성능을 낸다.
Cortex-M은 ARM 명령어 모드가 아예 없다. 그래서 함수 주소의 최하위 비트가 항상 1이다(Thumb 상태 표시). 벡터 테이블에 핸들러 주소를 넣을 때 컴파일러가 자동으로 +1 해 주는데, 직접 주소를 계산해 넣으면 이 비트를 빠뜨려 HardFault가 난다.
레지스터
-
R0~R12 — 범용 (R0~R3은 인자·반환값, R4~R11은 호출자 보존) R13 (SP) 스택 포인터 — MSP / PSP 두 개가 뱅킹됨 R14 (LR) 링크 레지스터 — 복귀 주소 R15 (PC) 프로그램 카운터
-
xPSR — 상태 레지스터 (플래그, 현재 인터럽트 번호)
-
CONTROL — 특권 수준, 스택 선택, FPU 활성
두 가지 실행 모드 / 두 가지 특권 수준
Handler 모드 : 예외·인터럽트 처리 중. 항상 특권. 항상 MSP 사용
- Thread — 모드 : 일반 코드. 특권/비특권 선택 가능. MSP 또는 PSP
RTOS는 이 구조를 활용한다 — 커널은 특권 + MSP, 태스크는 비특권 + PSP로 분리해 태스크가 시스템 레지스터를 건드리지 못하게 한다.
예외 모델 — 하드웨어가 많이 해 준다
- ① 자동 스태킹 — — R0-R3, R12, LR, PC, xPSR 을 하드웨어가 저장
- ② 테일체이닝 — — 연속 인터럽트에서 복원·저장 생략
- ③ 늦은 도착 — — 스태킹 중 더 높은 우선순위가 오면 그쪽 먼저
- ④ 벡터 테이블 — — 인터럽트별 핸들러 주소를 직접 점프
이 덕분에 ISR을 평범한 C 함수로 작성할 수 있다.
다른 아키텍처에서 필요한 __interrupt 같은 특수 키워드가 없다.
FPU — 선택적이고 함정이 있다
- M4F / M7 — : 단정밀도 FPU (M7은 배정밀도 옵션) M0/M0+/M3 : FPU 없음 → float 연산이 소프트웨어 에뮬레이션 (수십~수백 사이클)
FPU를 쓰려면 세 가지가 모두 맞아야 한다.
- ① CPACR 레지스터로 FPU 활성화 (startup 코드에서)
- ② 컴파일 옵션: -mfpu=fpv4-sp-d16 -mfloat-abi=hard
- ③ RTOS 사용 시 컨텍스트 스위칭에 FPU 레지스터 포함
①을 빠뜨리면 첫 float 연산에서 UsageFault가 난다. ③을 빠뜨리면 태스크 간에 float 값이 오염되는데, 재현이 어렵다.
자주 나오는 오해 — FPU 활성화는
CONTROL레지스터가 아니라CPACR(Coprocessor Access Control Register)로 한다.CONTROL의 FPCA 비트는 "현재 FPU를 쓰고 있는가"를 나타내는 상태 비트다.
SysTick — 모든 Cortex-M에 있는 타이머
24비트 다운 카운터. 0에 도달하면 예외 발생 RTOS의 틱, HAL_Delay 의 기준 아키텍처 표준이라 벤더가 달라도 동일하게 동작한다