Queue in RT-Thread RTOS – RT-Thread Tutorial Part 7

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 Mailbox in the RT-Thread RTOS. In this post, we will see the Message Queue in 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

Inter-thread Communication in RT-Thread RTOS

If we are working in a multithreaded environment, we need to send data from one thread to another thread. There are many ways to do that. Normally we use global variables or some memory segment for that purpose. Sometimes it is hard to use global data. Because it is difficult to keep track of the messages. To make our lives easier, RTOSs are will support a few inter-thread communication methods. RT-Thread RTOS supports the below inter-thread communication methods.

Message Queue in RT-Thread RTOS – RT-Thread Tutorial Part 7

Message Queue

Message Queuing is another commonly used inter-thread communication method, which is an extension of the mailbox. A queue is a FIFO (First In First Out) type buffer where data is written to the end (tail) of the queue and removed from the front (head) of the queue. A queue can either hold the data or a pointer to the data. A message queue can receive messages with unfixed lengths from threads or ISR and cache messages in their own memory space. So, the thread can put one or many messages to the queue.

Management of Message Queue

In RT-Thread RTOS, the queue supports the below operations.

Creating/initiating a queue

To dynamically create a message queue object, call the following function interface:

rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size,
                     rt_size_t max_msgs, rt_uint8_t flag);

The size of this memory = [message size + message header (for linked list connection) Size] X the number of messages in the message queue.

Input parameters and return values for rt_mq_create()

ParametersDescription
nameThe name of the message queue
msg_sizeThe maximum length of a message in the message queue, in bytes
max_msgsThe number of messages in the message queue
flagThe waiting method took by the message queue, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return——
RT_EOKSent successfully
The handle of the message queue objectSuccessful
RT_NULLFail

You can use the below API to create the Static message queue.

rt_err_t rt_mq_init(rt_mq_t mq, const char* name,
                    void *msgpool, rt_size_t msg_size,
                    rt_size_t pool_size, rt_uint8_t flag);

Input parameters and return values of rt_mq_init()

ParametersDescription
mqThe handle of the message queue object
nameThe name of the message queue
msgpoolPointer pointing to the buffer storing the messages
msg_sizeThe maximum length of a message in the message queue, in bytes
pool_sizeThe buffer size for storing messages
flagThe waiting method is taken by the message queue, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return——
RT_EOKSuccessful

Deleting/detaching a queue

You can use the below API to delete the dynamically created message queue (message queue which has been created using the rt_mq_create()).

rt_err_t rt_mq_delete(rt_mq_t mq);

If you have used a static message queue (message queue which has been initialized using rt_mq_init() ), then you can use the below API to detach the message queue.

rt_err_t rt_mq_detach(rt_mq_t mq);

When deleting/detaching a message queue, if a thread is suspended on the message queue object, the kernel first wakes up all threads suspended on the queue (the thread return value is –RT_ERROR), then releases the memory used by the queue and finally deletes/detaches the queue object.

Sending messages to the queue

We can send messages in three ways.

Send a message without waiting

The below API is used to send a message without waiting.

rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size);

Input parameters and return values of rt_mq_send()

ParameterDescription
mqThe handle of the message queue object
bufferMessage content
sizeMessage size
Return——
RT_EOKSuccessful
-RT_EFULLA message queue is full
-RT_ERRORFailed, indicating that the length of the sent message is greater than the maximum length of the message in the message queue.

If the queue is full, then this function will return an error code (-RT_EFULL). So, we can use this function in the thread as well as in the ISR.

Send a message with waiting

Users can also send messages to specified message queues through the following function interface:

rt_err_t rt_mq_send_wait(rt_mq_t mq,
                    const void *buffer,
                    rt_size_t size,
                    rt_int32_t timeout);

Input parameters and return values of rt_mb_send_wait()

ParameterDescription
mqThe handle of the message queue object
bufferMessage content
sizeMessage size
timeoutTimeout
Return——
RT_EOKSuccessful
-RT_EFULLA message queue is full
-RT_ERRORFailed, indicating that the length of the sent message is greater than the maximum length of the message in the message queue.

If the queue is full, then this function will wait based on the timeout value. If the timeout expires, then it will return -RT_EFULL. So, we cannot use this function in the ISR.

Send an emergency message

We know that Queue is a FIFO. But we can put the message also in the front. So that, the message will be delivered ASAP without waiting in the back. The below function is used to put the message into the front.

rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);

