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實驗室
23:52 /272
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /273
Real-Time Systems Concepts
Multitasking
Kernel
Scheduling
Mutual Exclusion
Message Passing
Interrupt
資工系網媒所 NEWS實驗室
23:52 /274
Foreground/Background Systems
Background Foreground
ISR
ISRISR
Time
Code execution
Task Level
Interrupt Level
資工系網媒所 NEWS實驗室
23:52 /275
Multitasking
Multitasking A process of scheduling and switching CPU between several tasks.
Related issuesContext Switch (Task Switch)
Resource Sharing
Critical Section
資工系網媒所 NEWS實驗室
23:52 /276
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實驗室
23:52 /277
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實驗室
23:52 /278
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實驗室
23:52 /279
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實驗室
23:52 /2710
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實驗室
23:52 /2711
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實驗室
23:52 /2712
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實驗室
23:52 /2713
Preemptive Kernel
Low Priority Task
High Priority Task
ISR
ISR makes the highpriority task ready Time
資工系網媒所 NEWS實驗室
23:52 /2714
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實驗室
23:52 /2715
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實驗室
23:52 /2716
Scheduling
Round-Robin SchedulingTasks executed sequentially
Task Priority AssignmentStatic priority
Rate Monotonic (RM)
Dynamic priorityEarliest-Deadline First (EDF)
Time-Driven SchedulingPinwheel
資工系網媒所 NEWS實驗室
23:52 /2717
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實驗室
23:52 /2718
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實驗室
23:52 /2719
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實驗室
23:52 /2720
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實驗室
23:52 /2721
Using Semaphore
TASK 1
TASK 2
PRINTERSEMAPHORE
Acquire Semaphore
Acquire Semaphore
"I am task #2!"
"I am task #1!"
資工系網媒所 NEWS實驗室
23:52 /2722
Synchronization
Synchronization mechanism is used between tasks or task to ISR.
Unilateral rendezvous
Bilateral rendezvous
資工系網媒所 NEWS實驗室
23:52 /2723
Unilateral rendezvous
ISR TASKPOST PEND
TASKPOST PENDTASK
資工系網媒所 NEWS實驗室
23:52 /2724
Bilateral rendezvous
TASK
POST PEND
TASK
POSTPEND
資工系網媒所 NEWS實驗室
23:52 /2725
Event Flags
OR
TASK
ISR
TASKPOST PEND
Semaphore
TASK
ISR
TASKPOST PEND
Semaphore
AND
Events
Events
DISJUNCTIVE SYNCHRONIZATION
CONJUNCTIVE SYNCHRONIZATION
資工系網媒所 NEWS實驗室
23:52 /2726
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實驗室
23:52 /2727
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實驗室
23:52 /2728
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實驗室
23:52 /2729
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實驗室
23:52 /2730
Interrupt Nesting
TIME
TASK
ISR #1
ISR #2
ISR #3
Interrupt #1
Interrupt #2
Interrupt #3
資工系網媒所 NEWS實驗室
23:52 /2731
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實驗室
23:52 /2732
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實驗室
23:52 /2733
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實驗室
23:52 /2734
Non-preemptive Kernel
TASK
CPU Context Saved
Interrupt Request
Interrupt Latency
Interrupt ResponseInterrupt Recovery
TASK
ISR
User ISR Code
TIME
CPU contextrestored
資工系網媒所 NEWS實驗室
23:52 /2735
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實驗室
23:52 /2736
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實驗室
23:52 /2737
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實驗室
23:52 /2738
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實驗室
23:52 /2739
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實驗室
23:52 /2740
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實驗室
23:52 /2741
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實驗室
23:52 /2742
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /2743
Kernel Structure
Task Control Blocks
Ready List
Task Scheduling
Interrupt under uC/OS-II
資工系網媒所 NEWS實驗室
23:52 /2744
Critical Sections
Archive this by disabling interrupt
OS_CPU.HOS_ENTER_CRITICAL()
OS_EXIT_CRITICAL()
資工系網媒所 NEWS實驗室
23:52 /2745
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實驗室
23:52 /2746
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實驗室
23:52 /2747
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實驗室
23:52 /2748
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實驗室
23:52 /2749
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實驗室
23:52 /2750
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實驗室
23:52 /2751
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實驗室
23:52 /2752
Removing a Task from the Ready List
if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp &= ~OSMapTbl[prio >> 3];
資工系網媒所 NEWS實驗室
23:52 /2753
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實驗室
23:52 /2754
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實驗室
23:52 /2755
Locking The Scheduler
void OSSchedLock (void){ if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); OSLockNesting++; OS_EXIT_CRITICAL(); }}
資工系網媒所 NEWS實驗室
23:52 /2756
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實驗室
23:52 /2757
Idle Task
OSTaskIdle()
Lowest priority, OS_LOWEST_PRIO
void OSTaskIdle (void *pdata){ pdata = pdata; for (;;) { OS_ENTER_CRITICAL(); OSIdleCtr++; OS_EXIT_CRITICAL(); }}
資工系網媒所 NEWS實驗室
23:52 /2758
Statistics Task
(%) 100 1OSIdleCtr
OSCPU UsageOSIdleCtrMax
資工系網媒所 NEWS實驗室
23:52 /2759
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實驗室
23:52 /2760
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實驗室
23:52 /2761
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實驗室
23:52 /2762
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實驗室
23:52 /2763
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實驗室
23:52 /2764
Beginning an ISR
void OSIntEnter (void){ OS_ENTER_CRITICAL(); OSIntNesting++; OS_EXIT_CRITICAL();}
資工系網媒所 NEWS實驗室
23:52 /2765
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實驗室
23:52 /2766
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實驗室
23:52 /2767
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實驗室
23:52 /2768
uC/OS-II Initialization
Initialize variables and data structures
Create the idle task OSTaskIdle()
Create the statistic task OSTaskStat()
資工系網媒所 NEWS實驗室
23:52 /2769
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實驗室
23:52 /2770
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實驗室
23:52 /2771
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /2772
Task Management
Task prototypeCreate a taskTask stacksStack checkingDelete a taskChange a task’s prioritySuspend a taskResume a taskQuery task information
資工系網媒所 NEWS實驗室
23:52 /2773
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實驗室
23:52 /2774
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實驗室
23:52 /2775
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實驗室
23:52 /2776
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實驗室
23:52 /2777
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實驗室
23:52 /2778
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實驗室
23:52 /2779
Fragmentation
3K
A(1K)
B(1K)
C(1K)
B(1K)
1K
1K
(1) (2) (3)
資工系網媒所 NEWS實驗室
23:52 /2780
OSTaskStkChk()
Computes the amount of free stack space by “walking” from the bottom of the stack until a nonzero value is found
資工系網媒所 NEWS實驗室
23:52 /2781
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實驗室
23:52 /2782
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實驗室
23:52 /2783
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實驗室
23:52 /2784
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實驗室
23:52 /2785
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實驗室
23:52 /2786
OSTaskSuspend()
ProceduresCheck the input priority
Remove the task from the ready list
Set the OS_STAT_SUSPEND flag in OS_TCB
Call OSSched()
資工系網媒所 NEWS實驗室
23:52 /2787
OSTaskResume()
ProceduresCheck the input priority
Clear the OS_STAT_SUSPEND bit in the OSTCBStat field
Set OSTCBDly to 0
Call OSSched()
資工系網媒所 NEWS實驗室
23:52 /2788
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實驗室
23:52 /2789
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /2790
Time Management
OSTimeDly()
OSTimeDlyHMSM()
OSTimeDlyResume()
OSTimeGet()
OSTimeSet()
資工系網媒所 NEWS實驗室
23:52 /2791
OSTimeDly()
void OSTimeDly (INT16U ticks) {
if (ticks > 0) { if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBDly = ticks; OSSched(); }}
資工系網媒所 NEWS實驗室
23:52 /2792
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實驗室
23:52 /2793
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實驗室
23:52 /2794
OSTimeGet() & OSTimeSet()
INT32U OSTimeGet (void) {
ticks = OSTime; return (ticks);}
void OSTimeSet (INT32U ticks) { OSTime = ticks;}
資工系網媒所 NEWS實驗室
23:52 /2795
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /2796
Intertask Communication & Synchronization
OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()
OSSchedLock()OSSchedUnlock()
SemaphoreMessage mailboxMessage queue
資工系網媒所 NEWS實驗室
23:52 /2797
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實驗室
23:52 /2798
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實驗室
23:52 /2799
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實驗室
23:52 /27100
ECB (Event Control Block)
資工系網媒所 NEWS實驗室
23:52 /27101
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實驗室
23:52 /27102
List of Free ECBs
資工系網媒所 NEWS實驗室
23:52 /27103
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實驗室
23:52 /27104
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實驗室
23:52 /27105
Semaphore
資工系網媒所 NEWS實驗室
23:52 /27106
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實驗室
23:52 /27107
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實驗室
23:52 /27108
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實驗室
23:52 /27109
Getting a Semaphore without Waiting
INT16U OSSemAccept (OS_EVENT *pevent) {
cnt = pevent->OSEventCnt; if (cnt > 0) { pevent->OSEventCnt--; } return (cnt);}
資工系網媒所 NEWS實驗室
23:52 /27110
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實驗室
23:52 /27111
Message Mailbox
資工系網媒所 NEWS實驗室
23:52 /27112
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實驗室
23:52 /27113
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實驗室
23:52 /27114
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實驗室
23:52 /27115
Getting a Message without Waiting
void *OSMboxAccept (OS_EVENT *pevent) {
msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } return (msg);}
資工系網媒所 NEWS實驗室
23:52 /27116
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實驗室
23:52 /27117
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實驗室
23:52 /27118
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實驗室
23:52 /27119
Message Queues
OSQCreate()
OSQPend()
OSQPost()
OSQPostFront()
OSQAccept()
OSQFlush()
OSQQuery()
資工系網媒所 NEWS實驗室
23:52 /27120
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實驗室
23:52 /27121
Message Queues (Cont.)
Task
ISR
Task
OSQPend()OSQAccept()OSQQuery()
OSQPost()OSQPostFront()OSQFlush()
OSQPost()OSQPostFront()OSQFlush()OSQAccept()
OSQCreate()
QueueMessage
N
資工系網媒所 NEWS實驗室
23:52 /27122
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實驗室
23:52 /27123
Queue Control Block
A queue control block contains following fields
OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries
資工系網媒所 NEWS實驗室
23:52 /27124
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實驗室
23:52 /27125
Message Queue Is a Circular Buffer
.OSQOut
.OSQIn.OSQEntries
.OSQSize
.OSQStart .OSQEnd
Pointer to message
.OSQOut
(1)
(2)
(3)
(4) (3)
(5) (5)
資工系網媒所 NEWS實驗室
23:52 /27126
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實驗室
23:52 /27127
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實驗室
23:52 /27128
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實驗室
23:52 /27129
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實驗室
23:52 /27130
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實驗室
23:52 /27131
OSQPostFront()
OSQPostFront() Is basically identical to OSQPost().
Uses OSQOut instead of OSQIn as the pointer to the next entry.
資工系網媒所 NEWS實驗室
23:52 /27132
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實驗室
23:52 /27133
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實驗室
23:52 /27134
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實驗室
23:52 /27135
OSQQuery()
Pass a OS_Q_DATA structure to query.
OS_Q_DATA contains following fieldsOSMsg
OSNMsgs
OSQSize
OSEventTbl[]
OSEventGrp
資工系網媒所 NEWS實驗室
23:52 /27136
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實驗室
23:52 /27137
Using a Message Queue When Reading Analog Inputs
TaskADCMUX
Timeout
OSQPend()
OSQPost()
Queue
Analog Inputs
(1)
(2)
(3)
(4)
(5)
資工系網媒所 NEWS實驗室
23:52 /27138
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實驗室
23:52 /27139
uC/OS-II
Real-Time Systems Concepts
Kernel Structure
Task Management
Time Management
Intertask Communication & Synchronization
Memory Management
資工系網媒所 NEWS實驗室
23:52 /27140
Memory Management
Overview
Memory Control Blocks
OSMemCreate()
OSMemGet()
OSMemPut()
OSMemQuery()
Examples
資工系網媒所 NEWS實驗室
23:52 /27141
ANSI C malloc() and free()
Dangerous in an embedded real-time system.
Fragmentation.
Non-deterministic.
資工系網媒所 NEWS實驗室
23:52 /27142
µ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實驗室
23:52 /27143
Multiple Memory Partitions
Partition #1 Partition #2 Partition #3 Partition #4
資工系網媒所 NEWS實驗室
23:52 /27144
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實驗室
23:52 /27145
Memory Control Block Data Structure
typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; } OS_MEM;
資工系網媒所 NEWS實驗室
23:52 /27146
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實驗室
23:52 /27147
OSMemCreate() (1)
0
OSMemAddr = addr
OSMemFreeList= addr
OSMemBlkSize = blksize
OSMemNBlks = nblks
OSMemNFree = nblks
Contiguous memory
pmem
OSMemCreate() arguments
資工系網媒所 NEWS實驗室
23:52 /27148
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實驗室
23:52 /27149
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實驗室
23:52 /27150
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實驗室
23:52 /27151
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實驗室
23:52 /27152
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實驗室
23:52 /27153
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實驗室
23:52 /27154
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實驗室
23:52 /27155
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實驗室
23:52 /27156
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); }}