Kernel Structure - structural aspects of μC/OS-II
Kernel Structure - structural aspects of μC/OS-II
Kernel Structure - structural aspects of μC/OS-II
906714 劉曙銘
906792 劉健民
904392 彭啟廷
Table of Contents
Critical Section
Task
Scheduling
ISR (Interrupt Service Routine)
Clock Ticker
Multitasking
Appendix
Critical Section
Shared resource is protected from being accessed
simultaneously by either tasks or ISRs.
μC/OS-II needs to disable interrupts in order to
access critical section of code, and re-enable
interrupts when done.
Kernel Service
OS_ENTER_CRITICAL ()
OS_EXIT_CRITICAL ()
Reference
OS_CPU.H
Task
Internal
A task is an infinite loop.
void myTask (void *pdata)
{
for (;;) {
// USER CODE, Call one of kernel services
}
}
A task that deletes itself when done.
void myTask (void *pdata)
{
// USER CODE
OSTaskDel (OS_PRIO_SELF);
}
64 tasks at most including two system tasks.
Kernel Service
OSTaskCreate()
OSTaskCreateExt()
Task (Cont 1)
Priority
The lower the priority number, the higher the priority of task.
Reserved Priority
0,1,2,3, OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2
OS_LOWEST_PRIO-1 and OS_LOWEST_PRIO
56 application tasks in fact.
Kernel Service
OSTaskChangePrio()
OSTaskDel()
Refenence
OS_CFG.H
Task (Cont 2)
Task States
WAITING
OSMBoxPost() OSMBoxPend()
OSQPost() OSQPend()
OSQPostFront()
OSTaskDel() OSSemPost() OSSemPend()
OSTaskResume() OSTaskSuspend()
OSTimeDlyResume() OSTimeDly()
OSTimeTick() OSTimeDlyHMSM()
OSTaskCreate()
OSTaskCreateExt() OSStart()
OSIntExit() Interrupt
OS_TASK_SW()
DORMANT READY RUNNING ISR
OSIntExit()
OSTaskDel()
Task is Preempted
OSTaskDel()
Task (Cont 3)
X
Figure [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
(Idle Task)
0 0 Y Y Y X X X
OS_ENTER_CRITICAL();
if ((OSLockNesting | OSIntNesting) == 0) {
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OS_TASK_SW();
}
}
OS_EXIT_CRITICAL();
}
Scheduling (Cont 2)
Source Code
Locking the Scheduler
void OSSchedLock (void)
{
if (OSRunning == TRUE) {
OS_ENTER_CRITICAL();
OSLockNesting++;
OS_EXIT_CRITICAL();
}
}
Unlocking the Scheduler
void OSSchedUnlock (void)
{
if (OSRunning == TRUE) {
OS_ENTER_CRITICAL();
if (OSLockNesting > 0) {
OSLockNesting--;
if ((OSLockNesting | OSIntNesting) == 0) {
OS_EXIT_CRITICAL();
OSSched();
} else {
OS_EXIT_CRITICAL();
}
} else {
OS_EXIT_CRITICAL();
}
}
}
Scheduling (Cont 3)
Caution
OSSchedLock() and OSSchedUnlock() must be used in
pairs.
The task that calls OSSchedUnlock() keeps control of
CPU forever!
After calling OSSchedLock(), your task must not make
any kernel service that will suspend execution of the
current task.
No other task will be allowed to run!
Reference
OS_CORE.C
ISR
Internal
A piece of code in assembly language.
Pseudo Code
myISR:
Save all CPU registers;
Call OSIntEnter();
Execute user assembly to service ISR;
Call OSIntExit();
Restore all CPU registers;
Execute a return from interrupt instruction;
OSIntEnter()
Notify μC/OS-II about beginning of ISR.
OSIntExit()
Notify μC/OS-II about leaving of ISR.
Reference
OS_CPU_A.ASM
ISR (Cont 1)
Source Code
void OSIntEnter (void)
{
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
}
void OSIntExit (void)
{
OS_ENTER_CRITICAL();
if ((--OSIntNesting | OSLockNesting) == 0) {
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw();
}
}
OS_EXIT_CRITICAL();
}
ISR (Cont 2)
Time
Task Response
Interrupt Request (1)
µC/OS-IIor your application
has interrupts disabled.
(2) Interrupt Recovery
Call Flow TASK TASK
No New HPT or,
Vectoring OSLockNesting > 0 Return from interrupt
(3) (9)
Saving Context Restore conte xt
(4) (8)
Notify kernel:
OSIntEnter() or, Notify kernel: OSIntExit()
OSIntNesting++ User ISR code (7)
(5)
(6)
Interrupt Response Notify kernel: OSIntExit()
(10)
Restore context
(11)
Return from interrupt
ISR signals a task
New HPT (12)
TASK
Interrupt Recovery
Task Response
ISR (Cont 3)
Run-time Stack
LOW MEMORY
SP must be adjusted
to point here.
HIGH MEMORY
Clock Ticker
Internal
Periodic time source to keep track of time delay and timeouts.
OSTCBDly in TCB
The higher the tick rate, the higher the overhead.
Must be enabled after multitasking has started.
Enable ticker interrupts at first task!
Source
Hardware timer
AC power line (50/60 Hz)
Pseudo Code
void OSTickISR(void)
{
Save processor registers;
Call OSIntEnter();
Call OSTimeTick();
Call OSIntExit();
Restore processor registers;
Execute a return from interrupt instruction;
}
Clock Ticker (Cont 1)
Source Code
void OSTimeTick (void)
{
OS_TCB *ptcb;
OSTimeTickHook();
ptcb = OSTCBList;
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {
OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0) {
if (--ptcb->OSTCBDly == 0) {
if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else {
ptcb->OSTCBDly = 1;
}
}
}
ptcb = ptcb->OSTCBNext;
OS_EXIT_CRITICAL();
}
OS_ENTER_CRITICAL();
OSTime++;
OS_EXIT_CRITICAL();
}
Multitasking
Initializing and starting μC/OS-II
void main (void)
{
OSInit(); // Initialize uC/OS-II
.
.
Create at least 1 task;
.
.
OSStart(); // Start multitasking!
}
OSInit()
Initialize all variables and data structures.
Create the idle task (OSTaskIdle()) which is always ready-to-run.
Create the statistic task (OSTaskStat()) optionally.
OSStart()
Find the highest priority task that have created.
Never return to the caller!
Multitasking (Cont 1)
Source Code
Start Multitasking
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];
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy();
}
}
Obtaining μC/OS-II’s version
INT16U OSVersion (void)
{
return (OS_VERSION);
}
Appendix 1 1 0
OSRdyGrp
0 0 0 0 0 0
Ready List
OSTCBPrioTbl[]
OSRdyTbl[] 0 [0]
0 [1]
0 [2]
0 0 0 0 0 0 0 0 0 [3]
0 [4]
0 0 0 0 0 0 0 0 0 [5]
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
0 0 0 0 0 0 0 0
0
1 1 0 0 0 0 0 0 0
0
[OS_LOWEST_PRIO - 1]
[OS_LOWEST_PRIO]
OSTaskStat() OSTaskIdle()
OS_TCB OS_TCB
OSTCBStk Ptr OSTCBStk Ptr
OSTCBExtPtr = NULL OSTCBExtPtr = NULL
OSTCBStk Botto m OSTCBStk Botto m
OSTCBStk Size = stack size OSTCBStk Size = stack size
OSTCBId = OS_LOWEST_PRIO OSTCBId = OS_LOWEST_PRIO
OSTCBList OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBEventPtr = NULL OSTCBEventPtr = NULL
OSPrioCur = 0 OSTCBMsg = NULL OSTCBMsg = NULL
OSPrioHighRdy = 0 0 OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
0
OSTCBCur = NULL OSTCBPrio = OS_LOWEST_PRIO-1
OSTCBX = 6
OSTCBPrio = OS_LOWEST_PRIO
OSTCBX = 7
OSTCBHighRdy = NULL OSTCBY = 7 OSTCBY = 7
OSTime = 0L OSTCBBitX = 0x40
OSTCBBitY = 0x80
OSTCBBitX = 0x80
OSTCBBitY = 0x80
OSIntNesting = 0 OSTCBDelReq = FALSE OSTCBDelReq = FALSE
OSLockNesting = 0
OSCtxSwCtr = 0
OSTaskCtr = 2
OSRunning = FALSE
OSCPUUsage = 0
OSIdleCtrMax = 0L
OSIdleCtrRun = 0L
OSIdleCtr = 0L Task Stack
OSStatRdy = FALSE Task Stack
Appendix 2
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
OSTCBFreeList OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev 0
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
OS_MAX_EVENTS
OS_EVENT OS_EVENT OS_EVENT OS_EVENT
OSEventFreeList OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
0
OSEventCnt OSEventCnt OSEventCnt OSEventCnt
OSEventType OSEventType OSEventType OSEventType
OSEventGrp OSEventGrp OSEventGrp OSEventGrp
OS_MAX_QS
OS_Q OS_Q OS_Q OS_Q
OSQFreeList OSQPtr
OSQStart
OSQPtr
OSQStart
OSQPtr
OSQStart
OSQPtr
OSQStart
0
OSQEnd OSQEnd OSQEnd OSQEnd
OSQIn OSQIn OSQIn OSQIn
OSQOut OSQOut OSQOut OSQOut
OSQSize OSQSize OSQSize OSQSize
OSQEntries OSQEntries OSQEntries OSQEntries
OS_MAX_MEM_PART
OS_MEM OS_MEM OS_MEM OS_MEM
OSRdyTbl[]
OSLockNesting = 0 0 1 0 0 0 0 0 0
OSCtxSwCtr = 0
OSTaskCtr = 3 0 0 0 0 0 0 0 0
OSRunning = TRUE 0 0 0 0 0 0 0 0
OSCPUUsage = 0 0 0 0 0 0 0 0 0
OSIdleCtrMax = 0L
OSIdleCtrRun = 0L 0 0 0 0 0 0 0 0
OSIdleCtr = 0L 0 0 0 0 0 0 0 0 OSTCBPrioTbl[]
OSStatRdy = FALSE 0 [0]
0 0 0 0 0 0 0 0 0 [1]
0 [2]
OSPrioCur =6 1 1 0 0 0 0 0 0 0 [3]
OSPrioHighRdy = 6 0 [4]
0 [5]
[6]
0
0
0
[OS_LOWEST_PRIO - 1]
[OS_LOWEST_PRIO]
OSTCBCur OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBHighRdy OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = 6 OSTCBId = OS_LOWEST_PRIO OSTCBId = OS_LOWEST_PRIO
OSTCBList OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBEventPtr = NULL OSTCBEventPtr = NULL OSTCBEventPtr = NULL
OSTCBMsg = NULL OSTCBMsg = NULL OSTCBMsg = NULL
0 OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY 0
OSTCBPrio = 6 OSTCBPrio = OS_LOWEST_PRIO-1 OSTCBPrio = OS_LOWEST_PRIO
OSTCBX = 6 OSTCBX = 6 OSTCBX = 7
OSTCBY = 0 OSTCBY = 7 OSTCBY = 7
OSTCBBitX = 0x40 OSTCBBitX = 0x40 OSTCBBitX = 0x80
OSTCBBitY = 0x01 OSTCBBitY = 0x80 OSTCBBitY = 0x80
OSTCBDelReq = FALSE OSTCBDelReq = FALSE OSTCBDelReq = FALSE
Task Stack
Task Stack
Task Stack
Appendix 4