Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .scripts/lint-targets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ c_board:
folders:
- core/src
- core/include
- firmware/c_board/src
- firmware/c_board/include
- firmware/c_board/app/src
- firmware/c_board/app/include
30 changes: 21 additions & 9 deletions .scripts/patch_cubemx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ STALE_FILES = (
Path(".mxproject"),
Path("CMakeLists.txt"),
Path("CMakePresets.json"),
Path("STM32F407XX_FLASH.ld"),
Path("cmake/starm-clang.cmake"),
Path("cmake/gcc-arm-none-eabi.cmake"),
)

PATCH_RULES = (
Expand All @@ -28,14 +30,23 @@ PATCH_RULES = (
),
(
re.compile(r"/[^\s\"')]+/Drivers/CMSIS/Include(?=$|[\s\"')])"),
r"${LIBRMCS_CMSIS_CORE_INCLUDE_DIR}",
r"${LIBRMCS_CMSIS_CORE_ROOT}/Core/Include",
),
)

ABSOLUTE_PATH_PATTERN = re.compile(r"(?:(?<=^)|(?<=[\s(]))/[^\s\"')]+")
PROJECT_LINK_LIBRARIES_PATTERN = re.compile(
r"target_link_libraries\(\$\{CMAKE_PROJECT_NAME\}\s+\$\{MX_LINK_LIBS\}\)"
DRIVERS_MIDDLEWARES_TO_EOF_PATTERN = re.compile(
r"^# Drivers Midllewares[\s\S]*\Z",
re.MULTILINE,
)
STM32CUBEMX_TAIL = """# Create stm32cubemx object library
add_library(stm32cubemx OBJECT)
target_sources(stm32cubemx PRIVATE ${STM32_Drivers_Src})
target_sources(stm32cubemx PRIVATE ${MX_Application_Src})
target_include_directories(stm32cubemx PUBLIC ${MX_Include_Dirs})
target_compile_definitions(stm32cubemx PUBLIC ${MX_Defines_Syms})
"""
STM32CUBEMX_TAIL_ANCHOR = "# Create stm32cubemx object library"


def parse_args() -> argparse.Namespace:
Expand All @@ -46,15 +57,15 @@ def parse_args() -> argparse.Namespace:
"--cubemx-root",
type=Path,
default=None,
help="Path to CubeMX root (default: firmware/c_board/cubemx).",
help="Path to CubeMX root (default: firmware/c_board/bsp/cubemx).",
)
return parser.parse_args()


def resolve_cubemx_root(cubemx_root_arg: Path | None) -> Path:
if cubemx_root_arg is not None:
return cubemx_root_arg.resolve()
return (Path(__file__).resolve().parent.parent / "firmware/c_board/cubemx").resolve()
return (Path(__file__).resolve().parent.parent / "firmware/c_board/bsp/cubemx").resolve()


def remove_stale_files(cubemx_root: Path) -> None:
Expand All @@ -73,10 +84,11 @@ def patch_stm32cubemx_cmake(cubemx_root: Path) -> None:
for pattern, replacement in PATCH_RULES:
patched = pattern.sub(replacement, patched)

patched = PROJECT_LINK_LIBRARIES_PATTERN.sub(
"target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${MX_LINK_LIBS})",
patched,
)
line_ending = "\r\n" if "\r\n" in original else "\n"
custom_tail = STM32CUBEMX_TAIL.replace("\n", line_ending)
patched, replacements = DRIVERS_MIDDLEWARES_TO_EOF_PATTERN.subn(custom_tail, patched)
if replacements == 0 and STM32CUBEMX_TAIL_ANCHOR not in patched:
raise ValueError("Marker '# Drivers Midllewares' not found in stm32cubemx CMake file")

