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

3.10 Clock Tick

µC/OS-II requires that you provide a periodic time source to keep track of time delays and timeouts. A tick should occur between 10 and 100 times per second, or Hertz. The faster the tick rate, the higher the overhead imposed on the system. The actual frequency of the clock tick depends on the desired tick resolution of your application. You can obtain a tick source by either dedicating a hardware timer, or generating an interrupt from an AC power line (50/60 Hz) signal.

You MUST enable ticker interrupts AFTER multitasking has started, i.e. after calling OSStart(). In other words, you should initialize and tick interrupts in the first task that executes following a call to OSStart(). A common mistake is to enable ticker interrupts between calling OSInit() and OSStart() as shown in listing 3.18.

void main(void)

 

 

{

 

 

.

 

 

.

 

 

OSInit();

/* Initialize µC/OS-II

*/

.

 

 

.

 

 

/* Application initialization code ...

*/

/* ... Create at least on task by calling OSTaskCreate()

*/

.

 

 

.

 

 

Enable TICKER interrupts; /* DO NOT DO THIS HERE!!!

*/

.

 

 

.

 

 

OSStart();

/* Start multitasking

*/

}

 

 

Listing 3.18, Incorrect way to start the ticker.

What could happen (and it has happened) is that the tick interrupt could be serviced before µC/OS -II starts the first task. At this point, µC/OS-II is in an unknown state and will cause your application to crash.

µC/OS-II’s clock tick is serviced by calling OSTimeTick() from a tick ISR. The tick ISR follows all the rules described in the previous section. The pseudo code for the tick ISR is shown in listing 3.19. This code must be written in assembly language because you cannot access CPU registers directly from C.

void OSTickISR(void)

{

Save processor registers;

Call OSIntEnter() or increment OSIntNesting; Call OSTimeTick();

Call OSIntExit();

Restore processor registers;

Execute a return from interrupt instruction;

}

Listing 3.19, Pseudo code for Tick ISR.

The code for OSTimeTick() is shown in listing 3.20. OSTimeTick() starts by calling a user definable function (OSTimeTickHook()) which can be used to extend the functionality of OSTimeTick() L3.20(1). I decided to call OSTimeTickHook() first to give your application a chance to do something as soon as the tick is serviced because you may have some time critical work to do. Most of the work done byOSTimeTick() basically consist of decrementing the OSTCBDly field for each OS_TCB (if it’s nonzero). OSTimeTick() follows the chain of OS_TCB starting at OSTCBList L3.20(2) until it reaches the idle task L3.20(3). When the OSTCBDly field of a task's OS_TCB is decremented to zero, the task is made ready to run L3.20(4). The task is not readied, however, if it was explicitly suspended by OSTaskSuspend() L3.20(5). The execution time of OSTimeTick() is directly proportional to the number of tasks created in an application.

void OSTimeTick (void)

{

OS_TCB *ptcb;

 

 

OSTimeTickHook();

 

(1)

ptcb = OSTCBList;

 

(2)

while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {

(3)

OS_ENTER_CRITICAL();

 

 

if (ptcb->OSTCBDly != 0) {

 

 

if (--ptcb->OSTCBDly == 0) {

 

 

if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {

(5)

OSRdyGrp

|= ptcb->OSTCBBitY;

(4)

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

 

} else {

 

 

ptcb->OSTCBDly = 1;

 

 

}

 

 

}

 

 

}

 

 

ptcb = ptcb->OSTCBNext;

 

 

OS_EXIT_CRITICAL();

 

 

}

 

 

OS_ENTER_CRITICAL();

 

(7)

OSTime++;

 

(6)

OS_EXIT_CRITICAL();

 

 

}

Listing 3.20, Code to service a tick.

OSTimeTick() also accumulates the number of clock ticks since power up in an unsigned 32-bit variable called OSTime L3.20(6). Note that I disable interrupts L3.20(7) before incrementing OSTime because on some processors, a 32-bit increment will most likely be done using multiple instructions.

If you don't like to make ISRs any longer than they must be, OSTimeTick() can be called at the task level as shown

