L1 and L3 _uCOS Task and scheduler concepts

Varsha506533 13 views 67 slides Aug 28, 2024
Slide 1
Slide 1 of 67
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67

About This Presentation

Lecture Notes


Slide Content

MicroC/OS-II : The Real-
Time Kernel

INTRODUCTION

Developed in C by Jean Labrosse in 1992
Currently, maintained by Micrium Inc. (
http://www.micrium.com/products/rtos/kernel/
rtos.html
)
The current version is C/OS-II v3.10(v2.52 for
textbook)

The new version C/OS-III provides more
features
◦Round-robin scheduling
Allow multiple tasks to run at the same priority level
◦Near zero interrupt disable time
◦Unlimited number of application tasks
◦Error checking and more. 
 

Licensing
◦Free distribution of  C/OS-II source and object code to
accredited Colleges and Universities w/o requiring licens
e
◦‘Object Code Distribution License’ is required for commer
cial products

 C/OS-II
◦A highly portable, ROMable, scalable, preemptive,
real-time, deterministic multitasking kernel for
microprocessors, microcontrollers and DSP-based
devices
◦Actual target: embedded system
◦Easily portable to many processor (
http://www.micrium.com/products/rtos/kernel/ports.
html
)

Major available ports
◦ACTEL (Cortex-M1)
◦ALTERA (NIOS II)
◦Analog Devices (ADSP-21xx)
◦ARM by various 3
rd
-party (Samsung, TI, PHILIPS,
etc.)
◦ATMEL (SAM7, SAM9)
◦Energy Micro (Cortex-M4F)
◦Freescale (9S08)
◦Fujitsu (FR-50, SPARClite)
◦Infineon (TriCore, 80C16x)
◦Intel (80x86)
◦Lattice(Mico32)

Major available ports
◦LUMINARY Micro (Cortex-M3)
◦Microchip (PIC24)
◦MIPS Technologies (M14K)
◦NXP (ARM7, ARM9)
◦Renesas (H8)
◦SAMSUNG (ARM7, ARM0)
◦ST (STR7, STR9)
◦TI (MSP-430, TMS320)
◦Toshiba (Cortex-M3)
◦XILINX (MicroBlaze)
◦Zilog (eZ80, Z-80 and Z-180)

Open source code
Portable
◦Written in ANSI C + target-specific code written in
assembly language
◦Run on most 8-, 16-, 32- or 64-bit platforms
◦Portable data types
typedef unsigned char INT8U
typedef unsigned intINT16U
typedef unsigned shortINT16U (for 32-bit)
typedef unsigned long INT32U

ROMable
◦Designed for embedded applications
◦Embedded as part of products
Scalability using conditional compilation
◦May contain only needed features for a small
footprint
◦Depending on the processor, the size can be
reduced as small as between 5KB to 24KB

Fully preemptible real-time, deterministic,
multitasking kernel for microprocessors,
microcontrollers and DSPs
Multitasking
◦Manage up to 64 tasks
8 system tasks and 56 application tasks
Up to 63 app tasks allowed
◦No round-robin allowed
Each task has a unique 64 priority levels

Deterministic
◦The execution time for most of the functions and
services is both constant and known in advance
◦The execution time is independent of the number of
tasks currently running
◦Exception
OSTimeTick()
Some event flag services(e.g., OSFlagCreate(),
OSFlagPost(), etc.)

Task stacks
◦Each tasks requires its own stack
◦Different stack sizes for different tasks
◦Exact size can be determined by stack-checking
feature
Reduce the amount of RAM needed by an each
application code
Use OSTaskStkChk()

System services
◦Semaphores
◦Mutual Exclusion Semaphores (to reduce priority
inversions)
◦Event Flags
◦Message Mailboxes
◦Message Queues
◦Task Management (Create, Delete, Change Priority,
Suspend/Resume etc.)
◦Fixed Sized Memory Block Management
◦Time Management
◦Timer Management

