This article is a continuation of the Series on RT-Thread STM32 Tutorials and carries the discussion on RT-Thread RTOS and implementation with STM32. The aim of this series is to provide easy and practical examples that anyone can understand. In our last post, we have seen how to create a project and a simple hello world program. In this post, we will see the RT-Thread RTOS Thread Management and STM32 LED Blinking using RT-Thread RTOS.
You can see the video explanation of Getting started with the RT-Thread RTOS.
Prerequisites
This is the continuation of the below tutorials. If you don’t read it, please read that also before this.
Tools and Components Required
- STM32F411 Dev Board (You can use any STM32F4 controller)
- RT-Thread Studio
STM32 GPIO LED Blinking using RTOS (RT-Thread Thread Management)
What is a thread in RTOS?
A thread is a single sequential flow of execution of tasks. A thread is the same thing as a task, but each thread runs in its own virtual memory space. In FreeRTOS they will divide the big task into multiple smaller tasks (Task Management). But in this RT-Thread RTOS, they are dividing the big task into multiple smaller threads (Thread Management). We don’t want to bore you, by talking about RTOS concepts as we assume that you knew that. If you want to learn it, you can check these articles.
RT-Thread RTOS Thread Management
In this section, we will see important things about the RT-Thread RTOS thread working mechanism. The main function of RT-Thread thread management is to manage and schedule threads. There are two types of threads in the system, namely system thread and the user thread. The system thread is the thread created by the RT-Thread kernel. The user thread is the thread created by the application.
In RT-Thread, the thread has five states,
- Initial State – The thread is in the initial state when it has just been created but has not started running. In this state, it should not participate in the scheduling.
- Ready State – In the ready state, the thread is queued according to priority, waiting to be executed;
- Running State – The thread is currently running.
- Suspended State (Blocking state) – It may be suspended and paused because the resource is unavailable or purposefully delayed by the code.
- Closed State – It will be turned to a closed state when the thread finishes running. So, it won’t participate in the thread scheduling.
RT-Thread supports a maximum of 256 thread priorities (0~255). The lower the number, the higher the priority, and 0 is the highest priority. The lowest priority is assigned to idle threads by default and is not used by users. When two or more threads have the same priority, then it will be scheduled using the Round Robin scheduling method with the help of a time slice.
RT-Thread RTOS Thread API
In RT-Thread RTOS, there are many APIs available to control the threads. We will see the important APIs here.
Thread Creation and Deletion
Creation
We can create the thread using the below function interface.
rt_thread_t rt_thread_create(const char* name,
void (*entry)(void* parameter),
void* parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick);
Parameters | Description |
---|---|
name | The name of the thread; the maximum length of the thread name is specified by macro RT_NAME_MAX in rtconfig.h, and the extra part is automatically truncated. |
entry | Thread entry function. |
parameter | Thread entry function’s parameter. |
stack_size | Thread stack size in bytes. |
priority | Priority of the thread. |
tick | The time slice size of the thread. The unit of the time slice (tick) is the tick of the operating system. When there are threads with the same priority in the system, this parameter specifies the maximum length of time of a thread for one schedule. At the end of this time slice run, the scheduler automatically selects the next ready state of the same priority thread to run. |
The above API creates a thread and it returns the thread handle in the success case, otherwise returns an ERROR.
Deletion
The below API is used to delete the thread.
rt_err_t rt_thread_delete(rt_thread_t thread);
Parameter | Description |
---|---|
thread | Thread handles to delete |
Note: If you use rt_thread_create()
, then the resources will be dynamically allocated. If you want to use the static resource, then you need to use the rt_thread_init()
function to create and initialize the thread and rt_thread_detach()
to delete the thread.
Run the thread
Once we create the thread, then it will be in the Initial state and it won’t be picked by the scheduler. So, we need to change the thread’s state to Ready state. The below interface is used to do that.
rt_err_t rt_thread_startup(rt_thread_t thread);
When this function is called, the state of the thread is changed to a ready state and placed in the corresponding priority queue for scheduling. If the newly started thread has a higher priority than the current thread, it will immediately switch to the new thread.
Thread Sleep or Delay
The below interfaces are used to delay or sleep the thread.
rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);
The above three function interfaces have the same effect. These will put the current thread to suspend state for a specified period of time.
Suspend and Resume Thread
The below APIs are used to suspend and resume the thread in the RT-Thread RTOS.
rt_err_t rt_thread_suspend (rt_thread_t thread);
rt_err_t rt_thread_resume (rt_thread_t thread);
Control the thread
If you want to control the thread (like changing the priority, or close the thread, etc), you can use the below function interface.
rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);
Function Parameters | Description |
---|---|
thread | Thread handle. |
cmd | Control command demand. RT_THREAD_CTRL_STARTUP – Start the thread RT_THREAD_CTRL_CLOSE – Close the thread RT_THREAD_CTRL_CHANGE_PRIORITY – Dynamically change the priority of a thread RT_THREAD_CTRL_INFO – Get thread information RT_THREAD_CTRL_BIND_CPU – Set thread bind cpu |
arg | Control parameter. |
Return | —— |
RT_EOK | Control execution is correct. |
-RT_ERROR | Failure. |
There are a few hook functions also available.
rt_thread_idle_sethook()
– When the Idle function runs, the idle hook function can be automatically executed.rt_thread_idle_delhook()
– This deletes the idle hook function which has been set using the above function.rt_scheduler_sethook()
– When there is a context switch( thread is switching from one to another), this hook function will be called.
Okay, that’s all the theory. These thread functions are similar to the FreeRTOS. Only the name is different. Now we will see the example program.
Connection
- LED1 – PA2
- On Board LED – PC13
- UART1 – PA9, PA10
Example Source Code
In the below example program, I am going to create two threads called thread1_function()
, and thread2_function()
. Thread 1 runs every 1 second and it blinks the LED which is connected to the PA2. Thread 2 runs every 2 seconds and it blinks the LED which is connected to the PC13. Please check the below program. You can also download the entire project from GitHub.
If you don’t know how to create the project, please refer to our previous tutorial.
#include <rtthread.h> #define DBG_TAG "main" #define DBG_LVL DBG_LOG #include <rtdbg.h> #include <drv_common.h> #include <rtdevice.h> #define LED1_PIN GET_PIN(A, 2) //PA2 #define LED2_PIN GET_PIN(C, 13) //PC13 static rt_thread_t threadId1 = RT_NULL; static rt_thread_t threadId2 = RT_NULL; /* Thread 1 */ static void thread1_function(void *parameter) { long value = 0; rt_pin_mode( LED1_PIN , PIN_MODE_OUTPUT); while (1) { LOG_D("Thread 1 is Running!\n"); rt_pin_write(LED1_PIN, value); value = ~value; rt_thread_mdelay(1000); } } /* Thread 2 */ static void thread2_function(void *parameter) { long value = 0; rt_pin_mode( LED2_PIN , PIN_MODE_OUTPUT); while (1) { LOG_D("Thread 2 is Running!\n"); rt_pin_write(LED2_PIN, value); value = ~value; rt_thread_mdelay(2000); } } int main(void) { /* Create thread 1 */ threadId1 = rt_thread_create("thread1_fn", //Name thread1_function, //Function address RT_NULL, //Thread function parameter 1024, //Stack Size 5, //Thread priority 10); //Time slice in ticks /* Create thread 1 */ threadId2 = rt_thread_create("thread2_fn", //Name thread2_function, //Function address RT_NULL, //Thread function parameter 1024, //Stack Size 5, //Thread priority 10); //Time slice in ticks /* Start both threads */ rt_thread_startup(threadId1); rt_thread_startup(threadId2); while(1); return RT_EOK; }
Output
You can see the output below.
\ | / - RT - Thread Operating System / | \ 4.0.3 build Feb 12 2023 2006 - 2020 Copyright by rt-thread team ←[0m[D/main] Thread 1 is Running! ←[0m ←[0m[D/main] Thread 2 is Running! ←[0m ←[0m[D/main] Thread 1 is Running! ←[0m ←[0m[D/main] Thread 1 is Running! ←[0m ←[0m[D/main] Thread 2 is Running! ←[0m ←[0m[D/main] Thread 1 is Running! ←[0m
What’s Next
In our next tutorial, we will see the timer in RT-Thread RTOS.
You can also read the below tutorials.

Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!