common.cmake 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. include(stm32/devices)
  2. foreach(FAMILY ${STM32_SUPPORTED_FAMILIES_LONG_NAME})
  3. # append short names (F0, F1, H7_M4, ...) to STM32_SUPPORTED_FAMILIES_SHORT_NAME
  4. string(REGEX MATCH "^STM32([CFGHLMUW]P?[0-9BL])_?(M0PLUS|M4|M7)?" FAMILY ${FAMILY})
  5. list(APPEND STM32_SUPPORTED_FAMILIES_SHORT_NAME ${CMAKE_MATCH_1})
  6. endforeach()
  7. list(REMOVE_DUPLICATES STM32_SUPPORTED_FAMILIES_SHORT_NAME)
  8. if(NOT STM32_TOOLCHAIN_PATH)
  9. if(DEFINED ENV{STM32_TOOLCHAIN_PATH})
  10. message(STATUS "Detected toolchain path STM32_TOOLCHAIN_PATH in environmental variables: ")
  11. message(STATUS "$ENV{STM32_TOOLCHAIN_PATH}")
  12. set(STM32_TOOLCHAIN_PATH $ENV{STM32_TOOLCHAIN_PATH})
  13. else()
  14. if(NOT CMAKE_C_COMPILER)
  15. set(STM32_TOOLCHAIN_PATH "/usr")
  16. message(STATUS "No STM32_TOOLCHAIN_PATH specified, using default: " ${STM32_TOOLCHAIN_PATH})
  17. else()
  18. # keep only directory of compiler
  19. get_filename_component(STM32_TOOLCHAIN_PATH ${CMAKE_C_COMPILER} DIRECTORY)
  20. # remove the last /bin directory
  21. get_filename_component(STM32_TOOLCHAIN_PATH ${STM32_TOOLCHAIN_PATH} DIRECTORY)
  22. endif()
  23. endif()
  24. file(TO_CMAKE_PATH "${STM32_TOOLCHAIN_PATH}" STM32_TOOLCHAIN_PATH)
  25. endif()
  26. if(NOT STM32_TARGET_TRIPLET)
  27. if(DEFINED ENV{STM32_TARGET_TRIPLET})
  28. message(STATUS "Detected target triplet STM32_TARGET_TRIPLET in environmental variables: ")
  29. message(STATUS "$ENV{STM32_TARGET_TRIPLET}")
  30. set(STM32_TARGET_TRIPLET $ENV{STM32_TARGET_TRIPLET})
  31. else()
  32. set(STM32_TARGET_TRIPLET "arm-none-eabi")
  33. message(STATUS "No STM32_TARGET_TRIPLET specified, using default: " ${STM32_TARGET_TRIPLET})
  34. endif()
  35. endif()
  36. set(CMAKE_SYSTEM_NAME Generic)
  37. set(CMAKE_SYSTEM_PROCESSOR arm)
  38. set(TOOLCHAIN_SYSROOT "${STM32_TOOLCHAIN_PATH}/${STM32_TARGET_TRIPLET}")
  39. set(TOOLCHAIN_BIN_PATH "${STM32_TOOLCHAIN_PATH}/bin")
  40. set(TOOLCHAIN_INC_PATH "${STM32_TOOLCHAIN_PATH}/${STM32_TARGET_TRIPLET}/include")
  41. set(TOOLCHAIN_LIB_PATH "${STM32_TOOLCHAIN_PATH}/${STM32_TARGET_TRIPLET}/lib")
  42. set(CMAKE_SYSROOT ${TOOLCHAIN_SYSROOT})
  43. find_program(CMAKE_OBJCOPY NAMES ${STM32_TARGET_TRIPLET}-objcopy HINTS ${TOOLCHAIN_BIN_PATH})
  44. find_program(CMAKE_OBJDUMP NAMES ${STM32_TARGET_TRIPLET}-objdump HINTS ${TOOLCHAIN_BIN_PATH})
  45. find_program(CMAKE_SIZE NAMES ${STM32_TARGET_TRIPLET}-size HINTS ${TOOLCHAIN_BIN_PATH})
  46. find_program(CMAKE_DEBUGGER NAMES ${STM32_TARGET_TRIPLET}-gdb HINTS ${TOOLCHAIN_BIN_PATH})
  47. find_program(CMAKE_CPPFILT NAMES ${STM32_TARGET_TRIPLET}-c++filt HINTS ${TOOLCHAIN_BIN_PATH})
  48. # This function adds a target with name '${TARGET}_always_display_size'. The new
  49. # target builds a TARGET and then calls the program defined in CMAKE_SIZE to
  50. # display the size of the final ELF.
  51. function(stm32_print_size_of_target TARGET)
  52. add_custom_target(${TARGET}_always_display_size
  53. ALL COMMAND ${CMAKE_SIZE} "$<TARGET_FILE:${TARGET}>"
  54. COMMENT "Target Sizes: "
  55. DEPENDS ${TARGET}
  56. )
  57. endfunction()
  58. # This function calls the objcopy program defined in CMAKE_OBJCOPY to generate
  59. # file with object format specified in OBJCOPY_BFD_OUTPUT.
  60. # The generated file has the name of the target output but with extension
  61. # corresponding to the OUTPUT_EXTENSION argument value.
  62. # The generated file will be placed in the same directory as the target output file.
  63. function(_stm32_generate_file TARGET OUTPUT_EXTENSION OBJCOPY_BFD_OUTPUT)
  64. get_target_property(TARGET_OUTPUT_NAME ${TARGET} OUTPUT_NAME)
  65. if (TARGET_OUTPUT_NAME)
  66. set(OUTPUT_FILE_NAME "${TARGET_OUTPUT_NAME}.${OUTPUT_EXTENSION}")
  67. else()
  68. set(OUTPUT_FILE_NAME "${TARGET}.${OUTPUT_EXTENSION}")
  69. endif()
  70. get_target_property(RUNTIME_OUTPUT_DIRECTORY ${TARGET} RUNTIME_OUTPUT_DIRECTORY)
  71. if(RUNTIME_OUTPUT_DIRECTORY)
  72. set(OUTPUT_FILE_PATH "${RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_FILE_NAME}")
  73. else()
  74. set(OUTPUT_FILE_PATH "${OUTPUT_FILE_NAME}")
  75. endif()
  76. add_custom_command(
  77. TARGET ${TARGET}
  78. POST_BUILD
  79. COMMAND ${CMAKE_OBJCOPY} -O ${OBJCOPY_BFD_OUTPUT} "$<TARGET_FILE:${TARGET}>" ${OUTPUT_FILE_PATH}
  80. BYPRODUCTS ${OUTPUT_FILE_PATH}
  81. COMMENT "Generating ${OBJCOPY_BFD_OUTPUT} file ${OUTPUT_FILE_NAME}"
  82. )
  83. endfunction()
  84. # This function adds post-build generation of the binary file from the target ELF.
  85. # The generated file will be placed in the same directory as the ELF file.
  86. function(stm32_generate_binary_file TARGET)
  87. _stm32_generate_file(${TARGET} "bin" "binary")
  88. endfunction()
  89. # This function adds post-build generation of the Motorola S-record file from the target ELF.
  90. # The generated file will be placed in the same directory as the ELF file.
  91. function(stm32_generate_srec_file TARGET)
  92. _stm32_generate_file(${TARGET} "srec" "srec")
  93. endfunction()
  94. # This function adds post-build generation of the Intel hex file from the target ELF.
  95. # The generated file will be placed in the same directory as the ELF file.
  96. function(stm32_generate_hex_file TARGET)
  97. _stm32_generate_file(${TARGET} "hex" "ihex")
  98. endfunction()
  99. # This function takes FAMILY (e.g. L4) and DEVICE (e.g. L496VG) to output TYPE (e.g. L496xx)
  100. function(stm32_get_chip_type FAMILY DEVICE TYPE)
  101. set(INDEX 0)
  102. foreach(C_TYPE ${STM32_${FAMILY}_TYPES})
  103. list(GET STM32_${FAMILY}_TYPE_MATCH ${INDEX} REGEXP)
  104. if(${DEVICE} MATCHES ${REGEXP})
  105. set(RESULT_TYPE ${C_TYPE})
  106. endif()
  107. math(EXPR INDEX "${INDEX}+1")
  108. endforeach()
  109. if(NOT RESULT_TYPE)
  110. message(FATAL_ERROR "Invalid/unsupported device: ${DEVICE}")
  111. endif()
  112. set(${TYPE} ${RESULT_TYPE} PARENT_SCOPE)
  113. endfunction()
  114. function(stm32_get_chip_info CHIP)
  115. set(ARG_OPTIONS "")
  116. set(ARG_SINGLE FAMILY DEVICE TYPE)
  117. set(ARG_MULTIPLE "")
  118. cmake_parse_arguments(PARSE_ARGV 1 ARG "${ARG_OPTIONS}" "${ARG_SINGLE}" "${ARG_MULTIPLE}")
  119. string(TOUPPER ${CHIP} CHIP)
  120. string(REGEX MATCH "^STM32([CFGHLMUW]P?[0-9BL])([0-9A-Z][0-9M][A-Z][0-9A-Z]).*$" CHIP ${CHIP})
  121. if((NOT CMAKE_MATCH_1) OR (NOT CMAKE_MATCH_2))
  122. message(FATAL_ERROR "Unknown chip ${CHIP}")
  123. endif()
  124. set(STM32_FAMILY ${CMAKE_MATCH_1})
  125. set(STM32_DEVICE "${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
  126. if(NOT (${STM32_FAMILY} IN_LIST STM32_SUPPORTED_FAMILIES_SHORT_NAME))
  127. message(FATAL_ERROR "Unsupported family ${STM32_FAMILY} for device ${CHIP}")
  128. endif()
  129. stm32_get_chip_type(${STM32_FAMILY} ${STM32_DEVICE} STM32_TYPE)
  130. if(ARG_FAMILY)
  131. set(${ARG_FAMILY} ${STM32_FAMILY} PARENT_SCOPE)
  132. endif()
  133. if(ARG_DEVICE)
  134. set(${ARG_DEVICE} ${STM32_DEVICE} PARENT_SCOPE)
  135. endif()
  136. if(ARG_TYPE)
  137. set(${ARG_TYPE} ${STM32_TYPE} PARENT_SCOPE)
  138. endif()
  139. endfunction()
  140. function(stm32_get_cores CORES)
  141. set(ARG_OPTIONS "")
  142. set(ARG_SINGLE CHIP FAMILY DEVICE)
  143. set(ARG_MULTIPLE "")
  144. cmake_parse_arguments(PARSE_ARGV 1 ARG "${ARG_OPTIONS}" "${ARG_SINGLE}" "${ARG_MULTIPLE}")
  145. if(ARG_CHIP)
  146. # TODO: I don't get why stm32_get_chip_info is called in stm32_get_cores
  147. stm32_get_chip_info(${ARG_CHIP} FAMILY ARG_FAMILY TYPE ARG_TYPE DEVICE ARG_DEVICE)
  148. elseif(ARG_FAMILY AND ARG_DEVICE)
  149. # TODO: I don't get why stm32_get_chip_type is called in stm32_get_cores
  150. stm32_get_chip_type(${ARG_FAMILY} ${ARG_DEVICE} ARG_TYPE)
  151. elseif(ARG_FAMILY)
  152. if(${ARG_FAMILY} STREQUAL "H7")
  153. set(${CORES} M7 M4 PARENT_SCOPE)
  154. elseif(${ARG_FAMILY} STREQUAL "WB")
  155. set(${CORES} M4 PARENT_SCOPE)
  156. elseif(${ARG_FAMILY} STREQUAL "WL")
  157. set(${CORES} M4 M0PLUS PARENT_SCOPE)
  158. elseif(${ARG_FAMILY} STREQUAL "MP1")
  159. set(${CORES} M4 PARENT_SCOPE)
  160. else()
  161. set(${CORES} "" PARENT_SCOPE)
  162. endif()
  163. return()
  164. else()
  165. message(FATAL_ERROR "Either CHIP or FAMILY or FAMILY/DEVICE should be specified for stm32_get_cores()")
  166. endif()
  167. # TODO following is the only part really used by FindCMSIS. Maybe a cleanup is needed
  168. if(${ARG_FAMILY} STREQUAL "H7")
  169. stm32h7_get_device_cores(${ARG_DEVICE} ${ARG_TYPE} CORE_LIST)
  170. elseif(${ARG_FAMILY} STREQUAL "WB")
  171. # note STM32WB have an M0 core but in current state of the art it runs ST stacks and is not needed/allowed to build for customer
  172. set(CORE_LIST M4)
  173. elseif(${ARG_FAMILY} STREQUAL "MP1")
  174. set(CORE_LIST M4)
  175. elseif(${ARG_FAMILY} STREQUAL "WL")
  176. stm32wl_get_device_cores(${ARG_DEVICE} ${ARG_TYPE} CORE_LIST)
  177. endif()
  178. set(${CORES} "${CORE_LIST}" PARENT_SCOPE)
  179. endfunction()
  180. function(stm32_get_memory_info)
  181. set(ARG_OPTIONS FLASH RAM CCRAM STACK HEAP RAM_SHARE)
  182. set(ARG_SINGLE CHIP FAMILY DEVICE CORE SIZE ORIGIN)
  183. set(ARG_MULTIPLE "")
  184. cmake_parse_arguments(INFO "${ARG_OPTIONS}" "${ARG_SINGLE}" "${ARG_MULTIPLE}" ${ARGN})
  185. if((NOT INFO_CHIP) AND ((NOT INFO_FAMILY) OR (NOT INFO_DEVICE)))
  186. message(FATAL_ERROR "Either CHIP or FAMILY/DEVICE is required for stm32_get_memory_info()")
  187. endif()
  188. if(INFO_CHIP)
  189. stm32_get_chip_info(${INFO_CHIP} FAMILY INFO_FAMILY TYPE INFO_TYPE DEVICE INFO_DEVICE)
  190. else()
  191. stm32_get_chip_type(${INFO_FAMILY} ${INFO_DEVICE} INFO_TYPE)
  192. endif()
  193. string(REGEX REPLACE "^[CFGHLMUW]P?[0-9BL][0-9A-Z][0-9M].([3468ABCDEFGHIYZ])$" "\\1" SIZE_CODE ${INFO_DEVICE})
  194. if(SIZE_CODE STREQUAL "3")
  195. set(FLASH "8K")
  196. elseif(SIZE_CODE STREQUAL "4")
  197. set(FLASH "16K")
  198. elseif(SIZE_CODE STREQUAL "6")
  199. set(FLASH "32K")
  200. elseif(SIZE_CODE STREQUAL "8")
  201. set(FLASH "64K")
  202. elseif(SIZE_CODE STREQUAL "B")
  203. set(FLASH "128K")
  204. elseif(SIZE_CODE STREQUAL "C")
  205. set(FLASH "256K")
  206. elseif(SIZE_CODE STREQUAL "D")
  207. set(FLASH "384K")
  208. elseif(SIZE_CODE STREQUAL "E")
  209. set(FLASH "512K")
  210. elseif(SIZE_CODE STREQUAL "F")
  211. set(FLASH "768K")
  212. elseif(SIZE_CODE STREQUAL "G")
  213. set(FLASH "1024K")
  214. elseif(SIZE_CODE STREQUAL "H")
  215. set(FLASH "1536K")
  216. elseif(SIZE_CODE STREQUAL "I")
  217. set(FLASH "2048K")
  218. elseif(SIZE_CODE STREQUAL "Y")
  219. set(FLASH "640K")
  220. elseif(SIZE_CODE STREQUAL "Z")
  221. set(FLASH "192K")
  222. else()
  223. set(FLASH "16K")
  224. message(WARNING "Unknow flash size for device ${DEVICE}. Set to ${FLASH}")
  225. endif()
  226. list(FIND STM32_${INFO_FAMILY}_TYPES ${INFO_TYPE} TYPE_INDEX)
  227. list(GET STM32_${INFO_FAMILY}_RAM_SIZES ${TYPE_INDEX} RAM)
  228. list(GET STM32_${INFO_FAMILY}_CCRAM_SIZES ${TYPE_INDEX} CCRAM)
  229. list(GET STM32_${INFO_FAMILY}_RAM_SHARE_SIZES ${TYPE_INDEX} RAM_SHARE)
  230. set(FLASH_ORIGIN 0x8000000)
  231. set(RAM_ORIGIN 0x20000000)
  232. set(CCRAM_ORIGIN 0x10000000)
  233. set(RAM_SHARE_ORIGIN 0x20030000)
  234. unset(TWO_FLASH_BANKS)
  235. if(INFO_FAMILY STREQUAL "F1")
  236. stm32f1_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} FLASH RAM)
  237. elseif(INFO_FAMILY STREQUAL "L1")
  238. stm32l1_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} FLASH RAM)
  239. elseif(INFO_FAMILY STREQUAL "F2")
  240. stm32f2_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} FLASH RAM)
  241. elseif(INFO_FAMILY STREQUAL "F3")
  242. stm32f3_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} FLASH RAM)
  243. elseif(INFO_FAMILY STREQUAL "H7")
  244. stm32h7_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} "${INFO_CORE}" RAM FLASH_ORIGIN RAM_ORIGIN TWO_FLASH_BANKS)
  245. elseif(INFO_FAMILY STREQUAL "WL")
  246. stm32wl_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} "${INFO_CORE}" RAM FLASH_ORIGIN RAM_ORIGIN TWO_FLASH_BANKS)
  247. elseif(INFO_FAMILY STREQUAL "WB")
  248. stm32wb_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} "${INFO_CORE}" RAM RAM_ORIGIN TWO_FLASH_BANKS)
  249. elseif(INFO_FAMILY STREQUAL "MP1")
  250. stm32mp1_get_memory_info(${INFO_DEVICE} ${INFO_TYPE} FLASH)
  251. endif()
  252. # when a device is dual core, each core uses half of total flash
  253. if(TWO_FLASH_BANKS)
  254. string(REGEX MATCH "([0-9]+)K" FLASH_KB ${FLASH})
  255. math(EXPR FLASH_KB "${CMAKE_MATCH_1} / 2")
  256. set(FLASH "${FLASH_KB}K")
  257. endif()
  258. if(INFO_FLASH)
  259. set(SIZE ${FLASH})
  260. set(ORIGIN ${FLASH_ORIGIN})
  261. elseif(INFO_RAM)
  262. set(SIZE ${RAM})
  263. set(ORIGIN ${RAM_ORIGIN})
  264. elseif(INFO_CCRAM)
  265. set(SIZE ${CCRAM})
  266. set(ORIGIN ${CCRAM_ORIGIN})
  267. elseif(INFO_RAM_SHARE)
  268. set(SIZE ${RAM_SHARE})
  269. set(ORIGIN ${RAM_SHARE_ORIGIN})
  270. elseif(INFO_STACK)
  271. if (RAM STREQUAL "2K")
  272. set(SIZE 0x200)
  273. else()
  274. set(SIZE 0x400)
  275. endif()
  276. set(ORIGIN ${RAM_ORIGIN}) #TODO: Real stack pointer?
  277. elseif(INFO_HEAP)
  278. if (RAM STREQUAL "2K")
  279. set(SIZE 0x100)
  280. else()
  281. set(SIZE 0x200)
  282. endif()
  283. set(ORIGIN ${RAM_ORIGIN}) #TODO: Real heap pointer?
  284. endif()
  285. if(INFO_SIZE)
  286. set(${INFO_SIZE} ${SIZE} PARENT_SCOPE)
  287. endif()
  288. if(INFO_ORIGIN)
  289. set(${INFO_ORIGIN} ${ORIGIN} PARENT_SCOPE)
  290. endif()
  291. endfunction()
  292. function(stm32_add_linker_script TARGET VISIBILITY SCRIPT)
  293. get_filename_component(SCRIPT "${SCRIPT}" ABSOLUTE)
  294. target_link_options(${TARGET} ${VISIBILITY} -T "${SCRIPT}")
  295. get_target_property(TARGET_TYPE ${TARGET} TYPE)
  296. if(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
  297. set(INTERFACE_PREFIX "INTERFACE_")
  298. endif()
  299. get_target_property(LINK_DEPENDS ${TARGET} ${INTERFACE_PREFIX}LINK_DEPENDS)
  300. if(LINK_DEPENDS)
  301. list(APPEND LINK_DEPENDS "${SCRIPT}")
  302. else()
  303. set(LINK_DEPENDS "${SCRIPT}")
  304. endif()
  305. set_target_properties(${TARGET} PROPERTIES ${INTERFACE_PREFIX}LINK_DEPENDS "${LINK_DEPENDS}")
  306. endfunction()
  307. if(NOT (TARGET STM32::NoSys))
  308. add_library(STM32::NoSys INTERFACE IMPORTED)
  309. target_compile_options(STM32::NoSys INTERFACE $<$<C_COMPILER_ID:GNU>:--specs=nosys.specs>)
  310. target_link_options(STM32::NoSys INTERFACE $<$<C_COMPILER_ID:GNU>:--specs=nosys.specs>)
  311. endif()
  312. if(NOT (TARGET STM32::Nano))
  313. add_library(STM32::Nano INTERFACE IMPORTED)
  314. target_compile_options(STM32::Nano INTERFACE $<$<C_COMPILER_ID:GNU>:--specs=nano.specs>)
  315. target_link_options(STM32::Nano INTERFACE $<$<C_COMPILER_ID:GNU>:--specs=nano.specs>)
  316. endif()
  317. if(NOT (TARGET STM32::Nano::FloatPrint))
  318. add_library(STM32::Nano::FloatPrint INTERFACE IMPORTED)
  319. target_link_options(STM32::Nano::FloatPrint INTERFACE
  320. $<$<C_COMPILER_ID:GNU>:-Wl,--undefined,_printf_float>
  321. )
  322. endif()
  323. if(NOT (TARGET STM32::Nano::FloatScan))
  324. add_library(STM32::Nano::FloatScan INTERFACE IMPORTED)
  325. target_link_options(STM32::Nano::FloatScan INTERFACE
  326. $<$<C_COMPILER_ID:GNU>:-Wl,--undefined,_scanf_float>
  327. )
  328. endif()