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

디버깅·신뢰성 — 임베디드 면접 (실제 기출 기반·심화)

"JTAG과 SWD 차이", "HardFault가 나면 원인을 어떻게 찾나", "스택 오버플로/메모리 손상 추적", "printf 없이 디버깅", "워치독 리셋 원인", "재현 안 되는 버그", "노이즈/EMC 대응" — 고장을 체계적으로 추적하고 견고하게 설계하는지를 본다. HardFault·디버그 인터페이스는 펌웨어 면접 필출.

함정 다발(★): ① JTAG과 SWD는 다른 기능? → 아님·동일 DAP 접근·핀만 다름HardFault는 그냥 리셋?fault 레지스터(CFSR/HFSR/BFAR/MMFAR)+스택된 PC로 원인 추적 ③ 스택 오버플로는 컴파일러가 잡음? → 런타임·MPU/워터마크 ④ 워치독 리셋=원인 모름? → 리셋 플래그+블랙박스 ⑤ printf로만 디버깅? → 타이밍 바꿈(Heisenbug).


1. JTAG vs SWD (★★ 단골 1순위)

실제 질문: "JTAG과 SWD 차이를 설명하라"(거의 필출) · "SWD는 핀 몇 개? 왜 SWD?" · "boundary scan이 뭔가?" · "여러 칩을 하나로 디버깅?"(데이지체인) (velog @embeddedjune·roboman)

  • JTAG(IEEE 1149.1): TAP 4핀 — TCK(클럭)·TMS(상태기계 제어)·TDI(입력)·TDO(출력) + 옵션 TRST. boundary scan: 각 핀에 셀을 두고 TDI→…→TDO로 시프트 → 칩 안 떼고 납땜·연결 검사. 여러 칩은 TDO→TDI 데이지체인.
  • SWD(Serial Wire Debug·ARM Cortex-M): 2선 — SWDIO(양방향)·SWCLK. 물리적으로 JTAG의 TMS/TCK 핀에 오버레이(커넥터 재사용).
  • 핵심(★): SWD는 JTAG과 동일한 디버그 기능에 접근 — 둘 다 같은 DAP(Debug Access Port = DP 물리연결 + AP 메모리/레지스터 접근)로 들어간다. 기능이 다른 게 아니라 핀만 4+ → 2로 줄인 전송계층. SWD는 Cortex-M 한정.
  • SWO(Serial Wire Output): SWD에 1핀 추가 → ITM 트레이스/printf를 코어 안 멈추고 출력(§3).

꼬리질문: "핀 부족 소형 MCU에 디버그+printf?" → SWD 2선 + SWO 1선(ITM)·UART 불필요. / "데이지체인 TDO 끊기면?" → 체인 스캔 불가·IDCODE 안 읽힘.

함정: ❌ "JTAG·SWD는 다른 기능" → 동일 DAP·핀 수만 다름. ❌ "SWD도 boundary scan" → boundary scan은 JTAG 고유(핀레벨 제조 테스트). ❌ "SWO가 SWD 데이터선" → 별도 출력 전용 핀.


2. HardFault 분석 (★★★ 펌웨어 면접 필출·가장 정확히)

실제 질문: "HardFault가 나면 원인을 어떻게 찾나?"(필출) · "널 포인터 역참조하면?" · "어느 줄에서 죽었는지 어떻게?" · "핸들러 안에서 뭘 보나?"

Fault 상태 레지스터(★ 정확한 주소):

레지스터주소역할
CFSR0xE000ED28UFSR(상위16)+BFSR(중간8)+MMFSR(하위8) 결합
HFSR0xE000ED2CFORCED(에스컬레이션)·VECTTBL
MMFAR0xE000ED34MemManage 폴트 주소
BFAR0xE000ED38BusFault 주소
  • 주요 비트: MMFSR DACCVIOL(데이터 접근 위반)·MMARVALID(bit7→MMFAR 유효) / BFSR PRECISERR(정확·복귀 PC가 원인)·IMPRECISERR(부정확·비동기)·STKERR(스택킹 폴트)·BFARVALID(bit7→BFAR 유효) / UFSR DIVBYZERO·UNALIGNED·UNDEFINSTR·NOCP(FPU 꺼진 채 FP) / HFSR FORCED(설정가능 폴트가 핸들러 비활성으로 HardFault로 에스컬레이션).
  • 자동 스택 프레임(8워드): 예외 진입 시 HW가 활성 스택(MSP/PSP)에 push — R0·R1·R2·R3·R12·LR·PC(offset 6=폴트 명령 위치)·xPSR.
