國立台灣大學 資訊工程學系 introduction to uc/os-ii

156
國國國國國國 國國國國國國 Introduction to uC/OS-II http://www.micrium.com/

Upload: erin-sherman

Post on 27-Dec-2015

298 views

Category:

Documents


2 download

TRANSCRIPT

國立台灣大學資訊工程學系

Introduction to uC/OS-II

http://www.micrium.com/

資工系網媒所 NEWS實驗室

14:03 /272

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /273

Real-Time Systems Concepts

Multitasking

Kernel

Scheduling

Mutual Exclusion

Message Passing

Interrupt

資工系網媒所 NEWS實驗室

14:03 /274

Foreground/Background Systems

Background Foreground

ISR

ISRISR

Time

Code execution

Task Level

Interrupt Level

資工系網媒所 NEWS實驗室

14:03 /275

Multitasking

Multitasking A process of scheduling and switching CPU between several tasks.

Related issuesContext Switch (Task Switch)

Resource Sharing

Critical Section

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2713

Preemptive Kernel

Low Priority Task

High Priority Task

ISR

ISR makes the highpriority task ready Time

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2716

Scheduling

Round-Robin SchedulingTasks executed sequentially

Task Priority AssignmentStatic priority

Rate Monotonic (RM)

Dynamic priorityEarliest-Deadline First (EDF)

Time-Driven SchedulingPinwheel

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2721

Using Semaphore

TASK 1

TASK 2

PRINTERSEMAPHORE

Acquire Semaphore

Acquire Semaphore

"I am task #2!"

"I am task #1!"

資工系網媒所 NEWS實驗室

14:03 /2722

Synchronization

Synchronization mechanism is used between tasks or task to ISR.

Unilateral rendezvous

Bilateral rendezvous

資工系網媒所 NEWS實驗室

14:03 /2723

Unilateral rendezvous

ISR TASKPOST PEND

TASKPOST PENDTASK

資工系網媒所 NEWS實驗室

14:03 /2724

Bilateral rendezvous

TASK

POST PEND

TASK

POSTPEND

資工系網媒所 NEWS實驗室

14:03 /2725

Event Flags

OR

TASK

ISR

TASKPOST PEND

Semaphore

TASK

ISR

TASKPOST PEND

Semaphore

AND

Events

Events

DISJUNCTIVE SYNCHRONIZATION

CONJUNCTIVE SYNCHRONIZATION

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2730

Interrupt Nesting

TIME

TASK

ISR #1

ISR #2

ISR #3

Interrupt #1

Interrupt #2

Interrupt #3

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2734

Non-preemptive Kernel

TASK

CPU Context Saved

Interrupt Request

Interrupt Latency

Interrupt ResponseInterrupt Recovery

TASK

ISR

User ISR Code

TIME

CPU contextrestored

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2742

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /2743

Kernel Structure

Task Control Blocks

Ready List

Task Scheduling

Interrupt under uC/OS-II

資工系網媒所 NEWS實驗室

14:03 /2744

Critical Sections

Archive this by disabling interrupt

OS_CPU.HOS_ENTER_CRITICAL()

OS_EXIT_CRITICAL()

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2752

Removing a Task from the Ready List

if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)

OSRdyGrp &= ~OSMapTbl[prio >> 3];

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2755

Locking The Scheduler

void OSSchedLock (void){ if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); OSLockNesting++; OS_EXIT_CRITICAL(); }}

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /2757

Idle Task

OSTaskIdle()

Lowest priority, OS_LOWEST_PRIO

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

資工系網媒所 NEWS實驗室

14:03 /2758

Statistics Task

(%) 100 1OSIdleCtr

OSCPU UsageOSIdleCtrMax

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2764

Beginning an ISR

void OSIntEnter (void){ OS_ENTER_CRITICAL(); OSIntNesting++; OS_EXIT_CRITICAL();}

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2768

uC/OS-II Initialization

Initialize variables and data structures

Create the idle task OSTaskIdle()

