Cleanup
[inav.git] / cmake / stm32.cmake
blob091cf31fd5db98dc47c35adb5fae9f80ffcd414c
1 include(stm32-bootloader)
2 include(stm32f4)
3 include(stm32f7)
4 include(stm32h7)
6 include(CMakeParseArguments)
8 option(DEBUG_HARDFAULTS "Enable debugging of hard faults via custom handler")
9 option(SEMIHOSTING "Enable semihosting")
11 message("-- DEBUG_HARDFAULTS: ${DEBUG_HARDFAULTS}, SEMIHOSTING: ${SEMIHOSTING}")
13 set(CMSIS_DIR "${MAIN_LIB_DIR}/main/CMSIS")
14 set(CMSIS_INCLUDE_DIR "${CMSIS_DIR}/Core/Include")
15 set(CMSIS_DSP_DIR "${MAIN_LIB_DIR}/main/CMSIS/DSP")
16 set(CMSIS_DSP_INCLUDE_DIR "${CMSIS_DSP_DIR}/Include")
18 set(CMSIS_DSP_SRC
19     BasicMathFunctions/arm_scale_f32.c
20     BasicMathFunctions/arm_sub_f32.c
21     BasicMathFunctions/arm_mult_f32.c
22     BasicMathFunctions/arm_offset_f32.c
23     TransformFunctions/arm_rfft_fast_f32.c
24     TransformFunctions/arm_cfft_f32.c
25     TransformFunctions/arm_rfft_fast_init_f32.c
26     TransformFunctions/arm_cfft_radix8_f32.c
27     TransformFunctions/arm_bitreversal2.S
28     CommonTables/arm_common_tables.c
29     ComplexMathFunctions/arm_cmplx_mag_f32.c
30     StatisticsFunctions/arm_max_f32.c
31     StatisticsFunctions/arm_rms_f32.c
32     StatisticsFunctions/arm_std_f32.c
33     StatisticsFunctions/arm_mean_f32.c
35 list(TRANSFORM CMSIS_DSP_SRC PREPEND "${CMSIS_DSP_DIR}/Source/")
37 set(STM32_STARTUP_DIR "${MAIN_SRC_DIR}/startup")
39 main_sources(STM32_VCP_SRC
40     drivers/serial_usb_vcp.c
41     drivers/usb_io.c
44 main_sources(STM32_SDCARD_SRC
45     drivers/sdcard/sdcard.c
46     drivers/sdcard/sdcard_spi.c
47     drivers/sdcard/sdcard_sdio.c
48     drivers/sdcard/sdcard_standard.c
51 # XXX: This code is not STM32 specific
52 main_sources(STM32_ASYNCFATFS_SRC
53     io/asyncfatfs/asyncfatfs.c
54     io/asyncfatfs/fat_standard.c
57 main_sources(STM32_MSC_SRC
58     msc/usbd_storage.c
61 main_sources(STM32_MSC_FLASH_SRC
62     msc/usbd_storage_emfat.c
63     msc/emfat.c
64     msc/emfat_file.c
67 main_sources(STM32_MSC_SDCARD_SRC
68     msc/usbd_storage_sd_spi.c
71 set(STM32_INCLUDE_DIRS
72     "${CMSIS_INCLUDE_DIR}"
73     "${CMSIS_DSP_INCLUDE_DIR}"
74     "${MAIN_SRC_DIR}/target"
77 set(STM32_DEFINITIONS
79 set(STM32_DEFAULT_HSE_MHZ 8)
80 set(STM32_LINKER_DIR "${MAIN_SRC_DIR}/target/link")
81 set(STM32_COMPILE_OPTIONS
82     -ffunction-sections
83     -fdata-sections
84     -fno-common
87 set(STM32_LINK_LIBRARIES
88     -lm
89     -lc
92 if(SEMIHOSTING)
93     list(APPEND STM32_LINK_LIBRARIES --specs=rdimon.specs -lrdimon)
94     list(APPEND STM32_DEFINITIONS SEMIHOSTING)
95 else()
96     list(APPEND STM32_LINK_LIBRARIES -lnosys)
97 endif()
99 set(STM32_LINK_OPTIONS
100     -nostartfiles
101     --specs=nano.specs
102     -static
103     -Wl,-gc-sections
104     -Wl,-L${STM32_LINKER_DIR}
105     -Wl,--cref
106     -Wl,--no-wchar-size-warning
107     -Wl,--print-memory-usage
110 macro(get_stm32_target_features output_var dir target_name)
111     execute_process(COMMAND "${CMAKE_C_COMPILER}" -E -dD -D${ARGV2} "${ARGV1}/target.h"
112         ERROR_VARIABLE _errors
113         RESULT_VARIABLE _result
114         OUTPUT_STRIP_TRAILING_WHITESPACE
115         OUTPUT_VARIABLE _contents)
117     if(NOT _result EQUAL 0)
118         message(FATAL_ERROR "error extracting features for stm32 target ${ARGV2}: ${_errors}")
119     endif()
121     string(REGEX MATCH "#define[\t ]+USE_VCP" HAS_VCP ${_contents})
122     if(HAS_VCP)
123         list(APPEND ${ARGV0} VCP)
124     endif()
125     string(REGEX MATCH "define[\t ]+USE_FLASHFS" HAS_FLASHFS ${_contents})
126     if(HAS_FLASHFS)
127         list(APPEND ${ARGV0} FLASHFS)
128     endif()
129     string(REGEX MATCH "define[\t ]+USE_SDCARD" HAS_SDCARD ${_contents})
130     if (HAS_SDCARD)
131         list(APPEND ${ARGV0} SDCARD)
132         string(REGEX MATCH "define[\t ]+USE_SDCARD_SDIO" HAS_SDIO ${_contents})
133         if (HAS_SDIO)
134             list(APPEND ${ARGV0} SDIO)
135         endif()
136     endif()
137     if(HAS_FLASHFS OR HAS_SDCARD)
138         list(APPEND ${ARGV0} MSC)
139     endif()
140 endmacro()
142 function(get_stm32_flash_size out size)
143     # 4: 16, 6: 32, 8: 64, B: 128, C: 256, D: 384, E: 512, F: 768, G: 1024, H: 1536, I: 2048 KiB
144     string(TOUPPER ${size} s)
145     if(${s} STREQUAL "4")
146         set(${out} 16 PARENT_SCOPE)
147         return()
148     endif()
149     if(${s} STREQUAL "6")
150         set(${out} 32 PARENT_SCOPE)
151         return()
152     endif()
153     if(${s} STREQUAL "8")
154         set(${out} 64 PARENT_SCOPE)
155         return()
156     endif()
157     if(${s} STREQUAL "8")
158         set(${out} 64 PARENT_SCOPE)
159         return()
160     endif()
161     if(${s} STREQUAL "B")
162         set(${out} 128 PARENT_SCOPE)
163         return()
164     endif()
165     if(${s} STREQUAL "C")
166         set(${out} 256 PARENT_SCOPE)
167         return()
168     endif()
169     if(${s} STREQUAL "D")
170         set(${out} 384 PARENT_SCOPE)
171         return()
172     endif()
173     if(${s} STREQUAL "E")
174         set(${out} 512 PARENT_SCOPE)
175         return()
176     endif()
177     if(${s} STREQUAL "F")
178         set(${out} 768 PARENT_SCOPE)
179         return()
180     endif()
181     if(${s} STREQUAL "G")
182         set(${out} 1024 PARENT_SCOPE)
183         return()
184     endif()
185     if(${s} STREQUAL "H")
186         set(${out} 1536 PARENT_SCOPE)
187         return()
188     endif()
189     if(${s} STREQUAL "I")
190         set(${out} 2048 PARENT_SCOPE)
191         return()
192     endif()
193 endfunction()
195 function(add_hex_target name exe hex)
196     add_custom_target(${name} ALL
197         cmake -E env PATH="$ENV{PATH}"
198         # TODO: Overriding the start address with --set-start 0x08000000
199         # seems to be required due to some incorrect assumptions about .hex
200         # files in the configurator. Verify wether that's the case and fix
201         # the bug in configurator or delete this comment.
202         ${CMAKE_OBJCOPY} -Oihex --set-start 0x08000000 $<TARGET_FILE:${exe}> ${hex}
203         BYPRODUCTS ${hex}
204     )
205 endfunction()
207 function(add_bin_target name exe bin)
208     add_custom_target(${name}
209         cmake -E env PATH="$ENV{PATH}"
210         ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${exe}> ${bin}
211         BYPRODUCTS ${bin}
212     )
213 endfunction()
215 function(generate_map_file target)
216     if(CMAKE_VERSION VERSION_LESS 3.15)
217         set(map "$<TARGET_FILE:${target}>.map")
218     else()
219         set(map "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.map")
220     endif()
221     target_link_options(${target} PRIVATE "-Wl,-Map,${map}")
222 endfunction()
224 function(set_linker_script target script)
225     set(script_path ${STM32_LINKER_DIR}/${args_LINKER_SCRIPT}.ld)
226     if(NOT EXISTS ${script_path})
227         message(FATAL_ERROR "linker script ${script_path} doesn't exist")
228     endif()
229     set_target_properties(${target} PROPERTIES LINK_DEPENDS ${script_path})
230     target_link_options(${elf_target} PRIVATE -T${script_path})
231 endfunction()
233 function(add_stm32_executable)
234     cmake_parse_arguments(
235         args
236         # Boolean arguments
237         ""
238         # Single value arguments
239         "FILENAME;NAME;OPTIMIZATION;OUTPUT_BIN_FILENAME;OUTPUT_HEX_FILENAME;OUTPUT_TARGET_NAME"
240         # Multi-value arguments
241         "COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;LINKER_SCRIPT;SOURCES"
242         # Start parsing after the known arguments
243         ${ARGN}
244     )
245     set(elf_target ${args_NAME}.elf)
246     add_executable(${elf_target})
247     target_sources(${elf_target} PRIVATE ${args_SOURCES})
248     target_include_directories(${elf_target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${args_INCLUDE_DIRECTORIES} ${STM32_INCLUDE_DIRS})
249     target_compile_definitions(${elf_target} PRIVATE ${args_COMPILE_DEFINITIONS})
250     target_compile_options(${elf_target} PRIVATE ${STM32_COMPILE_OPTIONS} ${args_COMPILE_OPTIONS})
251     if(WARNINGS_AS_ERRORS)
252         target_compile_options(${elf_target} PRIVATE -Werror)
253     endif()
254     if (IS_RELEASE_BUILD)
255         target_compile_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
256         target_link_options(${elf_target} PRIVATE ${args_OPTIMIZATION})
257     endif()
258     target_link_libraries(${elf_target} PRIVATE ${STM32_LINK_LIBRARIES})
259     target_link_options(${elf_target} PRIVATE ${STM32_LINK_OPTIONS} ${args_LINK_OPTIONS})
260     generate_map_file(${elf_target})
261     set_linker_script(${elf_target} ${args_LINKER_SCRIPT})
262     if(args_FILENAME)
263         set(basename ${CMAKE_BINARY_DIR}/${args_FILENAME})
264         set(hex_filename ${basename}.hex)
265         add_hex_target(${args_NAME} ${elf_target} ${hex_filename})
266         set(bin_filename ${basename}.bin)
267         add_bin_target(${args_NAME}.bin ${elf_target} ${bin_filename})
268     endif()
269     if(args_OUTPUT_BIN_FILENAME)
270         set(${args_OUTPUT_BIN_FILENAME} ${bin_filename} PARENT_SCOPE)
271     endif()
272     if(args_OUTPUT_TARGET_NAME)
273         set(${args_OUTPUT_TARGET_NAME} ${elf_target} PARENT_SCOPE)
274     endif()
275     if(args_OUTPUT_HEX_FILENAME)
276         set(${args_OUTPUT_HEX_FILENAME} ${hex_filename} PARENT_SCOPE)
277     endif()
278 endfunction()
280 function(target_stm32)
281     if(NOT arm-none-eabi STREQUAL TOOLCHAIN)
282         return()
283     endif()
284     # Parse keyword arguments
285     cmake_parse_arguments(
286         args
287         # Boolean arguments
288         "DISABLE_MSC;BOOTLOADER"
289         # Single value arguments
290         "HSE_MHZ;LINKER_SCRIPT;NAME;OPENOCD_TARGET;OPTIMIZATION;STARTUP;SVD"
291         # Multi-value arguments
292         "COMPILE_DEFINITIONS;COMPILE_OPTIONS;INCLUDE_DIRECTORIES;LINK_OPTIONS;SOURCES;MSC_SOURCES;MSC_INCLUDE_DIRECTORIES;VCP_SOURCES;VCP_INCLUDE_DIRECTORIES"
293         # Start parsing after the known arguments
294         ${ARGN}
295     )
296     set(name ${args_NAME})
298     if (args_HSE_MHZ)
299         set(hse_mhz ${args_HSE_MHZ})
300     else()
301         set(hse_mhz ${STM32_DEFAULT_HSE_MHZ})
302     endif()
304     set(target_sources ${STM32_STARTUP_DIR}/${args_STARTUP})
305     list(APPEND target_sources ${args_SOURCES})
306     file(GLOB target_c_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
307     file(GLOB target_h_sources "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
308     list(APPEND target_sources ${target_c_sources} ${target_h_sources})
310     set(target_include_directories ${args_INCLUDE_DIRECTORIES})
312     set(target_definitions ${STM32_DEFINITIONS} ${COMMON_COMPILE_DEFINITIONS})
314     get_stm32_target_features(features "${CMAKE_CURRENT_SOURCE_DIR}" ${name})
315     set_property(TARGET ${elf_target} PROPERTY FEATURES ${features})
317     if(VCP IN_LIST features)
318         list(APPEND target_sources ${STM32_VCP_SRC} ${args_VCP_SOURCES})
319         list(APPEND target_include_directories ${args_VCP_INCLUDE_DIRECTORIES})
320     endif()
321     if(SDCARD IN_LIST features)
322         list(APPEND target_sources ${STM32_SDCARD_SRC} ${STM32_ASYNCFATFS_SRC})
323     endif()
325     set(msc_sources)
326     if(NOT args_DISABLE_MSC AND MSC IN_LIST features)
327         list(APPEND target_include_directories ${args_MSC_INCLUDE_DIRECTORIES})
328         list(APPEND msc_sources ${STM32_MSC_SRC} ${args_MSC_SOURCES})
329         list(APPEND target_definitions USE_USB_MSC)
330         if(FLASHFS IN_LIST features)
331             list(APPEND msc_sources ${STM32_MSC_FLASH_SRC})
332         endif()
333         if (SDCARD IN_LIST features)
334             list(APPEND msc_sources ${STM32_MSC_SDCARD_SRC})
335         endif()
336     endif()
338     math(EXPR hse_value "${hse_mhz} * 1000000")
339     list(APPEND target_definitions "HSE_VALUE=${hse_value}")
341     if (MSP_UART) 
342         list(APPEND target_definitions "MSP_UART=${MSP_UART}")
343     endif()
345     if(args_COMPILE_DEFINITIONS)
346         list(APPEND target_definitions ${args_COMPILE_DEFINITIONS})
347     endif()
348     if(DEBUG_HARDFAULTS)
349         list(APPEND target_definitions DEBUG_HARDFAULTS)
350     endif()
352     string(TOLOWER ${PROJECT_NAME} lowercase_project_name)
353     set(binary_name ${lowercase_project_name}_${FIRMWARE_VERSION}_${name})
354     if(DEFINED BUILD_SUFFIX AND NOT "" STREQUAL "${BUILD_SUFFIX}")
355         set(binary_name "${binary_name}_${BUILD_SUFFIX}")
356     endif()
358     # Main firmware
359     add_stm32_executable(
360         NAME ${name}
361         FILENAME ${binary_name}
362         SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
363         COMPILE_DEFINITIONS ${target_definitions}
364         COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
365         INCLUDE_DIRECTORIES ${target_include_directories}
366         LINK_OPTIONS ${args_LINK_OPTIONS}
367         LINKER_SCRIPT ${args_LINKER_SCRIPT}
368         OPTIMIZATION ${args_OPTIMIZATION}
370         OUTPUT_HEX_FILENAME main_hex_filename
371         OUTPUT_TARGET_NAME main_target_name
372     )
374     set_property(TARGET ${main_target_name} PROPERTY OPENOCD_TARGET ${args_OPENOCD_TARGET})
375     set_property(TARGET ${main_target_name} PROPERTY OPENOCD_DEFAULT_INTERFACE stlink)
376     set_property(TARGET ${main_target_name} PROPERTY SVD ${args_SVD})
378     setup_firmware_target(${main_target_name} ${name} ${ARGN})
380     if(args_BOOTLOADER)
381         # Bootloader for the target
382         set(bl_suffix _bl)
383         add_stm32_executable(
384             NAME ${name}${bl_suffix}
385             FILENAME ${binary_name}${bl_suffix}
386             SOURCES ${target_sources} ${BOOTLOADER_SOURCES}
387             COMPILE_DEFINITIONS ${target_definitions} BOOTLOADER MSP_FIRMWARE_UPDATE
388             COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
389             INCLUDE_DIRECTORIES ${target_include_directories}
390             LINK_OPTIONS ${args_LINK_OPTIONS}
391             LINKER_SCRIPT ${args_LINKER_SCRIPT}${bl_suffix}
392             OPTIMIZATION ${args_OPTIMIZATION}
394             OUTPUT_BIN_FILENAME bl_bin_filename
395             OUTPUT_HEX_FILENAME bl_hex_filename
396             OUTPUT_TARGET_NAME bl_target_name
397         )
398         setup_executable(${bl_target_name} ${name})
400         # Main firmware, but for running with the bootloader
401         set(for_bl_suffix _for_bl)
402         add_stm32_executable(
403             NAME ${name}${for_bl_suffix}
404             FILENAME ${binary_name}${for_bl_suffix}
405             SOURCES ${target_sources} ${msc_sources} ${CMSIS_DSP_SRC} ${COMMON_SRC}
406             COMPILE_DEFINITIONS ${target_definitions} MSP_FIRMWARE_UPDATE
407             COMPILE_OPTIONS ${args_COMPILE_OPTIONS}
408             INCLUDE_DIRECTORIES ${target_include_directories}
409             LINK_OPTIONS ${args_LINK_OPTIONS}
410             LINKER_SCRIPT ${args_LINKER_SCRIPT}${for_bl_suffix}
411             OPTIMIZATION ${args_OPTIMIZATION}
413             OUTPUT_BIN_FILENAME for_bl_bin_filename
414             OUTPUT_HEX_FILENAME for_bl_hex_filename
415             OUTPUT_TARGET_NAME for_bl_target_name
416         )
417         setup_executable(${for_bl_target_name} ${name})
419         # Combined with bootloader and main firmware
420         set(with_bl_suffix _with_bl)
421         set(combined_hex ${CMAKE_BINARY_DIR}/${binary_name}${with_bl_suffix}.hex)
422         set(with_bl_target ${name}${with_bl_suffix})
423         add_custom_target(${with_bl_target}
424             ${CMAKE_SOURCE_DIR}/src/utils/combine_tool ${bl_bin_filename} ${for_bl_bin_filename} ${combined_hex}
425             BYPRODUCTS ${combined_hex}
426         )
427         add_dependencies(${with_bl_target} ${bl_target_name} ${for_bl_target_name})
428     endif()
430     # clean_<target>
431     set(generator_cmd "")
432     if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
433         set(generator_cmd "make")
434     elseif(CMAKE_GENERATOR STREQUAL "Ninja")
435         set(generator_cmd "ninja")
436     endif()
437     if (NOT generator_cmd STREQUAL "")
438         set(clean_target "clean_${name}")
439         add_custom_target(${clean_target}
440             WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
441             COMMAND ${generator_cmd} clean
442             COMMENT "Removing intermediate files for ${name}")
443         set_property(TARGET ${clean_target} PROPERTY
444             EXCLUDE_FROM_ALL 1
445             EXCLUDE_FROM_DEFAULT_BUILD 1)
446     endif()
447 endfunction()