• 沒有找到結果。

Event Control Blocks

在文檔中 µC/OS-II Goals Preface (頁 134-138)

Task

6.00 Event Control Blocks

µC/OS-II maintains the state of an ECB in a data structure called OS_EVENT (see uCOS_II.H). The state of an event consists of the event itself (a counter for a semaphore, a pointer for a message mailbox and an array of pointers for a queue) and, a waiting list for tasks waiting for the event to occur. Each semaphore, mailbox and queue is assigned an ECB. The data structure for an ECB is shown in Listing 6.1.

typedef struct {

void *OSEventPtr; /* Ptr to message or queue structure */

INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Wait list for event to occur */

INT16U OSEventCnt; /* Count (when event is a semaphore) */

INT8U OSEventType; /* Event type */

INT8U OSEventGrp; /* Group for wait list */

} OS_EVENT;

Listing 6.1, Event Control Block data structure

OSEventPtr is only used when the ECB is assigned to a mailbox or a queue. In this case, OSEventPtr points to the message when used for a mailbox or a pointer to a message queue data structure ( see section 6.06, Message Mailboxes and section 6.07, Message Queues ) .

OSEventTbl[] and OSEventGrp are similar to OSRdyTbl[] and OSRdyGrp, respectively except that they contain a list of tasks waiting on the event instead of being a list of tasks ready-to-run (see section 3.04, Ready List).

OSEventCnt is used to hold the semaphore count when the ECB is used for a semaphore (see section 6.05, Semaphores ).

OSEventType contains the type associated with the ECB and can have the following values:

OS_EVENT_SEM, OS_EVENT_TYPE_MBOX or OS_EVENT_TYPE_Q. This field is used to make sure you are accessing the proper object when you perform operations on these objects through µC/OS-II’s service calls.

Each task that needs to wait for the event to occur is placed in the wait list consisting of the two variables, .OSEventGrp and .OSEventTbl[] . Note that I used a dot (i.e. .) in front of the variable name to indicate that the variable is part of a data structure. Task priorities are grouped (8 tasks per group) in .OSEventGrp.

Each bit in .OSEventGrp is used to indicate whenever any task in a group is waiting for the event to occur. When a task is waiting, its corresponding bit in set in the wait table, .OSEventTbl[]. The size (in bytes) of .OSEventTbl[] depends on OS_LOWEST_PRIO (see uCOS_II.H). This allows µC/OS -II to reduce the amount of RAM (i.e. data space) when your application requires just a few task priorities.

The task that will be resumed when the event occurs is the highest priority task waiting for the event and corresponds to the lowest priority number which has a bit set in .OSEventTbl[]. The relationship between .OSEventGrp and .OSEventTbl[] is shown in Figure 6-2 and is given by the following rules:

Bit 0 in .OSEventGrp is 1 when any bit in .OSEventTbl[0] is 1.

Bit 1 in .OSEventGrp is 1 when any bit in .OSEventTbl[1] is 1.

Bit 2 in .OSEventGrp is 1 when any bit in .OSEventTbl[2] is 1.

Bit 3 in .OSEventGrp is 1 when any bit in .OSEventTbl[3] is 1.

Bit 4 in .OSEventGrp is 1 when any bit in .OSEventTbl[4] is 1.

Bit 5 in .OSEventGrp is 1 when any bit in .OSEventTbl[5] is 1.

Bit 6 in .OSEventGrp is 1 when any bit in .OSEventTbl[6] is 1.

Bit 7 in .OSEventGrp is 1 when any bit in .OSEventTbl[7] is 1.

0 1 2 3 4 5 6 7

8 9 10 11 12 13 14 15

16 17 18 19 20 21 22 23

24 25 26 27 28 29 30 31

32 33 34 35 36 37 38 39

40 41 42 43 44 45 46 47

48 49 50 51 52 53 54 55

56 57 58 59 60 61 62 63

Priority of task waiting for the event to occur.

Lowest Priority Task

(Idle Task, can NEVER be waiting) Highest Priority Task Waiting

X

Y .OSEventTbl[OS_LOWEST_PRIO / 8 + 1]

0 1 2 3 4 5 6 7

.OSEventGrp

