# STM32 (VS Code + Cmake) RAM 디버깅 환경 설정 가이드
**적용 보드:** Nucleo-F767ZI (타 칩셋도 주소와 메모리 크기만 변경하여 동일 적용 가능)
**개발 환경:** STM32CubeMX, VS Code, Cmake, Cortex-Debug (OpenOCD)
**목적:** 코드를 Flash 메모리가 아닌 RAM에 다운로드하고 실행하여 **1) Flash 메모리 수명 보호** 및 **2) 압도적으로 빠른 다운로드/디버깅 속도** 확보
---
## 1. RAM 전용 링커 스크립트(.ld) 생성
MCU가 코드를 Flash(`0x08000000`)가 아닌 RAM(`0x20000000`)에 배치하도록 링커 스크립트를 수정합니다.
1. 프로젝트 루트 경로의 `STM32F767ZITx_FLASH.ld` (또는 `STM32F767xx_FLASH.ld`) 파일을 복사합니다.
2. 복사한 파일의 이름을 **`STM32F767xx_RAM.ld`**로 변경합니다.
3. 새로 만든 `_RAM.ld` 파일을 열고, 최상단의 `MEMORY` 블록을 아래와 같이 수정하여 RAM(총 512KB)을 코드용 256KB, 데이터용 256KB로 반반 나눕니다.
```ld
/* STM32F767xx_RAM.ld */
MEMORY
{
/* RAM의 앞 256KB를 코드가 올라가는 FLASH 영역처럼 속여서 매핑 */
FLASH (rx) : ORIGIN = 0x20000000, LENGTH = 256K
/* 나머지 256KB를 실제 변수/데이터가 올라가는 RAM 공간으로 사용 */
RAM (xrw) : ORIGIN = 0x20040000, LENGTH = 256K
}
```
## 2. 인터럽트 벡터 테이블 위치 변경
코드가 RAM에서 실행되므로, 인터럽트 발생 시 참조하는 벡터 테이블의 기준 주소도 RAM으로 변경해야 합니다.
1. `Core/Src/system_stm32f7xx.c` 파일을 엽니다.
2. 상단의 `USER_VECT_TAB_ADDRESS` 주석을 해제하고, `VECT_TAB_BASE_ADDRESS`를 `0x20000000U`로 변경합니다.
```c
/* system_stm32f7xx.c */
#define USER_VECT_TAB_ADDRESS /* 주석 해제 (활성화) */
#if defined(USER_VECT_TAB_ADDRESS)
/* FLASH_BASE 대신 RAM의 시작 주소 입력 */
#define VECT_TAB_BASE_ADDRESS 0x20000000U
#define VECT_TAB_OFFSET 0x00000000U
#endif
```
## 3. CMakeLists.txt 링커 스크립트 교체
빌드 시 기존 FLASH 링커 스크립트 대신 우리가 만든 RAM 링커 스크립트를 사용하도록 지정합니다.
1. 최상단 `CMakeLists.txt` 파일을 엽니다.
2. `STM32F767xx_FLASH.ld` 부분을 찾아 **`STM32F767xx_RAM.ld`**로 변경합니다.
3. **[주의]** 파일 내에 `-T` 링커 옵션이 중복으로 들어가지 않도록 유의합니다. (링커 스크립트 중복 에러 방지)
```cmake
/* CMakeLists.txt 예시 */
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
-T${CMAKE_CURRENT_SOURCE_DIR}/STM32F767xx_RAM.ld
# ... 기타 옵션 ...
)
```
## 4. VS Code 자동 빌드 작업 설정 (`tasks.json`)
`F5`(디버깅)를 눌렀을 때, 이전 코드가 실행되는 것을 방지하고 **자동으로 최신 코드를 빌드**하도록 Task를 생성합니다.
1. `.vscode` 폴더 안에 **`tasks.json`** 파일을 생성합니다.
2. 아래의 Cmake 전용 빌드 코드를 붙여넣습니다.
```json
{
"version": "2.0.0",
"tasks": [
{
"type": "cmake",
"label": "Cmake Build Task",
"command": "build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
```
## 5. VS Code 디버거 설정 (`launch.json`)
빌드된 `.elf` 파일을 RAM에 올리고, 보드 리셋 시 엉뚱하게 Flash를 읽지 않고 **강제로 RAM으로 점프**하도록 설정합니다.
1. `.vscode` 폴더 안에 **`launch.json`** 파일을 생성(또는 수정)합니다.
2. 아래 코드를 붙여넣습니다.
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug in RAM",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/build/${workspaceFolderBasename}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"device": "STM32F767ZI",
"configFiles": [
"board/st_nucleo_f7.cfg"
],
"runToEntryPoint": "main",
"showDevDebugOutput": "none",
"preLaunchTask": "Cmake Build Task",
"postLaunchCommands": [
"set $sp = *(unsigned int*)0x20000000",
"set $pc = *(unsigned int*)0x20000004"
],
"postRestartCommands": [
"set $sp = *(unsigned int*)0x20000000",
"set $pc = *(unsigned int*)0x20000004"
]
}
]
}
```
* **`preLaunchTask`**: 디버깅 직전 `tasks.json`을 호출하여 자동 빌드 수행
* **`postLaunchCommands` / `postRestartCommands`**: 리셋 직후 MCU의 멱살을 잡고 PC(Program Counter)와 SP(Stack Pointer)를 강제로 RAM 주소로 고정하여 실행
## 6. 적용 및 실행 (가장 중요)
기존 Flash 빌드 캐시가 남아있으면 에러가 발생하므로, **반드시 캐시를 지우고 새로 빌드**해야 합니다.
1. 단축키 `Ctrl + Shift + P` -> **`Cmake: Delete Cache and Reconfigure`** 실행 (캐시 초기화)
2. 코드를 수정하고 **`F5`** 키 누르기
3. 하단 터미널에서 자동으로 빌드가 완료된 후 디버거가 실행되며 `main()` 함수 첫 줄에서 정지함.
> **✅ 최종 확인 방법**
> 디버깅 모드 진입 시 좌측 **'호출 스택(Call Stack)'** 또는 **'레지스터(Registers) -> Core -> pc'** 값이 **`0x2000...`** 대역으로 시작하면 완벽하게 RAM에서 동작 중인 것입니다!
|