STM32 부팅 과정

moonsyu·2026년 9월 9일

stm32

목록 보기
7/9

PC에서 프로그램을 만들고 보드에 기록하면, 보드는 자기 CPU와 메모리로 실행한다.

1. 각 파트별 역할

어떤 애역할
PC코드를 빌드하고, 완성된 프로그램을 보드에 기록하는 데 사용한다.
컴파일러C 코드를 STM32용 어셈블리어로 번역한다.
어셈블러어셈블리어를 CPU가 실행할 기계어 조각으로 바꾼다.
링커기계어 조각들을 합치고, 코드와 데이터가 들어갈 보드 메모리 주소를 정한다.
링커 스크립트 (.ld)링커가 참고하는 보드 메모리 배치 규칙이다.
startup 파일 (.s)이미 어셈블리어로 작성된 시작 코드다. 보드가 켜진 뒤 main() 실행을 준비한다.
STM32의 CPU보드에 저장된 기계어를 직접 실행한다.
보드의 Flash전원이 꺼져도 프로그램과 초기값을 보관한다.
보드의 RAM실행 중 변수와 함수 호출 등에 사용하는 작업 공간이다.
  • 조사한 시작 코드: startup_stm32f446retx.s
  • 조사한 배치 규칙: STM32F446RETX_FLASH.ld

01. STM32 프로젝트 파일 구성

2. Build 과정

코드 작성 → 컴파일·어셈블 → 링크 → 완성된 프로그램 → 보드에 기록

  • Build: PC에서 소스 코드를 실행 가능한 프로그램 파일로 바꾸는 과정. 이 프로젝트의 결과물은 STM32용 펌웨어다.
  • 링크: 여러 기계어 조각을 하나로 합치고 주소를 정하는 작업. PC와 보드를 연결한다는 뜻이 아니다.
  • 기록: ST-LINK 같은 도구로 완성된 프로그램을 보드의 Flash에 넣는 작업.
어떤 애역할
.o소스 파일을 변환해서 얻은 기계어 조각. 아직 다른 조각과 연결해야 한다.
.elf링크가 끝난 펌웨어 파일. 프로그램과 주소 정보 등을 담는다.
.map코드와 데이터가 어느 주소에 배치됐는지 보여주는 보고서.
.list기계어를 사람이 읽을 수 있는 어셈블리 명령으로 풀어 보여주는 파일.
makefile어떤 파일을 어떤 명령으로 빌드할지 적어 놓은 작업 순서표.

02. 전처리·컴파일·어셈블·링크와 보드 기록

3. 링커는 코드를 어디에 놓을까?

링커는 코드와 데이터를 역할에 맞는 보드 메모리 위치에 배치한다.

  • .ld는 배치 규칙을 제공하고, 링커가 그 규칙에 따라 주소를 정한다.
  • 대상은 STM32의 Flash와 RAM이다. 보드가 실행할 때 PC의 메모리를 빌려 쓰는 구조가 아니다.
  • 링크할 때는 주소가 펌웨어에 반영된다. 실제 Flash 기록과 부팅 중 RAM 초기화는 그 뒤에 이루어진다.

섹션은 성격이 비슷한 코드나 데이터를 묶어 놓은 것이다.

어떤 애역할
.text실행할 기계어 묶음. 이 프로젝트에서는 Flash에 둔다.
.rodata상수나 문자열처럼 바꾸지 않는 데이터 묶음. Flash에 둔다.
.data초기값이 있는 전역·정적 변수. 초기값은 Flash에 보관하고, 부팅할 때 RAM으로 복사해 사용한다.
.bss0으로 시작할 전역·정적 변수. 부팅할 때 해당 RAM 공간을 0으로 채운다.

예를 들어 전역 변수 int speed = 3;은 처음 값 3을 Flash에 보관하고, 실행 중 바뀌는 speed는 RAM에서 사용하는 식이다.

03. 링커 스크립트의 Flash·RAM 배치와 변수 초기화

4. 전원을 켜면 무엇부터 실행될까?

전원 켜짐·리셋 → CPU가 시작 위치 확인 → startup의 준비 작업 → main()

내장 Flash에 기록한 프로그램으로 부팅하는 경우의 흐름이다.

어떤 애역할
벡터 테이블초기 스택 값과 리셋·인터럽트 함수 주소 목록. CPU가 처음 실행할 위치를 찾는 데 사용한다.
Reset_Handler리셋 후 처음 실행되는 사용자 펌웨어의 함수. 부팅 준비를 시작한다.
SystemInit()CPU의 기본적인 실행 준비를 한다.
.data·.bss 초기화RAM의 변수에 초기값을 복사하거나 0을 채운다.
__libc_init_array()main() 전에 필요한 추가 초기화를 마무리한다.
main()우리가 작성한 응용 프로그램이 시작되는 함수다.
  • 현재 startup은 위 표의 순서대로 준비한다.
  • main()보다 먼저 실행되는 준비 코드가 있다는 점이 핵심이다.

04. CPU의 벡터 읽기와 Reset_Handler에서 main까지

5. main()에 도착한 뒤에는?

주변장치를 준비하고 → 반복문에서 원하는 동작을 계속 수행한다.

어떤 애역할
HAL_Init()하드웨어 제어 함수들을 쓰기 위한 기본 준비를 한다.
SystemClock_Config()보드가 사용할 클록, 즉 동작 속도의 기준을 설정한다.
MX_GPIO_Init()입출력 핀을 준비한다.
BSP_LED_Init()·BSP_PB_Init()보드의 LED와 버튼을 준비한다.
while (1)LED 제어 같은 작업을 계속 반복한다.
인터럽트 처리 함수버튼 입력 같은 이벤트가 생기면 실행 중인 작업을 잠시 중단해 처리하고, 끝나면 중단했던 코드로 돌아간다.
  • SystemInit()은 main() 이전, SystemClock_Config()는 main() 안에서 실행된다.
  • 기록이 끝난 보드는 PC 없이도 필요한 전원만 공급되면 자기 CPU·Flash·RAM으로 동작한다.

05. main 초기화와 버튼 인터럽트 처리 흐름

현재 프로젝트의 main.c 원본은 없어, main() 내부 순서는 기존 Debug/interrupt_hard.list를 기준으로 정리했다.

참고 자료

0개의 댓글