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 10 Current »

Relationships Between Tasks, ISRs, and a Semaphore

µC/OS-II semaphores consist of two elements: a 16-bit unsigned integer used to hold the semaphore count (0 to 65535) and a list of tasks waiting for the semaphore count to be greater than 0. µC/OS-II provides eight services to access semaphores: OSSemAccept(), OSSemCreate(), OSSemDel(), OSSemPend(), OSSemPendAbort()OSSemPost() and OSSemQuery().

To enable µC/OS-II semaphore services, you must set the configuration constants in OS_CFG.H. Specifically, table 7.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 semaphore services are enabled when OS_SEM_EN is set to 0. To enable the feature (i.e. service), simply set the configuration constant to 1. You will notice that OSSemCreate(), OSSemPend() and OSSemPost() cannot be individually disabled like the other services. That’s because they are always needed when you enable µC/OS-II semaphore management.Figure 7.1 shows a flow diagram to illustrate the relationship between tasks, ISRs, and a semaphore. Note that the symbology used to represent a semaphore is either a key or a flag. You would us a key symbol in such flow diagrams if the semaphore is used to access shared resources. The N next to the key represents how many resources are available. N is 1 for a binary semaphore. Use a flag symbol when a semaphore is used to signal the occurrence of an event. N in this case represents the number of times the event can be signaled. The hourglass represents a timeout that can be specified with the OSSemPend() call.

As you can see from Figure 7.1, a task or an ISR can call OSSemAccept(), OSSemPost() or OSSemQuery(). However, only tasks are allowed to call OSSemDel() or OSSemPend().

Creating a Semaphore, OSSemCreate()

A semaphore needs to be created before it can be used. You create a semaphore by calling OSSemCreate() (see next section) and specifying the initial count of the semaphore. The initial value of a semaphore can be between 0 and 65535. If you use the semaphore to signal the occurrence of one or more events, you would typically initialize the semaphore to 0. If you use the semaphore to access a single shared resource, you need to initialize the semaphore to 1 (i.e., use it as a binary semaphore). Finally, if the semaphore allows your application to obtain any one of n identical resources, initialize the semaphore to n and use it as a counting semaphore.

The code to create a semaphore is shown in Listing 7.1.

Figure 7.2 shows the content of the ECB just before OSSemCreate() returns.

Deleting a Semaphore, OSSemDel()

The code to delete a semaphore is shown in listing 7.2 and code will only be generated by the compiler if OS_SEM_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 semaphore. You should always use this function with great care. Generally speaking, before you would delete a semaphore, you would first delete all the tasks that access the semaphore.

Waiting on a Semaphore (blocking), OSSemPend()

The code to wait on a semaphore is shown in Listing 7.3.

Signaling a Semaphore, OSSemPost()

The code to signal a semaphore is shown in Listing 7.4.It’s important to note that a context switch does NOT occur if OSSemPost() is called by an ISR because context switching from an ISR can only occur when OSIntExit() is called at the completion of the ISR from the last nested ISR (see section 3.??, Interrupts under µC/OS-II).

Getting a Semaphore without Waiting (non-blocking), OSSemAccept()

It is possible to obtain a semaphore without putting a task to sleep if the semaphore is not available. This is accomplished by calling OSSemAccept() as shown in Listing 7.5.

The code that called OSSemAccept() needs to examine the returned value. A returned value of zero indicates that the semaphore is not available; a nonzero value indicates that the semaphore is available. Furthermore, a nonzero value indicates to the caller the number of resources that are available. Keep in mind that, in this case, one of the resources has been allocated to the calling task because the count has been decremented.

An ISR could use OSSemAccept(). However, it’s not recommended to have a semaphore shared between a task and an ISR. Semaphores are supposed to be task level objects. If a semaphore is used as a signalling object between an ISR and a task then, the ISR should only POST to the semaphore.

Obtaining the Status of a Semaphore, OSSemQuery()

OSSemQuery() allows your application to take a “snapshot” of an ECB that is used as a semaphore (Listing 7.6). OSSemQuery() receives two arguments: pevent contains a pointer to the semaphore, which is returned by OSSemCreate() when the semaphore is created, and pdata is a pointer to a data structure (OS_SEM_DATA, see uCOS_II.H) that holds information about the semaphore. Your application will thus need to allocate a variable of type OS_SEM_DATA that will be used to receive the information about the desired semaphore. I decided to use a new data structure because the caller should only be concerned with semaphore-specific data as opposed to the more generic OS_EVENT data structure, which contain two additional fields (.OSEventType and .OSEventPtr). OS_SEM_DATA contains the current semaphore count (.OSCnt) and the list of tasks waiting on the semaphore (.OSEventTbl[] and .OSEventGrp).

  • No labels