From 1e44cbf29d35ca020e0402f2a8289935abcb54c6 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 11 Sep 2016 11:46:21 +0200 Subject: o Almost working version, not quite. Probably not the right way to do stuff. --- README.md | 4 +- nrf51.cmake | 2 + nrf51/utils.cmake | 339 ++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 311 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 2e9ab8f..5b1ba16 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ## Goals and considerations -* Make microcontroller projects look and feel as much as possible as any other c/c++ project -* Use as much as possible of the chip vendor's SDK +* Make microcontroller projects look and feel as much as possible as any other c/c++ project. +* Use as much as possible of the chip vendor's SDK without requiring any changes to the SDK code. * Make the CMake code as uniform as feasible between platforms, but allow for platform-specific options and features. # Recommended layout diff --git a/nrf51.cmake b/nrf51.cmake index 4145f91..6746527 100644 --- a/nrf51.cmake +++ b/nrf51.cmake @@ -23,3 +23,5 @@ find_program(ARM_SIZE_TOOL arm-none-eabi-size ${TOOLCHAIN_DIR}/bin) set(CMAKE_C_COMPILER ${ARM_CC}) set(CMAKE_CXX_COMPILER ${ARM_CXX}) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +add_compile_options("-mcpu=cortex-m0" "-mthumb" "-mabi=aapcs" "--std=gnu99" "-Wall" "-mfloat-abi=soft") diff --git a/nrf51/utils.cmake b/nrf51/utils.cmake index ec92b78..df9cc35 100644 --- a/nrf51/utils.cmake +++ b/nrf51/utils.cmake @@ -1,74 +1,349 @@ -function(mcu_add_executable TARGET) - target_sources(${TARGET} PUBLIC - "${MCU_NRF51_SDK_PATH}/components/toolchain/system_nrf51.c" - "${MCU_NRF51_SDK_PATH}/components/toolchain/gcc/gcc_startup_nrf51.S") - target_include_directories(${TARGET} PUBLIC - ${MCU_NRF51_SDK_PATH}/components/device - ${MCU_NRF51_SDK_PATH}/components/toolchain - ${MCU_NRF51_SDK_PATH}/components/toolchain/gcc) +function(mcu_add_executable) + set(options) + set(oneValueArgs TARGET SDK_CONFIG SOFTDEVICE) + set(multiValueArgs) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT ARGS_TARGET) + message(FATAL_ERROR "MCU: Missing required argument: TARGET") + endif () + + target_sources(${ARGS_TARGET} PUBLIC "${MCU_NRF51_SDK_PATH}/components/toolchain/system_nrf51.c") + + # 12 might be too old + if ("${MCU_NRF51_SDK_VERSION}" VERSION_LESS 12) + target_sources(${ARGS_TARGET} PUBLIC "${MCU_NRF51_SDK_PATH}/components/toolchain/gcc/gcc_startup_nrf51.s") + else () + target_sources(${ARGS_TARGET} PUBLIC "${MCU_NRF51_SDK_PATH}/components/toolchain/gcc/gcc_startup_nrf51.S") + endif () - target_compile_definitions(${TARGET} PUBLIC NRF51) + # target_compile_options(${ARGS_TARGET} PUBLIC "-mcpu=cortex-m0" "-mthumb" "-mabi=aapcs" "--std=gnu99" "-Wall" "-mfloat-abi=soft") - target_compile_options(${TARGET} PUBLIC "-mcpu=cortex-m0" "-mthumb" "-mabi=aapcs" "--std=gnu99" "-Wall" "-mfloat-abi=soft") + if (ARGS_SDK_CONFIG) + get_filename_component(SDK_CONFIG ${ARGS_SDK_CONFIG} ABSOLUTE) + get_filename_component(SDK_CONFIG ${SDK_CONFIG} DIRECTORY) + set_target_properties(${ARGS_TARGET} PROPERTIES SDK_CONFIG "${SDK_CONFIG}") + message("set_target_properties(${ARGS_TARGET} PROPERTIES SDK_CONFIG ${SDK_CONFIG})") + endif () - target_include_directories(${TARGET} PUBLIC - ${MCU_NRF51_SDK_PATH}/components/toolchain/cmsis/include) + target_link_libraries(${ARGS_TARGET} PUBLIC "-L${MCU_NRF51_SDK_PATH}/components/toolchain/gcc") + target_link_libraries(${ARGS_TARGET} PUBLIC "-T${MCU_NRF51_SDK_PATH}/components/toolchain/gcc/nrf51_xxac.ld") - target_link_libraries(${TARGET} PUBLIC "-L${MCU_NRF51_SDK_PATH}/components/toolchain/gcc") - target_link_libraries(${TARGET} PUBLIC "-T${MCU_NRF51_SDK_PATH}/components/toolchain/gcc/nrf51_xxac.ld") + if (ARGS_SOFTDEVICE) + set_target_properties(${ARGS_TARGET} PROPERTIES MCU_SOFTDEVICE "${ARGS_SOFTDEVICE}") + _nrf51_create_softdevice(${ARGS_TARGET} ${ARGS_SOFTDEVICE}) + target_link_libraries(${ARGS_TARGET} PUBLIC ${ARGS_TARGET}-softdevice) + else () + target_include_directories(${ARGS_TARGET} PUBLIC ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/nrf_soc_nosd) + endif () + + _nrf5_set_from_main_target(${ARGS_TARGET} ${ARGS_TARGET}) endfunction() -function(mcu_nrf51_add_softdevice TARGET SOFTDEVICE) +function(_nrf_softdevice_includes VAR SOFTDEVICE) + list(APPEND list ${MCU_NRF51_SDK_PATH}/components/softdevice/s${SOFTDEVICE}/headers) + + if (MCU_NRF51_SDK_VERSION VERSION_GREATER 7) + if (${MCU_CHIP} MATCHES "nrf51.*") + list(APPEND list ${MCU_NRF51_SDK_PATH}/components/softdevice/s${SOFTDEVICE}/headers/nrf51) + elseif (${MCU_CHIP} MATCHES "nrf52.*") + list(APPEND list ${MCU_NRF51_SDK_PATH}/components/softdevice/s${SOFTDEVICE}/headers/nrf52) + endif () + endif () + + set(${VAR} ${list} PARENT_SCOPE) +endfunction() - if (SOFTDEVICE STREQUAL s130) - string(TOUPPER D_SOFTDEVICE ${SOFTDEVICE}) - target_include_directories(${TARGET} PUBLIC ${MCU_NRF51_SDK_PATH}/components/softdevice/${SOFTDEVICE}/headers) +function(_nrf51_create_softdevice TARGET SOFTDEVICE) + get_target_property(SDK_CONFIG ${TARGET} SDK_CONFIG) + + set(T ${TARGET}-softdevice) + + if (SOFTDEVICE STREQUAL 130) + _nrf51_add_library(${TARGET} ${T} SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/softdevice/common) + + target_include_directories(${T} PUBLIC + ${MCU_NRF51_SDK_PATH}/components/device + ${MCU_NRF51_SDK_PATH}/components/softdevice/common + ${SDK_CONFIG}) + + _nrf_softdevice_includes(SOFTDEVICE_INCLUDES ${SOFTDEVICE}) + target_include_directories(${T} PRIVATE ${SOFTDEVICE_INCLUDES}) + + # These should be libraries, not just includes added here + target_include_directories(${T} PUBLIC + ${MCU_NRF51_SDK_PATH}/components/libraries/util + ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/clock) + + _nrf5_set_from_main_target(${TARGET} ${T}) + _nrf5_gen_lib(${TARGET} ble ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} drv_common ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} hal ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} log ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} scheduler ADD_TO ${T}) else () - message(FATAL_ERROR "Unsupported softdevice: ${SOFTDEVICE}") + message(FATAL_ERROR "MCU: Unsupported softdevice: ${SOFTDEVICE}") + return() endif () - target_compile_definitions(${TARGET} PUBLIC ${D_SOFTDEVICE}) + target_compile_definitions(${TARGET} PUBLIC S${SOFTDEVICE}) target_compile_definitions(${TARGET} PUBLIC SOFTDEVICE_PRESENT) endfunction() +function(_nrf5_set_from_main_target MAIN_TARGET T) + # message("_nrf5_set_from_main_target: MAIN_TARGET=${MAIN_TARGET} T=${T}") + + if (${MCU_CHIP} MATCHES "nrf51.*") + target_compile_definitions(${T} PUBLIC NRF51) + if (${MCU_CHIP} MATCHES "nrf51822") + target_compile_definitions(${T} PUBLIC NRF51822) + else () + message(FATAL_ERROR "MCU: Unsupported nRF MCU chip: ${MCU_CHIP}") + endif () + elseif (${MCU_CHIP} MATCHES "nrf52.*") + target_compile_definitions(${T} PUBLIC NRF52) + else () + message(FATAL_ERROR "MCU: Unsupported MCU chip: ${MCU_CHIP}") + endif () + + target_include_directories(${T} PUBLIC + ${MCU_NRF51_SDK_PATH}/components/device + ${MCU_NRF51_SDK_PATH}/components/toolchain + ${MCU_NRF51_SDK_PATH}/components/toolchain/gcc + ${MCU_NRF51_SDK_PATH}/components/toolchain/cmsis/include + ) + + get_target_property(SDK_CONFIG ${MAIN_TARGET} SDK_CONFIG) + if (SDK_CONFIG) + # message("_nrf5_set_from_main_target: SDK_CONFIG=${SDK_CONFIG}") + target_include_directories(${T} PRIVATE ${SDK_CONFIG}) + endif () + + get_target_property(MCU_SOFTDEVICE ${MAIN_TARGET} MCU_SOFTDEVICE) + if (MCU_SOFTDEVICE) + _nrf_softdevice_includes(SOFTDEVICE_INCLUDES ${MCU_SOFTDEVICE}) + target_include_directories(${T} PRIVATE ${SOFTDEVICE_INCLUDES}) + endif () +endfunction() + # Toolchain files are executed many times when detecting c/c++ compilers, but it will only read the cache on the first # exeuction so the paths has to be saved to the environment as it is shared between executions. function(mcu_nrf51_detect_sdk) if (MCU_NRF51_SDK_PATH) - # message("NRF51 SDK already found: ${MCU_NRF51_SDK_PATH}") + # message("MCU: NRF51 SDK already found: ${MCU_NRF51_SDK_PATH}") return() endif () set(MCU_NRF51_SDK_PATH "$ENV{_MCU_NRF51_SDK_PATH}") if (MCU_NRF51_SDK_PATH) - # message("NRF51 SDK already found from ENV: ${MCU_NRF51_SDK_PATH}") + # message("MCU: NRF51 SDK already found from ENV: ${MCU_NRF51_SDK_PATH}") return() endif () - message("Detecting NRF51 SDK") + message("MCU: Detecting NRF51 SDK") if (NOT MCU_NRF51_SDK) - message(FATAL_ERROR "MCU_NRF51_SDK parameter cannot be empty.") + set(MCU_NRF51_SDK "" CACHE PATH "" FORCE) + message(FATAL_ERROR "MCU: MCU_NRF51_SDK parameter cannot be empty.") + return() endif () - # message("MCU_NRF51_SDK=${MCU_NRF51_SDK}") get_filename_component(MCU_NRF51_SDK_PATH "${MCU_NRF51_SDK}" ABSOLUTE) - # message("MCU_NRF51_SDK_PATH=${MCU_NRF51_SDK_PATH}") set(ENV{_MCU_NRF51_SDK_PATH} "${MCU_NRF51_SDK_PATH}") set(NOTES ${MCU_NRF51_SDK_PATH}/documentation/release_notes.txt) if (NOT EXISTS ${NOTES}) - message(FATAL_ERROR "Could not find 'documentation/release_notes.txt' under NRF SDK path: ${NOTES}") + message(FATAL_ERROR "MCU: Could not find 'documentation/release_notes.txt' under NRF SDK path: ${NOTES}") + endif () + + file(STRINGS ${NOTES} NOTES_LIST) + list(GET NOTES_LIST 0 NOTES_0) + + if (NOTES_0 MATCHES "nRF5.? SDK [^0-9]*([\\.0-9]*)") + set(MCU_NRF51_SDK_VERSION "${CMAKE_MATCH_1}") + else () + message(FATAL_ERROR "MCU: Could not detect SDK version.") + return() endif () - file(READ ${NOTES} NOTES LIMIT 100) + message("MCU: nRF51 SDK Path: ${MCU_NRF51_SDK_PATH} (Version: ${MCU_NRF51_SDK_VERSION})") + + set(MCU_NRF51_SDK_VERSION "${MCU_NRF51_SDK_VERSION}" CACHE STRING "MCU: nRF51 SDK version" FORCE) + set(MCU_NRF51_SDK_PATH "${MCU_NRF51_SDK_PATH}" CACHE PATH "MCU: nRF51 SDK path" FORCE) +endfunction() + +function(_nrf51_add_library MAIN_TARGET T) + # message("_nrf51_add_library(${MAIN_TARGET} ${T} ARGN=${ARGN})") + + set(options) + set(oneValueArgs EXCLUDE_SOURCES) + set(multiValueArgs SOURCE_DIR) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach (DIR IN LISTS ARGS_SOURCE_DIR) + file(GLOB_RECURSE SOURCES ${DIR}/*.c) + + if (ARGS_EXCLUDE_SOURCES) + list(FILTER SOURCES EXCLUDE REGEX ${ARGS_EXCLUDE_SOURCES}) + endif () + list(APPEND ALL_SOURCES ${SOURCES}) + + file(GLOB_RECURSE HEADERS LIST_DIRECTORIES TRUE ${DIR}/*.h) + list(APPEND ALL_HEADERS ${HEADERS}) + + # Add all directories that contain header files as private include directories + foreach (H IN LISTS HEADERS) + get_filename_component(D ${H} DIRECTORY) + list(APPEND INCLUDES ${D}) + endforeach () + list(SORT INCLUDES) + list(APPEND ALL_INCLUDES ${INCLUDES}) + endforeach () + + add_library(${T} ${type} ${ALL_SOURCES} ${ALL_HEADERS}) + target_include_directories(${T} PUBLIC ${ALL_INCLUDES}) + + list(LENGTH ALL_SOURCES l) + if (l EQUAL 0) + set_target_properties(${T} PROPERTIES LINKER_LANGUAGE CXX) + endif () + + _nrf5_set_from_main_target(${MAIN_TARGET} ${T}) +endfunction() + +# TODO: this is really a public function, move arguments to parsed arguments +function(_nrf5_gen_lib TARGET LIB) + set(options) + set(oneValueArgs ADD_TO) + set(multiValueArgs) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(T ${TARGET}-${LIB}) + + if (_MCU_NRF51_LIB_CREATED_${T}) + # message("MCU: already created: ${T}") + + if (ARGS_ADD_TO) + target_link_libraries(${ARGS_ADD_TO} PUBLIC ${T}) + endif () - # message("NOTES: ${NOTES}") - message("MCU_NRF51_SDK_VERSION: ${MCU_NRF51_VERSION}") + return() + endif () + + if (NOT LIB) + message(FATAL_ERROR "MCU: Missing required argument: LIB") + elseif (LIB STREQUAL ble) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/ble/common + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/ble/ble_advertising + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/ble/peer_manager) + + _nrf5_gen_lib(${TARGET} ble_flash ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} timer ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + + # Dependency of peer_manager + _nrf5_gen_lib(${TARGET} fds ADD_TO ${T}) + + # 12+ + _nrf5_gen_lib(${TARGET} fstorage ADD_TO ${T}) + elseif (LIB STREQUAL ble_dfu) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/ble/ble_services/ble_dfu) + + _nrf5_gen_lib(${TARGET} ble ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} bootloader ADD_TO ${T}) + elseif (LIB STREQUAL ble_flash) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/ble_flash) + + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL bootloader AND MCU_NRF51_SDK_VERSION VERSION_GREATER 7) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/bootloader) + + _nrf5_gen_lib(${TARGET} ble ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} gpiote ADD_TO ${T}) + if (MCU_NRF51_SDK_VERSION VERSION_GREATER 7) + _nrf5_gen_lib(${TARGET} section_vars ADD_TO ${T}) + endif () + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL button) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/button) + _nrf5_gen_lib(${TARGET} gpiote ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} hal ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} timer ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL delay AND MCU_NRF51_SDK_VERSION VERSION_GREATER 7) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/delay) + elseif (LIB STREQUAL drv_common) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/common) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL fds) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/fds) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} fstorage ADD_TO ${T}) + elseif (LIB STREQUAL fstorage) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/fstorage) + + _nrf5_gen_lib(${TARGET} section_vars ADD_TO ${T}) + elseif (LIB STREQUAL gpiote) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/gpiote) + _nrf5_gen_lib(${TARGET} drv_common ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} hal ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL hal) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/drivers_nrf/hal) + elseif (LIB STREQUAL scheduler) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/scheduler) + + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + elseif (LIB STREQUAL section_vars AND MCU_NRF51_SDK_VERSION VERSION_GREATER 7) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/experimental_section_vars) + elseif (LIB STREQUAL sensorsim) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/sensorsim) + elseif (LIB STREQUAL timer) + # TODO: make this configurable, could probably be a target property + + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/timer + EXCLUDE_SOURCES "app_timer_.*") + target_sources(${T} PUBLIC ${MCU_NRF51_SDK_PATH}/components/libraries/timer/app_timer_appsh.c) + + _nrf5_gen_lib(${TARGET} util ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} delay ADD_TO ${T}) + _nrf5_gen_lib(${TARGET} scheduler ADD_TO ${T}) + elseif (LIB STREQUAL util) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/util + EXCLUDE_SOURCES ".*cmock.*") + + _nrf5_gen_lib(${TARGET} log ADD_TO ${T}) + elseif (LIB STREQUAL log) + _nrf51_add_library(${TARGET} ${T} + SOURCE_DIR ${MCU_NRF51_SDK_PATH}/components/libraries/log) + target_include_directories(${T} PUBLIC ${MCU_NRF51_SDK_PATH}/components/log) + else () + message(FATAL_ERROR "MCU: Unsupported LIB: ${LIB}") + endif () + + if (ARGS_ADD_TO) + target_link_libraries(${ARGS_ADD_TO} PUBLIC ${T}) + endif () - # string(SUBSTRING ) - set(MCU_NRF51_SDK_PATH "${MCU_NRF51_SDK_PATH}" CACHE PATH "" FORCE) + set(_MCU_NRF51_LIB_CREATED_${T} TRUE CACHE BOOL "" FORCE) endfunction() -- cgit v1.2.3