in listing 3.21. To do this, you would create a task which has a higher priority than all your application tasks. The tick ISR would need to signal this high priority task by using either a semaphore or a message mailbox.

void TickTask (void *pdata)

 

{

 

pdata = pdata;

 

for (;;) {

 

OSMboxPend(...);

/* Wait for signal from Tick ISR */

OSTimeTick();

 

}

 

}

 

Listing 3.21, Code to service a tick.

You would obviously need to create a mailbo x (initialized to NULL) which would signal the task that a tick interrupt occurred. The tick ISR would now look as shown in listing 3.22.

void OSTickISR(void)

{

Save processor registers;

Call OSIntEnter() or increment OSIntNesting;

Post a ‘dummy’ message (e.g. (void *)1) to the tick mailbox;

Call OSIntExit();

Restore processor registers;

Execute a return from interrupt instruction;

}

Listing 3.22, Code to service a tick.

3.11 µC/OS-II Initialization

A requirement of µC/OS-II is that you call OSInit() before you call any of its other services. OSInit() initializes all of µC/OS-II’s variables and data structures (see OS_CORE.C).

OSInit() creates the idle task (OSTaskIdle()) which is always ready -to-run. The priority of OSTaskIdle() is always set to OS_LOWEST_PRIO. If OS_TASK_STAT_EN and OS_TASK_CREATE_EXT_EN (see OS_CFG.H) are both set to 1, OSInit() also creates the statistic task, OSTaskStat() and makes it ready-to-run. The priority of OSTaskStat() is always set to OS_LOWEST_PRIO – 1.

Figure 3-7 shows the relationship between some of µC/OS-II’s variables and data structures after calling OSInit(). The illustration assumes that:

1.OS_TASK_STAT_EN is set to 1 in OS_CFG.H

2.OS_LOWEST_PRIO is set to 63 in OS_CFG.H

3.OS_MAX_TASKS is set to a value higher that 2 in OS_CFG.H

The Task Control Blocks (OS_TCBs) of these two tasks are chained together in a doubly -linked list. OSTCBList points to the beginning of this chain. When a task is created, it is always placed at the beginning of the list. In other words, OSTCBList always points to the OS_TCB of last task created. The ends of the chain point to NULL (i.e. 0).

Because both tasks are ready-to-run, their corresponding bit in OSRdyTbl[] are set to 1. Also, because the bit of both tasks are on the same row in OSRdyTbl[], only one bit in OSRdyGrp is set to 1.

 

 

OSRdyGrp

 

Ready List

 

 

 

 

 

 

 

 

 

 

1

0

0

0

0

0

0

0

 

 

OSRdyTbl[]

 

 

OSTCBPrioTbl[]

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

[0]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

[1]

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

0

 

[2]

 

 

 

 

 

 

 

 

0

 

[3]

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

0

 

[4]

 

 

 

 

 

 

 

 

0

 

[5]

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

0

 

[6]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

 

 

 

 

 

 

 

 

 

 

1

1

0

0

0

0

0

0

 

0

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

[OS_LOWEST_PRIO - 1]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[OS_LOWEST_PRIO]

 

 

 

 

 

 

 

 

 

 

OSTaskStat()

OSTaskIdle()

 

 

 

 

 

 

 

 

 

 

 

 

OS_TCB

 

 

 

 

OS_TCB

 

 

OSTCBList

OSPrioCur

= 0

0

OSPrioHighRdy = 0

OSTCBCur

= NULL

 

OSTCBHighRdy

= NULL

 

OSTime

= 0L

 

OSIntNesting

= 0

 

OSLockNesting = 0

 

OSCtxSwCtr

= 0

 

OSTaskCtr

= 2

 

OSRunning

= FALSE

 

OSCPUUsage

= 0

 

OSIdleCtrMax

= 0L

 

OSIdleCtrRun

= 0L

 

OSIdleCtr

= 0L

 

OSStatRdy

= FALSE

 

OSTCBStkPtr

OSTCBExtPtr = NULL

OSTCBStkBottom

OSTCBStkSize = stack size