The process of sending an emergency message is almost the same as sending a message. The only difference is that when an emergency message is sent, the message block taken from the idle message list is not put at the end of the message queue, but at the head of the queue.

Input parameters and return values of rt_mq_urgent()

ParametersDescription
mqThe handle of the message queue object
bufferMessage content
sizeMessage size
Return——
RT_EOKSuccessful
-RT_EFULLA message queue is full
-RT_ERRORFail

Receive the message from the queue

To receive messages from the queue, we can use the below function. If the queue is empty, it will wait till the timeout. If the timeout expires, then it will return an error.

rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer,
                     rt_size_t size, rt_int32_t timeout);

Input parameters and return values of rt_mq_recv()

ParametersDescription
mqThe handle of the message queue object
bufferMessage content
sizeMessage size
timeoutSpecified timeout
Return——
RT_EOKReceived successfully
-RT_ETIMEOUTTimeout
-RT_ERRORFail, return error

Message Queue in RT-Thread Example

In the below example, we have created the two threads. Thread 1 is incrementing the count and sending the count value to the queue. Thread 2 will be waiting for the messages in the queue. Once the message is posted by thread 1, then thread 2 will wake up and read the data, and prints it.

Source code

You can get this entire project’s source code from GitHub.

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG

#include <rtdbg.h>
#include <drv_common.h>
#include <rtdevice.h>

/* Message queue control block */
static struct rt_messagequeue *mq;

static rt_thread_t threadId1 = RT_NULL;
static rt_thread_t threadId2 = RT_NULL;

/* Thread 1 */
static void thread1_function(void *parameter)
{
    uint32_t count = 0;
    while (1)
    {
        count++;
        LOG_D("Thread 1: count = %d\n", count);
        rt_mq_send(mq, (void*)&count, sizeof(uint32_t));
        rt_thread_mdelay(1000);
    }
}

/* Thread 2 */
static void thread2_function(void *parameter)
{
    uint32_t received_message = 0;
    while (1)
    {
        /* Receive message from the queue */
        if (rt_mq_recv(mq, &received_message, sizeof(uint32_t), RT_WAITING_FOREVER) == RT_EOK)
        {
            LOG_D("Thread2: Got a message, the message:%u\n", received_message);
        }
    }
}

int main(void)
{
    /* create queue object */
    mq = rt_mq_create("etx_mq", sizeof(uint32_t), 10, RT_IPC_FLAG_FIFO);
    if( mq  == RT_NULL )
    {
        LOG_D("Queue init failed.\n");
        return -1;
    }

    /* Create thread 1 */
    threadId1 = rt_thread_create("thread1_fn",        //Name
                                  thread1_function,   //Function address
                                  RT_NULL,            //Thread function parameter
                                  1024,               //Stack Size
                                  1,                  //Thread priority
                                  2000);              //Time slice in ticks

    /* Create thread 2 */
    threadId2 = rt_thread_create("thread2_fn",        //Name
                                  thread2_function,   //Function address
                                  RT_NULL,            //Thread function parameter
                                  1024,               //Stack Size
                                  1,                  //Thread priority
                                  2000);              //Time slice in ticks

    /* Start both threads */
    rt_thread_startup(threadId1);
    rt_thread_startup(threadId2);

    while(1);

    return RT_EOK;
}

Queue in RT-Thread – Output

 \ | /
- RT -     Thread Operating System
 / | \     4.1.1 build Mar  8 2023 09:55:56
 2006 - 2022 Copyright by RT-Thread team
←[0m[D/main] Thread 1: count = 1
←[0m
←[0m[D/main] Thread2: Got a message, the message:1
←[0m
←[0m[D/main] Thread 1: count = 2
←[0m
←[0m[D/main] Thread2: Got a message, the message:2
←[0m
←[0m[D/main] Thread 1: count = 3
←[0m
←[0m[D/main] Thread2: Got a message, the message:3
←[0m
←[0m[D/main] Thread 1: count = 4
←[0m
←[0m[D/main] Thread2: Got a message, the message:4
←[0m
←[0m[D/main] Thread 1: count = 5
←[0m
←[0m[D/main] Thread2: Got a message, the message:5
←[0m
←[0m[D/main] Thread 1: count = 6
←[0m
←[0m[D/main] Thread2: Got a message, the message:6
←[0m
←[0m[D/main] Thread 1: count = 7
←[0m
←[0m[D/main] Thread2: Got a message, the message:7
←[0m

In our next tutorial, we will see the signals 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
Subscribe
Notify of
guest

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

0 Comments
Inline Feedbacks
View all comments
Table of Contents