Interrupt management: 255 levels
Robust and Reliable
◦Used in 100s of commercial apps since 1992
◦Suitable for Safety Critical Systems common to
Aviation and Medical products
◦Certifiable for use in Safety Critical Systems
A Validation Suite provides all of the documentation
necessary to deliver µC/OS-II as a pre-certifiable
software component for safety critical systems
Include avionics RTCA DO-178B and EUROCAE/ ED-
12B, medical FDA 510(k), and IEC 61508 standard for
transportation and nuclear systems

Robust and Reliable
◦Revised
The source code for µC/OS-II is now 99% compliant
with the Motor Industry Software Reliability
Association (MISRA) C Coding Standards.
Improve the safety, reliability and predictability of C
programs in critical automotive systems.
Members of the MISRA consortium : Delco Electronics,
Ford Motor Company, Jaguar Cars Ltd., Lotus
Engineering, Lucas Electronics, Rolls-Royce, Rover
Group Ltd., etc.

Avionics
Medical equipment/devices
Data communications equipment
White goods (Appliances)
Mobile phones, PDAs, MIDs
Industrial controls
Consumer electronics
Automotive
A wide range of embedded applications

18
A task is a simple program that thinks it has the
CPU all to itself
Each Task has
◦Its own stack space
◦A priority based on its importance
A task contains YOUR application code

19
A task is an infinite loop
void Task (void *p_arg)
{
Do something with ‘argument’ p_arg;
Task initialization;
for (;;) {
/* Processing (Your Code) */
Wait for event; /* Time to expire ... */
/* Signal from ISR ... */
/* Signal from task ... */
/* Processing (Your Code) */
}
}
•A task can be deleted by call OSTaskDel()
–The task code is not actually deleted (also in memory)
–The OS doesn’t schedule it

Example
void YourTask (void *pdata) (1)
{
for (;;) { (2)
/* 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 */
}
}
•The argument is a
pointer to a void
–Allow pass any kind
of data to your task
•It is possible to create
many identical tasks
–EX: create 4 serial
ports task
–Each task has a
same code
–Pass different data
structure that
defines the serial
port’s parameters
(baud rate , I/O
port addresses,
interrupt vector,
etc)

uC/OS-II can manage up to 64 tasks
Each task needs to assign a priority
◦The lower the priority number, the higher the priority of the
task.
◦uC/OS-II reserves 8 priority (0, 1, 2, 3, OS_LOWEST_PRIO-3,
OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO )
◦Two system tasks:Idle Task, Statistics Task.
◦Only up to 56 application tasks
◦Task priority number is as the task identifier number
Always executes the highest priority task ready to run
Priority number service:OSTaskChangePrio() ,
OSTaskDel().
Create a task:OSTaskCreate(), OSTaskCreateExt().

22
High Priority Task
Low Priority Task
Task
Task
Task
Task
Task
Task
Event Event
Each Task
Infinite Loop
Importance

23
Tasks
Reside
In
ROM
Task Waiting For Event
Task
Ready-To-Run

24
To make it ready for multitasking
The kernel needs to have information about
your task
◦Its starting address
◦Its top-of-stack (TOS)
◦Its priority
◦Arguments passed to the task
◦Other information about your task

25
OSTaskCreateExt(void (*task)(void *parg),
void *parg,
OS_STK *pstk,
INT8U prio,
INT16U id,
OS_STK *pbos,
INT32U stk_size,
void *pext,
INT16U opt);

task is a pointer to the task's code.
parg is a pointer to an optional data area which
can be used to pass parameters to the task when
it is created.
pstk is a pointer to the task's top of stack.
prio is the task priority. A unique priority number
must be assigned to each task and the lower the
number, the higher the priority (i.e. the
importance) of the task. id is the task’s ID number.
At this time , the ID is not currently used in any
other function and has simply been added in

OSTaskCreateExt() for future expansion. You
should set the id to the same value as the task’s
priority.
pbos is a pointer to the task's bottom of stack.
pext is a pointer to a user supplied memory
location (typically a data structure) which is used
as a TCB extension. For example, this user
memory can hold the contents of floating-point
registers during a context switch, the time each
task takes to execute, the number of times the
task is switched-in, etc.