OSTCBId = OS_LOWEST_PRIO

OSTCBNext

OSTCBPrev

OSTCBEventPtr = NULL

OSTCBMsg = NULL

OSTCBDly = 0

OSTCBStat = OS_STAT_RDY

OSTCBPrio = OS_LOWEST_PRIO-1

OSTCBX = 6

OSTCBY = 7

OSTCBBitX = 0x40

OSTCBBitY = 0x80

OSTCBDelReq = FALSE

OSTCBStkPtr

 

 

 

 

 

 

OSTCBExtPtr = NULL

 

 

 

 

OSTCBStkBottom

 

 

 

 

 

OSTCBStkSize = stack size

 

 

 

 

OSTCBId = OS_LOWEST_PRIO

 

 

 

 

OSTCBNext

 

 

 

 

OSTCBPrev

 

 

 

 

OSTCBEventPtr = NULL

 

 

 

 

OSTCBMsg = NULL

 

 

 

0

OSTCBDly = 0

 

 

 

OSTCBStat = OS_STAT_RDY

 

 

OSTCBPrio = OS_LOWEST_PRIO

 

 

 

 

OSTCBX = 7

 

 

 

 

OSTCBY = 7

 

 

 

 

OSTCBBitX = 0x80

 

 

 

 

OSTCBBitY = 0x80

 

 

 

 

OSTCBDelReq = FALSE

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Task Stack

Task Stack

Figure 3-7, Data structures after calling OSInit()

µC/OS-II also initializes four pools of free data structures as shown in figure 3-8. Each of these pools are singly linked lists and allows µC/OS-II to quickly obtain and return an element from and to a pool. Note that the number of free OS_TCBs in the free pool is determined by OS_MAX_TASKS specified in OS_CFG.H. µC/OS -II automatically allocates OS_N_SYS_TASKS (see uCOS_II.H) OS_TCB entries automatically. This of course allows for sufficient task control blocks for the statistic task and the idle task. The lists pointed to by OSEventFreeList and OSQFreeList will be discussed in Chapter 6, Intertask Communication & Synchronization . The list pointed to by OSMemFreeList will be discussed in Chapter 7, Memory Management.

OSTCBFreeList

OS_MAX_TASKS

OS_TCB

OS_TCB

 

OS_TCB

 

OS_TCB

 

OSTCBStkPtr

OSTCBStkPtr

 

OSTCBStkPtr

 

OSTCBStkPtr

 

OSTCBExtPtr

OSTCBExtPtr

 

OSTCBExtPtr

 

OSTCBExtPtr

 

OSTCBStkBottom

OSTCBStkBottom

 

OSTCBStkBottom

 

OSTCBStkBottom

 

OSTCBStkSize

OSTCBStkSize

 

OSTCBStkSize

 

OSTCBStkSize

 

OSTCBId

OSTCBId

 

OSTCBId

 

OSTCBId

 

OSTCBNext

 

OSTCBNext

 

OSTCBNext

 

OSTCBNext

 

0

OSTCBPrev

OSTCBPrev

 

OSTCBPrev

 

OSTCBPrev

OSTCBEventPtr

OSTCBEventPtr

 

OSTCBEventPtr

 

OSTCBEventPtr

 

OSTCBMsg

OSTCBMsg

 

OSTCBMsg

 

OSTCBMsg

 

OSTCBDly

OSTCBDly

 

OSTCBDly

 

OSTCBDly

 

OSTCBStat

OSTCBStat

 

OSTCBStat

 

OSTCBStat

 

OSTCBPrio

OSTCBPrio

 

OSTCBPrio

 

OSTCBPrio

 

OSTCBX

OSTCBX

 

OSTCBX

 

OSTCBX

 

OSTCBY

OSTCBY

 

OSTCBY

 

OSTCBY

 

OSTCBBitX

OSTCBBitX

 

OSTCBBitX

 

OSTCBBitX

 

OSTCBBitY

OSTCBBitY

 

OSTCBBitY

 

OSTCBBitY

 

OSTCBDelReq

OSTCBDelReq

 

