Introduction to ThreadX Kernel Content#
[!NOTE]
This article contains too many images, which have not been transferred from our 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, and the actual support is not much better; 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 simply write a document to record them. This 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, allowing complete separation of hardware drivers and software logiccommon_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 refer to it, is—compared to the modules
version kernel and the smp
version kernel—actually no different in functionality from ordinary RTOS like FreeRTOS or 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 all be easily integrated into the system.
Which are the pure kernel source files?#
In the ThreadX operating system source code, there are two folders outlined in the image, which are actually all the source code we need to port the operating system kernel.
First, focus on the common folder; these are all the necessary source files, which are the files required 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 starts monitoring as an example, if the TX_ENABLE_EVENT_TRACE macro is not defined to enable monitoring, then this function will not do anything.
In the inc folder, there is also a file named tx_trace.h.
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; the source code and header files are required for the project. Additionally, be sure to exclude the potentially existing file tx_misra.S, which 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 the macro definitions like TX_ENABLE_EVENT_TRACE
that control whether the operating system functions 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 macro definitions.
This tx_user.h file has an example; in the operating system source code under common\inc
, there is a file named tx_user_sample.h
or similar as an example, but the tx_user.h file name needs to be created or renamed from its example file.
In common\src
, there is a file named tx_thread_initialize.c, which has 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?#
Although we are using 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 actually the interface for user programs after the kernel is started.
A simple analysis of this user interface function shows that it actually 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)
and create tasks after this function is called (at this point, the ThreadX kernel has already started). - Use the
tx_kernel_enter();
function in the main program to start the ThreadX kernel.
Pay attention to this file in the same folder as the example.
It defines some interrupt functions to take over the chip's interrupt handling and allow 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 the operating system's clock base of 10ms, meaning that tx_thread_sleep(1);
actually releases the kernel for 10ms.
In fact, this .S file still has places that need to be modified; 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 properly, 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; 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 code they need to port is different.
As for why it is necessary to do this, it will not be discussed here.
Which are the source files with module manager?#
For now, let's not worry too much; 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 code needed to port the kernel with a module manager.
Since we have already looked at the pure kernel porting content, we believe we have a certain understanding of the basic kernel and trace debugging tracking. Therefore, this content will not be elaborated on, 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 source folders outlined are needed, while module_lib is the source code for porting modules.
For now, let's not worry too much; 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 source folders outlined are needed, while module_lib is the source code for porting modules.
For now, let's not worry too much; 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 actually not 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 on here.
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 (which 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#
In fact, the method of enabling 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 a normal kernel is also fine.
This article was synchronously 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