Using Memory Partitions

Memory management services are enabled at compile time by setting the configuration constant OS_CFG_MEM_EN to DEF_ENABLED in os_cfg.h.

There are a number of operations to perform on memory partitions as summarized in the table below.

Memory Partition API Summary
Function NameOperation
OSMemCreate()Create a memory partition.
OSMemGet()Obtain a memory block from a memory partition.
OSMemPut()Return a memory block to a memory partition.

OSMemCreate() can only be called from task-level code, but OSMemGet() and OSMemPut() can be called by Interrupt Service Routines (ISRs).

The listing show in Returning a Memory Block to a Partition shows an example of how to use the dynamic memory allocation feature of μC/OS-III, as well as message-passing capabilities (see ). In this example, the task on the left reads and checks the value of analog inputs (pressures, temperatures, and voltage) and sends a message to the second task if any of the analog inputs exceed a threshold. The message sent contains information about which channel had the error, an error code, an indication of the severity of the error, and other information.

Error handling in this example is centralized. Other tasks, or even ISRs, can post error messages to the error-handling task. The error-handling task could be responsible for displaying error messages on a monitor (a display), logging errors to a disk, or dispatching other tasks to take corrective action based on the error.

Using a Memory Partition - Non Blocking

(1) The analog inputs are read by the task. The task determines that one of the inputs is outside a valid range and an error message needs to be sent to the error handler.

(2) The task then obtains a memory block from a memory partition so that it can place information regarding the detected error.

(3) The task writes this information to the memory block. As mentioned above, the task places the analog channel that is at fault, an error code, an indication of the severity, possible solutions, and more. There is no need to store a timestamp in the message, as time stamping is a built-in feature of µC/OS-III so the receiving task will know when the message was posted.

(4) Once the message is complete, it is posted to the task that will handle such error messages. Of course the receiving task needs to know how the information is placed in the message. Once the message is sent, the analog input task is no longer allowed (by convention) to access the memory block since it sent it out to be processed.

(5) The error handler task (on the right) normally pends on the message queue. This task will not execute until a message is sent to it.

(6) When a message is received, the error handler task reads the contents of the message and performs necessary action(s). As indicated, once sent, the sender will not do anything else with the message.

(7) Once the error handler task is finished processing the message, it simply returns the memory block to the memory partition. The sender and receiver therefore need to know about the memory partition or, the sender can pass the address of the memory partition as part of the message and the error handler task will know where to return the memory block to.

Sometimes it is useful to have a task wait for a memory block in case a partition runs out of blocks. µC/OS-III does not support pending on partitions, but it is possible to support this requirement by adding a counting semaphore (see Resource Management ) to guard the memory partition. The initial value of the counting semaphore would be set to the number of blocks in the partition. This is illustrated in the figure below.

Using a Memory Partition - Blocking

(1) To obtain a memory block, your code simply obtain the semaphore by calling OSSemPend() and then calls OSMemGet() to receive the memory block.

(2) To release a block, you simply return the memory block by calling OSMemPut() and then signal the semaphore by calling OSSemPost().

The above operations must be performed in order.

Note that the user may call OSMemGet() and OSMemPut() from an ISR since these functions do not block and in fact, execute very quickly. However, you cannot use blocking calls from ISRs.

Related pages