OSTCBDelReq

 

OSTCBDelReq

 

OSEventFreeList

OSQFreeList

OS_MAX_EVENTS

OS_EVENT

OS_EVENT

OS_EVENT

OS_EVENT

 

OSEventPtr

OSEventPtr

OSEventPtr

OSEventPtr

0

OSEventTbl[]

OSEventTbl[]

OSEventTbl[]

OSEventTbl[]

 

OSEventCnt

OSEventCnt

OSEventCnt

OSEventCnt

 

OSEventType

OSEventType

OSEventType

OSEventType

 

OSEventGrp

OSEventGrp

OSEventGrp

OSEventGrp

 

 

 

OS_MAX_QS

 

 

OS_Q

OS_Q

OS_Q

OS_Q

 

OSQPtr

OSQPtr

OSQPtr

OSQPtr

0

OSQStart

OSQStart

OSQStart

OSQStart

 

OSQEnd

OSQEnd

OSQEnd

OSQEnd

 

OSQIn

OSQIn

OSQIn

OSQIn

 

OSQOut

OSQOut

OSQOut

OSQOut

 

OSQSize

OSQSize

OSQSize

OSQSize

 

OSQEntries

OSQEntries

OSQEntries

OSQEntries

 

OS_MAX_MEM_PART

OSMemFreeList

OS_MEM

OS_MEM

OS_MEM

OS_MEM

 

OSMemAddr

OSMemAddr

OSMemAddr

OSMemAddr

 

OSMemFreeList

OSMemFreeList

OSMemFreeList

OSMemFreeList

0

OSMemBlkSize

OSMemBlkSize

OSMemBlkSize

OSMemBlkSize

OSMemNBlks

OSMemNBlks

OSMemNBlks

OSMemNBlks

 

OSNFree

OSNFree

OSNFree

OSNFree

 

Figure 3-8, Free Pools

3.12 Starting µC/OS-II

You start multitasking by calling OSStart() . Before you start µC/OS-II, however, you MUST create at least one of your application tasks as shown in listing 3.23.

void main (void)

 

 

{

 

 

OSInit();

/* Initialize uC/OS-II

*/

.

 

 

.

Create at least 1 task using either OSTaskCreate() or OSTaskCreateExt();

.

 

.

 

OSStart();

/* Start multitasking! OSStart() will not return */

}

 

 

Listing 3.23, Initializing and Starting µC/OS-II.

The code for OSStart() is shown in listing 3.24. When called, OSStart() finds the OS_TCB of the highest priority task that you have created (done through the ready list) L3.24(1). Then, OSStart() calls OSStartHighRdy() L3.24(2) (see OS_CPU_A.ASM) for the processor being used. Basically, OSStartHighRdy() restores the CPU registers by popping them off the task’s stack and then, executes a return from interrupt instruction which forces the CPU to execute your task’s code (see Section 9.04.01, OS_CPU_A.ASM, OSStartHighRdy() for details on how this is done for the 80x86). You should note that OSStartHighRdy() will never return to OSStart().

void OSStart (void)

{

INT8U y; INT8U x;

if (OSRunning == FALSE) {

 

y

= OSUnMapTbl[OSRdyGrp];

 

x

= OSUnMapTbl[OSRdyTbl[y]];

 

OSPrioHighRdy = (INT8U)((y << 3) + x);

 

OSPrioCur

= OSPrioHighRdy;

 

OSTCBHighRdy

= OSTCBPrioTbl[OSPrioHighRdy];

(1)

OSTCBCur

= OSTCBHighRdy;

 

OSStartHighRdy();

(2)

}

 

 

}

Listing 3.24, Starting multitasking.

Figure 3-9 shows the contents of the variables and data structures after multitasking has started. Here I assumed that the task you created has a priority of 6. You will notice that OSTaskCtr indicates that three tasks have been created, OSRunning is set toTRUE indicating that multitasking has started,OSPrioCur andOSPrioHighRdy contain the priority of your application task and, OSTCBCur and OSTCBHighRdy both point to the OS_TCB of your task.

 

 

 

 

