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