introduction to uc/os-ii
DESCRIPTION
Introduction to uC/OS-II. http://www.micrium.com/. uC/OS-II. Real-Time Systems Concepts Kernel Structure Task Management Time Management Intertask Communication & Synchronization Memory Management. Real-Time Systems Concepts. Multitasking Kernel Scheduling Mutual Exclusion - PowerPoint PPT PresentationTRANSCRIPT
國立台灣大學資訊工程學系
Introduction to uC/OS-II
http://www.micrium.com/
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /352
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /353
Real-Time Systems Concepts
Multitasking
Kernel
Scheduling
Mutual Exclusion
Message Passing
Interrupt
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /354
Foreground/Background Systems
Background Foreground
ISR
ISRISR
Time
Code execution
Task Level
Interrupt Level
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /355
Multitasking
Multitasking A process of scheduling and switching CPU between several tasks.
Related issuesContext Switch (Task Switch)
Resource Sharing
Critical Section
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /356
Multitasking
SP
CPU Registers
SP
Task Control Block
Priority
Context
Stack Stack Stack
CPU
MEMORY
TASK #1 TASK #2 TASK #n
SP
Task Control Block
Priority
SP
Task Control Block
Priority
Status Status Status
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /357
Task
A task, or called a thread, a simple program that thinks it has the CPU all to itself.
Each task is assigned a priority, its own set of CPU registers, and its own stack area .
Each task typically is an infinite loop that can be in any one of five states.
Ready, Running, Waiting, ISR, Dormant
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /358
Task States
RUNNINGREADY
OSTaskCreate()OSTaskCreateExt()
Task is Preempted
OSMBoxPend()OSQPend()
OSSemPend()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM()
OSMBoxPost()OSQPost()OSQPostFront()OSSemPost()OSTaskResume()OSTimeDlyResume()OSTimeTick()
OSTaskDel()
DORMANT
WAITING
OSStart()OSIntExit()
OS_TASK_SW()
OSTaskDel()
OSTaskDel()
Interrupt
OSIntExit()
ISR
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /359
Kernel
Kernel is the part of a multitasking system responsible for the management of tasks.
Context switching is the fundamental service of a kernel.
Non-Preemptive Kernel
v.s.
Preemptive Kernel
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3510
Non-Preemptive Kernel
Cooperative multitasking
A non-preemptive kernel allows each task to run until it voluntarily gives up control of the CPU.
An ISR can make a higher priority task ready to run, but the ISR always returns to the interrupted task.
Linux 2.4 is non-preemptive.
Linux 2.6 is preemptive.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3511
Non-Preemptive Kernel
Low Priority Task
High Priority Task
ISR
ISR makes the highpriority task ready
Low priority taskrelinquishes the CPU
Time
(1) (2)
(3)
(4)
(5)
(6)
(7)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3512
Preemptive Kernel
A preemptive kernel always executes the highest priority task that is ready to run.
µC/OS-II and most commercial real-time kernels are preemptive.
Much better response time.
Should not use non-reentrant functions, unless the functions are mutual exclusive.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3513
Preemptive Kernel
Low Priority Task
High Priority Task
ISR
ISR makes the highpriority task ready Time
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3514
Function Reentrancy
A reentrant function is a function that can be used by more than one task without fear of data corruption.
Reentrant functions either use local variables or protected global variables.
OS_ENTER_CRITICAL()
OS_EXIT_CRITICAL()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3515
Function Reentrancy
Non-Reentrant Function
staticstatic int Temp;
void swap(int *x, int *y)
{Temp = *x;*x = *y;*y = Temp;
}
Reentrant Functionvoid strcpy(char *dest, char
*src)
{
while (*dest++ = *src++) { ; } *dest = NULL;
}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3516
Scheduling
Round-Robin SchedulingTasks executed sequentially
Task Priority AssignmentStatic priority
Rate Monotonic (RM)
Dynamic priorityEarliest-Deadline First (EDF)
Time-Derived SchedulingPinwheel
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3517
Round-Robin
Kernel gives control to next task if the current task
has no work to do
completes
reaches the end of time-slice
Not supported in uC/OS-IIO(1) priority preemptive scheduling
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3518
Priority Inversion Problem
Task 1 (H)
Task 2 (M)
Task 3 (L)
Priority Inversion
Task 3 Get Semaphore
Task 1 Preempts Task 3
Task 1 Tries to get Semaphore
Task 2 Preempts Task 3
Task 3 Resumes
Task 3 Releases the Semaphore
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3519
Priority Inheritance
Task 1 (H)
Task 2 (M)
Task 3 (L)
Priority Inversion
Task 3 Get Semaphore
Task 1 Preempts Task 3
Task 1 Tries to get Semaphore(Priority of Task 3 is raised to Task 1's)
Task 3 Releases the Semaphore(Task 1 Resumes)
Task 1 Completes
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3520
Mutual Exclusion
Protected shared data of processes.
Exclusive access implementationDisabling and enabling interrupts
Test-and-Set
Disabling and enabling scheduler
SemaphoresSimple Semaphore
Counting Semaphore
Deadlock – set timeout for a semaphore
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3521
Using Semaphore
TASK 1
TASK 2
PRINTERSEMAPHORE
Acquire Semaphore
Acquire Semaphore
"I am task #2!"
"I am task #1!"
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3522
Synchronization
Synchronization mechanism is used between tasks or task to ISR.
Unilateral rendezvous
Bilateral rendezvous
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3523
Unilateral rendezvous
ISR TASKPOST PEND
TASKPOST PENDTASK
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3524
Bilateral rendezvous
TASK
POST PEND
TASK
POSTPEND
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3525
Event Flags
OR
TASK
ISR
TASKPOST PEND
Semaphore
TASK
ISR
TASKPOST PEND
Semaphore
AND
Events
Events
DISJUNCTIVE SYNCHRONIZATION
CONJUNCTIVE SYNCHRONIZATION
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3526
Message Passing
Intertask CommunicationUsing global variables or sending messages
Only communicate to ISR through global variables
Tasks are not aware when the global variables is changed unless task polls the content.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3527
Message Mailboxes
A Message Mailbox, also called a message exchange, is typically a pointer size variable.Operations
InitialPOSTPEND
necessary to wait for the message being deposited
ACCEPTAcknowledgement
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3528
Message Queues
A message queue is used to send one or more messages to a task.
A message queue is an array of message mailboxes.
Generally, FIFO is used.
µC/OS-II allows a task to get messages Last-In-First-Out (LIFO).
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3529
Interrupt
An interrupt is a hardware mechanism used to inform the CPU that an asynchronous event has occurred.
Interrupt Latency
Interrupt Response
Interrupt Recovery
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3530
Interrupt Nesting
TIME
TASK
ISR #1
ISR #2
ISR #3
Interrupt #1
Interrupt #2
Interrupt #3
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3531
Interrupt Latency
Disabling interrupts affects interrupt latency.
All real-time systems disable interrupts to manipulate critical sections of code.
Re-enable interrupts when the critical section has executed.
Interrupt latency = Maximum time to disable interrupts + Time to start the first instruction in ISR.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3532
Interrupt Response
Interrupt Response means time between the reception of the interrupt and the start of the user code which will handle the interrupt.
Interrupt response = Interrupt latency + Time to save CPU context
The worst case for interrupt response is adopted.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3533
Interrupt Recovery
Interrupt recovery is defined as the time required for the processor to return to the interrupted code.
Interrupt recovery = Time to determine if a high priority task is ready + Time to restore the CPU context of the highest priority task + time of executing return-from-interrupt.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3534
Non-preemptive Kernel
TASK
CPU Context Saved
Interrupt Request
Interrupt Latency
Interrupt ResponseInterrupt Recovery
TASK
ISR
User ISR Code
TIME
CPU contextrestored
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3535
Preemptive Kernel
TASK
CPU Context Saved
Kernel's ISREntry function
Interrupt Request
Interrupt Latency
Interrupt Response
Interrupt Recovery
TASK
ISR
Kernel's ISRExit function
User ISR Code
TIME
CPU contextrestored
Kernel's ISRExit function
CPU contextrestored
TASK
Interrupt Recovery
A
B
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3536
Non-Maskable Interrupts (NMIs)Service the most important time-critical ISR
Can not be disabled
Interrupt latency = Time to execution the longest instruction + Time to start execution the NMI ISRInterrupt response = Interrupt latency + Time to save CPU contextInterrupt recovery = Time to restore CPU context + time of executing return-from-interrupt
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3537
Clock Tick
A periodical interruptBe viewed as heartbeat
Application specific and is generally between 10ms and 200ms
Faster timer causes higher overhead
Delay problem should be considered in real-time kernel.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3538
Delaying a Task for 1 Tick
Tick Interrupt
Tick ISR
All higher priority tasks
Delayed Task
t1 t2t3
20 mS
(6 mS) (19 mS)(27 mS)
Call to delay 1 tick (20 mS)Call to delay 1 tick (20 mS)Call to delay 1 tick (20 mS)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3539
Clock TickSolve the problem
Increase the clock rate of your microprocessor.
Increase the time between tick interrupts.
Rearrange task priorities.
Avoid using floating-point math.
Get a compiler that performs better code optimization.
Write time-critical code in assembly language.
If possible, upgrade to a faster microprocessor in the same family.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3540
Memory Requirement
Be careful to avoid large RAM requirement
Large local arrays
Nested/Recursive function
Interrupt nesting
Stack used by libraries
Too many function arguments
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3541
Real-Time Kernels
Real-time OS allows real-time application to be designed and expanded easily.
The use of an RTOS simplifies the design process by splitting the application into separate tasks.
Real-time kernel requires more ROM/RAM and 2 to 4 percent overhead.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3542
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3543
Kernel Structure
Task Control Blocks
Ready List
Task Scheduling
Interrupt under uC/OS-II
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3544
Critical Sections
Archive this by disabling interrupt
OS_CPU.HOS_ENTER_CRITICAL()
OS_EXIT_CRITICAL()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3545
Tasks
Up to 64 tasks
Two tasks for system use(idle and statistic)
Priorities 0, 1, 2, 3, OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO for future use
The lower the priority number, the higher the priority of the task.
The task priority is also the task identifier.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3546
Task States
RUNNINGREADY
OSTaskCreate()OSTaskCreateExt()
Task is Preempted
OSMBoxPend()OSQPend()
OSSemPend()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM()
OSMBoxPost()OSQPost()OSQPostFront()OSSemPost()OSTaskResume()OSTimeDlyResume()OSTimeTick()
OSTaskDel()
DORMANT
WAITING
OSStart()OSIntExit()
OS_TASK_SW()
OSTaskDel()
OSTaskDel()
Interrupt
OSIntExit()
ISR
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3547
Task Control Blockstypedef 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;
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3548
OS_TCB Lists
TCBs store in OSTCBTbl[]
All TCBs are initialized and linked when uC/OS-II is initialized
0OSTCBFreeList OSTCBNext OSTCBNext OSTCBNext OSTCBNext
OSTCBTbl[0] OSTCBTbl[1] OSTCBTbl[2]
OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS-1]
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3549
Ready List
01234567
89101112131415
1617181920212223
2425262728293031
3233343536373839
4041424344454647
4849505152535455
5657585960616263
Task Priority #
Lowest Priority Task(Idle Task)
Highest Priority Task
X
Y
OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]01234567
OSRdyGrp
[7]
[6]
[5]
[4]
[3]
[2]
[1]
[0]
0 0 Y Y Y X X X
Bit position in OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]
Bit position in OSRdyGrp andIndex into OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]
Task's Priority
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3550
OSRdyGrp and 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.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3551
Making a Task Ready to Run
Index Bit mask (Binary)
0 00000001
1 00000010
2 00000100
3 00001000
4 00010000
5 00100000
6 01000000
7 10000000
Task’s Priority
0 0 Y Y Y X X X
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3552
Removing a Task from the Ready List
if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp &= ~OSMapTbl[prio >> 3];
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3553
Finding the Highest Priority Task
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y << 3) + x;
INT8U const OSUnMapTbl[] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
76543210 OSUnMapTbl[]
00000000 000000001 000000010 100000011 000000100 200000101 000000110 100000111 000001000 300001001 000001010 100001011 000001100 200001101 000001110 100001111 0…
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3554
Task Scheduler
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();
}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3555
Locking The Scheduler
void OSSchedLock (void){ if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); OSLockNesting++; OS_EXIT_CRITICAL(); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3556
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(); } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3557
Idle Task
OSTaskIdle()
Lowest priority, OS_LOWEST_PRIO
void OSTaskIdle (void *pdata){ pdata = pdata; for (;;) { OS_ENTER_CRITICAL(); OSIdleCtr++; OS_EXIT_CRITICAL(); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3558
Statistics Task
(%) 100 1OSIdleCtr
OSCPU UsageOSIdleCtrMax
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3559
Initializing the Statistic Task
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! */ }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3560
Initializing the Statistic Task
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();
}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3561
Statistics Taskvoid 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); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3562
Interrupts under uC/OS-II
Be written in assembly language or C code with in-line assembly.
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;
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3563
Servicing an Interrupt
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 applicationhas 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)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3564
Beginning an ISR
void OSIntEnter (void){ OS_ENTER_CRITICAL(); OSIntNesting++; OS_EXIT_CRITICAL();}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3565
Leaving an ISR
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();}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3566
Pseudo Code for Tick ISR
void OSTickISR(void){
Save processor registers;Call OSIntEnter() or increment OSIntNesting;Call OSTimeTick();Call OSIntExit();Restore processor registers;Execute a return from interrupt instruction;
}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3567
Service a Tickvoid 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();}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3568
uC/OS-II Initialization
Initialize variables and data structures
Create the idle task OSTaskIdle()
Create the statistic task OSTaskStat()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3569
After calling OSInit()
OSTCBStkPtrOSTCBExtPtr = NULLOSTCBStkBottomOSTCBStkSize = stack sizeOSTCBId = OS_LOWEST_PRIOOSTCBNextOSTCBPrevOSTCBEventPtr = NULLOSTCBMsg = NULLOSTCBDly = 0OSTCBStat = OS_STAT_RDYOSTCBPrio = OS_LOWEST_PRIO-1OSTCBX = 6OSTCBY = 7OSTCBBitX = 0x40OSTCBBitY = 0x80OSTCBDelReq = FALSE
OSTCBStkPtrOSTCBExtPtr = NULLOSTCBStkBottomOSTCBStkSize = stack sizeOSTCBId = OS_LOWEST_PRIOOSTCBNextOSTCBPrevOSTCBEventPtr = NULLOSTCBMsg = NULLOSTCBDly = 0OSTCBStat = OS_STAT_RDYOSTCBPrio = OS_LOWEST_PRIOOSTCBX = 7OSTCBY = 7OSTCBBitX = 0x80OSTCBBitY = 0x80OSTCBDelReq = FALSE
0 0
000
00
00000
[OS_LOWEST_PRIO][OS_LOWEST_PRIO - 1]
[0][1][2][3][4][5][6]
OS_TCB OS_TCBOSTaskStat() OSTaskIdle()
OSTCBPrioTbl[]
OSTCBList
OSPrioCur = 0OSPrioHighRdy = 0OSTCBCur = NULLOSTCBHighRdy = NULLOSTime = 0LOSIntNesting = 0OSLockNesting = 0OSCtxSwCtr = 0OSTaskCtr = 2OSRunning = FALSEOSCPUUsage = 0OSIdleCtrMax = 0LOSIdleCtrRun = 0LOSIdleCtr = 0LOSStatRdy = FALSE Task Stack
Task Stack
0 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 01 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0
OSRdyGrp
OSRdyTbl[]
Ready List
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3570
Starting uC/OS-II
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 */}
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) }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3571
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3572
Task Management
Task prototypeCreate a taskTask stacksStack checkingDelete a taskChange a task’s prioritySuspend a taskResume a taskQuery task information
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3573
Task Prototypevoid YourTask (void *pdata){ for (;;) { /* USER CODE */ Call one of uC/OS-II’s services: /* USER CODE */ }}
void YourTask (void *pdata){ /* USER CODE */ OSTaskDel(OS_PRIO_SELF);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3574
OSTaskCreate()
Check that the task priority is valid• Check that the task is unique• Set up the task stack
OSTaskStkInit()• Obtain and initialize OS_TCB from TCB pool
OSTCBInit()• Call OSTaskCreateHook() to extend the
functionality• Call OSSched() when OSTaskCreate() is
called from a task
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3575
OSTaskCreate()
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); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3576
OSTaskCreateExt()More flexibility, at the expense of overhead
The first four arguments are the same as OSTaskCreate()
id, assign a unique identifier for the task
pbos, a pointer that can perform stack checking
stk_size, specifies the size of the stack
pext, a pointer to extend the OS_TCB
opt, specifies whether stack checking is performed
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3577
OSTaskCreateExt()
INT8U OSTaskCreateExt (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio, INT16U id, OS_STK *pbos, INT32U stk_size, void *pext, INT16U opt){ void *psp; INT8U err; INT16U i; OS_STK *pfill; 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) … return (err); } else { OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3578
Task StacksStatic OS_STK MyTaskStack[stack_size];
OS_STK MyTaskStack[stack_size];
or
Using malloc() to allocate stack space
OS_STK *pstk;
pstk = (OS_STK *)malloc(stack_size);
if (pstk != (OS_STK *)0) { /* Make sure malloc() had enough space */
Create the task;
}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3579
Fragmentation
3K
A(1K)
B(1K)
C(1K)
B(1K)
1K
1K
(1) (2) (3)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3580
OSTaskStkChk()
Computes the amount of free stack space by “walking” from the bottom of the stack until a nonzero value is found
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3581
Stack Checking
.OSTCBStkBottom
.OSTCBStkSize
0
000
Free Stack Space
Used Stack Space
Initial TOS
DeepestStackGrowth
Stack Growth
LOW MEMORY
HIGH MEMORY
CurrentLocation ofStack Pointer
(1)
(2)
(3)
(4)(5)
(6)
(7)
(8)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3582
OSTaskDel()Return to the DORMANT stateThe code for the task will not be deletedProcedures
Prevent from deleting and idle taskPrevent from deleting a task from within an ISRVerify that the task to be deleted does existRemove the OS_TCBRemove the task from ready list or other listsSet .OSTCBStat to OS_STAT_RDYCall OSDummy()Call OSTaskDelHook()Remove the OS_TCB from priority tableCall OSSched()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3583
OSTaskDelReq()
Tell the task that owns memory buffers or semaphore to delete itself
ProceduresCheck the task’s priority
If the task’s priority is OS_PRIO_SELFReturn the flag of OSTCBDelReq
OtherwiseSet OSTCBDelReq of the task to OS_TASK_DEL_REQ
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3584
OSTaskDelReq() Examplevoid RequestorTask (void *pdata){ for (;;) { /* Application code */ if (‘TaskToBeDeleted()’ needs to be deleted) { while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) { OSTimeDly(1); } } /* Application code */ }}
void TaskToBeDeleted (void *pdata){ for (;;) { /* Application code */ if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) { Release any owned resources; De-allocate any dynamic memory; OSTaskDel(OS_PRIO_SELF); } else { /* Application code */ } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3585
OSTaskChangePrio()
Cannot change the priority of any idle task
ProceduresReserve the new priority by OSTCBPrioTbl[newprio] = (OS_TCB *) 1;
Remove the task from the priority table
Insert the task into new location of the priority table
Change the OS_TCB of the task
Call OSSched()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3586
OSTaskSuspend()
ProceduresCheck the input priority
Remove the task from the ready list
Set the OS_STAT_SUSPEND flag in OS_TCB
Call OSSched()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3587
OSTaskResume()
ProceduresCheck the input priority
Clear the OS_STAT_SUSPEND bit in the OSTCBStat field
Set OSTCBDly to 0
Call OSSched()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3588
OSTaskQuery()
INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata){ OS_TCB *ptcb; if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (prio == OS_PRIO_SELF) { (2) prio = OSTCBCur->OSTCBPrio; } if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { (3) OS_EXIT_CRITICAL(); return (OS_PRIO_ERR); } *pdata = *ptcb; (4) OS_EXIT_CRITICAL(); return (OS_NO_ERR);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3589
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3590
Time Management
OSTimeDly()
OSTimeDlyHMSM()
OSTimeDlyResume()
OSTimeGet()
OSTimeSet()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3591
OSTimeDly()
void OSTimeDly (INT16U ticks) {
if (ticks > 0) { if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBDly = ticks; OSSched(); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3592
OSTimeDlyHMSM()INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli) {{ INT32U ticks; INT16U loops; if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) { if (minutes > 59) { return (OS_TIME_INVALID_MINUTES); } if (seconds > 59) { return (OS_TIME_INVALID_SECONDS); } if (milli > 999) { return (OS_TIME_INVALID_MILLI); }
ticks = (INT32U)hours * 3600L * OS_TICKS_PER_SEC + (INT32U)minutes * 60L * OS_TICKS_PER_SEC + (INT32U)seconds) * OS_TICKS_PER_SEC + OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L; loops = ticks / 65536L; ticks = ticks % 65536L; OSTimeDly(ticks); while (loops > 0) { OSTimeDly(32768); OSTimeDly(32768); loops--; } return (OS_NO_ERR); } else { return (OS_TIME_ZERO_DLY); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3593
OSTimeDlyResume()
INT8U OSTimeDlyResume (INT8U prio) {
ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; if (ptcb != (OS_TCB *)0) { if (ptcb->OSTCBDly != 0) { ptcb->OSTCBDly = 0; if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OSSched(); } return (OS_NO_ERR); } else { return (OS_TIME_NOT_DLY); } } else { return (OS_TASK_NOT_EXIST); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3594
OSTimeGet() & OSTimeSet()
INT32U OSTimeGet (void) {
ticks = OSTime; return (ticks);}
void OSTimeSet (INT32U ticks) { OSTime = ticks;}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3595
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3596
Intertask Communication & Synchronization
OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()
OSSchedLock()OSSchedUnlock()
SemaphoreMessage mailboxMessage queue
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3597
OS_ENTER_CRITICAL() & OS_EXIT_CRITICAL()
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD == 1#define OS_ENTER_CRITICAL() asm CLI#define OS_EXIT_CRITICAL() asm STI#endif
#if OS_CRITICAL_METHOD == 2#define OS_ENTER_CRITICAL() asm {PUSHF; CLI}#define OS_EXIT_CRITICAL() asm POPF#endif
CLI…
CLI…STI
…STI…
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3598
Linux Example/* include/asm-i386/system.h */
/* interrupt control.. */#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x):)#define __restore_flags(x) __asm__ __volatile__("pushl %0; popfl": /* no output */ :"g" (x):"memory", "cc")#define __cli() __asm__ __volatile__("cli": : :"memory")#define __sti() __asm__ __volatile__("sti": : :"memory")
/* For spinlocks etc */#define local_irq_save(x) __asm__ __volatile__("pushfl; popl %0; cli":"=g" (x): :"memory")#define local_irq_restore(x) __restore_flags(x)#define local_irq_disable() __cli()#define local_irq_enable() __sti()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /3599
Locking and Unlocking the Scheduler
void OSSchedLock (void) { if (OSRunning == TRUE) { OSLockNesting++; }}
void OSSchedUnlock (void) { if (OSRunning == TRUE) { if (OSLockNesting > 0) { OSLockNesting--; if ((OSLockNesting | OSIntNesting) == 0) { OSSched(); } } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35100
ECB (Event Control Block)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35101
Event Control Block
typedef struct { void *OSEventPtr; /* Ptr to message or queue structure */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Wait list for event to occur */ INT16U OSEventCnt; /* Count (when event is a semaphore) */ INT8U OSEventType; /* Event type */ INT8U OSEventGrp; /* Group for wait list */} OS_EVENT;
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35102
List of Free ECBs
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35103
Wait Queue Functionsvoid OSEventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) {
y = OSUnMapTbl[pevent->OSEventGrp]; bity = OSMapTbl[y]; x = OSUnMapTbl[pevent->OSEventTbl[y]]; bitx = OSMapTbl[x]; prio = (INT8U)((y << 3) + x);
if ((pevent->OSEventTbl[y] &= ~bitx) == 0) { pevent->OSEventGrp &= ~bity; }
ptcb = OSTCBPrioTbl[prio]; ptcb->OSTCBDly = 0; ptcb->OSTCBEventPtr = (OS_EVENT *)0; ptcb->OSTCBMsg = msg;
ptcb->OSTCBStat &= ~msk; if (ptcb->OSTCBStat == OS_STAT_RDY) { OSRdyGrp |= bity; OSRdyTbl[y] |= bitx; }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35104
Wait Queue Functions
void OSEventTaskWait (OS_EVENT *pevent) {
OSTCBCur->OSTCBEventPtr = pevent; if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;}
void OSEventTO (OS_EVENT *pevent) {
if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35105
Semaphore
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35106
Creating a Semaphore
OS_EVENT *OSSemCreate (INT16U cnt) {
pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_SEM; pevent->OSEventCnt = cnt; OSEventWaitListInit(pevent); } return (pevent);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35107
Waiting for a Semaphorevoid OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) {
if (pevent->OSEventCnt > 0) { pevent->OSEventCnt--; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_SEM; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { OSEventTO(pevent); } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35108
Signaling a Semaphore
INT8U OSSemPost (OS_EVENT *pevent) {
if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventCnt < 65535) { pevent->OSEventCnt++; return (OS_NO_ERR); } else { return (OS_SEM_OVF); } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35109
Getting a Semaphore without Waiting
INT16U OSSemAccept (OS_EVENT *pevent) {
cnt = pevent->OSEventCnt; if (cnt > 0) { pevent->OSEventCnt--; } return (cnt);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35110
Obtaining the Status of a Semaphore
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata) {
pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSCnt = pevent->OSEventCnt; return (OS_NO_ERR);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35111
Message Mailbox
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35112
Creating a Mailbox
OS_EVENT *OSMboxCreate (void *msg) { pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_MBOX; pevent->OSEventPtr = msg; OSEventWaitListInit(pevent); } return (pevent);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35113
Waiting for a Message to Arrive at a Mailbox
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) {
msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_MBOX; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) { OSEventTO(pevent); } else { msg = pevent->OSEventPtr; pevent->OSEventPtr = (void *)0; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } } return (msg);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35114
Depositing a Message in a Mailbox
INT8U OSMboxPost (OS_EVENT *pevent, void *msg) {
if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_MBOX); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventPtr != (void *)0) { return (OS_MBOX_FULL); } else { pevent->OSEventPtr = msg; return (OS_NO_ERR); } }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35115
Getting a Message without Waiting
void *OSMboxAccept (OS_EVENT *pevent) {
msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } return (msg);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35116
Obtaining the Status of a Mailbox
INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) {
pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSMsg = pevent->OSEventPtr; return (OS_NO_ERR);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35117
Using a Mailbox as a Binary Semaphore
void Task1 (void *pdata) { for (;;) { OSMboxPend(MboxSem, 0, &err); /* Obtain access to resource(s) */ . . /* Task has semaphore, access resource(s) */ . OSMboxPost(MboxSem, (void )1); /* Release access to resource(s) */ }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35118
Using a Mailbox as a Time Delayvoid Task1 (void *pdata) { for (;;) { OSMboxPend(MboxTimeDly, TIMEOUT, &err); /* Delay task */ . . /* Code executed after time delay */ . }}
void Task2 (void *pdata) { for (;;) { OSMboxPost(MboxTimeDly, (void *)1); /* Cancel delay for Task1 */ . . }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35119
Message Queues
OSQCreate()
OSQPend()
OSQPost()
OSQPostFront()
OSQAccept()
OSQFlush()
OSQQuery()
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35120
Message Queues
A message queueAllows a task or an ISR to send pointer size variables to another task.
Each pointer points a specific data structure containing a ‘message’. Looks like a mailbox with multiple entries.Is like an array of mailboxes except that there is only one wait list.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35121
Message Queues (Cont.)
Task
ISR
Task
OSQPend()OSQAccept()OSQQuery()
OSQPost()OSQPostFront()OSQFlush()
OSQPost()OSQPostFront()OSQFlush()OSQAccept()
OSQCreate()
QueueMessage
N
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35122
Data Structures in a Message Queue
OSQEntriesOSQSize
OS_EVENT
OS_Q void *MsgTbl[]OSQPtr
OSQStart
OSQEndOSQIn
OSQOutOSQSize
OSQEntries
Array allocated by your application
Field not used!
01234567
63 62 61 60 59 58 57 56
OSEventGrp
OSEventCntOSEventPtr
OSEventTbl[]
(1)
(2) (3)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35123
Queue Control Block
A queue control block contains following fields
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35124
List of Free Queue Control Blocks
OSQFreeList 0
OS_Q
OSQPtrOSQStart
OSQEndOSQIn
OSQOutOSQSize
OSQEntries
OSQPtrOSQStart
OSQEndOSQIn
OSQOutOSQSize
OSQEntries
OSQPtrOSQStart
OSQEndOSQIn
OSQOutOSQSize
OSQEntries
OS_MAX_QS
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35125
Message Queue Is a Circular Buffer
.OSQOut
.OSQIn.OSQEntries
.OSQSize
.OSQStart .OSQEnd
Pointer to message
.OSQOut
(1)
(2)
(3)
(4) (3)
(5) (5)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35126
Creating a Queue
Specify the number of entries.
OSQCreate() requires that you allocate an array of pointers that hold the message.
The array must be declared as an array of pointers to void.
Once a message queue has been created, it cannot be deleted.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35127
OSQCreate() OS_EVENT *OSQCreate (void **start, INT16U size){ pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pq = OSQFreeList; if (OSQFreeList != (OS_Q *)0) { OSQFreeList = OSQFreeList->OSQPtr; } if (pq != (OS_Q *)0) { pevent->OSEventType = OS_EVENT_TYPE_Q; pevent->OSEventPtr = pq; OSEventWaitListInit(pevent); } else { pevent->OSEventPtr = (void *)OSEventFreeList; OSEventFreeList = pevent; pevent = (OS_EVENT *)0; } } return (pevent); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35128
OSQPend() (1)void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err){ pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } *err = OS_NO_ERR; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_Q; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR;
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35129
OSQPend() (2)
} else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { OSEventTO(pevent); msg = (void *)0; *err = OS_TIMEOUT; } else { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR; } } return (msg); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35130
OSQPost() INT8U OSQPost (OS_EVENT *pevent, void *msg){ if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { *pq->OSQIn++ = msg; pq->OSQEntries++; if (pq->OSQIn == pq->OSQEnd) { pq->OSQIn = pq->OSQStart; } } return (OS_NO_ERR); } }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35131
OSQPostFront()
OSQPostFront() Is basically identical to OSQPost().
Uses OSQOut instead of OSQIn as the pointer to the next entry.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35132
OSQPostFront() (Cont.)INT8U OSQPostFront (OS_EVENT *pevent, void *msg){ if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { if (pq->OSQOut == pq->OSQStart) { pq->OSQOut = pq->OSQEnd; } pq->OSQOut--; *pq->OSQOut = msg; pq->OSQEntries++; } return (OS_NO_ERR); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35133
OSQAccept()
void *OSQAccept (OS_EVENT *pevent){ pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } } else { msg = (void *)0; } return (msg); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35134
OSQFlush()
INT8U OSQFlush (OS_EVENT *pevent){ pq = pevent->OSEventPtr; pq->OSQIn = pq->OSQStart; pq->OSQOut = pq->OSQStart; pq->OSQEntries = 0; return (OS_NO_ERR);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35135
OSQQuery()
Pass a OS_Q_DATA structure to query.
OS_Q_DATA contains following fieldsOSMsg
OSNMsgs
OSQSize
OSEventTbl[]
OSEventGrp
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35136
OSQQuery() (Cont.)
INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata){ pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pq = (OS_Q *)pevent->OSEventPtr; if (pq->OSQEntries > 0) { pdata->OSMsg = pq->OSQOut; } else { pdata->OSMsg = (void *)0; } pdata->OSNMsgs = pq->OSQEntries; pdata->OSQSize = pq->OSQSize; return (OS_NO_ERR);}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35137
Using a Message Queue When Reading Analog Inputs
TaskADCMUX
Timeout
OSQPend()
OSQPost()
Queue
Analog Inputs
(1)
(2)
(3)
(4)
(5)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35138
Using a Queue as a Counting Semaphore
void main (void){ OSInit(); … QSem = OSQCreate(&QMsgTbl[0], N_RESOURCES); for (i = 0; i < N_RESOURCES; i++) { OSQPost(Qsem, (void *)1); } … OSTaskCreate(Task1, .., .., ..); … OSStart();}void Task1 (void *pdata){ for (;;) { OSQPend(&QSem, 0, &err); /* Obtain access to resource(s) */ Task has semaphore, access resource(s) OSMQPost(QSem, (void )1); /* Release access to resource(s) */ }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35139
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35140
Memory Management
Overview
Memory Control Blocks
OSMemCreate()
OSMemGet()
OSMemPut()
OSMemQuery()
Examples
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35141
ANSI C malloc() and free()
Dangerous in an embedded real-time system.
Fragmentation.
Non-deterministic.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35142
µC/OS-II malloc() and free()
Obtain a contiguous memory area.Memory blocks are the same size.Partition contains an integral number of blocks.Allocation and de-allocation is deterministic.
More than one memory partition can exist.Application can obtain memory blocks of different sizes. Memory block must always be returned to the partition from which it came from.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35143
Multiple Memory Partitions
Partition #1 Partition #2 Partition #3 Partition #4
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35144
Memory Control Blocks
Keeps track of memory partitions through MCB.
Each memory partition requires its own memory control block.
Initialization is done by OSMemInit().
Number of memory partitions must be set to at least 2.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35145
Memory Control Block Data Structure
typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; } OS_MEM;
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35146
List of Free Memory Control Blocks
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSMemNFree
0OSMemFreeList
OS_MAX_MEM_PART
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35147
OSMemCreate() (1)
0
OSMemAddr = addr
OSMemFreeList= addr
OSMemBlkSize = blksize
OSMemNBlks = nblks
OSMemNFree = nblks
Contiguous memory
pmem
OSMemCreate() arguments
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35148
OSMemCreate() (2)OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err){ pmem = OSMemFreeList; if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList>OSMemFreeList; } if (pmem == (OS_MEM *)0) { *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); } plink = (void **)addr; pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; pmem->OSMemAddr = addr; pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; *err = OS_NO_ERR; return (pmem); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35149
OSMemGet()
void *OSMemGet (OS_MEM *pmem, INT8U *err) { if (pmem->OSMemNFree > 0) { pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = *(void **)pblk; pmem->OSMemNFree--; *err = OS_NO_ERR; return (pblk); } else { *err = OS_MEM_NO_FREE_BLKS; return ((void *)0); }}
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35150
Returning a Memory Block
INT8U OSMemPut (OS_MEM *pmem, void *pblk) { if (pmem->OSMemNFree >= pmem->OSMemNBlks) return (OS_MEM_FULL); *(void **)pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; return (OS_NO_ERR); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35151
Obtaining Status about Memory Partition
Pass a OS_MEM_DATA structure to query.
OS_MEM_DATA contains following fieldsOSAddr
OSFreeList
OSBlkSize
OSNBlks
OSNFree
OSNUsed
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35152
OSMemQuery()
INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata){ pdata->OSAddr = pmem->OSMemAddr; (1) pdata->OSFreeList = pmem->OSMemFreeList; pdata->OSBlkSize = pmem->OSMemBlkSize; pdata->OSNBlks = pmem->OSMemNBlks; pdata->OSNFree = pmem->OSMemNFree; pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2) return (OS_NO_ERR); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35153
Using Dynamic Memory Allocation
ErrMsgPart
ErrMsgQ
ErrorHandler
AITask
0
OSMemGet() OSMemPut()
OSQPost() OSQPend()
OSTime
OSTimeGet()
(1)
AnalogInputs
(2)
(3)
(4)
(5) (6)
(7)
(8)
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35154
Waiting for Memory Blocks (1)
Sometimes it’s useful to have a task wait for a memory block in case a partition runs out of blocks.
µC/OS-II doesn’t support ‘pending’ on a partitions.
Can support this requirement by adding a counting semaphore.
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35155
Waiting for Memory Blocks (2)
void main (void){ … SemaphorePtr = OSSemCreate(100); PartitionPtr = OSMemCreate(Partition, 100, 32, &err); … OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); … OSStart(); }
資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 05:27 /35156
Waiting for Memory Blocks (3)
void Task (void *pdata){ INT8U err; INT8U *pblock; for (;;) { OSSemPend(SemaphorePtr, 0, &err); pblock = OSMemGet(PartitionPtr, &err); /* Use the memory block */ OSMemPut(PartitionPtr, pblock); OSSemPost(SemaphorePtr); }}