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 5 Next »

The code of Listing 3-4 through Listing 3-8 shows a more complete example and contains three tasks: a mutual exclusion, semaphore, and a message queue.

L3-4(1) Here we allocate storage for the OS_TCBs of each task.

L3-4(2) A mutual exclusion semaphore (a.k.a. a mutex) is a kernel object (a data structure) that is used to protect a shared resource from being accessed by more than one task. A task that wants to access the shared resource must obtain the mutex before it is allowed to proceed. The owner of the resource relinquishes the mutex when it has finished accessing the resource. This process is demonstrated in this example.

L3-4(3) A message queue is a kernel object through which Interrupt Service Routines (ISRs) and/or tasks send messages to other tasks. The sender “formulates” a message and sends it to the message queue. The task(s) wanting to receive these messages wait on the message queue for messages to arrive. If there are already messages in the message queue, the receiver immediately retrieves those messages. If there are no messages waiting in the message queue, then the receiver will be placed in a wait list associated with the message queue. This process will be demonstrated in this example.

L3-4(4) A stack is allocated for each task.

L3-4(5) The prototype of the tasks are declared.

Listing 3-5 shows the C entry point, i.e. main().

L3-5(1) Creating a mutex is simply a matter of calling OSMutexCreate(). You need to specify the address of the OS_MUTEX object that will be used for the mutex. Resource Management provides additional information about mutual exclusion semaphores.

You can assign an ASCII name to the mutex, which is useful when debugging.

L3-5(2) You create the message queue by calling OSQCreate() and specify the address of the OS_Q object. Message Passing provides additional information about message queues.

You can assign an ASCII name to the message queue which can also be useful during debugging.

You need to specify how many messages the message queue is allowed to receive. This value must be greater than zero. If the sender sends messages faster than they can be consumed by the receiving task, messages will be lost. This can be corrected by either increasing the size of the message queue, or increasing the priority of the receiving task.

L3-5(3) The first application task is created.

Listing 3-6 shows how to create other tasks once multitasking as started.

L3-6(1) Task #1 is created by calling OSTaskCreate(). If this task happens to have a higher priority than the task that creates it, µC/OS-III will immediately start Task #1. If the created task has a lower priority, OSTaskCreate() will return to AppTaskStart() and continue execution.

L3-6(2) Task #2 is created and if it has a higher priority than AppTaskStart(), µC/OS-III will immediately switch to that task.

L3-7(1) The task starts by waiting for one tick to expire before it does anything useful. If the µC/OS-III tick rate is configured for 1000 Hz, the task will be suspended for 1 millisecond.

L3-7(2) The task then sends a message to another task using the message queue AppQ. In this case, the example sends a fixed message of value “1,” but the message could have consisted of the address of a buffer, the address of a function, or whatever would need to be sent.

L3-7(3) The task then waits on the mutual exclusion semaphore since it needs to access a shared resource with another task. If the resource is already owned by another task, AppTask1() will wait forever for the mutex to be released by its current owner. The forever wait is specified by passing 0 as the second argument of the call.

L3-7(4) When OSMutexPend() returns, the task owns the resource and can therefore access the shared resource. The shared resource may be a variable, an array, a data structure, an I/O device, etc. You should note that we didn’t actually show the access to the shared resource. This is not relevant at this point.

L3-7(5) When the task is done with the shared resource, it must call OSMutexPost() to release the mutex.

L3-8(1) Task #2 starts by waiting for messages to be sent through the message queue AppQ. The task waits forever for a message to be received because the third argument specifies an infinite timeout.

When the message is received p_msg will contain the message (i.e., a pointer to “something”). In our case, AppTask2() will always receive a message value of ‘1’. Both the sender and receiver must agree as to the meaning of the message. The size of the message received is saved in “msg_size”. Note that “p_msg” could point to a buffer and “msg_size” would indicate the size of this buffer.

Also, when the message is received, “ts” will contain the timestamp of when the message was sent. A timestamp is the value read from a fairly fast free-running timer. The timestamp is typically an unsigned 32-bit (or more) value.

L3-8(2) Knowing when the message was sent allows the user to determine how long it took this task to get the message. This is done by reading the current timestamp and subtracting the timestamp of when the message was sent allows users to know how long it took for the message to be received. Note that the receiving task may not get the message immediately since ISRs or other higher-priority tasks might execute before the receiver gets to run.

L3-8(3) Here you would add your own code to process the received message.

  • No labels