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

 

 

 

OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASK

 

OSTCBTbl[0]

OSTCBTbl[1]

OSTCBTbl[2]

 

 

OSTCBFreeList

OSTCBNext

OSTCBNext

OSTCBNext

OSTCBNext

0

Figure 3-2, List of free OS_TCBs

3.04 Ready List

Each task is assigned a unique priority level between 0 and OS_LOWEST_PRIO, inclusively (see OS_CFG.H). Task priority OS_LOWEST_PRIO is always assigned to the idle task when µC/OS-II is initialized. You should note that OS_MAX_TASKS and OS_LOWEST_PRIO are unrelated. You can have only 10 tasks in an application while still having 32 priority levels (if you set OS_LOWEST_PRIO to 31).

Each task that is ready to run is placed in a ready list consisting of two variables, OSRdyGrp and OSRdyTbl[]. Task priorities are grouped (8 tasks per group) inOSRdyGrp. Each bit in OSRdyGrp is used to indicate whenever

any task in a group is ready to run. When a task is ready to run it also sets its corresponding bit in the ready table,

OSRdyTbl[]. The size of OSRdyTbl[] depends on OS_LOWEST_PRIO (see uCOS_II.H). This allows you to reduce the amount of RAM (i.e. data space) needed by µC/OS-II when your application requires few task priorities.

To determine which priority (and thus which task) will run next, the scheduler determines the lowest priority number that has its bit set in OSRdyTbl[]. The relationship between OSRdyGrp and OSRdyTbl[] is shown in Figure 3-3

and is given by the following rules:

Bit 0 in OSRdyGrp is 1 when any bit in OSRdyTbl[0] is 1.

Bit 1 in OSRdyGrp is 1 when any bit in OSRdyTbl[1] is 1.

Bit 2 in OSRdyGrp is 1 when any bit in OSRdyTbl[2] is 1.

Bit 3 in OSRdyGrp is 1 when any bit in OSRdyTbl[3] is 1.

Bit 4 in OSRdyGrp is 1 when any bit in OSRdyTbl[4] is 1.

Bit 5 in OSRdyGrp is 1 when any bit in OSRdyTbl[5] is 1.

Bit 6 in OSRdyGrp is 1 when any bit in OSRdyTbl[6] is 1.

Bit 7 in OSRdyGrp is 1 when any bit in OSRdyTbl[7] is 1.

 

 

OSRdyGrp

 

 

 

 

 

 

 

 

 

 

 

 

7

6

5

4

3

2

1

0

OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Highest Priority Task

 

 

 

 

 

 

 

 

 

 

 

 

 

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

Y

 

 

 

 

 

 

 

 

[4]

39

38

37

36

35

34

33

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

 

Task Priority #

Task's Priority

 

 

 

 

 

 

 

 

 

 

 

Lowest Priority Task

0 0 Y Y Y X

X X

 

(Idle Task)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Bit position in OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

Bit position in OSRdyGrp and

Index into OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

Figure 3-3, µC/OS-II’s Ready List

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

OSRdyGrp

|=

OSMapTbl[prio

>> 3];

OSRdyTbl[prio >> 3] |=

OSMapTbl[prio

& 0x07];

 

 

 

 

Listing 3.5, Making a task ready-to-run.

where prio is the task's priority.

As you can see from Figure 3-3, the lower 3 bits of the task's priority are used to determine the bit position in OSRdyTbl[], while the next three most significant bits are used to determine the index into OSRdyTbl[]. 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 below:

Index

Bit mask (Binary)

0

00000001

1

00000010

2

00000100

3

00001000

4

00010000

5

00100000

6

01000000

7

10000000

Table 3.1, Contents of OSMapTbl[].

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

if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) OSRdyGrp &= ~OSMapTbl[prio >> 3];

Listing 3.6, Removing a task from the ready list.

This code clears the ready bit of the task in OSRdyTbl[] and clears the bit in OSRdyGrp only if all tasks in a group are not ready to run, i.e. all bits in OSRdyTbl[prio >> 3] are 0. Another table lookup is performed, rather than scanning through the table starting with OSRdyTbl[0] to find the highest priority task ready to run. OSUnMapTbl[256] is a priority resolution table (see OS_CORE.C). Eight bits are used to represent when tasks are ready 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 ready to run is accomplished with the following section of code:

y = OSUnMapTbl[OSRdyGrp];

x = OSUnMapTbl[OSRdyTbl[y]]; prio = (y << 3) + x;

Listing 3.7, Finding the highest priority task ready-to-run.

