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

To find out about the latest version of µC/OS-II and how to obtain an upgrade, you should either contact the publisher or check the official µC/OS-II WEB site at www.uCOS-II.com.

3.14 OSEvent???() functions

You probably noticed that OS_CORE.C has four functions that were not mentioned in this chapter. These functions are OSEventWaitListInit(), OSEventTaskRdy(), OSEventTaskWait()and OSEventTO(). I placed these functions in OS_CORE.C but I will explain their use in Chapter 6, Intertask Communication & Synchronization.

Chapter 4

Task Management

We saw in the previous chapter that a task is either an infinite loop function or a function that deletes itself when it is done executing. Note that the task code is not actually deleted, µC/OS-II simply doesn’t know about the task anymore and thus that code will not run. A task look just like any other C function containing a return type and an argument but, it must never return. The return type of a task must always be declared to be void. The functions described in this chapter are found in the file OS_TASK.C. To review, a task must look as shown below.

void YourTask (void *pdata)

{

for (;;) {

/* USER CODE */

Call one of uC/OS-II’s services: OSMboxPend();

OSQPend();

OSSemPend(); OSTaskDel(OS_PRIO_SELF); OSTaskSuspend(OS_PRIO_SELF);

OSTimeDly();

OSTimeDlyHMSM();

/* USER CODE */

}

}

or,

void YourTask (void *pdata)

{

/* USER CODE */ OSTaskDel(OS_PRIO_SELF);

}

This chapter describes the services that allow your application to create a task, delete a task, change a task’s priority, suspend and resume a task and, allow your application to obtain information about a task.

µC/OS-II can manage up to 64 tasks although µC/OS-II reserves the four highest priority tasks and the four lowest priority tasks for its own use. This leaves you with up to 56 application tasks. The lower the value of the priority, the higher the priority of the task. In the current version of µC/OS-II, the task priority number also serves as the task identifier.

4.00 Creating a Task, OSTaskCreate()

In order for µC/OS-II to manage your task, you must ‘create’a task. You create a task by passing its address along with other arguments to one of two functions: OSTaskCreate() or OSTaskCreateExt(). OSTaskCreate()

is backward compatible with µC/OS while OSTaskCreateExt() is an ‘extended’version of OSTaskCreate() and provides additional features. A task can either be created using either function. A task can be created prior to the start of multitasking or by another task. You MUST create at least one task before you start multitasking (i.e. before you call OSStart()). A task cannot be created by an ISR.

The code for OSTaskCreate() is shown in listing 4.1. As can be seen, OSTaskCreate() requires four arguments. task is a pointer to the task code, pdata is a pointer to an argument that will be passed to your task when it starts executing, ptos is a pointer to the top of the stack that will be assigned to the task (see section 4.02, Task Stacks) and finally, prio is the desired task priority.

INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)

{

void *psp; INT8U err;

if (prio > OS_LOWEST_PRIO) {

(1)

return (OS_PRIO_INVALID);

 

}

 

OS_ENTER_CRITICAL();

 

if (OSTCBPrioTbl[prio] == (OS_TCB *)0) {

(2)

OSTCBPrioTbl[prio] = (OS_TCB *)1;

(3)

OS_EXIT_CRITICAL();

(4)

psp = (void *)OSTaskStkInit(task, pdata, ptos, 0);

(5)

err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0);

(6)

if (err == OS_NO_ERR) {

(7)

OS_ENTER_CRITICAL();

 

OSTaskCtr++;

(8)

OSTaskCreateHook(OSTCBPrioTbl[prio]);

(9)

OS_EXIT_CRITICAL();

 

if (OSRunning) {

(10)

OSSched();

(11)

}

 

} else {

 

OSTCBPrioTbl[prio] = (OS_TCB *)0;

(12)

}

 

return (err);

 

} else { OS_EXIT_CRITICAL();

return (OS_PRIO_EXIST);

}

}

Listing 4.1, OSTaskCreate()

OSTaskCreate() starts by checking that the task priority is valid L4.1(1). The priority of a task must be a number between 0 and OS_LOWEST_PRIO, inclusively. Next, OSTaskCreate() makes sure that a task has not already

been created at the desired priority L4.1(2). With µC/OS-II, all tasks must have a unique priority. If the desired priority is free then µC/OS-II ‘reserves’the priority by placing a non -NULL pointer in OSTCBPrioTbl[] L4.1(3).

This allows OSTaskCreate() to re-enable interrupts L4.1(4) while it sets up the rest of the data structures for the task.

OSTaskCreate() then calls OSTaskStkInit() L4.1(5) which is responsible for setting up the task stack. This function is processor specific and is found in OS_CPU_C.C. Refer to Chapter 8, Porting µC/OS-II for details on how to implement OSTaskStkInit(). If you already have a port of µC/OS-II for the processor you are intending to use then, you don’t need to be concerned about implementation details. OSTaskStkInit() returns the new top-of-stack (psp) which will be saved in the task’s OS_TCB. You should note that the fourth argument (i.e. opt) to

OSTaskStkInit() is set to 0. This is because, unlike OSTaskCreateExt(), OSTaskCreate() does not support options and thus, there are no options to pass to OSTaskStkInit().

µC/OS-II supports processors that have stacks that grow from either high memory to low memory or from low memory to high memory. When you call OSTaskCreate(), you must know how the stack grows (see OS_CPU.H (OS_STACK_GROWTH) of the processor you are using) because you must pass the task’s top-of-stack to OSTaskCreate() which can either be the lowest memory location of the stack or the highest memory location of the stack.

