Mailbox in RT-Thread RTOS – RT-Thread Tutorial Part 6

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 Mutex and Event in the RT-Thread RTOS. In this post, we will see the Inter-thread communication methods 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.

  • Mailbox
  • Message Queues
  • Signals

Mailbox in RT-Thread RTOS – RT-Thread Tutorial Part 6

Mailbox

The messages can be transmitted through the mailbox. A mailbox is a special memory location that one or more tasks can use to transfer data, or more generally for synchronization.

A mailbox is a data buffer that can store a fixed number of messages of a fixed size. Threads can store messages in a mailbox. If the mailbox is full, it will return an error. So, sending messages to the mailbox is a non-blocking operation. Therefore, we can use that in the ISR. A separate function is also available for sending messages with blocking. If the mailbox is full, then it will wait until it becomes free. We cannot use this function in the ISR. Of course, threads can also retrieve messages from mailboxes. In this case, the thread is blocked if no message is available in the mailbox based on the timeout value. Any number of tasks can use the same mailbox for storing and retrieving messages.

In RT-Thread RTOS, Using the mailbox, we can transfer up to 4 bytes of data. So, it can be 32 bits of data or a pointer to the buffer. It is low overhead and high efficiency.

Management of Mailbox

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

Creating/initiating a mailbox

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

rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);

Input parameters and return values of rt_mb_create()

ParametersDescription
nameThe name of the mailbox
sizeMailbox capacity
flagThe mailbox flag, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return——
RT_NULLCreation failed
The handle of the mailbox objectCreation successful

You can use the below API to create the Static mailbox.

  rt_err_t rt_mb_init(rt_mailbox_t mb,
                    const char* name,
                    void* msgpool,
                    rt_size_t size,
                    rt_uint8_t flag)

Input parameters and return values of rt_mb_init()

ParametersDescription
mbThe handle of the mailbox object
nameMailbox name
msgpoolBuffer pointer
sizeMailbox capacity
flagThe mailbox flag, which can take the following values: RT_IPC_FLAG_FIFO or RT_IPC_FLAG_PRIO
Return——
RT_EOKSuccessful

Deleting/detaching a mailbox

You can use the below API to delete the dynamically created mailbox (mailbox which has been created using the rt_mb_create()).

rt_err_t rt_mb_delete (rt_mailbox_t mb);

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

rt_err_t rt_mb_detach(rt_mailbox_t mb);

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

Send mail

Sending without waiting

The below API is used to send the mail to the mailbox.

rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);

This function is not a blocking call, thus we can call this from the ISR.

The message sent can be any data 32-bit formatted, an integer value or a pointer pointing to the buffer. When the mailbox is fully filled with mails, the thread or ISR that sent the mail will receive a return value of –RT_EFULL.

Sending with waiting

Users can also send mails to the specified mailboxes through the following function interface:

rt_err_t rt_mb_send_wait (rt_mailbox_t mb,
                      rt_uint32_t value,
                      rt_int32_t timeout);

The above function is blocking calls based on the timeout. If the mailbox is full, the thread sending the message will wait for the mailbox to release space as mails are received according to the set timeout parameter. So, it will be blocked until the timeout expires or the mailbox has a free space. We should not call this function from the ISR.

Note: Calling rt_mb_send_wait() with the timeout 0 is equal to calling the rt_mb_send().

Receive Mails

To receive mail from the mailbox, we can use the below function.

rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);

Input parameters and return values of rt_mb_recv()

ParametersDescription
mbThe handle of the mailbox object
valueMail content
timeoutTimeout
Return——
RT_EOKSent successfully
-RT_ETIMEOUTTimeout
-RT_ERRORFailed, return error

Mailbox 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 mailbox. Thread 2 will be waiting for the messages in the mailbox. 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>

/* Mailbox control block */
static struct rt_mailbox *mb;

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_mb_send(mb, (rt_uint32_t)&count);
        rt_thread_mdelay(1000);
    }
}

/* Thread 2 */
static void thread2_function(void *parameter)
{
    uint32_t *received_mail = NULL;
    while (1)
    {
        /* Receive mail from the mailbox */
        if (rt_mb_recv(mb, (rt_uint32_t *)&received_mail, RT_WAITING_FOREVER) == RT_EOK)
        {
            LOG_D("Thread2: Got a mail from mailbox, the message:%u\n", *received_mail);
        }
    }
}

int main(void)
{
    /* create mailbox object */
    mb = rt_mb_create("etx_mb", 1, RT_IPC_FLAG_FIFO);
    if( mb  == RT_NULL )
    {
        LOG_D("Mailbox 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;
}

Output

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

In our next tutorial, we will see the message queue 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