opt contains task specific options. The lower 8
bits are reserved by μC/OS-II but you can use the
upper 8 bits for application specific options. Each
option consist of a bit. The option is selected when
the bit is set. The current version of μC/OS-II
supports the following options:
OS_TASK_OPT_STK_CHK specifies whether
stack checking is allowed for the task.
OS_TASK_OPT_STK_CLR specifies whether the
stack needs to be cleared.
OS_TASK_OPT_SAVE_FP specifies whether
floating-point registers will be saved and the stack
needs to be cleared.

29
main
Disable Interrupts
Start the execution of the RTOS
Create the First Application Task (AppTaskStart)
Initialize internal OS structures
Disable
Interrupts
Initialize:
interrupt nesting counter
task counter
context switch counter
statistics
TCB and Events lists

OS_CFG.H
INCLUDES.H
µC/OS-II
(Processor Independent Code)
µC/OS-II Port
(Processor Specific Code)
µC/OS-II Configuration
(Application Specific)
Application Software
OS_CORE.C
OS_MBOX.C
OS_MEM.C
OS_Q.C
OS_SEM.C
OS_TASK.C
OS_TIME.C
uCOS_II.C
uCOS_II.H
OS_CPU.H
OS_CPU_A.ASM
OS_CPU_C.C
CPU Timer
Software
Hardware
uC uC
uC

To disable interrupts in order to access
critical sections of code and to reenable
interrupts when down.
◦The interrupt disable time affects the
responsiveness of system or real-time events
◦uC/OS-II defines two macros to disable/enable
interrupts
OS_ENTER_CRITICAL( )
OS_ENTER_CRITICAL asm CLI
OS_EXIT_CRITICAL( )
OS_EXIT_CRITICAL asm STI

When a task is created, it is assigned a Task
Control block, OS-TCB
◦To maintain the state of a task when it is
preempted
◦OS-TCB resides in RAMtypedef struct os_tcb {
OS_STK *OSTCBStkPtr;
#if OS_TASK_CREATE_EXT_EN
void *OSTCBExtPtr;
OS_STK *OSTCBStkBottom;
INT32U OSTCBStkSize;
INT16U OSTCBOpt;
INT16U OSTCBId;
#endif
struct os_tcb *OSTCBNext;
struct os_tcb *OSTCBPrev;
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN
OS_EVENT *OSTCBEventPtr;
#endif

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
void *OSTCBMsg;
#endif

INT16U OSTCBDly;
INT8U OSTCBStat;
INT8U OSTCBPrio;
INT8U OSTCBX;
INT8U OSTCBY;
INT8U OSTCBBitX;
INT8U OSTCBBitY;
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReq;
#endif
} OS_TCB;

OSTCBStkPtr
Point to the current top-of-stack for the task
Each task has its own stack
Each stack can be any size
Placing it at the first entry of structure
Make access this field easier from assembly language code

OSTCBExtPtr
Pointer to user definable data for TCB extension
Allow user to extend TCB without changing the
source code for uc/os-II
OS_TASK_CREATE_EXT_EN set to 1 to enable this
field
Place this pointer immediately after the stack
pointer

OSTCBStkBottom
Point to the bottom the the stack
OSTCBStkSize
The field is used by OSTaskStkChk()
The field is valid only if you set OS_TASK_CREATE_EXT_EN
to 1

OSTCBOpt
It holds options that can be passed to OSTaskCreateExt()
This field is valid only if you set OS_TASK_CREATE_EXT_EN
to 1
OS_TASK_OPT_STK_CHK 0x0001
OS_TASK_OPT_STK_CLR 0x0002
OS_TASK_OPT_SAVE_FP 0X0004
The stack only needs to be cleared if you intend to do
stack checking

OSTCBNext
OSTCBPrev
Used to double link OS_TCBs
This chain OS_TCBs is used by OSTimeTick() to
update the OSTCBDly field for each task
When the task is created ,its OS_TCB is linked in
this chain
When the task is deleted, its OS_TCB is removed

