임베디드 면접 학습 노트 목차

MCU·ARM Cortex-M — 임베디드 면접 (실제 기출 기반·심화)

"전원 켜면 어떻게 main까지 가나", "부팅 시 첫 두 워드는?", "MSP랑 PSP 차이, 언제 PSP를 쓰나", "벡터 테이블 역할", "NVIC가 뭐냐", "AHB vs APB", "ARM이 왜 RISC인가", "Cortex-M4랑 M0 차이", "JTAG 용도" — 프로세서 내부와 부팅을 아는지 보는 단골. RTOS·인터럽트·부트로더의 토대다.

펌웨어 면접의 단골 흐름: "보드에 전원을 넣으면 main까지 무슨 일이 일어나나?" → 여기서 막히면 임베디드 기본기가 없다고 본다.


1. ARM은 RISC·Cortex-M 계열 (★ 단골)

실제 질문: "RISC와 CISC 차이, ARM이 RISC 기반인 이유는?" · "Cortex-M4와 M0의 차이는?" (gyoogle ARM 프로세서·velog @verilog Q26)

  • RISC(ARM): 명령어가 단순·고정 길이·1사이클 지향 → 적은 트랜지스터·저전력·파이프라인 유리. CISC(x86): 복잡·가변 길이 명령. 임베디드는 전력·면적이 생명이라 RISC.
  • Cortex-M 계열: M0/M0+(최소·저전력·무 FPU), M3(범용), M4(DSP 명령 + 옵션 FPU), M7(고성능·옵션 L1 캐시). M0엔 FPU·DSP가 없다.

꼬리질문: "ARM이 임베디드를 장악한 이유?" → 저전력·라이선스(IP) 모델·풍부한 생태계. / "M4의 FPU는 항상 켜져 있나?" → 리셋 시 비활성. CPACR의 CP10/CP11을 켜야(CPACR |= (0xF<<20) + DSB/ISB) 활성, 안 켜고 부동소수 쓰면 폴트.

함정: ❌ "Cortex-M0에도 FPU가 있다" → 없다(M4F/M7부터 옵션).


2. 레지스터 (★ 단골)

레지스터역할
R0–R12범용
R13 = SP스택 포인터 — MSP/PSP로 뱅킹(3절)
R14 = LR링크 레지스터(복귀 주소·예외 시 EXC_RETURN)
R15 = PC프로그램 카운터
xPSR상태(APSR 플래그·IPSR 예외번호·EPSR Thumb 비트)
PRIMASK / BASEPRI / FAULTMASK인터럽트 마스킹(임계구역)
CONTROL스택 선택(MSP/PSP)·특권(privileged/unprivileged)·FP 컨텍스트 추적(FPCA)

⚠️ **FPU 활성은 CONTROL이 아니라 CPACR(CP10/CP11)**다. CONTROL의 FPCA는 FP 컨텍스트 사용 중인지 추적하는 상태 비트일 뿐 enable이 아니다.

깊이: PRIMASK=1(__disable_irq())는 모든 일반 인터럽트 차단 → 짧은 임계구역. BASEPRI지정 우선순위 이하만 차단(더 정교). 인터럽트 편의 공유 변수 보호에서 다시 나온다.


3. 동작 모드·MSP/PSP (★★ 단골·RTOS 직결)

실제 질문: "MSP와 PSP의 차이는? 언제 PSP를 쓰나?" (Aticleworld·velog @embeddedjune)

  • Thread 모드: 일반 코드(main·RTOS 태스크). 특권/비특권 가능, MSP 또는 PSP 사용.
  • Handler 모드: 예외·인터럽트(ISR). 항상 특권·항상 MSP.
  • MSP(Main Stack Pointer): 리셋 후 기본·모든 핸들러. PSP(Process Stack Pointer): RTOS가 태스크마다 따로 둠.

