부트로더와 앱은 별개 프로젝트다.
각각 빌드해서 각각 Flash에 굽는다.
프로젝트 구조
Workspace/
├── BMS_Bootloader/ ← 부트로더 프로젝트
│ ├── Core/
│ ├── Drivers/
│ └── STM32F103VE_FLASH.ld
│
└── BMS_App/ ← 앱 프로젝트
├── Core/
├── Drivers/
└── STM32F103VE_FLASH.ld ← 시작 주소 다름
CubeMX 설정
두 프로젝트 다 CubeMX로 생성.
동일한 MCU (STM32F103VE) 선택.
차이점:
- 부트로더: CAN, 최소한의 GPIO
- 앱: 전체 기능 (ADC, TIM, UART 등)
링커 스크립트 - 부트로더
STM32F103VE_FLASH.ld 수정:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* 부트로더 영역만 */
}
부트로더는 16KB만 사용.
링커 스크립트 - 앱
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08042800, LENGTH = 246K /* 앱 영역 */
}
앱은 0x08042800부터 시작.
빌드 확인
빌드 후 .map 파일 확인:
부트로더:
.text 0x08000000 0x2a4c
0x08000000 Reset_Handler
앱:
.text 0x08042800 0x1234
0x08042800 Reset_Handler
시작 주소가 다른 거 확인.
bin 파일 생성
hex나 elf 말고 bin이 필요함. CAN으로 전송할 거니까.
Post-build 명령 추가:
arm-none-eabi-objcopy -O binary ${ProjName}.elf ${ProjName}.bin
STM32CubeIDE에서:
- Project → Properties → C/C++ Build → Settings
- Build Steps → Post-build steps
Flash 굽기 순서
- 부트로더 먼저 (0x08000000)
- 앱은 부트로더 통해서 (또는 직접 0x08042800)
개발 중에는 ST-Link로 둘 다 직접 구울 수 있음.
# 부트로더
st-flash write bootloader.bin 0x08000000
# 앱
st-flash write app.bin 0x08042800
주의사항
앱 프로젝트에서 system_stm32f1xx.c 확인:
#define VECT_TAB_OFFSET 0x00000000U
이거 나중에 바꿔야 함. 앱의 Vector Table 위치 알려줘야 하니까.
일단은 그대로 두고, 부트로더에서 VTOR 설정해서 점프.
다음 글에서 링커 스크립트 상세 설명.