OSTCBDly
Used when a task needs to be delayed for a certain
number of clock ticks
A Task needs to pend for an event to occur with a
timeout
When this variable is 0,the task is not delayed or has no
timeout when waiting for an event
OSTCBEventPtr
It is a pointer to an event control block (ECB)
When waiting for an event (semaphore ,mbox,or
message) to occur ,it points to the ECB

OSTCBMsg
It is a pointer to a message that is sent to a task
It is modified while OSMboxPost() OSQPost()
OSQFrontPost() call OSEventTaskRdy()
OSTCBId
It is used to hold an identifier for the task
This field is currently not used
OSTCBPrio
Task Priority
A high-priority task has a low value

OSTCBStat: contain the state of the task
OS_STAT_RDY0x00/*Ready to run
OS_STAT_SEM0x01 /*Pending on semaphore
OS_STAT_MBOX 0x02 /*Pending on mailbox
OS_STAT_Q 0x04 /*Pending on queue
OS_STAT_SUSPEND 0x08 /*Task is suspend
OSTCBDelReq
To indicate whether or not a task that current task
be deleted

OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
◦ex. If OSTCBX==1,OSTCBY==6 then
OSTCBBitX=0000 0010
OSTCBBitY=0100 0000
OSTCBY= priority >> 3;
OSTCBBitY = OSMapTbl[priority >> 3];
OSTCBX= priority & 0x07;
OSTCBBitX = OSMapTbl[priority & 0x07];

OS_MAX_TASKS (in OS_CFG.H) specifies the maximum
number of tasks
◦We can reduce the amount of RAM needed by setting this variable
to the actual number of tasks needed in our application
All OS-TCBs are placed in OSTCBTbl[ ]
◦When uC/OS-II is initiialized, all OS-TCBs in the table are linked in
a singly linked list of free OS_TCBs
0OSTCBNextOSTCBNextOSTCBNextOSTCBNext
OSTCBTbl[0] OSTCBTbl[1] OSTCBTbl[2]
OSTCBFreeList
OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS-1]

Each task that is ready to run is placed in a
ready list consisting of two variables
◦OSRdyGrp and OSRdyTbl[ ]
◦Eight task priorities are grouped in OSRdyGrp
◦Each bit in OSRdyGrp indicates when a task in a
group is ready to run
◦Which priority tasks that are ready to run in a group
of OSRdyGrp is required to look up OSRdyTbl[ ]
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

76543210
15141312111098
2322212019181716
3130292827262524
3938373635343332
4746454443424140
5554535251504948
6362616059585756
76543210
00YYYXXX
[0]
[7]
[6]
[5]
[4]
[3]
[2]
[1]
Lowest Priority Task
Task Priority #
Highest Priority Task
OSRdyTbl[OS_LOWEST_PRIO/8+1]
OSRdyGrp
Task’s Priority
X
Y

EX: if OSRdyGrp contains 01101000  OSUnMapTbl[OSRdyGrp] =3, it
means 3th group is the highest priority
If OSRdyTbl[3] = 11100100, then OSUnMapTbl[OSRdyTbl[3]]=2, the means
is that the task priority 3*8+2=26 is the highest priority ready task.
Getting a pointer to the OS-TCB for the corresponding task
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
Removing a task from the ready list
if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp &= ~OSMapTbl[prio >> 3];
Finding the highest priority task ready to
run
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y << 3) + x;

Task-level scheduling is performed by OSSched()
ISR-level scheduling is handled by OSIntExit()
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();
}
Task Scheduler
The stack frame for a ready task always looks as if an interrupt just occurred and
all processor registers were saved onto it  the uC/OS-II has to do context switch
is restore all processor registers from the task’s stack and execute a return from
interrupt

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) { (1)
OS_EXIT_CRITICAL();
OSSched(); (2)
} else {
OS_EXIT_CRITICAL();
}
} else {
OS_EXIT_CRITICAL();
}
}
}

void OSTaskIdle (void *pdata)
{
pdata = pdata;
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtr++;
OS_EXIT_CRITICAL();
}
}

uC/OS-II provides run-time statistics
◦OSTaskState() executes every second and computes the percent
CPU usage
◦OSStateInit() is called before you create your other application tasks
◦The startup code in Main() must create only one task before calling
OSStart().
◦From this one task, you must call OSStatInit() before you create
your other application tasks
void main (void)
{
OSInit(); /* Initialize uC/OS-II (1)*/
/* Install uC/OS-II's context switch vector */
/* Create your startup task (for sake of discussion, TaskStart()) (2)*/
OSStart(); /* Start multitasking (3)*/
}
void TaskStart (void *pdata)
{
/* Install and initialize µC/OS-II’s ticker (4)*/
OSStatInit(); /* Initialize statistics task (5)*/
/* Create your application task(s) */
for (;;) {
/* Code for TaskStart() goes here! */
}
}

