프로그래밍/STM32

[STM32] cmake build(feat .bin, .elf, .hex 추출)

Beginner:) 2023. 9. 3.
320x100

먼저 나의 작업환경을 tree -L 4로 출력한 Directory 구조이다.

.
├── CMakeLists.txt
├── MAIN
│   └── board
│       └── F4
│           ├── Core
│           ├── Drivers
│           ├── stm32f411re
│           └── ledtest2.ioc
├── Toolchain
│   ├── arm-none-eabi
│   ├── bin
│   ├── lib
│   ├── share
│   └── toolchain_arm_9.3.1.cmake

 

./CMakeLists.txt

cmake_minimum_required(VERSION 3.10.2)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)

# project settings
project(temp 
  LANGUAGES C CXX ASM
  VERSION 1.0.0
)

# CMake Module 등록
set(CMAKE_MODULE_PATH
  ${CMAKE_MODULE_PATH}
  ${CMAKE_SOURCE_DIR}/Toolchain
  ${CMAKE_SOURCE_DIR}/MAIN/board/F4/stm32f411re
)

#CMake Toolchain Module 불러오기
include(toolchain_arm_9.3.1)

set(EXECUTABLE ${PROJECT_NAME}.elf)

if(1)
  include(stm32f411re)
endif()

# 빌드 후 .hex, .bin 파일 추출 
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
  COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE} ${PROJECT_NAME}.hex
  COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE} ${PROJECT_NAME}.bin
)

# 사용자 명령어로 make flash와 make erase 명령어를 추가 
set(FLASH_START 0x8000000)

add_custom_target(flash 
  COMMAND st-flash --reset write ${PROJECT_NAME}.bin ${FLASH_START}
  DEPENDS ${PROJECT_NAME}.elf
)

add_custom_target(erase 
	COMMAND st-flash erase
)

set(CMAKE_MODULE_PATH) : 모듈을 불러오는 부분으로, 잘 기억이 안나는데 add_sub_directoris?를 하면 해당파일의 set으로 정의한 명령어들이 부모 CMakeLists에서는 등록이 안되어있더라. 그래서 module을 가져오는 방식을 택했고. 작동방식은 CMAKE_MODULE_PATH를 설정하게 되면, 해당 폴더의 .cmake파일을 모두 Load한다(Run 하진 않고 얹어 놓는 ?)

 

include() : CMAKE_MODULE_PATH에 있는 모듈들을 불러온다. 여기서는 Toolchain과 stm32f411 board에 관한 라이브러리들을 정의한 cmake 파일을 실행한다.

 

add_custom_command(): 사용자 명령어를 추가하는 방법으로 해당 파일에서는 POST_BUILD, 즉 빌드가 끝난 후에 Toolchain의 OBJCOPY명령어를 사용하여 elf 파일을 hex와 bin으로 변환해준다. flash는 플래싱 명령어, erase는 board 데이터를 삭제하는 명령어이다. 

 

 

./Toolchain/toolchain_arm_9.3.1.cmake

# specify cross compilers and tools
message("Toolchain path : ${CMAKE_CURRENT_LIST_DIR}")

set(CMAKE_STAGING_PREFIX ${CMAKE_CURRENT_LIST_DIR}/bin)

set(CMAKE_C_COMPILER ${CMAKE_STAGING_PREFIX}/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER ${CMAKE_STAGING_PREFIX}/arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER ${CMAKE_STAGING_PREFIX}/arm-none-eabi-gcc)
set(CMAKE_AR ${CMAKE_STAGING_PREFIX}/arm-none-eabi-ar)
set(CMAKE_OBJCOPY ${CMAKE_STAGING_PREFIX}/arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP ${CMAKE_STAGING_PREFIX}/arm-none-eabi-objdump)
set(SIZE ${CMAKE_STAGING_PREFIX}/arm-none-eabi-size)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)

Toolchain의 경로와 명령어 alias를 설정

 

./MAIN/board/F4/stm32f411re

message("Board : STM32F411RE ${CMAKE_CURRENT_LIST_DIR}")

set(LINKER_FILE ${CMAKE_CURRENT_LIST_DIR}/STM32F411RETX_FLASH.ld)
set(STM32F4_PATH ${CMAKE_CURRENT_LIST_DIR}/..)

add_compile_definitions(STM32F411xE)

# 해당 폴더의 파일만 찾는다.
file(GLOB SRC_FILES CONFIGURE_DEPENDS
  *.c
)

# 해당 폴더를 포함해서 하위 폴더까지의 파일도 찾는다.
file(GLOB_RECURSE SRC_FILES_RECURSE CONFIGURE_DEPENDS
    ${STM32F4_PATH}/Core/*.c
    ${STM32F4_PATH}/Drivers/*.c
)

# Build the executable based on the source files
add_executable(${EXECUTABLE}  
  ${SRC_FILES}
  ${SRC_FILES_RECURSE}

  ${STM32F4_PATH}/Core/Startup/startup_stm32f411retx.s
  )

#target_compile_definitions(${EXECUTABLE} PRIVATE
#  -DSTM32F411Tx
#)

# List of includ directories
target_include_directories(${EXECUTABLE} PRIVATE 
${STM32F4_PATH}/Core/Inc
  ${STM32F4_PATH}/Drivers/CMSIS/Device/ST/STM32F4xx/Include
  ${STM32F4_PATH}/Drivers/CMSIS/Include
  ${STM32F4_PATH}/Drivers/STM32F4xx_HAL_Driver/Inc
  )

# Compiler options
target_compile_options(${EXECUTABLE} PRIVATE
  -mcpu=cortex-m4
  -mthumb
  
  -mfpu=fpv4-sp-d16
  -mfloat-abi=hard

  -fdata-sections
  -ffunction-sections

  -Wall
  -O0
  -g3
  )

# Linker options
target_link_options(${EXECUTABLE} PRIVATE
  -T${LINKER_FILE}
  -mcpu=cortex-m4
  -mthumb
  -mfpu=fpv4-sp-d16
  -mfloat-abi=hard
  -specs=nano.specs
  -lc
  -lm
  -Wl,-Map=${PROJECT_NAME}.map,--cref
  -Wl,--gc-sections
  -Xlinker -print-memory-usage -Xlinker
  )

이부분은 HW에 지식이 짧아... 잘모르겠다.

그저 짧은 이해력으로 간단히 설명하자면 build에 필요한 경로 설정과 board에 대한 각종 옵션들을 적어준다.

 

 

이제 프로젝트 루트 디렉토리로 이동한 후, cmake build, make 명령어를 사용하게 되면 각 종 파일들이 생성된다

mkdir build
cd build
cmake ../
make all

 

 

여기서 사용자 커맨드로 추가하였던 make flash 명령어를 입력하게되면 code가 실행된다. LED를 깜빡이는 코드를 넣었는데 LD2인 초록색 램프가 깜빡이는 것을 볼 수 있다.

 

마찬가지로 make erase를 사용하면 board의 데이터가 삭제된다.

반응형

댓글