Introduction to ThreadX Kernel Content#
[!NOTE]
This article contains too many images, which have not been transferred from their own server and still use public image hosting, so loading images may be slow.
ThreadX has been donated to the Eclipse Foundation, and the current open-source code is here.
I usually use the fork from STMicroelectronics, but the actual support is not much better, and the usual pitfalls still exist.
The ThreadX kernel includes three components: the ThreadX operating system kernel, Modules, and trace debugging monitoring. In the ThreadX source code, these components are often mixed together. Therefore, I will write a simple document to record them. It serves as both a porting tutorial and a record of the library structure.
All images in this document are located above the descriptive text related to the images. This is all the content of the ThreadX source code.
It shows three versions of the system kernel:
common
Standard kernelcommon_module
Kernel with module loading capability, where hardware drivers and software logic can be completely separatedcommon_smp
Kernel with multi-core MCU support
The kernel porting goal is to use these components:
- ThreadX operating system kernel
- Modules
- Trace debugging monitoring
Pure Kernel Porting#
The pure kernel, as I mentioned, is—compared to the modules
version kernel and the smp
version kernel, functionally similar to ordinary RTOS like FreeRTOS and BIOS. It is just more convenient to port other components of ThreadX, and the naming is more consistent; for example, NetX, usbX, and FileX can be easily integrated into the system.
Which are the pure kernel source codes?#
In the ThreadX operating system source code, there are two folders outlined in the image, which are actually all the source codes we need to port the operating system kernel.
First, focus on the common folder; these are actually the required source codes, which are the files needed for our project, but there are still some noteworthy points.
In the stc folder, there are some source files named tx_trace_xx, which are used for trace debugging monitoring.
Taking this function that enables monitoring as an example, if the TX_ENABLE_EVENT_TRACE macro is not defined to enable the monitoring feature, then this function will not do anything.
In the inc folder, there is also a tx_trace.h file.
If the TX_ENABLE_EVENT_TRACE macro is not enabled, it also does almost nothing.
Returning to the source code folder, let's focus on the ports folder.
Find the corresponding kernel.
Find the corresponding compiler; both the source code and header files are required for the project. Additionally, be sure to exclude the potentially existing file tx_misra.S, as it may already have tx_misra.c defined.
A brief introduction to the tx_port.h file in ports/kernel_name/compiler_name/inc
: this is the only interface to adjust ThreadX, similar to macros like TX_ENABLE_EVENT_TRACE
that control whether the operating system features are enabled or not, which can be written in the overall define section of the compiler.
However, note that line 79 provides another .h interface for us to define. We can write the TX_INCLUDE_USER_DEFINE_FILE
macro in the overall define of the compiler and then create a custom tx_user.h file to control the operating system macros.
This tx_user.h file has a sample, and there is a file named tx_user_sample.h
or similar under the operating system source code common\inc
as an example, but the tx_user.h file name needs to be created or renamed from its sample file.
In common\src
, there is a tx_thread_initialize.c file, which contains a variable that can be checked at runtime to view the configuration status. This variable is also declared as extern in tx_thread.h, so when using the ThreadX operating system, this variable can be checked anywhere and cannot be redeclared.
How to enable it?#
Although we use the ac6 compiler, we can still first look at the gnu folder because it contains a simple example of creating a task.
Here!
A simple analysis of the example:
- This part is the header file, which only includes tx_api.h.
- This part is the main entry.
- This part is a function that must be defined by the user; this function name will be called when _tx_initialize_kernel_enter() starts the thread kernel, which is essentially the interface provided to our user program after the kernel starts.
A simple analysis of this user interface function shows that it demonstrates several main APIs of ThreadX, such as requesting memory space, using this memory space to create tasks, creating message queues, creating message counts, and other commonly used APIs. Specific usage can be checked in the source code.
Combining the entire example, we know the most basic operations for using the ThreadX kernel:
- Include
tx_api.h
. - Define
void tx_application_define(void *first_unused_memory)
function, and create tasks after this function is called (at this point, the ThreadX kernel has already started). - Use
tx_kernel_enter();
function in the main program to start the ThreadX kernel.
Focus on this file in the same folder as the example.
It defines some interrupt functions to take over the chip's interrupt handling, allowing the ThreadX operating system to run. Be sure to modify
SYSTEM_CLOCK
and SYSTICK_CYCLES
; in the example shown, 600000
represents the chip's main frequency clock of 6M, and 100
represents that the operating system's clock base is 10ms, meaning that tx_thread_sleep(1);
actually releases the kernel for 10ms.
In fact, this .S file still has places that need modification; it seems that some interrupts are not defined. It is best to use stm32cubeMX to automatically generate one and then paste it into your project. If the operating system does not run normally, the most likely issue is with this tx_initialize_low_level.s.
Add this line to the overall define of the compiler: TX_INCLUDE_USER_DEFINE_FILE
.
Kernel Porting with Module Manager#
First, confirm a concept: what are module managers and modules?
The module manager has the ThreadX kernel and the ability to drive hardware, and it can load executable binary content of modules from certain storage media (for example, loading modules starting from the address 0x8100000 in internal flash); modules do not have the ability to drive hardware, do not have the ThreadX kernel, and cannot work independently, but exist as a separate project that can be compiled and released independently.
Thus, the module manager and modules are two separate projects, and the source codes they need to port are different.
As for the necessity of doing this, it will not be discussed here.
Which are the source codes with module manager?#
You can ignore the details for now; just include these two folders in your project. In the ThreadX operating system source code, there are three folders outlined in the image, which contain all the source codes needed to port the kernel with a module manager.
Since we have already looked at the pure kernel porting content, we assume a certain understanding of the basic kernel and trace debugging. Therefore, these contents will not be elaborated further, and we will only discuss the differences from the pure kernel.
Focus on the common_modules
folder.
As the kernel of the module manager, the two outlined source code folders are needed, while module_lib is the source code for module porting.
You can ignore the details for now; just include all the contents of these two folders in your project, and adjustments can be made later.
Focus on the ports_modules
folder.
Find your corresponding architecture.
Find your corresponding compiler.
The two outlined source code folders are needed, while module_lib is the source code for module porting.
Ignore the details for now; just include all the contents of these two folders in your project, and adjustments can be made later.
Then find or use stm32cubeMX to automatically generate a tx_initialize_low_level.S. Since stm32cubeMX does not support generating module projects, it is not actually suitable. Successfully using modules requires a lot of your own adaptation and operations.
In the project shown in the image, it is recommended to look for examples.
The tx_initialize_low_level.S has already been introduced in the pure kernel porting section, so it will not be elaborated further.
Returning to this folder, find the file named txm_module_user_sample.h, copy it, and rename it to txm_module_user.h. When the overall define of the compiler is set to TXM_MODULE_INCLUDE_USER_DEFINE_FILE, the header file named txm_module_user.h (must be the same) will be called in both the module manager project and the module project to control the operating system functions.
The content of txm_module_user.h
is roughly as follows:
Remember that tx_user.h
also needs to be created, as explained in the pure kernel section.
How to enable it#
In fact, the method of enabling it is the same as that of the pure kernel. However, note that when using this kernel, the standard practice is to make all business logic into modules for loading. However, establishing the module project and adapting the two is quite troublesome, and I have not fully figured it out yet, so I have not made it into a document.
But treating it as an ordinary kernel is also fine.
This article was synchronized and updated to xLog by Mix Space. The original link is https://www.yono233.cn/posts/shoot/24_7_15_%E6%9C%80%E5%85%A8%E8%AE%A4%E8%AF%81RTOS%E2%80%94%E2%80%94azure_threadX%E7%A7%BB%E6%A4%8D%E6%95%99%E7%A8%8B