STM32F407VE용 324바이트 컴팩트 MBR 부트로더
STM32F407VE용 이 기본 부트로더(MBR)는 플래시 첫 번째 섹터(0x08000000)에 위치하며, 0x08060000의 보조 부트로더로 제어를 넘깁니다. 점프 전에 인터럽트 벡터 테이블을 검증합니다: SRAM 범위(0x20000000–0x2001FFFF)의 스택 포인터, 플래시(0x08000000–0x080FFFFF) 내 ResetHandler 주소(Thumb 모드 비트 설정).
검증 실패 시 PE13 핀 LED를 10Hz(주기 100ms, 듀티 50%)로 깜빡여 오류를 표시합니다. 표준 라이브러리, 외부 인터럽트 제거, DWT 코어 타이머로 지연 구현으로 코드를 324바이트로 최적화했습니다.
NOR 플래시 레이아웃:
| 섹터 | 시작 주소 | 크기, KB | 내용 |
|------|---------------|----------|------------------|
| 0 | 0x08000000 | 16 | 기본 부트로더 |
| 1–3 | 0x08004000–0x0800C000 | 16×3 | NVRAM |
| 4–6 | 0x08010000–0x08040000 | 64+128+128 | 애플리케이션 |
| 7 | 0x08060000 | 128 | 보조 부트로더 |
MBR에서 절약한 매 바이트가 첫 섹터 NVRAM 공간을 늘립니다.
최적화 단계
ARM-GCC와 GNU Make로 반복 최적화:
- 초기 HAL 구현: 25,192 바이트.
- -O0 디버그 제거: 12,052 바이트.
- -Os -flto: 9,684 바이트.
- DeepSeek + -Os -flto: 2,124 바이트.
- -nostdlib, no libc_init: 652 바이트.
- 최소 벡터 테이블: 324 바이트.
주요 컴파일러 플래그:
-nostdlib -nostartfiles -ffreestanding-ffunction-sections -fdata-sections -Wl,--gc-sections-Os(크기 최적화),-mcpu=cortex-m4 -mthumb
C 구현
단일 main.c 파일로 HAL 없이 레지스터 직접 접근:
// main.c - STM32F407VE 부트로더
#include <stdint.h>
#define APP_BASE 0x08060000UL
#define SRAM_BASE 0x20000000UL
#define SRAM_END 0x2001FFFFUL
#define FLASH_BASE 0x08000000UL
#define FLASH_END 0x080FFFFFUL
// 주변 장치
#define RCC_BASE 0x40023800UL
#define GPIOE_BASE 0x40021000UL
#define DWT_BASE 0xE0001000UL
#define RCC_AHB1ENR (*((volatile uint32_t*)(RCC_BASE + 0x30)))
#define GPIOx_MODER (*((volatile uint32_t*)(GPIOE_BASE + 0x00)))
#define GPIOx_ODR (*((volatile uint32_t*)(GPIOE_BASE + 0x14)))
#define DWT_CYCCNT (*((volatile uint32_t*)(DWT_BASE + 0x04)))
#define DWT_CTRL (*((volatile uint32_t*)(DWT_BASE + 0x00)))
typedef struct {
uint32_t stack_ptr;
uint32_t reset_handler;
} VectorTable_t;
static inline int is_valid_sram(uint32_t addr) {
return ((SRAM_BASE <= addr) && (addr <= SRAM_END));
}
static inline int is_valid_flash(uint32_t addr) {
return ((FLASH_BASE <= addr) && (addr <= FLASH_END));
}
// DWT 초기화
static void dwt_init(void) {
*(volatile uint32_t*)0xE000EDF0 |= (1UL << 24);
DWT_CTRL |= 1;
}
// 168MHz에서 ~ms 지연
static void delay_ms(uint32_t ms) {
uint32_t start = DWT_CYCCNT;
uint32_t cycles = ms * 16000;
while ((DWT_CYCCNT - start) < cycles);
}
// 10Hz로 PE13 LED 깜빡임
static void blink_led(void) __attribute__((noreturn));
static void blink_led(void) {
RCC_AHB1ENR |= (1 << 4);
GPIOx_MODER &= ~(3 << 26);
GPIOx_MODER |= (1 << 26);
dwt_init();
while(1) {
GPIOx_ODR |= (1 << 13);
delay_ms(50);
GPIOx_ODR &= ~(1 << 13);
delay_ms(50);
}
}
static int is_valid_vector_table(const VectorTable_t *app_vec) {
if (!is_valid_sram(app_vec->stack_ptr)) return 0;
uint32_t reset_addr = app_vec->reset_handler;
if (!is_valid_flash(reset_addr & ~1)) return 0;
if ((reset_addr & 1) == 0) return 0;
return 1;
}
typedef void (*pFunction)(void);
int main(void) {
const VectorTable_t *app_vec = (const VectorTable_t*)APP_BASE;
if (is_valid_vector_table(app_vec)) {
pFunction jump = (pFunction)app_vec->reset_handler;
jump();
}
blink_led();
}
프로젝트 빌드
디버그 및 패키징 지원 Makefile:
CFLAGS += -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=softfp
CFLAGS += -Os -ffunction-sections -fdata-sections -nostdlib
CFLAGS += -nostartfiles -fno-builtin -ffreestanding
LDFLAGS += -T gcc_arm_mbr.ld -Wl,--gc-sections
SOURCES = main.c system_stm32f4xx.c
OBJECTS = $(SOURCES:.c=.o) startup_stm32f407xx.o
all: $(TARGET).bin
startup_stm32f407xx.S에서 bl __libc_init_array 제거하고 벡터 테이블을 필수 항목(Stack, Reset, NMI, HardFault)으로 축소했습니다.
주요 요점
- 324바이트 크기로 첫 섹터 NVRAM 15+KB 확보.
- 벡터 테이블 검증으로 손상 코드 방지.
- DWT 타이머로 SysTick/PLL 없이 정밀 지연.
- 레지스터 직접 접근으로 오버헤드 최소화.
- 전체 빌드: ARM-GCC + 커스텀 링커 스크립트, 표준 라이브러리 없음.
— Editorial Team
아직 댓글이 없습니다.