unresolved = sorted(set(ABSOLUTE_PATH_PATTERN.findall(patched)))
if unresolved:
Expand Down
33 changes: 17 additions & 16 deletions Dockerfile.build_firmware
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,25 @@ SHELL ["/bin/bash", "-c"]
WORKDIR /src
RUN --mount=type=bind,target=/src,source=.,readonly \
set -euo pipefail \
&& mkdir -p /output \
&& LIBRMCS_PROJECT_VERSION="$(.scripts/generate_version)" \
&& for board in rmcs_board c_board; do \
for config in debug release; do \
build_dir="/output/build-${board}-${config}"; \
cmake --preset "${config}" -S "firmware/${board}" -B "${build_dir}"; \
cmake --build "${build_dir}"; \
elf_path="${build_dir}/output/librmcs-firmware.elf"; \
if [ ! -f "${elf_path}" ]; then \
elf_path="${build_dir}/librmcs-firmware.elf"; \
fi; \
if [ ! -f "${elf_path}" ]; then \
echo "Missing firmware ELF for ${board} (${config})" >&2; \
exit 1; \
fi; \
mv "${elf_path}" "/output/librmcs-firmware-${board}-${LIBRMCS_PROJECT_VERSION}-${config}.elf"; \
done; \
&& for board in rmcs_board; do \
build_dir="/tmp/build-${board}"; \
cmake --preset release -S "firmware/${board}" -B "${build_dir}"; \
cmake --build "${build_dir}"; \
elf_path="${build_dir}/output/librmcs-firmware.elf"; \
if [ ! -f "${elf_path}" ]; then \
elf_path="${build_dir}/librmcs-firmware.elf"; \
fi; \
cp "${elf_path}" "/output/librmcs-firmware-${board}-${LIBRMCS_PROJECT_VERSION}.elf"; \
done \
&& rm -rf /output/build-*
&& for board in c_board; do \
build_dir="/tmp/build-${board}"; \
cmake --preset release -S "firmware/${board}" -B "${build_dir}"; \
cmake --build "${build_dir}"; \
cp "${build_dir}/app/${board}_app.elf" \
"/output/librmcs-firmware-${board}-${LIBRMCS_PROJECT_VERSION}.elf"; \
done

FROM scratch AS output
COPY --from=build /output/ /
147 changes: 42 additions & 105 deletions firmware/c_board/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.28)
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)

# Language standards
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
Expand All @@ -13,21 +12,14 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

set(CMAKE_PROJECT_NAME librmcs-firmware)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(${CMAKE_PROJECT_NAME})
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
enable_language(C CXX ASM)

project(librmcs-firmware LANGUAGES C CXX ASM)

