CORTEX-M · UART · EXCEPTION FRAME

UART 디버거의 덤프는 어느 시점의 레지스터인가

인터럽트 안에서 값을 출력할 수 있다고 해서 중단 직전의 문맥이 보존되는 것은 아닙니다. 소스의 호출 순서와 예외 스택 프레임을 나누어 읽습니다.

D에서 R까지 CPU는 대기 코드를 실행합니다

Amit Tayade의 UART_Triggered_Mini_Debugger에서 c615621을 기준으로 읽었습니다. USART2_IRQHandler가 D를 받으면 디버거 함수를 부릅니다. 함수는 CPSID I와 UART RX 인터럽트 비활성화를 수행한 뒤 덤프를 출력하고, 수신 플래그를 폴링해 R을 기다립니다.

따라서 RX 인터럽트를 막아도 폴링으로 재개 문자를 받을 수 있습니다. 이것은 하드웨어 디버거의 halt가 아니라 ISR 안의 대기 루프입니다. 마스킹 가능한 인터럽트의 지연과 주변장치·실시간 작업에 미치는 영향은 별도 문제이며 NMI·HardFault까지 모두 멈춘다고 설명하지 않습니다.

흐름과 판단을 나누어 그린 자체 개념도
  1. 예외 진입 → 하드웨어가 기본 프레임 저장

  2. C 핸들러·함수 호출 → 현재 레지스터 변경 가능

  3. 덤프·R 폴링 → 인터럽트 허용 후 복귀

고정 버전 수신 핸들러 · 인터럽트 매크로

현재 PC는 중단된 프로그램의 PC가 아닙니다

Cortex-M의 기본 예외 프레임에는 R0–R3, R12, LR, PC, xPSR이 저장됩니다. 이 예시의 캡처 함수는 그 프레임 대신 호출 이후의 현재 레지스터를 읽습니다. 함수 내부에서 읽은 PC를 중단 직전 명령어의 주소로 해석하면 안 됩니다.

실제로 문맥을 복원하려면 EXC_RETURN에 따른 스택 선택, 기본·확장 프레임과 정렬을 확인해야 합니다. R4–R11 등 기본 프레임 밖의 값도 컴파일러가 바꾸기 전에 보존하는 설계가 필요합니다. 여기서는 검증하지 않은 예외 진입 어셈블리나 바로 기록할 펌웨어를 제공하지 않습니다.

ST PM0214 Rev 10: 예외 진입·복귀와 마스크

버퍼 주소와 마스크도 캡처 시점에 영향을 줍니다

inline asm의 입력 버퍼 주소는 r 제약으로 레지스터를 사용합니다. 그 레지스터는 이미 캡처를 위한 주소를 담고 있으므로 원래 응용 코드 값이라고 할 수 없습니다. GCC의 입력·출력·clobber 계약과 생성된 명령을 함께 확인해야 합니다.

PRIMASK는 CPSID I 뒤에 읽습니다. 따라서 이 값은 인터럽트를 막기 전 상태의 증거가 아닙니다. 재개할 때 CPSIE I를 실행한다고 해서 이전 마스크 값을 저장해 복원하는 것도 아닙니다.

캡처와 재개 구현 · GCC 15.1: extended asm 계약

초기화 크기의 단위를 맞춥니다

시작 코드에서는 .data·.bss 크기를 주소의 바이트 차이로 구하고 uint32_t 포인터를 한 칸씩 움직이는 루프의 반복 횟수로 씁니다. 바이트 수 N에 대해 N번의 32비트 접근을 하면 명목 구간의 네 배를 접근합니다. 바이트 순회와 워드 순회를 혼용하지 않아야 합니다.

이는 고정 소스에서 확인한 범위 계산 문제입니다. 실제 링크 배치·최적화 결과, 보드 부팅·UART 로그는 검증하지 않았습니다. 저장소의 실행 안내나 덤프 화면만 보고 문맥이 보존되고 재개에 성공했다고 판단하지 않습니다.

고정 버전 시작 코드