왜 두 스택인가?(★ 핵심 꼬리) RTOS는 커널/ISR은 MSP, 각 태스크는 자기 PSP를 쓴다 → 태스크 스택이 넘쳐도 커널 스택을 안 건드림(안정성)·컨텍스트 스위칭 때 PSP만 교체하면 됨. CONTROL 레지스터 SPSEL 비트로 Thread 모드 스택을 MSP↔PSP 전환.

다이어그램 로딩 중…

함정: ❌ "ISR도 PSP를 쓴다" → Handler 모드는 항상 MSP.


4. 부팅 시퀀스 — 전원에서 main까지 (★★★ 최빈출·재검증)

실제 질문: "Cortex-M 부팅 시 첫 두 워드는 무엇인가?" · "전원을 켜면 main까지 어떤 과정?" (Baewonchan Medium·velog @embeddedjune SW Analyse)

다이어그램 로딩 중…
  1. 리셋 → 코어가 주소 0x0000_0000의 첫 워드를 읽어 MSP에 로드(스택 꼭대기).
  2. 0x0000_0004의 워드(리셋 벡터)를 PC에 로드Reset_Handler로 점프(Thread 모드·MSP·특권).
  3. SystemInit(클럭/PLL·VTOR — 클럭을 먼저 올려야 이후가 빠름) 호출.
  4. C 런타임(__main/crt0)이 .data를 Flash→RAM 복사, .bss0 클리어(C 편) → main.

⚠️ 3·4의 순서는 toolchain 의존이다. 표준 CMSIS/ARM CompilerReset_Handler → SystemInit() → __main(.data/.bss) → main이고, 일부 GCC 베어메탈 startup.data/.bss → SystemInit → main. 단정하지 말 것.

그래서 **벡터 테이블의 0번 엔트리는 ISR이 아니라 "초기 스택 포인터 값"**이고, 1번이 Reset_Handler다. 이게 "첫 두 워드" 질문의 정답.

꼬리질문: ".data 초기값은 어디 있었나?" → Flash(부팅 시 RAM 복사). / "startup이 main 전에 또 하는 일?" → 클럭 설정·C++라면 전역 생성자 호출.

함정: ❌ "벡터 테이블 0번이 첫 ISR이다" → 0번은 초기 MSP 값.


5. 벡터 테이블·NVIC·VTOR (★ 단골)

실제 질문: "인터럽트 벡터 테이블의 역할은?" · "벡터 테이블의 기본 주소는?" · "NVIC가 무엇인가?" (velog @verilog Q27·Q28·Q72)

  • 벡터 테이블: 각 예외/인터럽트의 핸들러 주소 배열. 인터럽트가 오면 코어가 해당 엔트리로 직접 점프(원인 검색 불필요 → 빠름).
  • 기본 주소: 보통 0x0000_0000(Flash 시작). **VTOR(Vector Table Offset Register)**로 재배치 가능(Cortex-M0+·M3·M4·M7 — 순수 M0는 VTOR 없음).
  • NVIC(Nested Vectored Interrupt Controller): Cortex-M 내장. 인터럽트 enable·우선순위·중첩(nested)을 관리. 우선순위 숫자가 작을수록 높고, 선점/서브 우선순위로 그룹핑하며, RTOS는 컨텍스트 스위칭을 **PendSV(최저 우선순위)**로 미룬다(인터럽트·RTOS 편에서 심화).

VTOR가 왜 중요?(★) 부트로더가 자기 벡터 테이블로 시작한 뒤 앱으로 점프할 때, VTOR를 앱의 벡터 테이블 주소로 바꾼다. OTA·듀얼뱅크 부트의 핵심.

꼬리질문: "벡터 테이블을 RAM으로 옮기는 이유?" → 런타임 ISR 교체·부트로더↔앱 전환(VTOR). / "벡터 테이블 엔트리 주소의 LSB가 1인 이유?" → Thumb 비트(7절).

함정: ❌ "벡터 테이블은 항상 0번지에 고정" → VTOR로 재배치 가능.


6. 버스 — AHB vs APB (★ 단골)