OSRdyGrp

 

Ready List

 

 

 

 

 

 

 

OSTime

= 0L

1

0

0

0

0

0

0

1

 

OSRdyTbl[]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OSIntNesting

= 0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OSLockNesting

= 0

 

 

 

 

 

 

 

0

1

0

0

0

0

0

0

 

 

OSCtxSwCtr

= 0

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

OSTaskCtr

= 3

 

 

 

 

 

 

 

 

 

OSRunning

= TRUE

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

OSCPUUsage

= 0

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

OSIdleCtrMax

= 0L

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

 

 

OSIdleCtrRun

= 0L

 

 

 

 

 

 

 

OSTCBPrioTbl[]

OSIdleCtr

= 0L

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

OSStatRdy

= FALSE

 

 

 

 

 

 

 

0

0

0

0

0

0

0

0

0

[0]

 

 

 

 

 

 

 

 

 

0

[1]

OSPrioCur

= 6

 

 

 

 

 

 

 

1

1

0

0

0

0

0

0

0

[2]

 

 

 

 

 

 

 

0

[3]

OSPrioHighRdy = 6

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

[4]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

[5]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[6]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

[OS_LOWEST_PRIO - 1]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[OS_LOWEST_PRIO]

 

YouAppTask()

 

 

 

OSTaskStat()

 

 

 

OSTaskIdle()

 

 

OS_TCB

 

 

 

 

 

 

 

OS_TCB

 

 

 

 

 

 

OS_TCB

 

OSTCBCur

OSTCBHighRdy

OSTCBList

0

OSTCBStkPtr OSTCBExtPtr = NULL

OSTCBStkBottom OSTCBStkSize = stack size

OSTCBId = 6

OSTCBNext

OSTCBPrev

OSTCBEventPtr = NULL OSTCBMsg = NULL

OSTCBDly = 0

OSTCBStat = OS_STAT_RDY

OSTCBPrio = 6

OSTCBX = 6

OSTCBY = 0 OSTCBBitX = 0x40

OSTCBBitY = 0x01 OSTCBDelReq = FALSE

OSTCBStkPtr

OSTCBExtPtr = NULL

OSTCBStkBottom

OSTCBStkSize = stack size

OSTCBId = OS_LOWEST_PRIO

OSTCBNext

OSTCBPrev

OSTCBEventPtr = NULL

OSTCBMsg = NULL

OSTCBDly = 0

OSTCBStat = OS_STAT_RDY

OSTCBPrio = OS_LOWEST_PRIO-1

OSTCBX = 6

OSTCBY = 7

OSTCBBitX = 0x40

OSTCBBitY = 0x80

OSTCBDelReq = FALSE

OSTCBStkPtr

 

 

 

 

 

 

OSTCBExtPtr = NULL

 

 

 

 

OSTCBStkBottom

 

 

 

 

 

OSTCBStkSize = stack size

 

 

 

 

OSTCBId = OS_LOWEST_PRIO

 

 

 

 

OSTCBNext

 

 

 

 

OSTCBPrev

 

 

 

 

OSTCBEventPtr = NULL

 

 

 

 

OSTCBMsg = NULL

 

 

 

0

OSTCBDly = 0

 

 

 

OSTCBStat = OS_STAT_RDY

 

 

OSTCBPrio = OS_LOWEST_PRIO

 

 

 

 

OSTCBX = 7

 

 

 

 

OSTCBY = 7

 

 

 

 

OSTCBBitX = 0x80

 

 

 

 

OSTCBBitY = 0x80

 

 

 

 

OSTCBDelReq = FALSE

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Task Stack

Task Stack

Task Stack

Figure 3-9, Variables and Data Structures after calling OSStart()

3.13 Obtaining µC/OS-II’s version

You can obtain the current version of µC/OS-II from your application by calling OSVersion(). OSVersion() returns the version number multiplied by 100. In other words, version 1.00 would be returned as 100.

INT16U OSVersion (void)

{

return (OS_VERSION);

}

Listing 3.25, Getting µC/OS-II’s version.

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