...
Figure 3.1 shows the µC/OS-II architecture and its relationship with the hardware. When you use µC/OS-II in an application, you are responsible for providing the Application Software and the µC/OS-II Configuration sections. This book and CD contain all the source code for the Processor-Independent Code section as well as the Processor-Specific Code section for the Intel 80x86, real mode, large model. If you intend to use µC/OS-II on a different processor, you need to either obtain a copy of a port for the processor you intend to use or write one yourself if the desired processor port is not available. Check the official µC/OS-II Web site at www.micrium.com for a list of available ports.
Figure 3.1 µC/OS-II File Structure.
Critical Sections, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
...
Multitasking is started by calling OSStart()
. OSStart()
MUST only be called once during startup and starts the highest priority task that has been created during your initialization code. The highest priority task is thus placed in the TASK RUNNING state. Only one task can be running at any given time. A ready task will not run until all higher priority tasks are either placed in the wait state or are deleted.
Figure 3.2 Task states.
The running task may delay itself for a certain amount of time by calling either OSTimeDly()
or OSTimeDlyHMSM()
. This task would be placed in the TASK WAITING state until the time specified in the call expires. Both of these functions force an immediate context switch to the next highest priority task that is ready to run. The delayed task is made ready to run by OSTimeTick()
when the desired time delay expires (see section 3.??, Clock Tick). OSTimeTick()
is an internal function to µC/OS-II and thus, you don’t have to actually call this function from your code.
...
The maximum number of tasks (OS_MAX_TASKS) that an application can have is specified in OS_CFG.H
and determines the number of OS_TCBs allocated for your application. You can reduce the amount of RAM needed by setting OS_MAX_TASKS
to the actual number of tasks needed in your application. All OS_TCBs are placed in OSTCBTbl[]
. Note that µC/OS-II allocates OS_N_SYS_TASKS
(see uCOS_II.H) extra OS_TCBs for internal use. Currently, one is used for the idle task, and another is used for the statistic task (if OS_TASK_STAT_EN
in OS_CFG.H
is set to 1). When µC/OS-II is initialized, all OS_TCBs in the table are linked in a singly-linked list of free OS_TCBs, as shown in Figure 3.3. When a task is created, the OS_TCB
pointed to by OSTCBFreeList
is assigned to the task, and OSTCBFreeList
is adjusted to point to the next OS_TCB
in the chain. When a task is deleted, its OS_TCB
is returned to the list of free OS_TCBs.
...
of free OS_TCBs.
An OS_TCB
is initialized by the function OS_TCBInit()
(see Listing 3.6) when a task is created. OS_TCBInit()
is called by either OSTaskCreate()
or OSTaskCreateExt()
(see Chapter 4, Task Management). OS_TCBInit()
receives seven arguments:
prio | is the task priority, |
ptos | is a pointer to the top of stack once the stack frame has been built by |
pbos | is a pointer to the stack bottom and is stored in the .OSTCBStkBottom field of the OS_TCB. |
id | is the task identifier and is saved in the .OSTCBId field. |
stk_size | is the total size of the stack and is saved in the .OSTCBStkSize field of the OS_TCB. |
pext | is the value to place in the .OSTCBExtPtr field of the OS_TCB. |
opt | is the |
(5) The presence of the flag .OSTCBDelReq in OS_TCB
depends on whether OS_TASK_DEL_EN
has been enabled (see OS_CFG.H
). In other words, if you never intend to delete tasks, you can save yourself the storage area of a BOOLEAN in every single OS_TCB.
(6) In order to save a bit of processing time during scheduling, OS_TCBInit()
precalculates some fields. I decided to exchange execution time in favor of data space storage.
(7) If you don’t intend to use any semaphores, mutexes, message mailboxes and message queues in your application then the field .OSTCBEventPtr in the OS_TCB
would not be present.
(8) If you enabled event flags (i.e. you set OS_FLAGS_EN
to 1 in OS_CFG.H
) then the pointer to an event flag node is intitialized to point to nothing because the task is not waiting for an event flag, it’s only being created.
(9) In V2.04, I added a call to a function that can be defined in the processor’s port file – OSTCBInitHook()
. This allows you to add extensions to the OS_TCB. 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. However, you would typically store this additional information in memory that would be allocated by your application. Note that interrupts are enabled when OS_TCBInit()
calls OSTCBInitHook()
.
(10) OS_TCBInit()
disables interrupts when it needs to insert the OS_TCB
into the doubly linked list of tasks that have been created.
(11) OS_TCBInit()
then calls OSTaskCreateHook()
, which is a user-specified function that allows you to extend the functionality of OSTaskCreate()
or OSTaskCreateExt()
. OSTaskCreateHook()
can be declared either in OS_CPU_C.C
(if OS_CPU_HOOKS_EN
is set to 1) or elsewhere (if OS_CPU_HOOKS_EN
is set to 0). Note that interrupts are enabled when OS_TCBInit()
calls OSTaskCreateHook()
.
You should note that I could have called only one of the two hook functions: OSTCBInitHook()
or OSTaskCreateHook()
. The reason there are two functions is to allow you to group (i.e. encapsulate) items that are tied with the OS_TCB
in OSTCBInitHook()
and other task related initialization in OSTaskCreateHook()
.
(12) The list starts at OSTCBList
, and the OS_TCB
of a new task is always inserted at the beginning of the list.
...
. |
Ready List
Each task is assigned a unique priority level between 0 and OS_LOWEST_PRIO
, inclusive (see OS_CFG.H
). Task priority OS_LOWEST_PRIO
is always assigned to the idle task when µC/OS-II is initialized. 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).
...