실제 질문: "AHB와 APB의 차이는?" (velog @verilog Q25)

다이어그램 로딩 중…
  • AHB(Advanced High-performance Bus): 고속·코어·메모리·고속 주변장치(DMA·일부 GPIO).
  • APB(Advanced Peripheral Bus): 저속·단순·대부분 주변장치(UART·I2C·SPI·타이머). AHB-APB 브리지로 연결. 둘 다 AMBA(ARM 버스 표준).

깊이: APB는 클럭 도메인이 따로(보통 느림) → 주변장치 클럭/prescaler 설정이 데이터시트마다 다르다. 타이머·UART baud 계산이 APB 클럭 기준임을 놓치면 통신이 안 된다.

함정: ❌ "모든 주변장치가 AHB에 붙는다" → 대부분 저속은 APB.


7. 예외 자동 스태킹·Thumb·비트밴딩 (★ 심화)

  • 예외 진입 시 하드웨어 자동 스태킹: 코어가 8개 레지스터(xPSR·PC·LR·R12·R3–R0)를 스택에 자동 push → ISR을 일반 C 함수로 작성 가능(AAPCS caller-saved 보존). 복귀 시 자동 pop.
  • EXC_RETURN: 예외 진입 때 LR에 매직값이 들어가 복귀 모드·스택·FPU 상태를 인코딩 — 0xFFFF_FFF9(Thread+MSP)·0xFFFF_FFFD(Thread+PSP)·0xFFFF_FFF1(Handler 복귀, 중첩 인터럽트). FPU 사용 시 bit[4]=0(확장 프레임). ISR이 이 값으로 복귀하면 하드웨어가 정확히 복원.
  • Thumb-2 ISA: Cortex-M은 Thumb 상태만 실행(ARM 상태 없음)·16/32비트 혼합으로 코드 밀도↑. 그래서 벡터 테이블의 함수 주소는 항상 LSB=1(Thumb 비트) — 짝수 주소로 점프하면 INVSTATE UsageFault(미처리·비활성 시 HardFault로 승격).
  • 비트밴딩(bit-banding): SRAM·주변장치의 비트 하나를 별도 별칭 주소에 매핑 → 읽기-수정-쓰기 없이 원자적 단일 비트 접근(인터럽트와 안전). ARMv7-M 옵션(M3/M4가 보통 지원·M7 미지원).

꼬리질문: "ISR에서 레지스터를 직접 보존 안 해도 되나?" → caller-saved 8개는 하드웨어가 자동 → C 함수로 충분. / "FPU 쓰면 컨텍스트 스위칭은?" → 예외 진입 시 HW가 S0–S15+FPSCR만 자동 스태킹, S16–S31은 RTOS가 SW로 저장. lazy stacking은 S0–S15의 실제 push를 FP 명령 실행 시까지 지연(기본 ON).


8. 클럭·PLL·Bring-up·디버깅 (★ 실무 단골)

실제 질문: "PLL이 무엇인가?" · "JTAG의 용도는?" · "보드 bring-up 시 첫 확인 항목은?" · "디버깅 방법 3가지?" (velog @verilog Q13·Q17·Q24·Q139·Q140)

  • PLL(Phase-Locked Loop): 저속 외부/내부 클럭을 체배해 코어 고속 클럭 생성(예: 8MHz → 168MHz). 부팅 초기 SystemInit에서 설정.
  • JTAG/SWD: 디버그·플래시 쓰기·정지/스텝/레지스터·메모리 관찰. SWD는 JTAG의 2핀(SWDIO/SWCLK) 경량판(핀 절약).
  • Bring-up 첫 확인: ① 전원(전압 레일) ② 클럭(오실레이터·PLL lock) ③ MMIO 접근성(레지스터 read/write) — 이게 안 되면 그 위 코드는 의미 없다.
  • 디버깅 3종: UART printf(로그)·GPIO 토글(오실로스코프로 타이밍·도달 여부)·JTAG/SWD(중단점·메모리).