다이어그램 로딩 중…
  • 어느 스택?(MSP/PSP): EXC_RETURN(LR)의 bit2가 스택 선택 비트 → 핸들러에서 TST LR,#4로 MSP/PSP를 골라 프레임 추출. (bit4=FPU 확장 프레임 여부.)
  • 흔한 원인: 널/초기화 안 된 포인터·정렬 안 된 접근·해제된 포인터·스택 오버플로(STKERR)·FPU 꺼진 채 FP(NOCP). 0 나눗셈·미정의 명령은 원래 UsageFault → 핸들러 비활성 시 HardFault 에스컬레이션(SCB->CCRDIV_0_TRP로 트랩).

꼬리질문: "어느 줄에서 죽었나?" → 스택된 PC→.map 대조·주소 폴트면 BFAR/MMFAR. / "BFAR=0x0?" → 널 역참조 가능성(VALID 비트 먼저). / "재현 안 되는 HardFault?" → 핸들러에서 coredump(PC·LR·CFSR·HFSR·BFAR·SP)를 예약 RAM/flash에 저장 후 재부팅 시 업로드(Memfault류).

함정: ❌ "HardFault는 그냥 리셋" → fault 레지스터+PC로 추적. ❌ "스택된 PC가 항상 정확" → IMPRECISERR(비동기 버스폴트)면 부정확(ACTLR.DISDEFWBUF로 precise 강제 가능). ❌ "0 나눗셈=HardFault" → 정확히는 UsageFault(트랩 켜야).


3. 브레이크포인트·트레이스 (★ 단골)

실제 질문: "HW BP vs SW BP 차이?" · "watchpoint가 뭔가?" · "flash 코드에 BP 몇 개?" · "코어 안 멈추고 로그?"(ITM/SWO)

  • SW BP: 원래 명령을 BKPT 명령으로 치환·halt 후 복원 → RAM 코드에 한해 무제한.
  • HW BP(FPB·Flash Patch and Breakpoint): 비교기 기반 → flash/ROM 코드도 가능하나 개수 제한(Cortex-M3는 명령 비교기 6개·M0/M0+는 최대 4개).
  • watchpoint(DWT·Data Watchpoint and Trace): 데이터 주소 접근 감시 — 특정 변수가 읽히거나 쓰일 때 halt → 변수 손상 추적 필수.
  • ITM/SWO: ITM->PORT에 쓰면 printf 트레이스가 TPIU→SWO 1핀으로 코어 거의 안 멈추고 출력(Serial Wire Viewer). ETM은 더 풍부한 명령 트레이스.

꼬리질문: "어떤 변수를 누가 망가뜨리는지 모를 때?" → DWT watchpoint를 그 주소에 걸어 쓰는 순간 halt→콜스택. / "flash BP 개수가 부족하면?" → 코드를 RAM에 올려 SW BP.

함정: ❌ "HW BP 무제한" → FPB 비교기 수 제한. ❌ "watchpoint=breakpoint" → BP는 명령 주소·watchpoint는 데이터 접근.


4. 스택/메모리 손상 (★★ 단골)

실제 질문: "스택 오버플로를 어떻게 탐지/추적?" · "버퍼 오버런으로 옆 변수가 망가지면?" · "RTOS 태스크 스택 크기를 어떻게 정하나?"

  • FreeRTOS configCHECK_FOR_STACK_OVERFLOW: Method 1(스위치 시 SP가 범위 내인지 — 빠르나 스위치 사이 오버플로는 놓침)·Method 2(스택을 패턴으로 채우고 마지막 유효 영역 훼손 검사·Method1 포함). 오버플로 시 vApplicationStackOverflowHook() 호출.
  • uxTaskGetStackHighWaterMark(): 시작 이후 남은 최소 스택(워터마크) → 0에 가까울수록 임박 → 스택 사이징 근거.
  • MPU 가드: 스택 끝에 접근불가 가드 영역 → 침범 시 MemManage Fault로 즉시. 버퍼 오버런(인접 변수·TCB 손상)은 DWT watchpoint로 손상 주소 감시가 정석.

꼬리질문: "오버플로 난 태스크?" → Hook의 pcTaskName·각 태스크 워터마크. / "스택을 얼마로?" → 워터마크 측정 + 최악 콜체인 + ISR 여유(마진 크게).

