Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Mailbox Configuration

A message mailbox (or simply a mailbox) is a µC/OS-II object that allows a task or an ISR to send a pointer-sized variable to another task. The pointer is typically initialized to point to some application specific data structure containing a “message.” µC/OS-II provides seven services to access mailboxes: OSMboxCreate(), OSMboxDel()OSMboxPend(), OSMboxPost(), OSMboxPostOpt(), OSMboxAccept(), and OSMboxQuery().

To enable µC/OS-II message mailbox services, you must set configuration constants in OS_CFG.H. Specifically, table 10.1 shows which services are compiled based on the value of configuration constants found in OS_CFG.H. You should note that NONE of the mailbox services are enabled when OS_MBOX_EN is set to 0. To enable specific features (i.e. service) listed in Table 10.1, simply set the configuration constant to 1. You will notice that OSMboxCreate() and OSMboxPend() cannot be individually disabled like the other services. That’s because they are always needed when you enable µC/OS-II message mailbox management. You must enable at least one of the post services: OSMboxPost() and OSMboxPostOpt().

Table 10.1 Mailbox configuration constants in OS_CFG.H.

µC/OS-II Mailbox Service

Enabled when set to 1 in OS_CFG.H

OSMboxAccept()

OS_MBOX_ACCEPT_EN

OSMboxCreate()

 

OSMboxDel()

OS_MBOX_DEL_EN

OSMboxPend()

 

OSMboxPost()

OS_MBOX_POST_EN

OSMboxPostOpt()

OS_MBOX_POST_OPT_EN

OSMboxQuery()

OS_MBOX_QUERY_EN

Figure 10.1 shows a flow diagram to illustrate the relationship between tasks, ISRs, and a message mailbox. Note that the symbology used to represent a mailbox is an I-beam. The hourglass represents a timeout that can be specified with the OSMboxPend() call. The content of the mailbox is a pointer to a message. What the pointer points to is application specific. A mailbox can only contain one pointer (mailbox is full) or a pointer to NULL (mailbox is empty).

As you can see from Figure 10.1, a task or an ISR can call OSMboxPost() or OSMboxPostOpt(). However, only tasks are allowed to call OSMboxDel(), OSMboxPend() and OSMboxQuery(). Your application can have just about any number of mailboxes. The limit is set by OS_MAX_EVENTS in OS_CFG.H.

Figure 10.1 Relationships between tasks, ISRs, and a message mailbox.

Creating a Mailbox, OSMboxCreate()

A mailbox needs to be created before it can be used. Creating a mailbox is accomplished by calling OSMboxCreate() and specifying the initial value of the pointer. Typically, the initial value is a NULL pointer, but a mailbox can initially contain a message. If you use the mailbox to signal the occurrence of an event (i.e., send a message), you typically initialize it to a NULL pointer because the event (most likely) has not occurred. If you use the mailbox to access a shared resource, you initialize the mailbox with a non-NULL pointer. In this case, you basically use the mailbox as a binary semaphore.

The code to create a mailbox is shown in Listing 10.1.Figure 10.2 ECB just before OSMboxCreate() returns.

Deleting a Mailbox, OSMboxDel()

The code to delete a mailbox is shown in listing 10.2 and this code will only be generated by the compiler if OS_MBOX_DEL_EN is set to 1 in OS_CFG.H. This is a function you must use with caution because multiple tasks could attempt to access a deleted mailbox. You should always use this function with great care. Generally speaking, before you would delete a mailbox, you would first delete all the tasks that can access the mailbox.

Waiting for a Message at a Mailbox, OSMboxPend()

The code to wait for a message to arrive at a mailbox is shown in Listing 10.3.

Sending a message to a mailbox, OSMboxPost()

The code to deposit a message in a mailbox is shown in Listing 10.4.Note that a context switch does not occur if OSMboxPost() is called by an ISR because context switching from an ISR only occurs when OSIntExit() is called at the completion of the ISR and from the last nested ISR (see section 3.09, Interrupts under µC/OS-II).

Sending a message to a mailbox, OSMboxPostOpt()

You can also post a message to a mailbox using an alternate and more powerful function called OSMboxPostOpt(). The reason there are two post calls is for backwards compatibility with previous versions of µC/OS-II. OSMboxPostOpt() is the newer function and can replace OSMboxPost(). In addition, OSMboxPostOpt() allows posting a message to all tasks (i.e. broadcast) waiting on the mailbox. The code to deposit a message in a mailbox is shown in Listing 10.5.Note that a context switch does not occur if OSMboxPostOpt() is called by an ISR because context switching from an ISR only occurs when OSIntExit() is called at the completion of the ISR and from the last nested ISR (see section 3.10, Interrupts under µC/OS-II).

Getting a message without waiting (non-blocking), OSMboxAccept()

You can obtain a message from a mailbox without putting a task to sleep if the mailbox is empty. This is accomplished by calling OSMboxAccept(), shown in Listing 10.6.The code that called OSMboxAccept() must examine the returned value. If OSMboxAccept() returns a NULL pointer, then a message was not available. A non-NULL pointer indicates that a message was deposited in the mailbox. An ISR should use OSMboxAccept() instead of OSMboxPend().

You can use OSMboxAccept() to flush (i.e., empty) the contents of a mailbox.

Obtaining the status of a mailbox, OSMboxQuery()

OSMboxQuery() allows your application to take a snapshot of an ECB used for a message mailbox. The code for this function is shown in Listing 10.7. OSMboxQuery() is passed two arguments: pevent contains a pointer to the message mailbox, which is returned by OSMboxCreate() when the mailbox is created, and pdata is a pointer to a data structure (OS_MBOX_DATA, see uCOS_II.H) that holds information about the message mailbox. Your application needs to allocate a variable of type OS_MBOX_DATA that will be used to receive the information about the desired mailbox. I decided to use a new data structure because the caller should only be concerned with mailbox-specific data, as opposed to the more generic OS_EVENT data structure, which contains two additional fields (.OSEventCnt and .OSEventType). OS_MBOX_DATA contains the current contents of the message (.OSMsg) and the list of tasks waiting for a message to arrive (.OSEventTbl[] and .OSEventGrp).

Using a Mailbox as a Binary Semaphore

A message mailbox can be used as a binary semaphore by initializing the mailbox with a non-NULL pointer [(void *)1 works well]. A task requesting the “semaphore” calls OSMboxPend() and releases the “semaphore” by calling OSMboxPost(). Listing 10.8 shows how this works. You can use this technique to conserve code space if your application only needs binary semaphores and mailboxes. In this case, set OS_MBOX_EN to 1 and OS_SEM_EN to 0 so that you use only mailboxes instead of both mailboxes and semaphores.

Using a Mailbox instead of OSTimeDly()

The timeout feature of a mailbox can be used to simulate a call to OSTimeDly(). As shown in Listing 10.9, Task1() resumes execution after the time period expires if no message is received within the specified TIMEOUT. This is basically identical to OSTimeDly(TIMEOUT). However, the task can be resumed by Task2() when Task(2) post a “dummy” message to the mailbox before the timeout expires. This is the same as calling OSTimeDlyResume() had Task1() called OSTimeDly(). Note that the returned message is ignored because you are not actually looking to get a message from another task or an ISR.

  • No labels