Mailboxes in Nucleus SE: A Practical Guide to Configuration and Usage
View the RTOS Revealed series
Mailboxes were introduced in an earlier article as one of the most straightforward inter‑task communication mechanisms in Nucleus SE—right after signals. They offer a low‑cost, highly flexible way to transfer simple data between tasks.
Using Mailboxes
In Nucleus SE, mailboxes are defined at build time. A maximum of 16 mailboxes can be configured per application. If you configure zero mailboxes, the compiler omits all related data structures and API code, keeping the binary lean.
A mailbox is essentially a storage slot that can hold a single variable of type ADDR. Only one task may write to a mailbox at a time. Once full, subsequent write attempts will fail until the mailbox is read or reset. Depending on the API options, an attempt to write to a full mailbox may return an error or suspend the task until space becomes available.
Mailboxes vs. Queues
Some operating systems replace mailboxes with a single‑entry queue. While a queue can mimic a mailbox’s behavior, it carries extra overhead—head and tail pointers, larger data structures, and more code paths—leading to higher memory usage and execution time.
In Nucleus SE, you can choose either mailboxes or queues. If your design uses many queues but only a few mailboxes, swapping a mailbox for a queue will increase data size slightly but remove mailbox‑specific API code, simplifying maintenance. It’s easy to test both configurations to compare memory footprint and performance.
Queues will be covered in a future article.
Configuring Mailboxes
Number of Mailboxes
The key macro in nuse_config.h is NUSE_MAILBOX_NUMBER. The default value is 0, meaning no mailboxes are enabled. You may set it to any integer between 1 and 16. A compile‑time check in nuse_config_check.h will trigger an error if the value is out of range.
Setting a non‑zero value activates the mailbox subsystem: data structures are sized, and the API enabling symbols are processed.
API Enables
Each mailbox API call has a corresponding #define in nuse_config.h:
NUSE_MAILBOX_SENDNUSE_MAILBOX_RECEIVENUSE_MAILBOX_RESETNUSE_MAILBOX_INFORMATIONNUSE_MAILBOX_COUNT
By default all are set to FALSE, disabling the call and its implementation. To use an API, enable the corresponding macro by setting it to TRUE. Enabling an API with no mailboxes configured will cause a compile‑time error (except NUSE_Mailbox_Count(), which is always available). Using a disabled API will produce a link‑time error.
/* Number of mailboxes in the system – 0-16 */
#define NUSE_MAILBOX_NUMBER 0
/* Service call enablers: */
#define NUSE_MAILBOX_SEND FALSE
#define NUSE_MAILBOX_RECEIVE FALSE
#define NUSE_MAILBOX_RESET FALSE
#define NUSE_MAILBOX_INFORMATION FALSE
#define NUSE_MAILBOX_COUNT FALSE
Mailbox Service Calls
Nucleus SE offers nine mailbox‑related service calls. The ones implemented in SE are:
- NUSE_Mailbox_Send() – write a message to a mailbox.
- NUSE_Mailbox_Receive() – read a message from a mailbox.
- NUSE_Mailbox_Reset() – clear a mailbox without suspending tasks.
- NUSE_Mailbox_Information() – query status of a mailbox.
- NUSE_Mailbox_Count() – return the number of configured mailboxes.
Other functions such as creation, deletion, bulk retrieval, and broadcast are not implemented in SE.
Write and Read Operations
Mailboxes support two core operations: sending (writing) and receiving (reading). Both APIs are available in Nucleus RTOS and Nucleus SE, with some differences in flexibility and error handling.
Sending to a Mailbox
In Nucleus RTOS the NU_Send_To_Mailbox call supports indefinite or timed suspension if the mailbox is full. Nucleus SE offers a simplified version: suspension is optional and timeouts are not supported.
Sample prototype for Nucleus SE:
STATUS NUSE_Mailbox_Send(NUSE_MAILBOX mailbox, ADDR *message, U8 suspend);
Parameters:
mailbox– mailbox index.message– pointer to anADDRvariable.suspend–NUSE_NO_SUSPENDorNUSE_SUSPEND.
Return values include NUSE_SUCCESS, NUSE_INVALID_MAILBOX, NUSE_MAILBOX_FULL, and NUSE_MAILBOX_WAS_RESET.
Implementation Overview
When blocking is disabled, the routine checks the mailbox status flag. If the mailbox is empty, it writes the data and marks the mailbox as full; otherwise it returns NUSE_MAILBOX_FULL.
With blocking enabled, the code loops until the message is successfully posted or the task is woken by a receive operation. If a task is suspended on the mailbox, it is resumed immediately after a successful send.
The following excerpt demonstrates the core logic when blocking is enabled (simplified for readability):
do {
if (!NUSE_Mailbox_Status[mailbox]) {
// Mailbox empty – store data and wake a waiting task if any.
} else if (suspend == NUSE_NO_SUSPEND) {
return NUSE_MAILBOX_FULL;
} else {
// Suspend task until the mailbox becomes empty.
}
} while (suspend == NUSE_SUSPEND);
In summary, the mailbox API balances simplicity and flexibility, allowing developers to choose between immediate failure or task suspension based on their application’s timing requirements.
Embedded
- Stainless Steel Explained: Composition, Production, and Global Impact
- Diodes and Rectifiers: Fundamentals, Operation, and Key Parameters
- Understanding Conductors and Insulators: From Quantum Mechanics to Practical Applications
- C# Fundamentals: Input and Output Essentials
- Semaphores in Nucleus RTOS: Utility Services & Data Structures
- Semaphores in Nucleus SE: Overview, Configuration, and API Essentials
- Event Flag Groups in Nucleus SE: An Introductory Guide to Configuration and API Usage
- Partition Memory in Nucleus RTOS/SE: Utility Services and Data Structures
- Partition Memory in Nucleus SE: Configuration, APIs, and Best Practices
- Queues in Nucleus SE: Introduction and Core Service Calls