STM32 GPIO LED Blinking using RTOS (RT-Thread Thread Management) – RT-Thread Tutorial Part 2

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.


This is the continuation of the below tutorials. If you don’t read it, please read that also before this.

Tools and Components Required

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


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);
nameThe 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.
entryThread entry function.
parameterThread entry function’s parameter.
stack_sizeThread stack size in bytes.
priorityPriority of the thread.
tickThe 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.


The below API is used to delete the thread.

rt_err_t rt_thread_delete(rt_thread_t thread);
threadThread 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 ParametersDescription
threadThread handle.
cmdControl 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
argControl parameter.
RT_EOKControl execution is correct.

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.


  • 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"

#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;

/* 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;

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 */


    return RT_EOK;


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[D/main] Thread 2 is Running!
←[0m[D/main] Thread 1 is Running!
←[0m[D/main] Thread 1 is Running!
←[0m[D/main] Thread 2 is Running!
←[0m[D/main] Thread 1 is Running!

What’s Next

In our next tutorial, we will see the timer in RT-Thread RTOS.

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials – STM32Zephyr RTOS Tutorials – ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Table of Contents