함정: ❌ "스택 오버플로는 컴파일러가 잡음" → 런타임 현상·MPU/워터마크 필요(-fstack-usage 정적 추정은 재귀/ISR 못 잡음). ❌ "Method 1이면 다 잡음" → 스위치 사이는 놓침 → Method 2/MPU 병행.


5. assert·로깅·watchdog·coredump (★★ 단골)

실제 질문: "워치독 리셋이 떴는데 원인을 모르면?" · "필드에서 가끔 리부팅, 어떻게?" · "메모리 적은 MCU에서 로깅?" · "assert를 릴리즈에 남기나?"

  • 리셋 원인 플래그(★): STM32 RCC_CSR(IWDGRSTF·WWDGRSTF·SFTRSTF·BORRSTF·PORRSTF…)·AVR MCUSR. 부팅 시 이 플래그로 워치독 vs 브라운아웃 vs 소프트 vs 파워온 구분 → "원인 모름"이 아님. 읽고 반드시 클리어(sticky).
  • 블랙박스 로깅: 예약/비휘발 RAM 링버퍼(__attribute__((section(".noinit"))))에 최근 이벤트 → 크래시·리셋 후에도 잔존·printf보다 비침습. coredump: 폴트 시 레지스터+스택을 덤프 후 재연결 시 업로드·심볼라이즈. 로그 레벨(ERROR/WARN/INFO/DEBUG)로 양 제어.
  • assert: 개발 중 즉시 halt·릴리즈는 로깅+안전 리셋으로 전환이 일반적.

꼬리질문: "워치독 리셋 후 원인?" → RCC_CSR 플래그 + 블랙박스 + coredump. / "워치독을 어디서 kick?" → 모든 태스크가 살아있다는 플래그를 모아 한 곳에서(한 태스크가 main을 굶겨도 다른 태스크가 kick하면 못 잡음).

함정: ❌ "워치독 리셋이면 원인 못 찾음" → 리셋 플래그+블랙박스로 추적. ❌ "리셋 플래그는 자동 클리어" → sticky·직접 클리어 안 하면 다음 부팅 오판.


6. EMC/ESD·전원 신뢰성 (★ 단골)

실제 질문: "노이즈로 오동작/리셋, 어떻게 대응?" · "디커플링 커패시터는 왜·어디에?" · "브라운아웃 보호?" · "ESD 보호 회로?"

  • 디커플링/바이패스 커패시터: 저ESR 세라믹 0.1~1µF를 각 전원핀 바로 옆에 → 스위칭 순간전류 공급·고주파 노이즈 필터(루프 인덕턴스↓). 대용량 벌크캡 병행.
  • BOR(Brown-Out Reset): 공급전압이 신뢰 동작 한계 아래로 떨어지면 MCU를 리셋 상태로 유지 → 복귀 시 정상 재시작 → 불완전 전압의 비결정 동작·플래시 손상 방지. 임계 레벨 설정 가능.
  • ESD 보호: GPIO에 TVS/ESD 다이오드로 클램프(내장 보호는 제한적·외부 필수). 견고한 그라운드 플레인·장거리/노이즈엔 *차동(RS-485/CAN)*으로 공통모드 제거(07편).

꼬리질문: "가끔 리셋, SW인지 HW인지?" → 리셋 플래그(BORRSTF vs 워치독 vs 소프트)로 1차 분기. / "노이즈로 통신 깨짐?" → 차동·종단저항·디커플링·접지 재검토.

함정: ❌ "디커플링캡은 아무 데나" → 각 전원핀 바로 옆(멀면 효과 급감). ❌ "전압 흔들림=SW 버그" → BOR/전원 무결성일 수 있음(BORRSTF 확인).


7. 필드 디버깅 — 재현 안 되는 버그 (★★ 시니어 단골)

실제 질문: "재현이 안 되는 버그를 어떻게 디버깅?" · "printf 넣으니 버그가 사라진다, 왜?" · "현장에서만 죽는 디바이스 원인 파악?"

  • Heisenbug: 관찰/디버깅하면 사라지거나 양상이 바뀌는 버그. printf·브레이크포인트가 실행 타이밍·상태를 바꿔 버그를 숨김(타이밍·동시성·race에서 흔함·probe effect).
  • printf의 함정: 타이밍을 바꿔 time-critical에서 Heisenbug 유발·리셋 전에 못 보면 증거 소실. → 대안: SWO/ITM 트레이스(비침습)·로직 애널라이저(외부 관측·코드 무변경)·DWT 사이클카운터(시간 측정)·coredump 업로드(필드 폴트의 레지스터/스택을 ELF로 심볼라이즈·fleet 단위 dedup).
  • 전략: 로그·통계로 조건을 좁히고·블랙박스로 크래시 직전 상태 보존·동일 크래시를 fleet 단위로 묶어 빈도/패턴 파악.