For example, if OSRdyGrp contains 01101000 (binary) then the table lookup OSUnMapTbl[OSRdyGrp] would yield a value of 3, which corresponds to bit #3 in OSRdyGrp. Notes that bit positions are assumed to start on the right with bit #0 being the rightmost bit. Similarly, if OSRdyTbl[3] contained 11100100 (binary) then OSUnMapTbl[OSRdyTbl[3]] would result in a value of 2 (i.e. bit #2). The task priority (prio) would then be 26 (3 * 8 + 2)! Getting a pointer to the OS_TCB for the corresponding task is done by indexing into OSTCBPrioTbl[] using the task's priority.

3.05 Task Scheduling

µC/OS-II always executes the highest priority task ready to run. The determination of which task has the highest priority and thus, which task will be next to run is determined by the scheduler. Task level scheduling is performed by OSSched(). ISR level scheduling is handled by another function ( OSIntExit()) and will be described later. The code for OSSched() is shown in Listing 3.8.

µC/OS-II's task scheduling time is constant irrespective of the number of tasks created in an application. OSSched() exits if called from an ISR (i.e. OSIntNesting > 0) or if scheduling has been disabled because your application called OSSchedLock() at least once (i.e. OSLockNesting > 0) L3.8(1). If OSSched() is not called from an ISR and the scheduler is enabled then OSSched() determines the priority of the highest priority task that is ready to run L3.8(2). A task that is ready to run has its corresponding bit set in OSRdyTbl[]. Once the highest priority task has been found, OSSched() verifies that the highest priority task is not the current task. This is done to avoid an

unnecessary context switch L3.8(3). Note that µC/OS used to obtain OSTCBHighRdy and compared it with OSTCBCur. On 8 and some 16-bit processors, this operation was relatively slow because comparison was made on pointers instead of 8-bit integers as it is now done in µC/OS-II. Als o, there is no point of looking up OSTCBHighRdy in OSTCBPrioTbl[] unless we actually need to do a context switch. The combination of comparing 8-bit values instead of pointers and looking upOSTCBHighRdy only when needed should make µC/OS-II faster than µC/OS on 8 and some 16-bit processors.

void OSSched (void)

{

INT8U y;

 

OS_ENTER_CRITICAL();

 

if ((OSLockNesting | OSIntNesting) == 0) {

(1)

y

= OSUnMapTbl[OSRdyGrp];

(2)

OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

(2)

if (OSPrioHighRdy != OSPrioCur) {

(3)

 

OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

(4)

 

OSCtxSwCtr++;

(5)

}

OS_TASK_SW();

(6)

 

 

}

OS_EXIT_CRITICAL();

}

Listing 3.8, Task Scheduler

To perform a context switch, we need to have OSTCBHighRdy point to the OS_TCB of the highest priority task which is done by indexing into OSTCBPrioTbl[] using OSPrioHighRdy L3.8(4). Next, the statistic counter OSCtxSwCtr is incremented to keep track of the number of context switches L3.8(5). Finally, the macro OS_TASK_SW() is invoked to do the actual context switch L3.8(6).

A context switch simply consist of saving the processor registers on the stack of the task being suspended, and restoring the registers of the higher-priority task from its stack. In µC/OS-II, the stack frame for a ready task always looks as if an interrupt has just occurred and all processor registers were saved onto it. In other words, all that µC/OS-II has to do to run a ready task is to restore all processor registers from the task’s stack and execute a return from interrupt. To switch context, you should implement OS_TASK_SW() so that you simulate an interrupt. Most processors provide either software interrupt or TRAP instructions to accomplish this. The interrupt service routine

(ISR) or trap handler (also called the ‘exception handler’) MUST vector to the assembly language function OSCtxSw(). OSCtxSw() expects to have OSTCBHighRdy point to the OS_TCB of the task to switch in and OSTCBCur point to the OS_TCB of the task being suspended. Refer to chapter 8, Porting µC/OS -II for additional details on OSCtxSw().

All of the code inOSSched() is considered a critical section. Interrupts are disabled to prevent ISRs from setting the

ready bit of one or more tasks during the process of finding the highest priority task ready to run. Note that OSSched() could be written entirely in assembly language to reduce scheduling time. OSSched() was written in

C for readability, portability and also to minimize assembly language.

3.06 Locking and Unlocking the Scheduler

The OSSchedLock() function is used to prevent task rescheduling until its counterpart, OSSchedUnlock(), is called. The code for these functions is shown in Listing 3.9 and 3.10. The task that calls OSSchedLock() keeps control of the CPU even though other higher priority tasks are ready to run. Interrupts, however, are still recognized

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