Once OSTaskStkInit() has completed setting up the stack, OSTaskCreate() calls OSTCBInit() L4.1(6) to obtain and initialize an OS_TCB from the pool of free OS_TCBs. The code for OSTCBInit() is shown in listing 4.2 but is found in OS_CORE.C instead of OS_TASK.C. OSTCBInit() first tries to obtain an OS_TCB from the OS_TCB pool L4.2(1). If the pool contained a free OS_TCB L4.2(2) then the OS_TCB is initialized L4.2(3). Note that once an OS_TCB is allocated, we can re-enable interrupts because, at this point, the creator of the task ‘owns’the OS_TCB and it cannot be corrupted by another concurrent task creation. We can thus proceed to initialize some of the OS_TCB fields with interrupts enabled.

INT8U OSTCBInit (INT8U prio,

OS_STK *ptos, OS_STK *pbos, INT16U id,

INT16U stk_size, void *pext, INT16U

opt)

{

 

 

 

OS_TCB *ptcb;

 

 

 

OS_ENTER_CRITICAL();

 

 

 

ptcb = OSTCBFreeList;

 

 

(1)

if (ptcb != (OS_TCB *)0) {

 

(2)

OSTCBFreeList

= ptcb->OSTCBNext;

 

OS_EXIT_CRITICAL();

 

 

 

ptcb->OSTCBStkPtr

= ptos;

(3)

ptcb->OSTCBPrio

= (INT8U)prio;

 

ptcb->OSTCBStat

= OS_STAT_RDY;

 

ptcb->OSTCBDly

= 0;

 

 

#if OS_TASK_CREATE_EXT_EN

= pext;

 

ptcb->OSTCBExtPtr

 

ptcb->OSTCBStkSize

= stk_size;

 

ptcb->OSTCBStkBottom = pbos;

 

ptcb->OSTCBOpt

= opt;

 

ptcb->OSTCBId

= id;

 

 

#else

 

 

 

 

pext

=

pext;

 

 

stk_size

=

stk_size;

 

 

pbos

=

pbos;

 

 

opt

= opt;

 

#endif

id

= id;

 

 

 

 

 

#if OS_TASK_DEL_EN

 

 

 

#endif

ptcb->OSTCBDelReq

= OS_NO_ERR;

 

 

 

 

 

 

ptcb->OSTCBY

= prio >> 3;

 

 

ptcb->OSTCBBitY

= OSMapTbl[ptcb->OSTCBY];

 

 

ptcb->OSTCBX

= prio & 0x07;

 

 

ptcb->OSTCBBitX

= OSMapTbl[ptcb->OSTCBX];

 

#if

OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_SEM_EN

#endif

ptcb->OSTCBEventPtr

= (OS_EVENT *)0;

 

 

 

 

 

#if

OS_MBOX_EN || (OS_Q_EN && (OS_MAX_QS >= 2))

 

#endif

ptcb->OSTCBMsg

= (void *)0;

 

 

 

 

 

 

OS_ENTER_CRITICAL();

 

 

(4)

 

OSTCBPrioTbl[prio]

= ptcb;

(5)

 

ptcb->OSTCBNext

= OSTCBList;

 

 

ptcb->OSTCBPrev

= (OS_TCB *)0;

 

 

if (OSTCBList != (OS_TCB *)0) {

 

 

OSTCBList->OSTCBPrev = ptcb;

 

 

}

 

 

 

 

OSTCBList

 

= ptcb;

 

 

OSRdyGrp

 

|= ptcb->OSTCBBitY;

(6)

 

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

 

 

OS_EXIT_CRITICAL();

 

 

 

 

return (OS_NO_ERR);

 

 

(7)

} else {

 

 

 

 

OS_EXIT_CRITICAL();

 

 

 

return (OS_NO_MORE_TCB);

}

}

Listing 4.2, OSTCBInit()

We disable interrupts L4.2(4) when we need to insert the OS_TCB into the doubly linked list of tasks that have been created L4.2(5). The list starts at OSTCBList and the OS_TCB of a new task is always inserted at the beginning of the list. Finally, the task is made ready to run L4.2(6) and OSTCBInit() returns to its caller (OSTaskCreate()) with a code indicating that an OS_TCB has been allocated and initialized L4.2(7).

We can now continue the discussion of OSTaskCreate() (see listing 4.1) Upon return from OSTCBInit(), OSTaskCreate() checks the return code L4.1(7) and upon success, increments the counter of the number of tasks created, OSTaskCtr L4.1(8). If OSTCBInit() failed, the priority level is relinquished by setting the entry in

OSTCBPrioTbl[prio] to 0 L4.1(12). OSTaskCreate() then calls OSTaskCreateHook() L4.1(9) which is a user specified function that allows you to extend the functionality of OSTaskCreate(). For example, you

could initialize and store the contents of floating-point registers, MMU registers or anything else that can be associated with a task. You would, however, typically store this additional information in memory that would be allocated by your application. OSTaskCreateHook() can be declared either in OS_CPU_C.C (if OS_CPU_HOOKS_EN is set to 1) or elsewhere. Note that interrupts are disabled when OSTaskCreate() calls OSTaskCreateHook(). Because of this, you should keep the code in this function to a minimum because it can directly impact interrupt

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