1. Introduction
ThreadX is a real-time operating system (RTOS), designed for embedded systems.
It offers two functional modes:
- Common mode: It offers the common RTOS functionalities such as thread management and synchronization, memory pool management, messaging, and event handling.
- Module mode: An advanced usage mode that allows loading and unloading of pre-linked ThreadX modules on-the-fly through a module manager.
The ThreadX core provides the common RTOS features, such as management of threads, semaphores, mutexes and SW timers. The bock diagram below shows the different functional blocks in the ThreadX core.
The Azure RTOS ThreadX library is provided with a FreeRTOS compatibility layer. This adaptation layer allows the user to develop a ThreadX application using FreeRTOS APIs.
1.1. Unique features
ThreadX offers a set of unique features that give higher flexibility to the user:
- Various scheduling policies and preemption threshold [1]
- On-fly properties update [2]
- Object notifications [3]
- Event Chaining [4]
- Runtime performance information [5]
- Tracing Mechanism [6]
1.2. Folder/file structure
- common: contains the implementation of all ThreadX APIs. In addition it provides some utility features: SW timers, performance information and tracing features.
- common_modules: contains the implementation of the ThreadX Module feature, allowing the dynamic loading of a prelinked ThreadX module. It is split into two folders:
- module_lib: implements the txm_*.c API and should be used instead of tx_*.c when writing a ThreadX module.
- module_manager: implements the functional block to be put on top of the ThreadX core to handle module loading, unloading, running, and so on.
- ports/<core>/<compiler>: contains the implementation of the kernel scheduler, mostly in assembly language.
- ports_module/<core>/<compiler>: contains the implementation of the ThreadX module related scheduler to fit with Module Manager requirements. The files in this directory are used instead of the port's files when the ThreadX Module is enabled.
More details about ThreadX features are available in the official documentation[7]
2. STM32 integration
There are two possible modes: Common Mode and Module Mode.
2.1. Common Mode:
To correctly run ThreadX on STM32 based MCUs, the application should provide the 3 following user-level files:
- tx_initialize_low_level.s: implements the tx_initialize_low_level() function called by the threadX kernel to initialize the RTOS heap base address and setup the SYSTick_Handler().
As tx_initialize_low_level.s is compiler and core dependent, a template of this file is provided for each compiler/core in the ThreadX source tree.
- stm32XXX_hal_timebase_tim.c: Implements a timebase used by the HAL drivers, as the systick is reserved for the ThreadX kernel scheduler.
- tx_user.h: configures the ThreadX RTOS using some of defines. A template of this file is provided in the ThreadX source tree. It is included in the ThreadX stack by the define TX_INCLUDE_USER_DEFINE_FILE.
The LowPower feature can be enabled by defining TX_LOW_POWER symbol as Assembler defined symbol. threadx/utility/low_power/tx_low_power.c file and threadx/utility/low_power paths should be imported in the project.
More information about ThreadX LowPower feature can be found in the application readme file.
For the Cortex-M33 that support the TrustZone feature, application needs to provide the following configuration:
- TrustZone disabled:
- TX_SINGLE_MODE_NON_SECURE should be added for both C and ASM compiler .
- ports/cortex_m33/<compiler>/tx*secure_stack*[.s/.c] should not be imported in the project
- TrustZone enabled:
- ThreadX “common/src” should be imported into the non-secure project.
- All port/cortex_m33/<compiler> files are imported into non-secure project except the file tx_thread_secure_stack.c that is imported in the secure project.
- No Preprocessor flags are needed: by default, ThreadX is configured in TrustZone Mode.
2.2. Module mode:
In addition to the common mode files, which need to be kept on the module manager side, the application should provide the following user-level file in the module side.
- txm_module_preamble.s: A preamble is required with each Module to expose the module configuration to the Module Manager. Particularly the preamble contains information such as the module unique ID and attributes.
3. CMSIS-RTOS API Support
The CMSIS-RTOS v2 (CMSIS-RTOS2) provides generic RTOS interfaces for Arm® Cortex® processor-based devices. It provides a standardized API for software components that require RTOS functionality.
The list of features supported for ThreadX is as follows:
Feature | Supported | Short description |
---|---|---|
Kernel Information and control | Y | Provides version/system information and starts/controls the RTOS Kernel. More… |
Thread Management | Y | Defines, creates, and controls thread functions. More… |
Thread Flags | N | Synchronizes threads using flags. More… |
Event Flags | Y | Synchronizes threads using event flags. More… |
Generic Wait Functions | Y | Waits for a certain period of time. More… |
Timer Management | Y | Creates and controls timer and timer callback functions. More… |
Mutex Management | Y | Synchronizes resource access using Mutual Exclusion (Mutex). More… |
Semaphores | Y | Accesses shared resources simultaneously from different threads. More… |
Memory Pool | N | Manages thread-safe fixed-size blocks of dynamic memory. More… |
Message Queue | Y | Exchanges messages between threads in a FIFO-like operation. More… |
For more information about CMSIS-RTOS v2 APIs, please refer to the ARM manual: CMSIS-RTOS API v2.
For more information about the implementation of CMSIS-RTOS wrapper for ThreadX, please refer to its readme.
4. FreeRTOS API Support
The FreeRTOS adaptation layer for ThreadX provides a set of APIs to configure, initialize and use ThreadX through FreeRTOS APIs. API Support by Category:
- Task creation, control and utilities
- Semaphores and Mutexes
- Queues
- Queue Sets
- Direct to Task Notifications
- Software Timers
- Event Groups
ThreadX flags required configuration:
Name | Default Value | Description |
---|---|---|
configUSE_16_BIT_TICKS | 0 | Set to 1 to use 16-bit tick. |
configSTACK_DEPTH_TYPE | uint16_t | Use to override the type used to specify stack depth. |
configTICK_RATE_HZ | - | Set the kernel tick rate, used by the pdMS_TO_TICKS() macro. |
configMAX_PRIORITIES | - | Maximum number of priorities. Must be less than or equal to the configured number of ThreadX priorities. |
configMINIMAL_STACK_SIZE | 512U | Minimum stack size, used as the stack size of the idle task if TX_FREERTOS_IDLE_STACK is not defined. |
configTOTAL_HEAP_SIZE | - | Amount of internal memory allocated to the adaptation layer when creating FreeRTOS objects. Can be set to 0 to disable dynamic allocation. |
INCLUDE_vTaskDelete | 1 | Set to 0 to disable the task delete API. When disabled the adaptation layer will not create the idle task to save resources. |
TX_FREERTOS_IDLE_STACK | 512U | Define to a macro invoked on internal assertion failures from within the adaptation layer. |
configASSERT | - | Define to a macro invoked for invalid arguments. |
For more information about the implementation of the FreeRTOS adaptation layer for ThreadX, please refer to its readme [8]
5. How to use
5.1. Common Mode
1. In order to initialize and configure Azure RTOS ThreadX kernel, the user needs to include the tx_api.h file.
2. Call tx_kernel_enter function from the main.
/* Start the ThreadX kernel */
tx_kernel_enter();
This function initializes the internal ThreadX data structure before calling the application’s definition function (tx_application_define) and starting the scheduler.
3. The user also needs to properly define the initial system resources in the tx_application_define function. Examples of system resources include threads, queues, memory pools, event flag groups, mutexes, timers and semaphores.
VOID tx_application_define(VOID *first_unused_memory)
{
VOID *memory_ptr = first_unused_memory;
/* USER CODE BEGIN tx_application_define */
/* User can add his own implementation to define the initial ThreadX system resources*/
/* USER CODE END tx_application_define */
}
The input parameter of tx_application_define is the first available RAM address to be used for the run-time memory allocation of thread stacks, queues and memory pools.
4. Initialize system resources using ThreadX APIs :
- Thread creation using ThreadX API :
/* Create ThreadOne. */
if (tx_thread_create(&ThreadOne, "Thread One", ThreadOne_Entry, 0,
pointer, THREAD_ONE_STACK_SIZE,
THREAD_ONE_PRIORITY, THREAD_ONE_PREEMPTION_THRESHOLD,
TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
status = TX_THREAD_ERROR;
}
- Mutex creation using ThreadX API :
/* Create the Mutex */
if (tx_mutex_create(&MutexOne, "Mutex One", TX_NO_INHERIT) != TX_SUCCESS)
{
ret = TX_MUTEX_ERROR;
}
5. Define the entry function for each created thread :
void ThreadOne_Entry(ULONG thread_input)
{
/* User can add his own implementation*/
}
5.2. Low Power Feature
The LowPower feature support needs to expose the following configuration flags in the “tx_user.h” file:
- TX_LOW_POWER_TIMER_SETUP: A macro to setup a timer expiration.
- TX_LOW_POWER_TICKLESS: When enabled ThreadX will ignore active timer wakeup events.
- TX_LOW_POWER_USER_ENTER: A macro that defines how to make the system enter LowPower mode.
- TX_LOW_POWER_USER_EXIT: A macro that defines how to make the system exit LowPower mode.
- TX_LOW_POWER_USER_TIMER_ADJUST: A Macro to get the amount of ticks the system has been in LowPower mode.
Example of LowPower flags configuration:
/* Define the LowPower macros and flags */
/* Define a macro that sets up a low power clock and keep track of time */
void App_ThreadX_LowPower_Setup(unsigned long cnt);
#define TX_LOW_POWER_TIMER_SETUP App_ThreadX_LowPower_Setup(_cnt)
/* Define the TX_LOW_POWER_TICKLESS to disable the internal ticks */
#define TX_LOW_POWER_TICKLESS
/* A user defined macro to make the system enter low power mode */
void App_ThreadX_LowPower_Enter();
#define TX_LOW_POWER_USER_ENTER App_ThreadX_LowPower_Enter()
/* A user defined macro to make the system exit low power mode */
void App_ThreadX_LowPower_Exit();
#define TX_LOW_POWER_USER_EXIT App_ThreadX_LowPower_Exit()
/* User's low-power macro to obtain the amount of time (in ticks) the system has been in low power mode */
unsigned long App_ThreadX_LowPower_TimerAdjust(void)
#define TX_LOW_POWER_USER_TIMER_ADJUST App_ThreadX_LowPower_TimerAdjust()
5.3. TrustZone Feature
The ThreadX TrustZone feature requires exposing the following configuration flags in the “tx_user.h” file:
- TX_THREAD_SECURE_STACK_MINIMUM: Defines the minimum size of secure stack.
- TX_THREAD_SECURE_STACK_MAXIMUM: Defines the maximum size of secure stack.
5.4. Module Mode
5.4.1. Module Manager
- In order to initialize and configure Azure RTOS ThreadX kernel in module mode, the user needs to include the “txm_module.h” file.
- Call tx_kernel_enter function from the main.
/* Start the ThreadX kernel */
tx_kernel_enter();
- The user also needs to properly define the initial system resources in the tx_application_define function. Examples of system resources include threads, queues, memory pools, event flag groups, mutexes, timers and semaphores.
VOID tx_application_define(VOID *first_unused_memory)
{
VOID *memory_ptr = first_unused_memory;
/* USER CODE BEGIN tx_application_define */
/* User can add his own implementation to define the initial ThreadX system resources*/
/* USER CODE END tx_application_define */
}
The input parameter of tx_application_define is the first available RAM address to be used for the run-time memory allocation of thread stacks, queues and memory pools.
- The user needs to create a module manager thread that:
- Initialize the module manager.
status = txm_module_manager_initialize((VOID *) module_data_area, MODULE_DATA_SIZE);
- Create a pool for module objects
status = txm_module_manager_object_pool_create(object_memory, OBJECT_MEM_SIZE);
- Register the module manager memory fault notification
status = txm_module_manager_memory_fault_notify(module_fault_handler);
- Load the module from his specific address.
status = txm_module_manager_in_place_load(&ModuleOne, "Module One", (VOID *) MODULE_FLASH_ADDRESS);
- Configure the memory management (example: enable the shared memory for the module).
status = txm_module_manager_external_memory_enable(&ModuleOne, (void*)READONLY_REGION, SHARED_MEM_SIZE, TXM_MODULE_ATTRIBUTE_READ_ONLY);
- Start the module.
status = txm_module_manager_start(&ModuleOne);
- Stop the module.
status = txm_module_manager_stop(&ModuleOne);
- Unload the module.
status = txm_module_manager_unload(&ModuleOne);
- Initialize the module manager.
5.4.2. Module
In order to initialize and configure the module, the user needs to :
- Define “TXM_MODULE” and to include the “txm_module.h” file.
- Define the default module entry function “default_module_start”.
VOID default_module_start(ULONG id)
{
/* User can add his own implementation to define the initial ThreadX module system resources*/
}
- Initialize system resource using ThreadX APIs:
- Allocate object from the created memory pool for module objects.
txm_module_object_allocate((void*)&MainThread, sizeof(TX_THREAD));
- Create system resource using ThreadX common API. Example:
/* Create ThreadOne. */
if (tx_thread_create(&ThreadOne, "Thread One", ThreadOne_Entry, 0,
pointer, THREAD_ONE_STACK_SIZE,
THREAD_ONE_PRIORITY, THREAD_ONE_PREEMPTION_THRESHOLD, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
status = TX_THREAD_ERROR;
}
- Request access to the module manager object:
status = txm_module_object_pointer_get(TXM_QUEUE_OBJECT, "Resident Queue", (VOID **)&ResidentQueue);
5.4.3. IDE Configuration for Module Mode
This following steps are provided as example for IAR EWARM IDE:
- Project Options -> C/C++ Compiler -> Code Tab -> Position-Independence section: Check "Code and read-only data (ropi)" and "Read/write data (rwpi)" options
- Project Options -> C/C++ Compiler -> Language 1 Tab -> C dialect section: Uncheck "Require prototypes"
- Project Options -> Output Converter: Check "Generate additional output" option, set "Raw binary" as output format, check "Override default" and change the name to "Tx_Module.bin"
- Project Options -> Linker -> Library Tab: Check "Override default program entry" option, check "Entry symbol" and put "_txm_module_thread_shell_entry" in the case
6. Migration from FreeRTOS to ThreadX
ThreadX supports the same standard groups of APIs as most RTOSs like FreeRTOS. It is possible to use either CMSIS-RTOS wrapping layer or to use ThreadX FreeRTOS wrapping layer in order to migrate from an RTOS to ThreadX. The table below provides list of equivalent APIs between FreeRTOS and ThreadX.
Feature | ThreadX | FreeRTOS | Example of ThreadX APIs | Example of FreeRTOS APIs |
---|---|---|---|---|
Thread management | Supported | Supported | tx_thread_create tx_thread_sleep tx_thread_suspend |
xTaskCreate vTaskDelay vTaskSuspend |
Message Queue | Supported | Supported | tx_queue_create tx_queue_send tx_queue_receive |
xQueueCreate xQueueSend xQueueReceive |
Event Flags | Supported | Supported | tx_event_flags_create tx_event_flags_get tx_event_flags_set |
xEventGroupCreate xEventGroupGetBits xEventGroupSetBits |
Mutex | Supported | Supported | tx_mutex_create tx_mutex_put, tx_mutex_get |
xSemaphoreCreateMutex |
Semaphore | Supported | Supported | tx_semaphore_create tx_semaphore_put tx_semaphore_get |
xSemaphoreCreateCounting xSemaphoreGive xSemaphoreTake |
Software Timer | Supported | Supported | tx_timer_create tx_timer_delete |
xTimerCreate xTimerDelete |
Memory Mangement | Advanced (using Byte Pools and Block Pools) |
Simple | ||
Low Power | Supported | Supported | ||
TrustZone | Supported | Supported | ||
BasePri | Supported | Supported | ||
MPU | In Module Mode |
Managed in FreeRTOS Kernel |
7. Applications
STM32Cube firmware provides a set of functional applications covering the main features of Azure RTOS ThreadX. The ThreadX applications for STM32 MCUs are listed below.
ThreadX application | Overview |
---|---|
Tx_Thread_Creation | This application provides an example of Azure RTOS ThreadX stack usage, it shows how to develop an application using the ThreadX thread management APIs. It demonstrates how to create and destroy multiple threads using Azure RTOS ThreadX APIs. In addition, it shows how to use a preemption threshold between threads, and change priorities on-fly.
For more information please refer to the application readme file. |
Tx_Thread_MsgQueue | This application provides an example of Azure RTOS ThreadX stack usage, it shows how to develop an application using the ThreadX message queue APIs. It demonstrates how to send and receive messages between threads using ThreadX message queue APIs. In addition, it shows how to use the event chaining feature.
For more information please refer to the application readme file. |
Tx_Thread_Sync | This application provides an example of Azure RTOS ThreadX stack usage. It shows how to develop an application using the ThreadX synchronization APIs.
For more information please refer to application readme file. |
Tx_FreeRTOS_Wrapper | This application provides an example of Azure RTOS ThreadX stack usage. It shows how to develop an application using the FreeRTOS adaptation layer for ThreadX.
For more information please refer to application readme file. |
Tx_CMSIS_Wrapper | This application provides an example CMSIS RTOS adaptation layer for Azure RTOS ThreadX. It shows how to develop an application using the CMSIS-RTOS v2 APIs, and demonstrates how to create multiple threads using CMSIS-RTOS v2 for ThreadX APIs.
For more information please refer to application readme file. |
Tx_MPU | This application provides an example of Azure RTOS ThreadX stack usage, it shows how to develop an application using the ThreadX Module feature. It demonstrates how to load, start and unload modules. In addition, it shows how ThreadX memory protection on modules using the Memory Protection Unit (MPU). This application is available only for products where MPU feature is available.
For more information please refer to application readme file. |
Tx_LowPower | This application provides an example of Azure RTOS ThreadX stack usage, it shows how to develop an application using the ThreadX in Low Power mode. It demonstrates how to configure the Low Power feature of ThreadX stack. In addition, it shows how to use ThreadX macro related to the Low Power feature.
For more information please refer to application readme file. |
Tx_SecureLEDToggle_TrustZone | This application provides an example of Azure RTOS ThreadX stack usage, it shows how to develop an application using the ThreadX when the TrustZone feature is enabled (TZEN=1). The application is running ThreadX thread in non-secure context that is invoking a secure function to toggle a led each 1 sec. This application is available only for products where TrustZone feature is available.
For more information please refer to application readme file. |
8. References