[7]

[6]

[5]

[4]

[3]

[2]

[1]

[0]

0 0 Y Y Y X X X

Bit position in .OSEventTbl[OS_LOWEST_PRIO / 8 + 1]

Bit position in .OSEventGrp and

Index into .OSEventTbl[OS_LOWEST_PRIO / 8 + 1]

Task's Priority

Figure 6-2, Wait list for task waiting for an event to occur.

The following piece of code is used to place a task in the wait list list:

pevent->OSEventGrp |= OSMapTbl[prio >> 3];

pevent->OSEventTbl[prio >> 3] |= OSMapTbl[prio & 0x07];

Listing 6.2, Making a task wait for an event.

prio is the task's priority and pevent is a pointer to the event control block.

You should realize from listing 6.2 that inserting a task in the wait list always takes the same amount of time and does not depend on how many ta sks are in your system. Also, from Figure 6 -2, the lower 3 bits of the task's priority are used to determine the bit position in .OSEventTbl[], while the next three most significant bits are used to determine the index into .OSEventTbl[]. Note that OSMapTbl[] (see OS_CORE.C) is a table in ROM, used to equate an index from 0 to 7 to a bit mask as shown in the table 6.1.

Index Bit mask (Binary)

0 00000001

1 00000010

2 00000100

3 00001000

4 00010000

5 00100000

6 01000000

7 10000000

Table 6.1, Contents of OSMapTbl[].

A task is removed from the wait list by reversing the process. The following code is executed in this case:

if ((pevent->OSEventTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) { pevent->OSEventGrp &= ~OSMapTbl[prio >> 3];

}

Listing 6.3, Removing a task from a wait list.

This code clears the bit corresponding to the task in .OSEventTbl[] and clears the bit in .OSEventGrp only if all tasks in a group are not waiting, i.e. all bits in .OSEventTbl[prio >> 3] are 0. Another table lookup is performed, rather than scanning through the table starting with .OSEventTbl[0], to find the highest priority task that is waiting for the event. OSUnMapTbl[256] is a priority resolution table (see OS_CORE.C). Eight bits are used to represent when tasks are waiting in a group. The least significant bit has the highest priority. Using this byte to index the table returns the bit position of the highest priority bit set, a number between 0 and 7. Determining the priority of the highest priority task waiting for the event is accomplished with the following section of code:

y = OSUnMapTbl[pevent->OSEventGrp];

x = OSUnMapTbl[pevent->OSEventTbl[y]];

prio = (y << 3) + x;

Listing 6.4, Finding the highest priority task waiting for the event.

For example, if .OSEventGrp contains 01101000 (binary) then the table lookup OSUnMapTbl[.OSEventGrp]

would yield a value of 3, which corresponds to bit #3 in .OSEventGrp. Notes that bit positions are assumed to start on the right with bit #0 being the rightmost bit. Similarly, if .OSEventTbl[3] contained 11100100 (binary) then OSUnMapTbl[.OSEventTbl[3]] would result in a value of 2 (i.e. bit #2). The priority of the task waiting ( prio) would then be 26 (3 * 8 + 2)!

The number of ECBs to allocate depends on the number of semaphores, mailboxes and queues needed for your application. The number of ECBs is established by the #define OS_MAX_EVENTS which you define in OS_CFG.H. When OSInit() is called (see section 3.11), all ECBs are linked in a singly linked list - the list of free ECBs (see figure 6-3). When a semaphore, mailbox or queue is created, an ECB is removed from this list and initialized. ECBs cannot be returned to the list of free ECB because semaphores, mailboxes and queues cannot be deleted.

OSEventFreeList

OS_MAX_EVENTS

0 OS_EVENT

Figure 6-3, List of free ECBs.

There are four common operations that can be performed on ECBs:

1) Initialize an ECB 2) Make a task ready

3) Make a task wait for an event

4) Make a task ready because a timeout occurred while waiting for an event.

To avoid duplicating code and thus to reduce code size, four functions have been created to performs these operations:

OSEventWaitListInit(), OSEventTaskRdy(), OSEventWait() and OSEventTO(), respectively.

在文檔中 µC/OS-II Goals Preface (頁 134-138)