꼬리질문: "printf가 타이밍을 바꾸면?" → SWO/ITM·로직 애널라이저·DWT 타임스탬프. / "필드에서 죽는 디바이스?" → 블랙박스(noinit RAM)+워치독 리셋 플래그+coredump. / "race 의심?" → 외부 로직애널라이저로 비침습 관측·락/임계영역 점검.

함정: ❌ "printf로만 디버깅" → 타이밍 변경(Heisenbug). ❌ "재현 안 되면 못 고침" → 로그·통계·coredump로 추적. ❌ "디버거 붙이면 다 보임" → race는 halt 순간 사라짐.


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

질문핵심 답
JTAG vs SWD동일 DAP·기능 같고 핀만(4+ vs 2)·SWD는 Cortex-M·SWO 트레이스
boundary scanJTAG·핀 안 떼고 연결 검사·데이지체인
HardFault 원인CFSR/HFSR/BFAR/MMFAR + 스택된 PC
어느 줄?스택 PC(offset6)→맵파일·주소면 BFAR/MMFAR
MSP/PSP 판별EXC_RETURN bit2
HW vs SW BPFPB(개수 제한·flash) vs BKPT(RAM·무제한)·watchpoint=DWT 데이터
스택 오버플로런타임·FreeRTOS method1/2·워터마크·MPU 가드
워치독 리셋 원인RCC_CSR 플래그+블랙박스+coredump
디커플링캡0.1µF 전원핀 옆·노이즈 필터
브라운아웃BOR로 저전압 시 리셋 유지
재현 안 되는 버그Heisenbug·SWO/로직애널라이저·coredump·통계

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

  • "HardFault에서 stacked PC가 부정확하면?" → IMPRECISERR(비동기 버스폴트)·쓰기버퍼 끄면 precise.
  • "변수가 언제 망가지는지 모를 때?" → DWT watchpoint를 그 주소에.
  • "워치독을 한 곳에서만 kick하는 이유?" → 태스크 하나가 main을 굶겨도 다른 태스크 kick으로 못 잡음 → 플래그 집계.
  • "printf가 race를 숨긴다?" → probe effect → 외부 로직애널라이저·트레이스로 비침습 관측.
  • "필드 크래시를 fleet로 어떻게?" → coredump 업로드·동일 크래시 dedup·빈도 집계(Memfault류).

한 줄 요약JTAG(4핀·boundary scan)·SWD(2핀·Cortex-M·동일 DAP·기능 같고 핀만·SWO 트레이스). HardFault는 **CFSR(0xE000ED28)/HFSR/BFAR/MMFAR + 스택된 PC(offset6)**로 원인 추적(MSP/PSP는 EXC_RETURN bit2·0 나눗셈은 UsageFault). BP는 HW(FPB·제한)·SW(BKPT·RAM)·watchpoint(DWT). 스택 오버플로는 런타임·FreeRTOS method1/2·워터마크·MPU. 신뢰성은 리셋 플래그(RCC_CSR)+블랙박스+coredump·디커플링캡(전원핀 옆)·BOR·ESD TVS. 재현 안 되는 버그는 Heisenbug(printf가 타이밍 변경)→SWO/로직애널라이저/coredump·통계로 추적.

(출처 — 한국 면접 기출·1차자료 교차검증 2026-06: velog @embeddedjune(디버그·워치독)·roboman(JTAG/SWD) · 1차자료: Memfault — Cortex-M HardFault 디버깅·SEGGER KB — Cortex-M Fault·Keil AN209 — Fault Exceptions·ARM Developer — JTAG/SWD Interface·FreeRTOS — Stack overflow checking·Microchip AN2587 — EMI/EMC/ESD·Heisenbug — Wikipedia 교차검증.)

임베디드 C++·코드 품질 — vtable·예외/RTTI·동적할당·MISRA·volatile면접 시나리오·트러블슈팅 — 종합·트레이드오프(베어메탈/RTOS)·저전력·STAR