꼬리질문: "printf 디버깅의 함정?" → 느리고 재진입·블로킹이라 ISR·타이밍을 왜곡(인터럽트 편). 대안 GPIO 토글·SWO ITM. / "부트로더의 역할?" → 앱 검증·업데이트·VTOR 전환 후 점프.


한국 임베디드 면접 단골 Q&A (답변 골격)

질문핵심 답
RISC vs CISC·ARM단순·고정길이·저전력(RISC) / ARM은 RISC
M0 vs M4M0 저전력·무FPU / M4 DSP+옵션 FPU
레지스터R0-12·SP(MSP/PSP)·LR(EXC_RETURN)·PC·xPSR·CONTROL
MSP vs PSP커널/ISR=MSP, 태스크=PSP(격리·스위칭)
Thread vs Handler일반(priv/unpriv·MSP/PSP) vs 예외(항상 특권·MSP)
부팅 첫 두 워드0x0=초기 MSP, 0x4=Reset_Handler
전원→mainMSP·PC 로드→startup(.data/.bss)→SystemInit→main
벡터 테이블·VTOR핸들러 주소 배열·재배치(부트로더/OTA)
NVIC벡터·우선순위·중첩 인터럽트 컨트롤러
AHB vs APB고속(메모리·코어) vs 저속 주변장치·브리지
자동 스태킹·Thumb예외 시 8레지스터 HW push·함수 주소 LSB=1
PLL / JTAG클럭 체배 / 디버그·플래시·SWD 경량판
bring-up·디버깅전원·클럭·MMIO / printf·GPIO토글·JTAG

꼬리질문 대비 (상 난이도)

  • "RTOS는 왜 PSP를 쓰나?" → 태스크별 스택 격리·오버플로가 커널 안 건드림·스위칭 시 PSP만 교체.
  • "부트로더에서 앱으로 점프하려면?" → VTOR를 앱 벡터 테이블로 + 앱 초기 MSP 설정 + 리셋 핸들러로 점프.
  • "벡터 테이블 함수 주소를 짝수로 넣으면?" → Thumb 비트(LSB)=0 → 점프 시 UsageFault/HardFault.
  • "임계구역은 PRIMASK? BASEPRI?" → PRIMASK는 모든 인터럽트 막아 지연↑ → BASEPRI로 낮은 우선순위만 막거나 최소화.
  • "printf가 안 찍힌다, 어디부터?" → 전원·클럭·UART 핀·baud(APB 클럭 기준)·GPIO 토글로 도달 확인.

한 줄 요약 — ARM=RISC, Cortex-M(M0 무FPU↔M4 DSP+FPU↔M7 L1). 레지스터 R0-12·SP(MSP/PSP)·LR(EXC_RETURN)·xPSR·CONTROL·PRIMASK/BASEPRI. Thread(MSP/PSP) vs Handler(항상 MSP·특권). 부팅=0x0→MSP·0x4→Reset_Handler→startup(.data/.bss)→SystemInit→main. 벡터 테이블(핸들러 배열·VTOR 재배치)·NVIC·고속 AHB/저속 APB. 예외 8레지스터 자동 스태킹·Thumb 전용(주소 LSB=1)·비트밴딩. PLL 체배·JTAG/SWD·bring-up(전원·클럭·MMIO).

(출처 — 한국 면접 기출·1차자료 교차검증 2026-06: velog @verilog Firmware 직무적성(Q13·17·24·25·26·27·28·72·139·140)·gyoogle ARM 프로세서·velog @embeddedjune SW Analyse·Aticleworld MSP vs PSP · ARMv7-M Architecture Reference Manual(레지스터·예외·EXC_RETURN·VTOR)·ARM Cortex-M Generic User Guide·AMBA AHB/APB 사양 교차검증.)

메모리·아키텍처 — 메모리맵·MMU/MPU·캐시·DMA·엔디안·정렬인터럽트 — 벡터·우선순위·latency·재진입·ISR 금기·디바운싱