cancel
Showing results for 
Search instead for 
Did you mean: 

ThreadX Modules with CMake

dbit
Associate II

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.

1 ACCEPTED SOLUTION

Accepted Solutions
dbit
Associate II

For those following along, I have been able to resolve this by implementing a few things.

  1. I have taken the sample linker file for the module editing to the correct memorydbit_0-1751450223532.png
  2. I have added the `gcc_setup.s` to my application sourcesdbit_2-1751450266246.png
  3. I have amended the `gcc-arm-none-eabi.cmake` to not attempt to link in a main or an `.init` into the map file by adding `-nostartfiles -e _txm_module_thread_shell_entry` to the C link flagsdbit_3-1751450293914.png

This allowed me to load into the correct part of memory with the preamble being populated at the start of the memory section

dbit_4-1751450342169.png

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.  

View solution in original post

4 REPLIES 4
Khaled_DHIF
ST Employee

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,

Please mark my answer as best by clicking on the “Accept as solution" button if it fully answered your question. This will help other users find this solution faster.​

Thanks Khaled,

I have in my linker already: 

dbit_0-1750695264711.png

to the corresponding region:

dbit_1-1750695295782.png

Then above every method and global I have the relevant attribute:

dbit_2-1750695422529.png

This allows the Module region to be populated:

dbit_3-1750695518811.png

However my module does not get loaded properly by the manager as it does not read the length of the code properly. 

dbit_0-1750771788075.png

Do you know why this could be?

My thinking is that the ThreadX library itself needs to be within the section?

dbit
Associate II

As an extra, this is the memory within the section that I have loaded my module into:

dbit_0-1751017925662.png

 

dbit
Associate II

For those following along, I have been able to resolve this by implementing a few things.

  1. I have taken the sample linker file for the module editing to the correct memorydbit_0-1751450223532.png
  2. I have added the `gcc_setup.s` to my application sourcesdbit_2-1751450266246.png
  3. I have amended the `gcc-arm-none-eabi.cmake` to not attempt to link in a main or an `.init` into the map file by adding `-nostartfiles -e _txm_module_thread_shell_entry` to the C link flagsdbit_3-1751450293914.png

This allowed me to load into the correct part of memory with the preamble being populated at the start of the memory section

dbit_4-1751450342169.png

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.