2025-06-13 3:30 AM
Hello community,
I have been working towards getting a prototype ThreadX modules project on my board (Nucleo U545RE-Q) using CMake from a generated STM32CubeMX project.
I have been loosely following the documentation https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/threadx-modules/
I have been able to build a ThreadX Module as a library, and a ThreadX Module Manager as a library - CMake samples below:
# Interface library for includes and symbols
add_library(module_1 INTERFACE)
target_include_directories(module_1 INTERFACE ${MX_Include_Dirs})
target_compile_definitions(module_1 INTERFACE ${MX_Defines_Syms})
# Create STM32_Drivers static library
target_link_libraries(STM32_Drivers PUBLIC module_1)
# Create ThreadX static library
add_library(ThreadXModules OBJECT)
target_sources(ThreadXModules PRIVATE ${Module_sources})
target_link_libraries(ThreadXModules PUBLIC module_1)
# Interface library for includes and symbols
add_library(module_manager INTERFACE)
target_include_directories(module_manager INTERFACE ${MX_Include_Dirs})
target_compile_definitions(module_manager INTERFACE ${MX_Defines_Syms})
# Create STM32_Drivers static library
target_link_libraries(STM32_Drivers PUBLIC module_manager)
# Create ThreadX static library
add_library(ThreadX_ModMan OBJECT)
target_sources(ThreadX_ModMan PRIVATE ${ThreadX_Src} ${ThreadX_Module_Src} ${ThreadX_Module_Manager_Src})
target_link_libraries(ThreadX_ModMan PUBLIC module_manager)
These are added as subdirectories from the top level CMake and linked:
# Add STM32CubeMX generated sources
add_subdirectory(cmake/stm32cubemx)
add_subdirectory(cmake/module_manager)
add_subdirectory(cmake/module_1)
. . .
# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
stm32cubemx
# Add user defined libraries
module_1
module_manager
)
As I am very new to this, I seem to be missing a final step that allows my module code to not be discarded as my .map file shows:
Discarded input sections
...
.text.demo_module_start
0x00000000 0x8c CMakeFiles/uart_out.dir/Core/Src/app_module.c.obj
.text.MainThread_Entry
0x00000000 0xbc CMakeFiles/uart_out.dir/Core/Src/app_module.c.obj
I have taken care to ensure that my module 'main' is called 'demo_module_start' which corresponds to the name within my 'txm_module_preamble.s':
/* Define public symbols. */
.global __txm_module_preamble
/* Define application-specific start/stop entry points for the module. */
.global demo_module_start
/* Define common external refrences. */
.global _txm_module_thread_shell_entry
.global _txm_module_callback_request_thread_entry
__txm_module_preamble:
.dc.l 0x4D4F4455 // Module ID
.dc.l 0x6 // Module Major Version
.dc.l 0x1 // Module Minor Version
.dc.l 32 // Module Preamble Size in 32-bit words
.dc.l 0x12345678 // Module ID (application defined)
.dc.l 0x02000007 // Module Properties where:
// Bits 31-24: Compiler ID
// 0 -> IAR
// 1 -> ARM
// 2 -> GNU
// Bits 23-3: Reserved
// Bit 2: 0 -> Disable shared/external memory access
// 1 -> Enable shared/external memory access
// Bit 1: 0 -> No MPU protection
// 1 -> MPU protection (must have user mode selected - bit 0 set)
// Bit 0: 0 -> Privileged mode execution
// 1 -> User mode execution
.dc.l _txm_module_thread_shell_entry - . - 0 // Module Shell Entry Point
.dc.l demo_module_start - . - 0 // Module Start Thread Entry Point
What final step am I missing to allow 'demo_module_start' to be given an address such that I can call it from:
txm_module_manager_in_place_load(&my_module1, "my module1", (VOID *) ADDRESS_OF_MODULE_1);
My understanding is that as the module is not being called directly it must be getting thrown out, how do I force the linker to place it within the .map file?
Thanks in advance.
Solved! Go to Solution.
2025-07-02 3:00 AM
For those following along, I have been able to resolve this by implementing a few things.
This allowed me to load into the correct part of memory with the preamble being populated at the start of the memory section
To do so I have had to split my project such that two linker files are separately used, two elf files created and flashed one after another.
2025-06-19 6:46 AM
Hello @dbit ,
To prevent your ThreadX module code (e.g., 'demo_module_start') from being discarded by the linker, you can modify your linker script to keep the relevant sections using the 'KEEP()' directive. For example, add this to your linker script:
/* Keep ThreadX module preamble and entry point */
KEEP(*(.txm_module_preamble))
KEEP(*(.text.demo_module_start))
KEEP(*(.text.demo_module_*))
Also, ensure your module entry function is placed in the '.text.demo_module_start' section by adding this attribute in your C code:
void demo_module_start(void) __attribute__((section(".text.demo_module_start"), used));
This forces the linker to retain your module code so it can be loaded dynamically via 'txm_module_manager_in_place_load()'.
Kind regards,
2025-06-24 6:30 AM - edited 2025-06-24 6:33 AM
Thanks Khaled,
I have in my linker already:
to the corresponding region:
Then above every method and global I have the relevant attribute:
This allows the Module region to be populated:
However my module does not get loaded properly by the manager as it does not read the length of the code properly.
Do you know why this could be?
My thinking is that the ThreadX library itself needs to be within the section?
2025-06-27 2:52 AM
As an extra, this is the memory within the section that I have loaded my module into:
2025-07-02 3:00 AM
For those following along, I have been able to resolve this by implementing a few things.
This allowed me to load into the correct part of memory with the preamble being populated at the start of the memory section
To do so I have had to split my project such that two linker files are separately used, two elf files created and flashed one after another.