Create the statistic task OSTaskStat()

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2771

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /2772

Task Management

Task prototypeCreate a taskTask stacksStack checkingDelete a taskChange a task’s prioritySuspend a taskResume a taskQuery task information

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2779

Fragmentation

3K

A(1K)

B(1K)

C(1K)

B(1K)

1K

1K

(1) (2) (3)

資工系網媒所 NEWS實驗室

14:03 /2780

OSTaskStkChk()

Computes the amount of free stack space by “walking” from the bottom of the stack until a nonzero value is found

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2787

OSTaskResume()

ProceduresCheck the input priority

Clear the OS_STAT_SUSPEND bit in the OSTCBStat field

Set OSTCBDly to 0

Call OSSched()

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /2789

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /2790

Time Management

OSTimeDly()

OSTimeDlyHMSM()

OSTimeDlyResume()

OSTimeGet()

OSTimeSet()

資工系網媒所 NEWS實驗室

14:03 /2791

OSTimeDly()

void OSTimeDly (INT16U ticks) {

if (ticks > 0) { if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBDly = ticks; OSSched(); }}

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /2794

OSTimeGet() & OSTimeSet()

INT32U OSTimeGet (void) {

ticks = OSTime; return (ticks);}

void OSTimeSet (INT32U ticks) { OSTime = ticks;}

資工系網媒所 NEWS實驗室

14:03 /2795

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /2796

Intertask Communication & Synchronization

OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()

OSSchedLock()OSSchedUnlock()

SemaphoreMessage mailboxMessage queue

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27100

ECB (Event Control Block)

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27102

List of Free ECBs

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27105

Semaphore

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27109

Getting a Semaphore without Waiting

INT16U OSSemAccept (OS_EVENT *pevent) {

cnt = pevent->OSEventCnt; if (cnt > 0) { pevent->OSEventCnt--; } return (cnt);}

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27111

Message Mailbox

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27119

Message Queues

OSQCreate()

OSQPend()

OSQPost()

OSQPostFront()

OSQAccept()

OSQFlush()

OSQQuery()

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27121

Message Queues (Cont.)

Task

ISR

Task

OSQPend()OSQAccept()OSQQuery()

OSQPost()OSQPostFront()OSQFlush()

OSQPost()OSQPostFront()OSQFlush()OSQAccept()

OSQCreate()

QueueMessage

N

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27123

Queue Control Block

A queue control block contains following fields

OSQPtr

OSQStart

OSQEnd

OSQIn

OSQOut

OSQSize

OSQEntries

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27131

OSQPostFront()

OSQPostFront() Is basically identical to OSQPost().

Uses OSQOut instead of OSQIn as the pointer to the next entry.

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /27135

OSQQuery()

Pass a OS_Q_DATA structure to query.

OS_Q_DATA contains following fieldsOSMsg

OSNMsgs

OSQSize

OSEventTbl[]

OSEventGrp

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27137

Using a Message Queue When Reading Analog Inputs

TaskADCMUX

Timeout

OSQPend()

OSQPost()

Queue

Analog Inputs

(1)

(2)

(3)

(4)

(5)

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27139

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

資工系網媒所 NEWS實驗室

14:03 /27140

Memory Management

Overview

Memory Control Blocks

OSMemCreate()

OSMemGet()

OSMemPut()

OSMemQuery()

Examples

資工系網媒所 NEWS實驗室

14:03 /27141

ANSI C malloc() and free()

Dangerous in an embedded real-time system.

Fragmentation.

Non-deterministic.

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27143

Multiple Memory Partitions

Partition #1 Partition #2 Partition #3 Partition #4

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27145

Memory Control Block Data Structure

typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; } OS_MEM;

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /27147

OSMemCreate() (1)

0

OSMemAddr = addr

OSMemFreeList= addr

OSMemBlkSize = blksize

OSMemNBlks = nblks

OSMemNFree = nblks

Contiguous memory

pmem

OSMemCreate() arguments

資工系網媒所 NEWS實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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實驗室

14:03 /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); }}