Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2012 / uCOS / uCOSII_ebook.pdf
Скачиваний:
70
Добавлен:
10.02.2015
Размер:
1.08 Mб
Скачать

is waiting for time to expire L5.3(3). Whenever the OS_TCB field OSTCBDly contains a non-zero value, the task is waiting for time to expire, whether because the task called OSTimeDly(), OSTimeDlyHMSM() or any of the PEND functions described in Chapter 6. The delay is then cancelled by forcing OSTCBDly to zero L5.3(4). A delayed task may also have been suspended and thus, the task is only made ready-to-run if the task was not suspended L5.3(5). The task is placed in the ready list when the above conditions are satisfied L5.3(6). At this point, we call the scheduler to see if the resumed task has a higher priority than the current task L5.3(7). This could result in a context switch.

You should note that you could also have a task delay itself by waiting on a semaphore, mailbox or a queue with a timeout (see Chapter 6). You would resume such a task by simply posting to the semaphore, mailbox or queue, respectively. The only problem with this scenario is that it requires that you allocate an event control block (see section 6.00) and thus your application would consume a little bit more RAM.

5.03 System time, OSTimeGet() and OSTimeSet()

Whenever a clock tick occurs, µC/OS-II increments a 32-bit counter. This counter starts at zero when you initiate multitasking by calling OSStart() and rolls over after 4,294,967,295 ticks. At a tick rate of 100 Hz, this 32-bit

counter rolls over every 497 days. You can obtain the current value of this counter by calling OSTimeGet(). You can also change the value of the counter by calling OSTimeSet(). The code for both functions is shown in listing 5.4. Note that interrupts are disabled when accessing OSTime. This is because incrementing and copying a 32-bit value on most 8-bit processors requires multiple instructions that must be treated indivisibly.

INT32U OSTimeGet (void)

{

INT32U ticks;

OS_ENTER_CRITICAL(); ticks = OSTime; OS_EXIT_CRITICAL(); return (ticks);

}

void OSTimeSet (INT32U ticks)

{

OS_ENTER_CRITICAL(); OSTime = ticks; OS_EXIT_CRITICAL();

}

Listing 5.4, Obtaining and setting the system time.

Chapter 6

Intertask Communication &

Synchronization

µC/OS-II provides many mechanisms to protect shared data and provide intertask communication. We have already seen two such mechanisms:

1)Disabling and enabling interrupts through the two macros OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL(), respectively. You use these macros when two tasks or a task and an ISR need to

share data. See section 3.00, Critical Sections, section 8.03.02, OS_CPU.H, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() and, section 9.03.02, OS_CPU.H, Critical Sections.

2)Locking and unlocking µC/OS-II’s scheduler with OSSchedLock() and OSSchedUnlock(), respectively. Again, you use these services to access shared data. See section 3.06, Locking and Unlocking the Scheduler.

This chapter discusses the other three types of services provided by µC/OS -II: Semaphores, Message mailboxes and Message queues.

Figure 6-1 shows how tasks and Interrupt Service Routines (ISRs) can interact with each other. A task or an ISR signals a task F6-1A(1) through a kernel object called an Event Control Block (ECB). The signal is considered to be an event which explains my choice of this name. A task can wait for another task or an ISR to signal the object F6-1A(2). You should note that only tasks areallowed to wait for events to occur –an ISR is not allowed to wait on an ECB. An optional timeout F6-1A(3) can be specified by the waiting task in case the object is not signaled within a specified time period. Multiple tasks can wait for a task or an ISR to signal an ECB F6-1B. When the ECB is signaled, only the highest priority task waiting on the ECB will be ‘signaled’and thus will be made ready-to-run. An ECB can either be a semaphore, a message mailbox or a message queue as we will see later. When an ECB is used as a semaphore, tasks will both wait and signal the ECB F6-1C(4).

ISR

Task

ISR

Task

Task

Task

Signal

ECB

Wait

 

 

(1) (2)

Timeout

(3)

Signal

 

ECB

Wait

(1)

 

(2)

 

 

Timeout

(3)

Signal

Wait

 

 

ECB

Signal

Wait

Wait/Signal Timeout

(4)

ECB

Wait/Signal Timeout

(4)

Task

A

Task

Task

B

Task

C

Figure 6-1, Use of Event Control Blocks.

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.

 

 

.OSEventGrp

 

 

 

 

 

 

 

 

 

 

7

6

5

4

3

2

1

0

.OSEventTbl[OS_LOWEST_PRIO / 8 + 1]

 

 

 

 

 

 

 

 

 

 

 

Highest Priority Task Waiting

 

 

 

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

 

 

 

[0]

7

6

5

4

3

2

1

0

 

 

 

 

 

 

 

 

[1]

15

14

13

12

11

10

9

8

 

 

 

 

 

 

 

 

[2]

23

22

21

20

19

18

17

16

 

 

 

 

 

 

 

 

[3]

31

30

29

28

27

26

25

24

 

 

 

 

 

 

 

 

[4]

39

38

37

36

35

34

33

Y

 

 

 

 

 

 

 

 

32

 

 

 

 

 

 

 

 

[5]

47

46

45

44

43

42

41

40

 

 

 

 

 

 

 

 

[6]

55

54

53

52

51

50

49

48

 

 

 

 

 

 

 

 

[7]

63

62

61

60

59

58

57

56

Priority of task waiting for the event to occur.

Task's Priority

0 0 Y Y Y X X X

 

Lowest Priority Task

 

 

 

 

 

 

 

 

 

 

(Idle Task, can NEVER be waiting)

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

Bit position in .OSEventGrp and

Index into .OSEventTbl[OS_LOWEST_PRIO / 8 + 1]

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 tasks 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:

Соседние файлы в папке uCOS