set(LIBRMCS_PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../..")
cmake_path(ABSOLUTE_PATH LIBRMCS_PROJECT_ROOT NORMALIZE)

set(LIBRMCS_STM32_HAL_DRIVER_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/stm32f4xx-hal-driver")
set(LIBRMCS_STM32_DEVICE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cmsis-device-f4")
set(LIBRMCS_CMSIS_CORE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cmsis-core")
set(LIBRMCS_CMSIS_CORE_INCLUDE_DIR "${LIBRMCS_CMSIS_CORE_ROOT}/Core/Include")
set(LIBRMCS_TINYUSB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/tinyusb")

if(NOT DEFINED LIBRMCS_PROJECT_VERSION OR LIBRMCS_PROJECT_VERSION STREQUAL "")
execute_process(
Expand All @@ -40,56 +32,7 @@ if(NOT DEFINED LIBRMCS_PROJECT_VERSION OR LIBRMCS_PROJECT_VERSION STREQUAL "")
endif()
message(STATUS "Librmcs project version: ${LIBRMCS_PROJECT_VERSION}")

add_executable(${CMAKE_PROJECT_NAME})

# Add libstdc++ for C++ code.
list(APPEND TOOLCHAIN_LINK_LIBRARIES "stdc++")

add_subdirectory(cubemx/cmake/stm32cubemx)

add_library(tinyusb_device OBJECT)
target_sources(tinyusb_device PRIVATE
"${LIBRMCS_TINYUSB_ROOT}/src/tusb.c"
"${LIBRMCS_TINYUSB_ROOT}/src/common/tusb_fifo.c"
"${LIBRMCS_TINYUSB_ROOT}/src/device/usbd.c"
"${LIBRMCS_TINYUSB_ROOT}/src/device/usbd_control.c"
"${LIBRMCS_TINYUSB_ROOT}/src/class/vendor/vendor_device.c"
"${LIBRMCS_TINYUSB_ROOT}/src/portable/synopsys/dwc2/dwc2_common.c"
"${LIBRMCS_TINYUSB_ROOT}/src/portable/synopsys/dwc2/dcd_dwc2.c"
)
target_include_directories(tinyusb_device SYSTEM PUBLIC
"${LIBRMCS_TINYUSB_ROOT}/src"
)
target_include_directories(tinyusb_device PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_compile_definitions(tinyusb_device PUBLIC
CFG_TUSB_MCU=OPT_MCU_STM32F4
)
target_link_libraries(tinyusb_device PUBLIC
stm32cubemx
)

# Mark CubeMX/HAL headers as SYSTEM so they show up as `-isystem` in
# compile_commands.json (clang-tidy should not warn on third-party code).
if(TARGET stm32cubemx)
get_target_property(HAL_INCLUDE_DIRS stm32cubemx INTERFACE_INCLUDE_DIRECTORIES)
if(HAL_INCLUDE_DIRS AND NOT HAL_INCLUDE_DIRS STREQUAL "HAL_INCLUDE_DIRS-NOTFOUND")
set_property(TARGET stm32cubemx PROPERTY INTERFACE_INCLUDE_DIRECTORIES "")
target_include_directories(stm32cubemx SYSTEM INTERFACE ${HAL_INCLUDE_DIRS})
endif()
endif()

# --- Compile options ---
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
-fvisibility=hidden
$<$<COMPILE_LANGUAGE:CXX>:-Wall -Wextra -Wpedantic>
$<$<COMPILE_LANGUAGE:CXX>:-fno-unwind-tables>
$<$<COMPILE_LANGUAGE:CXX>:-fno-asynchronous-unwind-tables>
$<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>
)

# --- HOST_DEBUGGER support ---
option(HOST_DEBUGGER "Debugger runs outside Dev Container (Docker)" OFF)
set(SOURCE_PATH_MAP "" CACHE PATH "(In container) Map container source path to a host-visible path for debugger")

Expand All @@ -103,55 +46,49 @@ endif()
if(NOT SOURCE_PATH_MAP STREQUAL "")
set(SOURCE_PATH_MAP "${SOURCE_PATH_MAP}/")
cmake_path(NORMAL_PATH SOURCE_PATH_MAP)

target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
add_compile_options(
"-fdebug-prefix-map=${LIBRMCS_PROJECT_ROOT}=${SOURCE_PATH_MAP}"
"-ffile-prefix-map=${LIBRMCS_PROJECT_ROOT}=${SOURCE_PATH_MAP}"
)
endif()

# Debug build: append -Og (overrides toolchain's -O0, GCC takes last)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Og)
endif()

# --- User application sources ---
file(GLOB_RECURSE APP_SOURCES CONFIGURE_DEPENDS src/*.cpp src/*.c)
file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS
"${LIBRMCS_PROJECT_ROOT}/core/src/*.cpp"
"${LIBRMCS_PROJECT_ROOT}/core/src/*.c"
)
file(GLOB SEGGER_C_SOURCES bsp/SEGGER/RTT/*.c)
file(GLOB SEGGER_ASM_SOURCES bsp/SEGGER/RTT/*.S)

target_sources(${CMAKE_PROJECT_NAME} PRIVATE
${APP_SOURCES}
${CORE_SOURCES}
${SEGGER_C_SOURCES}
${SEGGER_ASM_SOURCES}
)

# --- Include paths ---
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
${LIBRMCS_PROJECT_ROOT}
)

# SEGGER RTT is third-party code; treat its headers as system headers.
target_include_directories(${CMAKE_PROJECT_NAME} SYSTEM PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/bsp/SEGGER/RTT
${CMAKE_CURRENT_SOURCE_DIR}/bsp/SEGGER/Config
)

# --- Defines ---
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
LIBRMCS_PROJECT_VERSION_STRING="${LIBRMCS_PROJECT_VERSION}"
$<$<CONFIG:Release>:NDEBUG>
)

# Remove wrong libob.a dependency (CubeMX toolchain quirk)
list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_LIBRARIES ob)

target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
stm32cubemx
tinyusb_device
)
set(LIBRMCS_STM32_HAL_DRIVER_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/stm32f4xx-hal-driver")
set(LIBRMCS_STM32_DEVICE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cmsis-device-f4")
set(LIBRMCS_CMSIS_CORE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cmsis-core")
set(LIBRMCS_STM32_CUBEMX_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/bsp/cubemx")

add_subdirectory("${LIBRMCS_STM32_CUBEMX_ROOT}/cmake/stm32cubemx" SYSTEM)


function(c_board_apply_target_options target linker_file)
target_include_directories(${target} PRIVATE
${LIBRMCS_PROJECT_ROOT}
)

target_compile_options(${target} PRIVATE
-fvisibility=hidden
$<$<COMPILE_LANGUAGE:CXX>:-Wall -Wextra -Wpedantic>
$<$<COMPILE_LANGUAGE:CXX>:-fno-unwind-tables>
$<$<COMPILE_LANGUAGE:CXX>:-fno-asynchronous-unwind-tables>
$<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>
)

target_compile_definitions(${target} PRIVATE
LIBRMCS_PROJECT_VERSION_STRING="${LIBRMCS_PROJECT_VERSION}"
$<$<CONFIG:Release>:NDEBUG>
)

target_link_libraries(${target} PRIVATE
stdc++
m
stm32cubemx
)
target_link_options(${target} PRIVATE
"-Wl,-Map=$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.map"
"-T${LIBRMCS_STM32_CUBEMX_ROOT}/${linker_file}"
)
endfunction()


add_subdirectory(app)
2 changes: 1 addition & 1 deletion firmware/c_board/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"toolchainFile": "${sourceDir}/cubemx/cmake/gcc-arm-none-eabi.cmake"
"toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake"
},
{
"name": "debug",
Expand Down
53 changes: 53 additions & 0 deletions firmware/c_board/app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
add_executable(c_board_app)

set(C_BOARD_APP_TINYUSB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../bsp/tinyusb")
cmake_path(ABSOLUTE_PATH C_BOARD_APP_TINYUSB_ROOT NORMALIZE)
set(C_BOARD_APP_TINYUSB_COMMON_SOURCES
"${C_BOARD_APP_TINYUSB_ROOT}/src/tusb.c"
"${C_BOARD_APP_TINYUSB_ROOT}/src/common/tusb_fifo.c"
"${C_BOARD_APP_TINYUSB_ROOT}/src/device/usbd.c"
"${C_BOARD_APP_TINYUSB_ROOT}/src/device/usbd_control.c"
"${C_BOARD_APP_TINYUSB_ROOT}/src/portable/synopsys/dwc2/dwc2_common.c"
"${C_BOARD_APP_TINYUSB_ROOT}/src/portable/synopsys/dwc2/dcd_dwc2.c"
)

add_library(tinyusb_app OBJECT)
target_sources(tinyusb_app PRIVATE
${C_BOARD_APP_TINYUSB_COMMON_SOURCES}
"${C_BOARD_APP_TINYUSB_ROOT}/src/class/vendor/vendor_device.c"
)
target_include_directories(tinyusb_app SYSTEM PUBLIC
"${C_BOARD_APP_TINYUSB_ROOT}/src"
)
target_include_directories(tinyusb_app PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_compile_definitions(tinyusb_app PUBLIC
CFG_TUSB_MCU=OPT_MCU_STM32F4
)
target_link_libraries(tinyusb_app PUBLIC
stm32cubemx
)

file(GLOB_RECURSE C_BOARD_APP_SOURCES CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
"${LIBRMCS_PROJECT_ROOT}/core/src/*.cpp"
"${LIBRMCS_PROJECT_ROOT}/core/src/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../bsp/SEGGER/RTT/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/../bsp/SEGGER/RTT/*.S"
)
target_sources(c_board_app PRIVATE
${C_BOARD_APP_SOURCES}
)

target_include_directories(c_board_app SYSTEM PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../bsp/SEGGER/RTT"
"${CMAKE_CURRENT_SOURCE_DIR}/../bsp/SEGGER/Config"
)

target_link_libraries(c_board_app PRIVATE
tinyusb_app
)

c_board_apply_target_options(c_board_app "STM32F407XX_APP.ld")
Loading