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