uC/OS-II has only three tasks to manage when main() calls
OSStart()
◦TaskStart(), OSTaskIdle(), and OSTaskStat()
◦TaskStart() requires call OSStartInit() before creating other AP tasks
main()
{
OSInit(); (1)
Install context switch vector; (2)
Create TaskStart(); (3)
OSStart();
}
TaskStart()
{
Init uC/OS-II's ticker; (5)
OSStatInit(): (6)
OSTimeDly(2); (7)
OSIdleCtr = 0; (12)
OSTimeDly(1 second); (13)
OSIdleCtrMax = OSIdleCtr; (15)
OSStatRdy = TRUE; (16)
for (;;) {
Task code;
}
}
OSTaskStat()
{
while (OSStatRdy == FALSE) { (8)
OSTimeDly(2 seconds); (9)
}
for (;;) {
Compute Statistics; (17)
}
}
OSTaskIdle()
{
for (;;) {
OSIdleCtr++; (10)
}
for (;;) {
OSIdleCtr++; (14)
}
Scheduler
Scheduler
Scheduler
After 2 ticks
After 1 second
Scheduler
Highest Priority OS_LOWEST_PRIOOS_LOWEST_PRIO - 1
2 ticks
1 second
2 seconds
(4)
(11)
Figure 3.4 Statistic task initialization

Variable OSIdleCtr records how much ticks are consumed
in the idle task
First, the OSStatInit() measures the maximum value of
OSIdleCtr when the system doesn’t do anything
OSTaskStat() calculates the following equation every
second, which represent the OS CPU usage
void OSStatInit (void)
{
OSTimeDly(2);
OS_ENTER_CRITICAL();
OSIdleCtr = 0L;
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC);
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr;
OSStatRdy = TRUE;
OS_EXIT_CRITICAL();
}







axOSIdleCtrM
OSIdleCtr
UsageOSCPU 1100
(%)

void OSTaskStat (void *pdata)
{
INT32U run;
INT8S usage;


pdata = pdata;
while (OSStatRdy == FALSE) { (1)
OSTimeDly(2 * OS_TICKS_PER_SEC);
}
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtrRun = OSIdleCtr;
run = OSIdleCtr;
OSIdleCtr = 0L;
OS_EXIT_CRITICAL();
if (OSIdleCtrMax > 0L) {
usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); (2)
if (usage > 100) {
OSCPUUsage = 100;
} else if (usage < 0) {
OSCPUUsage = 0;
} else {
OSCPUUsage = usage;
}
} else {
OSCPUUsage = 0;
}
OSTaskStatHook(); (3)
OSTimeDly(OS_TICKS_PER_SEC);
}
}

OSIntEnter() : increase the global variable OSIntNesting
◦uC/OS-II allows nesting interrupt
OSIntExit() : decide whether requires to do the context
switch or not
◦If OSIntNexting > 0, the ISR direct return to the Interrupted
task or ISR
◦If scheduling has been disabled (OSLockNesting > 0), the
uC/OS-II will return to the interrupted task
YourISR:
Save all CPU registers; (1)
Call OSIntEnter() or, increment OSIntNesting directly; (2)
Execute user code to service ISR; (3)
Call OSIntExit(); (4)
Restore all CPU registers; (5)
Execute a return from interrupt instruction; (6)
ISRs under uC/OS-II

