From 0e8992713add011c6868b5a27605db446a1ea87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Mon, 31 Aug 2026 11:53:52 -0400 Subject: [PATCH] Corrected the target template to describe how the framework actually works templates/target/ documented a structure the repository does not have, and following it produced a build that could not configure. Its app/CMakeLists.txt compiled ../../../../apps/threadx_demo/main.c, but there is no apps/ directory and never has been, so the first thing a new contributor hit was a CMake error on a path that does not exist. Of the three shared root directories the template declared governed, only one was real: /bsp real - both framework targets implement board.h, led.h, console.h /cmake dead - cmake/utilities.cmake was referenced by nothing. All four targets carry their own copy, and the root file was byte-identical to the NUCLEO one apart from a license URL typo /apps absent - referenced by the template, docs/architecture.md, and the template's own CMake, but never created The template now says what the framework does: applications and toolchain files live with their target. The claim that applications have no compile-time dependency on vendor headers is retired rather than restated, because neither existing demo satisfies it - both include their board_config.h for memory sizing and vendor headers for board-specific startup self-tests. A portable shared application layer stays documented as a goal, labelled as one. templates/target/app/main.c is added because the template now points at it. It depends only on and the contracts and uses static thread stacks, so it avoids needing the board's memory extents and will compile for any target implementing the interfaces. It is a starting point to grow in place, not a shared application. Also removed the template's dead SHARED_APP_DIR and its guarded include of ${SHARED_CMAKE_DIR}/gcc-arm-none-eabi.cmake, a file that was never added, so the include silently never fired. The template's BSP CMake now uses SHARED_BSP_DIR instead of a five-level relative path, matching what both real targets do, and CMAKE_C_STANDARD moves from 11 to 99 per AGENTS.md. The deleted cmake/utilities.cmake is recoverable from history if the intent was for it to become the shared location; nothing referenced it in this state, and leaving a duplicate that looks authoritative invites edits that have no effect. Verified the NUCLEO target still builds clean (22068 B ROM, 6000 B RAM) and its Renode suite still passes; neither target used the removed file. Assisted-by: Claude Opus 5 (1M context) --- cmake/utilities.cmake | 50 ----------- docs/architecture.md | 15 ++-- templates/target/CMakeLists.txt | 17 ++-- templates/target/README.md | 16 ++-- templates/target/app/CMakeLists.txt | 5 +- templates/target/app/main.c | 105 ++++++++++++++++++++++++ templates/target/lib/bsp/CMakeLists.txt | 2 +- 7 files changed, 135 insertions(+), 75 deletions(-) delete mode 100644 cmake/utilities.cmake create mode 100644 templates/target/app/main.c diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake deleted file mode 100644 index 2686c1f8..00000000 --- a/cmake/utilities.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) Microsoft -# Copyright (c) 2024 Eclipse Foundation -# -# This program and the accompanying materials are made available -# under the terms of the MIT license which is available at -# https://opensource.org/licenses/MIT. -# -# SPDX-License-Identifier: MIT -# -# Contributors: -# Microsoft - Initial version -# Frédéric Desbiens - 2024 version. - -function(post_build TARGET) - if(CMAKE_C_COMPILER_ID STREQUAL "IAR") - add_custom_target(${TARGET}.bin ALL - DEPENDS ${TARGET} - COMMAND ${CMAKE_IAR_ELFTOOL} --bin ${TARGET}.elf ${TARGET}.bin) - elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") - add_custom_target(${TARGET}.bin ALL - DEPENDS ${TARGET} - COMMAND ${CMAKE_OBJCOPY} -Obinary ${TARGET}.elf ${TARGET}.bin - COMMAND ${CMAKE_OBJCOPY} -Oihex ${TARGET}.elf ${TARGET}.hex) - else() - message(FATAL_ERROR "Unknown CMAKE_C_COMPILER_ID ${CMAKE_C_COMPILER_ID}") - endif() -endfunction() - -function(set_target_linker TARGET LINKER_SCRIPT) - if(CMAKE_C_COMPILER_ID STREQUAL "IAR") - target_link_options(${TARGET} PRIVATE --config ${LINKER_SCRIPT}) - target_link_options(${TARGET} PRIVATE --map=${TARGET}.map) - elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_options(${TARGET} PRIVATE -T${LINKER_SCRIPT}) - target_link_options(${TARGET} PRIVATE -Wl,-Map=${TARGET}.map) - set_target_properties(${TARGET} PROPERTIES SUFFIX ".elf") - - else() - message(FATAL_ERROR "Unknown CMAKE_C_COMPILER_ID ${CMAKE_C_COMPILER_ID}") - endif() -endfunction() - -macro(print_all_variables) - message(STATUS "print_all_variables------------------------------------------{") - get_cmake_property(_variableNames VARIABLES) - foreach (_variableName ${_variableNames}) - message(STATUS "${_variableName}=${${_variableName}}") - endforeach() - message(STATUS "print_all_variables------------------------------------------}") -endmacro() diff --git a/docs/architecture.md b/docs/architecture.md index e0049690..b932fcbe 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -9,8 +9,8 @@ This document describes the architecture, design philosophy, directory structure The BSP framework is designed to be **additive and non-invasive**, allowing new boards to be integrated without modifying existing board implementations. 1. **Legacy Isolation**: The board directories that predate this framework (`/MXChip`, `/OpenHW`, `/STMicroelectronics`) remain completely untouched, preserving their drivers, submodules, and build systems. -2. **Platform-Independent Applications**: Target applications use only the abstract BSP interfaces and have no compile-time dependency on vendor-specific HALs, SDKs, or hardware registers. -3. **Reusable Infrastructure**: Shared CMake toolchains and build utilities are centralized under `/cmake` to eliminate duplicated build configuration across supported boards. +2. **Hardware Access Through the BSP**: Application logic reaches LEDs and the console through the abstract interfaces in `/bsp`, not through vendor registers. Applications are target-resident: each target owns its demo under `app/`, and today's demos do additionally include their own `board_config.h` for memory sizing and vendor headers for board-specific startup self-tests. A fully portable shared application layer is a goal of the framework, not a property it has yet. +3. **Independent Build Configuration**: Each target carries its own `cmake/` toolchain files and build helpers. Nothing in the build is shared between targets, so changing one board cannot break another. --- @@ -24,11 +24,12 @@ samplex/ (repository root) ├── OpenHW/ # [Pre-framework] Standalone board sample ├── STMicroelectronics/ # [Pre-framework] Standalone board samples ├── targets/ # [Framework] Supported BSP target boards -│ └── Microchip/ -│ └── POLARFIRE_ICICLE_RENODE/ # Board-specific BSP implementation & Renode target +│ ├── Microchip/ +│ │ └── POLARFIRE_ICICLE_RENODE/ # Board-specific BSP implementation & Renode target +│ └── STMicroelectronics/ +│ └── NUCLEO_F401RE/ # Board-specific BSP implementation & Renode target ├── bsp/ # [Framework] Abstract BSP interface definitions │ └── include/bsp/ # board.h, led.h, console.h -├── cmake/ # [Framework] Shared CMake configuration and utilities ├── docs/ # [Framework] Architecture and onboarding documentation └── templates/ # [Framework] Templates for onboarding new boards ``` @@ -62,6 +63,6 @@ Every board added to the framework under `/targets` must implement the abstract 1. **Create the Target Folder**: Create a new directory under `targets///` using `/templates/target/` as the starting point. 2. **Define Local Configuration**: Create a `board_config.h` file containing board-specific settings such as clock configuration, UART parameters, and ThreadX memory allocation. 3. **Implement the BSP APIs**: Implement the interfaces defined in `/bsp/include/bsp/` using the vendor SDK or direct register access. -4. **Configure CMake**: Add the board target to `CMakeLists.txt`, build the BSP as a static library, and link it with the desired application from `/apps/`. +4. **Configure CMake**: Add the board target to `CMakeLists.txt`, supply the target's toolchain file under its own `cmake/`, build the BSP as a static library, and link it with the application in the target's `app/` directory. -Once a board implements the required BSP interfaces, any compatible application under `/apps` can be built for that board without modifying the application source. +Start from `templates/target/app/main.c`, which depends only on `` and the `` contracts and therefore builds on any target that implements them. Grow it in place as the board needs; there is no shared `/apps` directory to link an application from. diff --git a/templates/target/CMakeLists.txt b/templates/target/CMakeLists.txt index 13ac5b52..f68bc8d2 100644 --- a/templates/target/CMakeLists.txt +++ b/templates/target/CMakeLists.txt @@ -11,20 +11,21 @@ cmake_minimum_required(VERSION 3.15) # TODO: Replace 'TARGET_BOARD_TEMPLATE' with your target board name (e.g. MY_CUSTOM_BOARD) project(TARGET_BOARD_TEMPLATE C CXX ASM) -set(CMAKE_C_STANDARD 11) +# AGENTS.md requires C99 compatibility. +set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) -# Define root paths +# Define root paths. Only libs/ and bsp/ are shared; the toolchain file and any +# CMake helper modules belong to this target, under cmake/. get_filename_component(WORKSPACE_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) set(SHARED_LIB_DIR "${WORKSPACE_ROOT}/libs") -set(SHARED_APP_DIR "${WORKSPACE_ROOT}/apps") set(SHARED_BSP_DIR "${WORKSPACE_ROOT}/bsp") -set(SHARED_CMAKE_DIR "${WORKSPACE_ROOT}/cmake") -# Include GNU ARM Toolchain setup if building for bare-metal ARM Cortex-M -if(EXISTS "${SHARED_CMAKE_DIR}/gcc-arm-none-eabi.cmake") - include("${SHARED_CMAKE_DIR}/gcc-arm-none-eabi.cmake") -endif() +# TODO: Add this target's cmake/ directory and select its toolchain file, e.g. +# if(NOT CMAKE_TOOLCHAIN_FILE) +# set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/-toolchain.cmake") +# endif() +# list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) # Global compiler flags add_compile_options( diff --git a/templates/target/README.md b/templates/target/README.md index 43a35a13..a5be06db 100644 --- a/templates/target/README.md +++ b/templates/target/README.md @@ -12,11 +12,11 @@ This directory contains the skeletal blueprint for onboarding a new hardware boa ## 1. Dependency Flow Architecture -The following diagram illustrates how the generic application layer is decoupled from physical MCU registers using the BSP framework: +The following diagram illustrates how application code reaches hardware through the BSP framework rather than through vendor registers directly: ```mermaid flowchart TD - App["Generic Application (apps/threadx_demo/main.c)"] + App["Application (targets/<Vendor>/<Board>/app/)"] BSP_API["BSP Interface Contract (bsp/include/bsp/)"] Target_BSP["Target BSP Driver Library (targets/<Vendor>/<Board>/lib/bsp/)"] Vendor_SDK["Vendor SDK / Platform Support Libraries"] @@ -33,9 +33,8 @@ flowchart TD ```text Repository │ -├── apps/ (Platform-independent application logic) ├── bsp/ (Target-agnostic C interface contracts) -├── cmake/ (Shared build infrastructure & toolchains) +├── libs/ (Shared RTOS components: ThreadX, NetX Duo, FileX, USBX) └── targets/ (Independent board support implementations) ├── STMicroelectronics/NUCLEO_F401RE/ └── Microchip/POLARFIRE_ICICLE_RENODE/ @@ -47,9 +46,11 @@ Repository To maintain long-term framework maintainability and portability, the following root directories should generally remain **unchanged** when onboarding a new board: -* `/apps`: Contains shared example applications and reusable demos (such as `threadx_demo`). Applications in this directory interact with hardware solely through the abstract headers in ``. Developers may also add additional applications alongside the provided examples. * `/bsp`: Defines the target-agnostic C interface contracts (`board.h`, `led.h`, `console.h`). New board targets must implement these existing interfaces rather than modifying core interface definitions. -* `/cmake`: Contains shared cross-compilation toolchain settings and build utility functions. +* `/libs`: Shared RTOS components consumed by every target as submodules. Targets reference these rather than vendoring their own copy. + +> [!NOTE] +> **Applications are currently target-resident.** Each target owns its demo under `targets///app/`, along with its own `cmake/` toolchain files and build helpers. A shared `/apps` layer is a goal of this framework, not something it provides yet: today's demos also include their target's `board_config.h` for memory sizing and vendor headers for board-specific startup self-tests. Onboard a new board by starting from the app in this template, not by linking one from a shared directory. > [!NOTE] > **Core Architectural Principle**: @@ -74,7 +75,8 @@ The table below maps common embedded software components to their designated loc | **BSP Driver Implementation** | `targets///lib/bsp/src/` | Target developer (`bsp_board.c`, `bsp_led.c`, `bsp_console.c`) | | **Target Specification Constants** | `targets///lib/bsp/include/board_config.h` | Target developer (declarative defines only) | | **Target Build Automation** | `targets///scripts/build.ps1` | Target developer (PowerShell automation template) | -| **Shared Application Code** | `/apps//` | Framework shared application layer (remains in root) | +| **Application Code** | `targets///app/` | Target developer (start from this template's `app/main.c`) | +| **Toolchain & Build Helpers** | `targets///cmake/` | Target developer (cross-compilation settings per target) | --- diff --git a/templates/target/app/CMakeLists.txt b/templates/target/app/CMakeLists.txt index 1fad0eaa..6e9a585f 100644 --- a/templates/target/app/CMakeLists.txt +++ b/templates/target/app/CMakeLists.txt @@ -15,8 +15,9 @@ set(SOURCES # ${COMMON_DIR}/startup/startup_mcu.s # ${COMMON_DIR}/startup/tx_initialize_low_level.S - # Link the shared platform-independent ThreadX application - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../apps/threadx_demo/main.c + # This target's ThreadX application. Applications are target-resident: + # there is no shared apps/ directory to link one from. + ${CMAKE_CURRENT_SOURCE_DIR}/main.c # Link GCC Newlib syscall stubs ${CMAKE_CURRENT_SOURCE_DIR}/../lib/bsp/src/newlib_stubs.c diff --git a/templates/target/app/main.c b/templates/target/app/main.c new file mode 100644 index 00000000..668cf681 --- /dev/null +++ b/templates/target/app/main.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +/* + * Minimal ThreadX starting point for a new board target. + * + * This file deliberately depends on nothing but and the generic BSP + * contracts in , so it compiles for any target that implements them. + * Thread stacks are static, which avoids needing the board's memory extents. + * + * Once the board boots this, grow the demo in place. Real targets do include + * their own board_config.h and vendor headers - for byte-pool sizing and for + * board-specific startup self-tests - and that is expected; applications live + * with their target rather than in a shared directory. + */ + +#include "tx_api.h" + +#include "bsp/board.h" +#include "bsp/console.h" +#include "bsp/led.h" + +#include + +#define DEMO_STACK_SIZE 1024 +#define BLINK_PERIOD_TICKS (TX_TIMER_TICKS_PER_SECOND / 2) +#define REPORT_PERIOD_TICKS (TX_TIMER_TICKS_PER_SECOND) + +static TX_THREAD blink_thread; +static TX_THREAD report_thread; + +static UCHAR blink_stack[DEMO_STACK_SIZE]; +static UCHAR report_stack[DEMO_STACK_SIZE]; + +static void console_print(const char *text) +{ + bsp_console_write(text, strlen(text)); +} + +static void blink_thread_entry(ULONG parameter) +{ + (void)parameter; + + while (1) + { + bsp_led_toggle(); + tx_thread_sleep(BLINK_PERIOD_TICKS); + } +} + +static void report_thread_entry(ULONG parameter) +{ + (void)parameter; + + while (1) + { + console_print("[template] ThreadX is running\r\n"); + tx_thread_sleep(REPORT_PERIOD_TICKS); + } +} + +void tx_application_define(void *first_unused_memory) +{ + (void)first_unused_memory; + + /* TODO: Create a TX_BYTE_POOL from first_unused_memory if this target's + * demo outgrows static stacks. Doing so needs the board's RAM extent, so + * it belongs with the target rather than in shared code. */ + + (void)tx_thread_create(&blink_thread, "blink thread", blink_thread_entry, 0, + blink_stack, DEMO_STACK_SIZE, + 10, 10, TX_NO_TIME_SLICE, TX_AUTO_START); + + (void)tx_thread_create(&report_thread, "report thread", report_thread_entry, 0, + report_stack, DEMO_STACK_SIZE, + 11, 11, TX_NO_TIME_SLICE, TX_AUTO_START); +} + +int main(void) +{ + bsp_board_init(); + + console_print("\r\n=== Eclipse ThreadX target template ===\r\n"); + + /* TODO: Run any board-specific startup self-tests here, before the + * scheduler starts, so failures are reported even if it never runs. */ + + tx_kernel_enter(); + + while (1) + { + } +} diff --git a/templates/target/lib/bsp/CMakeLists.txt b/templates/target/lib/bsp/CMakeLists.txt index de096665..8b7ddebb 100644 --- a/templates/target/lib/bsp/CMakeLists.txt +++ b/templates/target/lib/bsp/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(target_bsp STATIC # Export BSP headers and shared abstract C BSP headers to PUBLIC include paths target_include_directories(target_bsp PUBLIC include - ${CMAKE_CURRENT_LIST_DIR}/../../../../../bsp/include + ${SHARED_BSP_DIR}/include ) # Link ThreadX and vendor HAL dependencies if required