Interrupt Request
TASK TASK
Vectoring
Saving Context
Notify kernel:
OSIntEnter() or,
OSIntNesting++
User ISR code
Notify kernel: OSIntExit()
Restore context
Notify kernel: OSIntExit()
Restore context
Return from interrupt
Return from interrupt
TASK
Interrupt Response
Interrupt Recovery
Interrupt Recovery
µC/OS-IIor your application
has interrupts disabled.
Time
ISR signals a task
No New HPT or,
OSLockNesting > 0
New HPT
Task Response
Task Response
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
Figure 3.5 Servicing an interrupt

void OSIntEnter (void)
{
OS_ENTER_CRITICAL();
OSIntNesting++;
OS_EXIT_CRITICAL();
}
void OSIntExit (void)
{
OS_ENTER_CRITICAL(); (1)
if ((--OSIntNesting | OSLockNesting) == 0) { (2)
OSIntExitY = OSUnMapTbl[OSRdyGrp]; (3)
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw(); (4)
}
}
OS_EXIT_CRITICAL();
}

There are two functions to do the context switch
◦OSIntCtxSw() called by OSIntExit() : interrupt level context switch
◦OS_TASK_SW() called by OSSched() : Task level context switch
◦The context switch is done by the iret
Processor Status Word
Interrupt Return Address
LOW MEMORY
HIGH MEMORY
Stack Growth
SP must be adjusted
to point here.
This new SP is saved into
the preempted task's OS_TCB.
Saved Processor Registers
Return address to caller of OSIntExit()
Return address to caller of OSIntCtxSw()
Processor Status Word
SP Points Here!
(1)
(2)
(3)
(4)
(5)
(6)

Provide a periodic time source to keep track of
time delays and timeout
The ticker interrupts must be enable after
multitaking has started
◦After calling OSStart()
void OSTickISR(void)
{
Save processor registers;
Call OSIntEnter() or increment OSIntNesting;
Call OSTimeTick();
Call OSIntExit();
Restore processor registers;
Execute a return from interrupt instruction;
}

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();
}

OSTimeTick() can be called at the task level
to reduce the tick ISR service time
void TickTask (void *pdata)
{
pdata = pdata;
for (;;) {
OSMboxPend(...); /* Wait for signal from Tick ISR */
OSTimeTick();
}
}
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;
}

OSInit() initializes all uC/OS-II variables and
data structures
OSInit() creates the idle task OSTaskIdle()
OSInit() may create OSTaskStat(), if
OS_TASK_STAT_EN=1
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 */
}

OSTCBStkPtr
OSTCBExtPtr = NUL L
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_LOWEST_PRIO
OSTCBNext
OSTCBPr ev
OSTCBEven tPtr = NU LL
OSTCBMsg = NU LL
OSTCBD ly = 0
OSTCBStat = OS_STAT_R DY
OSTCBPr io = OS_LOWEST_PR IO-1
OSTCBX = 6
OSTCBY = 7
OSTCBBitX = 0x40
OSTCBBitY = 0x80
OSTCBD elReq = FAL SE
OSTCBStkPtr
OSTCBExtPtr = NU LL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_LOWEST_PRIO
OSTCBNex t
OSTCBPrev
OSTCBEven tPtr = NU LL
OSTCBMsg = NU LL
OSTCBD ly = 0
OSTCBStat = OS_STAT_RDY
OSTCBPrio = OS_LOWEST_PRIO
OSTCBX = 7
OSTCBY = 7
OSTCBBitX = 0x80
OSTCBBitY = 0x80
OSTCBD elReq = FAL SE
0 0
0
0
0
0
0
0
0
0
0
0
[OS_LOWEST_PR IO]
[OS_LOWEST_PR IO - 1]
[0]
[1]
[2]
[3]
[4]
[5]
[6]
OS_TCB OS_TCB
OSTaskStat() OSTaskIdle()
OSTCBPrioTbl[]
OSTCBList
OSPrioCur = 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 Task Stack
Task Stack
00000000
00000000
00000000
00000000
00000000
00000000
00000000
11000000
10000000
OSRdyGrp
OSRdyTbl[]
Ready List
Figure 3.7
Data structures after calling OSInit()

OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq
OS_ TCB
0OSTCBFreeList
OS_MAX_TASKS
0OSEventFreeList
OS_MAX_EVENTS
OS_ EV ENT OS_ EV ENT OS_ EV ENT OS_ EV ENT
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp
OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq
OS_ TCB
OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq
OS_ TCB
OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp
OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp
OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp
OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq
OS_ TCB
0OSQFreeList
OS_MAX_QS
OS_ Q OS_ Q OS_ Q
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree
0OSMemFreeList
OS_MAX_MEM_PART
OS_ MEM
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree
OS_ MEM OS_ MEM OS_ MEM
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree
OS_ Q

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)
}
}

PSW = 0x0202
SEG task
OFF task
AX = 0xAAAA
BX = 0xBBBB
CX = 0xCCCC
DX = 0xDDDD
SI = 0x2222
DI = 0x3333
BP = 0x1111
SP = 0x0000
ES = 0x4444
DS = Current DS
LOW MEMORY
HIGH MEMORY
Simulate PUSH ES
Simulate PUSH DS
Simulate PUSHA
Simulate Interrupt
Stack Growth
SEG pdata
OFF pdata
SEG task
OFF task
Simulate call to task
OSTCBHighRdy->OSTCBStkPtr
SS:SP points here after executing:
POP DS
POP ES
POPA
IRET
Figure 9.3 80x86 Stack frame when task is created

_OSStartHighRdy PROC FAR
MOV AX, SEG _OSTCBHighRdy ; Reload DS
MOV DS, AX ;
LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr (1)
MOV SS, ES:[BX+2] ;
MOV SP, ES:[BX+0] ;
;
POP DS ; Load task's context (2)
POP ES ; (3)
POPA ; (4)
;
IRET ; Run task (5)
_OSStartHighRdy ENDP

OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_LOWEST_PRIO
OSTCBNext
OSTCBPrev
OSTCBEve ntPtr = NULL
OSTCBMsg = NULL
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBPrio = OS_LOWEST_PRIO- 1
OSTCBX = 6
OSTCBY = 7
OSTCBBitX = 0x40
OSTCBBitY = 0x80
OSTCBDe lRe q = FALSE
OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_ LOWEST_ PRIO
OSTCBNext
OSTCBPrev
OSTCBEve ntPtr = NULL
OSTCBMsg = NULL
OSTCBDly = 0
OSTCBStat = OS_ STAT_ RDY
OSTCBPrio = OS_LOWEST_ PRIO
OSTCBX = 7
OSTCBY = 7
OSTCBBitX = 0x80
OSTCBBitY = 0x80
OSTCBDe lRe q = FALSE
0
0
0
0
0
0
0
0
0
0
[OS_ LOWEST_ PRIO]
[OS_ LOWEST_ PRIO - 1]
[0 ]
[1 ]
[2 ]
[3 ]
[4 ]
[5 ]
[6 ]
OS_TCB OS_TCB
OSTaskStat() OSTaskIdle()
OSTCBPrioTbl[]
OSTime = 0L
OSIntNesting = 0
OSLockNesting = 0
OSCtxSwCtr = 0
OSTaskCtr = 3
OSRunning = TRUE
OSCPUUsage = 0
OSIdleCtrMax = 0L
OSIdleCtrRun = 0L
OSIdleCtr = 0L
OSStatRdy = FALSE
OSPrioCur = 6
OSPrioHighRdy = 6
Task Stack
Task Stack
OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = 6
OSTCBNext
OSTCBPrev
OSTCBEve ntPtr = NULL
OSTCBMsg = NULL
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBPrio = 6
OSTCBX = 6
OSTCBY = 0
OSTCBBitX = 0x40
OSTCBBitY = 0x01
OSTCBDelRe q = FALSE
0
OS_ TCB
YouAppTask()
OSTCBList
Task Stack
OSRdyGrp
OSRdyTbl[]
Ready List
01000000
00000000
00000000
00000000
00000000
00000000
00000000
11000000
10000001
OSTCBHighRdy
OSTCBCur
Variables and data structures
after calling OSStart()
Tags