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

Introduction to uC/OS-II

  • Upload
    dong

  • View
    28

  • Download
    0

Embed Size (px)

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 Presentation

Citation preview

Page 1: Introduction to uC/OS-II

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

Introduction to uC/OS-II

http://www.micrium.com/

Page 2: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /352

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 3: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /353

Real-Time Systems Concepts

Multitasking

Kernel

Scheduling

Mutual Exclusion

Message Passing

Interrupt

Page 4: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /354

Foreground/Background Systems

Background Foreground

ISR

ISRISR

Time

Code execution

Task Level

Interrupt Level

Page 5: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /355

Multitasking

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

Related issuesContext Switch (Task Switch)

Resource Sharing

Critical Section

Page 6: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /356

Multitasking

SP

CPU Registers

SP

Task Control Block

Priority

Context

Stack Stack Stack

CPU

MEMORY

TASK #1 TASK #2 TASK #n

SP

Task Control Block

Priority

SP

Task Control Block

Priority

Status Status Status

Page 7: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /357

Task

A task, or called a thread, a simple program that thinks it has the CPU all to itself.

Each task is assigned a priority, its own set of CPU registers, and its own stack area .

Each task typically is an infinite loop that can be in any one of five states.

Ready, Running, Waiting, ISR, Dormant

Page 8: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /358

Task States

RUNNINGREADY

OSTaskCreate()OSTaskCreateExt()

Task is Preempted

OSMBoxPend()OSQPend()

OSSemPend()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM()

OSMBoxPost()OSQPost()OSQPostFront()OSSemPost()OSTaskResume()OSTimeDlyResume()OSTimeTick()

OSTaskDel()

DORMANT

WAITING

OSStart()OSIntExit()

OS_TASK_SW()

OSTaskDel()

OSTaskDel()

Interrupt

OSIntExit()

ISR

Page 9: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /359

Kernel

Kernel is the part of a multitasking system responsible for the management of tasks.

Context switching is the fundamental service of a kernel.

Non-Preemptive Kernel

v.s.

Preemptive Kernel

Page 10: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3510

Non-Preemptive Kernel

Cooperative multitasking

A non-preemptive kernel allows each task to run until it voluntarily gives up control of the CPU.

An ISR can make a higher priority task ready to run, but the ISR always returns to the interrupted task.

Linux 2.4 is non-preemptive.

Linux 2.6 is preemptive.

Page 11: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3511

Non-Preemptive Kernel

Low Priority Task

High Priority Task

ISR

ISR makes the highpriority task ready

Low priority taskrelinquishes the CPU

Time

(1) (2)

(3)

(4)

(5)

(6)

(7)

Page 12: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3512

Preemptive Kernel

A preemptive kernel always executes the highest priority task that is ready to run.

µC/OS-II and most commercial real-time kernels are preemptive.

Much better response time.

Should not use non-reentrant functions, unless the functions are mutual exclusive.

Page 13: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3513

Preemptive Kernel

Low Priority Task

High Priority Task

ISR

ISR makes the highpriority task ready Time

Page 14: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3514

Function Reentrancy

A reentrant function is a function that can be used by more than one task without fear of data corruption.

Reentrant functions either use local variables or protected global variables.

OS_ENTER_CRITICAL()

OS_EXIT_CRITICAL()

Page 15: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3515

Function Reentrancy

Non-Reentrant Function

staticstatic int Temp;

void swap(int *x, int *y)

{Temp = *x;*x = *y;*y = Temp;

}

Reentrant Functionvoid strcpy(char *dest, char

*src)

{

while (*dest++ = *src++) { ; } *dest = NULL;

}

Page 16: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3516

Scheduling

Round-Robin SchedulingTasks executed sequentially

Task Priority AssignmentStatic priority

Rate Monotonic (RM)

Dynamic priorityEarliest-Deadline First (EDF)

Time-Derived SchedulingPinwheel

Page 17: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3517

Round-Robin

Kernel gives control to next task if the current task

has no work to do

completes

reaches the end of time-slice

Not supported in uC/OS-IIO(1) priority preemptive scheduling

Page 18: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3518

Priority Inversion Problem

Task 1 (H)

Task 2 (M)

Task 3 (L)

Priority Inversion

Task 3 Get Semaphore

Task 1 Preempts Task 3

Task 1 Tries to get Semaphore

Task 2 Preempts Task 3

Task 3 Resumes

Task 3 Releases the Semaphore

(1)

(2)

(3)

(4)

(5)

(6)

(7)

(8)

(9)

(10)

(11)

(12)

Page 19: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3519

Priority Inheritance

Task 1 (H)

Task 2 (M)

Task 3 (L)

Priority Inversion

Task 3 Get Semaphore

Task 1 Preempts Task 3

Task 1 Tries to get Semaphore(Priority of Task 3 is raised to Task 1's)

Task 3 Releases the Semaphore(Task 1 Resumes)

Task 1 Completes

(1)

(2)

(3)

(4)

(5)

(6)

(7)

(8)

(9)

(10)

(11)

Page 20: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3520

Mutual Exclusion

Protected shared data of processes.

Exclusive access implementationDisabling and enabling interrupts

Test-and-Set

Disabling and enabling scheduler

SemaphoresSimple Semaphore

Counting Semaphore

Deadlock – set timeout for a semaphore

Page 21: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3521

Using Semaphore

TASK 1

TASK 2

PRINTERSEMAPHORE

Acquire Semaphore

Acquire Semaphore

"I am task #2!"

"I am task #1!"

Page 22: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3522

Synchronization

Synchronization mechanism is used between tasks or task to ISR.

Unilateral rendezvous

Bilateral rendezvous

Page 23: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3523

Unilateral rendezvous

ISR TASKPOST PEND

TASKPOST PENDTASK

Page 24: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3524

Bilateral rendezvous

TASK

POST PEND

TASK

POSTPEND

Page 25: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3525

Event Flags

OR

TASK

ISR

TASKPOST PEND

Semaphore

TASK

ISR

TASKPOST PEND

Semaphore

AND

Events

Events

DISJUNCTIVE SYNCHRONIZATION

CONJUNCTIVE SYNCHRONIZATION

Page 26: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3526

Message Passing

Intertask CommunicationUsing global variables or sending messages

Only communicate to ISR through global variables

Tasks are not aware when the global variables is changed unless task polls the content.

Page 27: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3527

Message Mailboxes

A Message Mailbox, also called a message exchange, is typically a pointer size variable.Operations

InitialPOSTPEND

necessary to wait for the message being deposited

ACCEPTAcknowledgement

Page 28: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3528

Message Queues

A message queue is used to send one or more messages to a task.

A message queue is an array of message mailboxes.

Generally, FIFO is used.

µC/OS-II allows a task to get messages Last-In-First-Out (LIFO).

Page 29: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3529

Interrupt

An interrupt is a hardware mechanism used to inform the CPU that an asynchronous event has occurred.

Interrupt Latency

Interrupt Response

Interrupt Recovery

Page 30: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3530

Interrupt Nesting

TIME

TASK

ISR #1

ISR #2

ISR #3

Interrupt #1

Interrupt #2

Interrupt #3

Page 31: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3531

Interrupt Latency

Disabling interrupts affects interrupt latency.

All real-time systems disable interrupts to manipulate critical sections of code.

Re-enable interrupts when the critical section has executed.

Interrupt latency = Maximum time to disable interrupts + Time to start the first instruction in ISR.

Page 32: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3532

Interrupt Response

Interrupt Response means time between the reception of the interrupt and the start of the user code which will handle the interrupt.

Interrupt response = Interrupt latency + Time to save CPU context

The worst case for interrupt response is adopted.

Page 33: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3533

Interrupt Recovery

Interrupt recovery is defined as the time required for the processor to return to the interrupted code.

Interrupt recovery = Time to determine if a high priority task is ready + Time to restore the CPU context of the highest priority task + time of executing return-from-interrupt.

Page 34: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3534

Non-preemptive Kernel

TASK

CPU Context Saved

Interrupt Request

Interrupt Latency

Interrupt ResponseInterrupt Recovery

TASK

ISR

User ISR Code

TIME

CPU contextrestored

Page 35: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3535

Preemptive Kernel

TASK

CPU Context Saved

Kernel's ISREntry function

Interrupt Request

Interrupt Latency

Interrupt Response

Interrupt Recovery

TASK

ISR

Kernel's ISRExit function

User ISR Code

TIME

CPU contextrestored

Kernel's ISRExit function

CPU contextrestored

TASK

Interrupt Recovery

A

B

Page 36: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3536

Non-Maskable Interrupts (NMIs)Service the most important time-critical ISR

Can not be disabled

Interrupt latency = Time to execution the longest instruction + Time to start execution the NMI ISRInterrupt response = Interrupt latency + Time to save CPU contextInterrupt recovery = Time to restore CPU context + time of executing return-from-interrupt

Page 37: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3537

Clock Tick

A periodical interruptBe viewed as heartbeat

Application specific and is generally between 10ms and 200ms

Faster timer causes higher overhead

Delay problem should be considered in real-time kernel.

Page 38: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3538

Delaying a Task for 1 Tick

Tick Interrupt

Tick ISR

All higher priority tasks

Delayed Task

t1 t2t3

20 mS

(6 mS) (19 mS)(27 mS)

Call to delay 1 tick (20 mS)Call to delay 1 tick (20 mS)Call to delay 1 tick (20 mS)

Page 39: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3539

Clock TickSolve the problem

Increase the clock rate of your microprocessor.

Increase the time between tick interrupts.

Rearrange task priorities.

Avoid using floating-point math.

Get a compiler that performs better code optimization.

Write time-critical code in assembly language.

If possible, upgrade to a faster microprocessor in the same family.

Page 40: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3540

Memory Requirement

Be careful to avoid large RAM requirement

Large local arrays

Nested/Recursive function

Interrupt nesting

Stack used by libraries

Too many function arguments

Page 41: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3541

Real-Time Kernels

Real-time OS allows real-time application to be designed and expanded easily.

The use of an RTOS simplifies the design process by splitting the application into separate tasks.

Real-time kernel requires more ROM/RAM and 2 to 4 percent overhead.

Page 42: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3542

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 43: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3543

Kernel Structure

Task Control Blocks

Ready List

Task Scheduling

Interrupt under uC/OS-II

Page 44: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3544

Critical Sections

Archive this by disabling interrupt

OS_CPU.HOS_ENTER_CRITICAL()

OS_EXIT_CRITICAL()

Page 45: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3545

Tasks

Up to 64 tasks

Two tasks for system use(idle and statistic)

Priorities 0, 1, 2, 3, OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO for future use

The lower the priority number, the higher the priority of the task.

The task priority is also the task identifier.

Page 46: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3546

Task States

RUNNINGREADY

OSTaskCreate()OSTaskCreateExt()

Task is Preempted

OSMBoxPend()OSQPend()

OSSemPend()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM()

OSMBoxPost()OSQPost()OSQPostFront()OSSemPost()OSTaskResume()OSTimeDlyResume()OSTimeTick()

OSTaskDel()

DORMANT

WAITING

OSStart()OSIntExit()

OS_TASK_SW()

OSTaskDel()

OSTaskDel()

Interrupt

OSIntExit()

ISR

Page 47: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3547

Task Control Blockstypedef struct os_tcb {

OS_STK *OSTCBStkPtr;

 #if OS_TASK_CREATE_EXT_EN

void *OSTCBExtPtr;

OS_STK *OSTCBStkBottom;

INT32U OSTCBStkSize;

INT16U OSTCBOpt;

INT16U OSTCBId;

#endif

  struct os_tcb *OSTCBNext;

struct os_tcb *OSTCBPrev;

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN

OS_EVENT *OSTCBEventPtr;

#endif

 #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN

void *OSTCBMsg;

#endif

INT16U OSTCBDly;

INT8U OSTCBStat;

INT8U OSTCBPrio;

INT8U OSTCBX;

INT8U OSTCBY;

INT8U OSTCBBitX;

INT8U OSTCBBitY;

#if OS_TASK_DEL_EN

BOOLEAN OSTCBDelReq;

#endif

} OS_TCB;

Page 48: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3548

OS_TCB Lists

TCBs store in OSTCBTbl[]

All TCBs are initialized and linked when uC/OS-II is initialized

0OSTCBFreeList OSTCBNext OSTCBNext OSTCBNext OSTCBNext

OSTCBTbl[0] OSTCBTbl[1] OSTCBTbl[2]

OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS-1]

Page 49: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3549

Ready List

01234567

89101112131415

1617181920212223

2425262728293031

3233343536373839

4041424344454647

4849505152535455

5657585960616263

Task Priority #

Lowest Priority Task(Idle Task)

Highest Priority Task

X

Y

OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]01234567

OSRdyGrp

[7]

[6]

[5]

[4]

[3]

[2]

[1]

[0]

0 0 Y Y Y X X X

Bit position in OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

Bit position in OSRdyGrp andIndex into OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

Task's Priority

Page 50: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3550

OSRdyGrp and OSRdyTbl[]

Bit 0 in OSRdyGrp is 1 when any bit in OSRdyTbl[0] is 1.

Bit 1 in OSRdyGrp is 1 when any bit in OSRdyTbl[1] is 1.

Bit 2 in OSRdyGrp is 1 when any bit in OSRdyTbl[2] is 1.

Bit 3 in OSRdyGrp is 1 when any bit in OSRdyTbl[3] is 1.

Bit 4 in OSRdyGrp is 1 when any bit in OSRdyTbl[4] is 1.

Bit 5 in OSRdyGrp is 1 when any bit in OSRdyTbl[5] is 1.

Bit 6 in OSRdyGrp is 1 when any bit in OSRdyTbl[6] is 1.

Bit 7 in OSRdyGrp is 1 when any bit in OSRdyTbl[7] is 1.

Page 51: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3551

Making a Task Ready to Run

Index Bit mask (Binary)

0 00000001

1 00000010

2 00000100

3 00001000

4 00010000

5 00100000

6 01000000

7 10000000

Task’s Priority

0 0 Y Y Y X X X

OSRdyGrp |= OSMapTbl[prio >> 3];

OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];

Page 52: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3552

Removing a Task from the Ready List

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

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

Page 53: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3553

Finding the Highest Priority Task

y = OSUnMapTbl[OSRdyGrp];

x = OSUnMapTbl[OSRdyTbl[y]];

prio = (y << 3) + x;

INT8U const OSUnMapTbl[] = {

0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0

};

76543210 OSUnMapTbl[]

00000000 000000001 000000010 100000011 000000100 200000101 000000110 100000111 000001000 300001001 000001010 100001011 000001100 200001101 000001110 100001111 0…

Page 54: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3554

Task Scheduler

void OSSched (void)

{

INT8U y;

OS_ENTER_CRITICAL();

if ((OSLockNesting | OSIntNesting) == 0) { (1)

y = OSUnMapTbl[OSRdyGrp]; (2)

OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); (2)

if (OSPrioHighRdy != OSPrioCur) { (3)

OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (4)

OSCtxSwCtr++; (5)

OS_TASK_SW(); (6)

}

}

OS_EXIT_CRITICAL();

}

Page 55: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3555

Locking The Scheduler

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

Page 56: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3556

Unlocking The Scheduler

void OSSchedUnlock (void)

{ if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); if (OSLockNesting > 0) { OSLockNesting--; if ((OSLockNesting | OSIntNesting) == 0) { (1) OS_EXIT_CRITICAL(); OSSched(); (2) } else { OS_EXIT_CRITICAL(); } } else { OS_EXIT_CRITICAL(); } }}

Page 57: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3557

Idle Task

OSTaskIdle()

Lowest priority, OS_LOWEST_PRIO

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

Page 58: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3558

Statistics Task

(%) 100 1OSIdleCtr

OSCPU UsageOSIdleCtrMax

Page 59: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3559

Initializing the Statistic Task

void main (void){ OSInit(); /* Initialize uC/OS-II (1)*/ /* Install uC/OS-II's context switch vector */ /* Create your startup task (for sake of discussion, TaskStart()) (2)*/ OSStart(); /* Start multitasking (3)*/}

void TaskStart (void *pdata){ /* Install and initialize µC/OS-II’s ticker (4)*/ OSStatInit(); /* Initialize statistics task (5)*/ /* Create your application task(s) */ for (;;) { /* Code for TaskStart() goes here! */ }}

Page 60: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3560

Initializing the Statistic Task

void OSStatInit (void)

{

OSTimeDly(2);

OS_ENTER_CRITICAL();

OSIdleCtr = 0L;

OS_EXIT_CRITICAL();

OSTimeDly(OS_TICKS_PER_SEC);

OS_ENTER_CRITICAL();

OSIdleCtrMax = OSIdleCtr;

OSStatRdy = TRUE;

OS_EXIT_CRITICAL();

}

Page 61: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3561

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

Page 62: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3562

Interrupts under uC/OS-II

Be written in assembly language or C code with in-line assembly.

YourISR: Save all CPU registers; (1) Call OSIntEnter() or, increment OSIntNesting directly; (2) Execute user code to service ISR; (3) Call OSIntExit(); (4) Restore all CPU registers; (5) Execute a return from interrupt instruction;

Page 63: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3563

Servicing an Interrupt

Interrupt Request

TASK TASK

Vectoring

Saving Context

Notify kernel:OSIntEnter() or,OSIntNesting++ User ISR code

Notify kernel: OSIntExit()

Restore context

Notify kernel: OSIntExit()

Restore context

Return from interrupt

Return from interrupt

TASK

Interrupt Response

Interrupt Recovery

Interrupt Recovery

µC/OS-IIor your applicationhas interrupts disabled.

Time

ISR signals a task

No New HPT or,OSLockNesting > 0

New HPT

Task Response

Task Response

(1)

(2)

(3)

(4)

(5)

(6)

(7)

(8)

(9)

(10)

(11)

(12)

Page 64: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3564

Beginning an ISR

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

Page 65: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3565

Leaving an ISR

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

Page 66: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3566

Pseudo Code for Tick ISR

void OSTickISR(void){

Save processor registers;Call OSIntEnter() or increment OSIntNesting;Call OSTimeTick();Call OSIntExit();Restore processor registers;Execute a return from interrupt instruction;

}

Page 67: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3567

Service a Tickvoid OSTimeTick (void){ OS_TCB *ptcb; OSTimeTickHook(); (1) ptcb = OSTCBList; (2) while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { (3) OS_ENTER_CRITICAL(); if (ptcb->OSTCBDly != 0) { if (--ptcb->OSTCBDly == 0) { if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { (5) OSRdyGrp |= ptcb->OSTCBBitY; (4) OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { ptcb->OSTCBDly = 1; } } } ptcb = ptcb->OSTCBNext; OS_EXIT_CRITICAL(); } OS_ENTER_CRITICAL(); (7) OSTime++; (6) OS_EXIT_CRITICAL();}

Page 68: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3568

uC/OS-II Initialization

Initialize variables and data structures

Create the idle task OSTaskIdle()

Create the statistic task OSTaskStat()

Page 69: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3569

After calling OSInit()

OSTCBStkPtrOSTCBExtPtr = NULLOSTCBStkBottomOSTCBStkSize = stack sizeOSTCBId = OS_LOWEST_PRIOOSTCBNextOSTCBPrevOSTCBEventPtr = NULLOSTCBMsg = NULLOSTCBDly = 0OSTCBStat = OS_STAT_RDYOSTCBPrio = OS_LOWEST_PRIO-1OSTCBX = 6OSTCBY = 7OSTCBBitX = 0x40OSTCBBitY = 0x80OSTCBDelReq = FALSE

OSTCBStkPtrOSTCBExtPtr = NULLOSTCBStkBottomOSTCBStkSize = stack sizeOSTCBId = OS_LOWEST_PRIOOSTCBNextOSTCBPrevOSTCBEventPtr = NULLOSTCBMsg = NULLOSTCBDly = 0OSTCBStat = OS_STAT_RDYOSTCBPrio = OS_LOWEST_PRIOOSTCBX = 7OSTCBY = 7OSTCBBitX = 0x80OSTCBBitY = 0x80OSTCBDelReq = FALSE

0 0

000

00

00000

[OS_LOWEST_PRIO][OS_LOWEST_PRIO - 1]

[0][1][2][3][4][5][6]

OS_TCB OS_TCBOSTaskStat() OSTaskIdle()

OSTCBPrioTbl[]

OSTCBList

OSPrioCur = 0OSPrioHighRdy = 0OSTCBCur = NULLOSTCBHighRdy = NULLOSTime = 0LOSIntNesting = 0OSLockNesting = 0OSCtxSwCtr = 0OSTaskCtr = 2OSRunning = FALSEOSCPUUsage = 0OSIdleCtrMax = 0LOSIdleCtrRun = 0LOSIdleCtr = 0LOSStatRdy = FALSE Task Stack

Task Stack

0 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 00 0 0 0 0 0 0 01 1 0 0 0 0 0 0

1 0 0 0 0 0 0 0

OSRdyGrp

OSRdyTbl[]

Ready List

Page 70: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3570

Starting uC/OS-II

void main (void){ OSInit(); /* Initialize uC/OS-II */ . . Create at least 1 task using either OSTaskCreate() or OSTaskCreateExt(); . . OSStart(); /* Start multitasking! OSStart() will not return */}

void OSStart (void){ INT8U y; INT8U x;  if (OSRunning == FALSE) { y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; OSPrioHighRdy = (INT8U)((y << 3) + x); OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (1) OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); (2) }}

Page 71: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3571

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 72: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3572

Task Management

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

Page 73: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3573

Task Prototypevoid YourTask (void *pdata){ for (;;) { /* USER CODE */ Call one of uC/OS-II’s services: /* USER CODE */ }}

void YourTask (void *pdata){ /* USER CODE */ OSTaskDel(OS_PRIO_SELF);}

Page 74: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3574

OSTaskCreate()

Check that the task priority is valid• Check that the task is unique• Set up the task stack

OSTaskStkInit()• Obtain and initialize OS_TCB from TCB pool

OSTCBInit()• Call OSTaskCreateHook() to extend the

functionality• Call OSSched() when OSTaskCreate() is

called from a task

Page 75: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3575

OSTaskCreate()

INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio){ void *psp; INT8U err; if (prio > OS_LOWEST_PRIO) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { (2) OSTCBPrioTbl[prio] = (OS_TCB *)1; (3) OS_EXIT_CRITICAL(); (4) psp = (void *)OSTaskStkInit(task, pdata, ptos, 0); (5) err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); (6) if (err == OS_NO_ERR) { (7) OS_ENTER_CRITICAL(); OSTaskCtr++; (8) OSTaskCreateHook(OSTCBPrioTbl[prio]); (9) OS_EXIT_CRITICAL(); if (OSRunning) { (10) OSSched(); (11) } } else { OSTCBPrioTbl[prio] = (OS_TCB *)0; (12) } return (err); } else { OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST); }}

Page 76: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3576

OSTaskCreateExt()More flexibility, at the expense of overhead

The first four arguments are the same as OSTaskCreate()

id, assign a unique identifier for the task

pbos, a pointer that can perform stack checking

stk_size, specifies the size of the stack

pext, a pointer to extend the OS_TCB

opt, specifies whether stack checking is performed

Page 77: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3577

OSTaskCreateExt()

INT8U OSTaskCreateExt (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio, INT16U id, OS_STK *pbos, INT32U stk_size, void *pext, INT16U opt){ void *psp; INT8U err; INT16U i; OS_STK *pfill; if (prio > OS_LOWEST_PRIO) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { (2) OSTCBPrioTbl[prio] = (OS_TCB *)1; (3) OS_EXIT_CRITICAL(); (4) … return (err); } else { OS_EXIT_CRITICAL(); return (OS_PRIO_EXIST); }}

Page 78: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3578

Task StacksStatic OS_STK MyTaskStack[stack_size];

OS_STK MyTaskStack[stack_size];

or

Using malloc() to allocate stack space

OS_STK *pstk;

pstk = (OS_STK *)malloc(stack_size);

if (pstk != (OS_STK *)0) { /* Make sure malloc() had enough space */

Create the task;

}

Page 79: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3579

Fragmentation

3K

A(1K)

B(1K)

C(1K)

B(1K)

1K

1K

(1) (2) (3)

Page 80: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3580

OSTaskStkChk()

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

Page 81: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3581

Stack Checking

.OSTCBStkBottom

.OSTCBStkSize

0

000

Free Stack Space

Used Stack Space

Initial TOS

DeepestStackGrowth

Stack Growth

LOW MEMORY

HIGH MEMORY

CurrentLocation ofStack Pointer

(1)

(2)

(3)

(4)(5)

(6)

(7)

(8)

Page 82: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3582

OSTaskDel()Return to the DORMANT stateThe code for the task will not be deletedProcedures

Prevent from deleting and idle taskPrevent from deleting a task from within an ISRVerify that the task to be deleted does existRemove the OS_TCBRemove the task from ready list or other listsSet .OSTCBStat to OS_STAT_RDYCall OSDummy()Call OSTaskDelHook()Remove the OS_TCB from priority tableCall OSSched()

Page 83: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3583

OSTaskDelReq()

Tell the task that owns memory buffers or semaphore to delete itself

ProceduresCheck the task’s priority

If the task’s priority is OS_PRIO_SELFReturn the flag of OSTCBDelReq

OtherwiseSet OSTCBDelReq of the task to OS_TASK_DEL_REQ

Page 84: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3584

OSTaskDelReq() Examplevoid RequestorTask (void *pdata){ for (;;) { /* Application code */ if (‘TaskToBeDeleted()’ needs to be deleted) { while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) { OSTimeDly(1); } } /* Application code */ }}

void TaskToBeDeleted (void *pdata){ for (;;) { /* Application code */ if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) { Release any owned resources; De-allocate any dynamic memory; OSTaskDel(OS_PRIO_SELF); } else { /* Application code */ } }}

Page 85: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3585

OSTaskChangePrio()

Cannot change the priority of any idle task

ProceduresReserve the new priority by OSTCBPrioTbl[newprio] = (OS_TCB *) 1;

Remove the task from the priority table

Insert the task into new location of the priority table

Change the OS_TCB of the task

Call OSSched()

Page 86: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3586

OSTaskSuspend()

ProceduresCheck the input priority

Remove the task from the ready list

Set the OS_STAT_SUSPEND flag in OS_TCB

Call OSSched()

Page 87: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3587

OSTaskResume()

ProceduresCheck the input priority

Clear the OS_STAT_SUSPEND bit in the OSTCBStat field

Set OSTCBDly to 0

Call OSSched()

Page 88: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3588

OSTaskQuery()

INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata){ OS_TCB *ptcb; if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { (1) return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); if (prio == OS_PRIO_SELF) { (2) prio = OSTCBCur->OSTCBPrio; } if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { (3) OS_EXIT_CRITICAL(); return (OS_PRIO_ERR); } *pdata = *ptcb; (4) OS_EXIT_CRITICAL(); return (OS_NO_ERR);}

Page 89: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3589

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 90: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3590

Time Management

OSTimeDly()

OSTimeDlyHMSM()

OSTimeDlyResume()

OSTimeGet()

OSTimeSet()

Page 91: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3591

OSTimeDly()

void OSTimeDly (INT16U ticks) {

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

Page 92: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3592

OSTimeDlyHMSM()INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli) {{ INT32U ticks; INT16U loops; if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) { if (minutes > 59) { return (OS_TIME_INVALID_MINUTES); } if (seconds > 59) { return (OS_TIME_INVALID_SECONDS); } if (milli > 999) { return (OS_TIME_INVALID_MILLI); }

ticks = (INT32U)hours * 3600L * OS_TICKS_PER_SEC + (INT32U)minutes * 60L * OS_TICKS_PER_SEC + (INT32U)seconds) * OS_TICKS_PER_SEC + OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L; loops = ticks / 65536L; ticks = ticks % 65536L; OSTimeDly(ticks); while (loops > 0) { OSTimeDly(32768); OSTimeDly(32768); loops--; } return (OS_NO_ERR); } else { return (OS_TIME_ZERO_DLY); }}

Page 93: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3593

OSTimeDlyResume()

INT8U OSTimeDlyResume (INT8U prio) {

ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; if (ptcb != (OS_TCB *)0) { if (ptcb->OSTCBDly != 0) { ptcb->OSTCBDly = 0; if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OSSched(); } return (OS_NO_ERR); } else { return (OS_TIME_NOT_DLY); } } else { return (OS_TASK_NOT_EXIST); }}

Page 94: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3594

OSTimeGet() & OSTimeSet()

INT32U OSTimeGet (void) {

ticks = OSTime; return (ticks);}

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

Page 95: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3595

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 96: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3596

Intertask Communication & Synchronization

OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()

OSSchedLock()OSSchedUnlock()

SemaphoreMessage mailboxMessage queue

Page 97: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3597

OS_ENTER_CRITICAL() & OS_EXIT_CRITICAL()

#define OS_CRITICAL_METHOD 2

#if OS_CRITICAL_METHOD == 1#define OS_ENTER_CRITICAL() asm CLI#define OS_EXIT_CRITICAL() asm STI#endif

#if OS_CRITICAL_METHOD == 2#define OS_ENTER_CRITICAL() asm {PUSHF; CLI}#define OS_EXIT_CRITICAL() asm POPF#endif

CLI…

CLI…STI

…STI…

Page 98: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3598

Linux Example/* include/asm-i386/system.h */

/* interrupt control.. */#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x):)#define __restore_flags(x) __asm__ __volatile__("pushl %0; popfl": /* no output */ :"g" (x):"memory", "cc")#define __cli() __asm__ __volatile__("cli": : :"memory")#define __sti() __asm__ __volatile__("sti": : :"memory")

/* For spinlocks etc */#define local_irq_save(x) __asm__ __volatile__("pushfl; popl %0; cli":"=g" (x): :"memory")#define local_irq_restore(x) __restore_flags(x)#define local_irq_disable() __cli()#define local_irq_enable() __sti()

Page 99: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /3599

Locking and Unlocking the Scheduler

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

void OSSchedUnlock (void) { if (OSRunning == TRUE) { if (OSLockNesting > 0) { OSLockNesting--; if ((OSLockNesting | OSIntNesting) == 0) { OSSched(); } } }}

Page 100: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35100

ECB (Event Control Block)

Page 101: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35101

Event Control Block

typedef struct { void *OSEventPtr; /* Ptr to message or queue structure */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Wait list for event to occur */ INT16U OSEventCnt; /* Count (when event is a semaphore) */ INT8U OSEventType; /* Event type */ INT8U OSEventGrp; /* Group for wait list */} OS_EVENT;

Page 102: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35102

List of Free ECBs

Page 103: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35103

Wait Queue Functionsvoid OSEventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) {

y = OSUnMapTbl[pevent->OSEventGrp]; bity = OSMapTbl[y]; x = OSUnMapTbl[pevent->OSEventTbl[y]]; bitx = OSMapTbl[x]; prio = (INT8U)((y << 3) + x);

if ((pevent->OSEventTbl[y] &= ~bitx) == 0) { pevent->OSEventGrp &= ~bity; }

ptcb = OSTCBPrioTbl[prio]; ptcb->OSTCBDly = 0; ptcb->OSTCBEventPtr = (OS_EVENT *)0; ptcb->OSTCBMsg = msg;

ptcb->OSTCBStat &= ~msk; if (ptcb->OSTCBStat == OS_STAT_RDY) { OSRdyGrp |= bity; OSRdyTbl[y] |= bitx; }}

Page 104: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35104

Wait Queue Functions

void OSEventTaskWait (OS_EVENT *pevent) {

OSTCBCur->OSTCBEventPtr = pevent; if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;}

void OSEventTO (OS_EVENT *pevent) {

if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;}

Page 105: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35105

Semaphore

Page 106: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35106

Creating a Semaphore

OS_EVENT *OSSemCreate (INT16U cnt) {

pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_SEM; pevent->OSEventCnt = cnt; OSEventWaitListInit(pevent); } return (pevent);}

Page 107: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35107

Waiting for a Semaphorevoid OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) {

if (pevent->OSEventCnt > 0) { pevent->OSEventCnt--; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_SEM; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if (OSTCBCur->OSTCBStat & OS_STAT_SEM) { OSEventTO(pevent); } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } }}

Page 108: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35108

Signaling a Semaphore

INT8U OSSemPost (OS_EVENT *pevent) {

if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventCnt < 65535) { pevent->OSEventCnt++; return (OS_NO_ERR); } else { return (OS_SEM_OVF); } }}

Page 109: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35109

Getting a Semaphore without Waiting

INT16U OSSemAccept (OS_EVENT *pevent) {

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

Page 110: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35110

Obtaining the Status of a Semaphore

INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata) {

pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSCnt = pevent->OSEventCnt; return (OS_NO_ERR);}

Page 111: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35111

Message Mailbox

Page 112: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35112

Creating a Mailbox

OS_EVENT *OSMboxCreate (void *msg) { pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pevent->OSEventType = OS_EVENT_TYPE_MBOX; pevent->OSEventPtr = msg; OSEventWaitListInit(pevent); } return (pevent);}

Page 113: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35113

Waiting for a Message to Arrive at a Mailbox

void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) {

msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_MBOX; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } else if (OSTCBCur->OSTCBStat & OS_STAT_MBOX) { OSEventTO(pevent); } else { msg = pevent->OSEventPtr; pevent->OSEventPtr = (void *)0; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; } } return (msg);}

Page 114: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35114

Depositing a Message in a Mailbox

INT8U OSMboxPost (OS_EVENT *pevent, void *msg) {

if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_MBOX); OSSched(); return (OS_NO_ERR); } else { if (pevent->OSEventPtr != (void *)0) { return (OS_MBOX_FULL); } else { pevent->OSEventPtr = msg; return (OS_NO_ERR); } }}

Page 115: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35115

Getting a Message without Waiting

void *OSMboxAccept (OS_EVENT *pevent) {

msg = pevent->OSEventPtr; if (msg != (void *)0) { pevent->OSEventPtr = (void *)0; } return (msg);}

Page 116: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35116

Obtaining the Status of a Mailbox

INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) {

pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pdata->OSMsg = pevent->OSEventPtr; return (OS_NO_ERR);}

Page 117: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35117

Using a Mailbox as a Binary Semaphore

void Task1 (void *pdata) { for (;;) { OSMboxPend(MboxSem, 0, &err); /* Obtain access to resource(s) */ . . /* Task has semaphore, access resource(s) */ . OSMboxPost(MboxSem, (void )1); /* Release access to resource(s) */ }}

Page 118: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35118

Using a Mailbox as a Time Delayvoid Task1 (void *pdata) { for (;;) { OSMboxPend(MboxTimeDly, TIMEOUT, &err); /* Delay task */ . . /* Code executed after time delay */ . }}

void Task2 (void *pdata) { for (;;) { OSMboxPost(MboxTimeDly, (void *)1); /* Cancel delay for Task1 */ . . }}

Page 119: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35119

Message Queues

OSQCreate()

OSQPend()

OSQPost()

OSQPostFront()

OSQAccept()

OSQFlush()

OSQQuery()

Page 120: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35120

Message Queues

A message queueAllows a task or an ISR to send pointer size variables to another task.

Each pointer points a specific data structure containing a ‘message’. Looks like a mailbox with multiple entries.Is like an array of mailboxes except that there is only one wait list.

Page 121: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35121

Message Queues (Cont.)

Task

ISR

Task

OSQPend()OSQAccept()OSQQuery()

OSQPost()OSQPostFront()OSQFlush()

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

OSQCreate()

QueueMessage

N

Page 122: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35122

Data Structures in a Message Queue

OSQEntriesOSQSize

OS_EVENT

OS_Q void *MsgTbl[]OSQPtr

OSQStart

OSQEndOSQIn

OSQOutOSQSize

OSQEntries

Array allocated by your application

Field not used!

01234567

63 62 61 60 59 58 57 56

OSEventGrp

OSEventCntOSEventPtr

OSEventTbl[]

(1)

(2) (3)

Page 123: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35123

Queue Control Block

A queue control block contains following fields

OSQPtr

OSQStart

OSQEnd

OSQIn

OSQOut

OSQSize

OSQEntries

Page 124: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35124

List of Free Queue Control Blocks

OSQFreeList 0

OS_Q

OSQPtrOSQStart

OSQEndOSQIn

OSQOutOSQSize

OSQEntries

OSQPtrOSQStart

OSQEndOSQIn

OSQOutOSQSize

OSQEntries

OSQPtrOSQStart

OSQEndOSQIn

OSQOutOSQSize

OSQEntries

OS_MAX_QS

Page 125: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35125

Message Queue Is a Circular Buffer

.OSQOut

.OSQIn.OSQEntries

.OSQSize

.OSQStart .OSQEnd

Pointer to message

.OSQOut

(1)

(2)

(3)

(4) (3)

(5) (5)

Page 126: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35126

Creating a Queue

Specify the number of entries.

OSQCreate() requires that you allocate an array of pointers that hold the message.

The array must be declared as an array of pointers to void.

Once a message queue has been created, it cannot be deleted.

Page 127: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35127

OSQCreate() OS_EVENT *OSQCreate (void **start, INT16U size){ pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)0) { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } if (pevent != (OS_EVENT *)0) { pq = OSQFreeList; if (OSQFreeList != (OS_Q *)0) { OSQFreeList = OSQFreeList->OSQPtr; } if (pq != (OS_Q *)0) { pevent->OSEventType = OS_EVENT_TYPE_Q; pevent->OSEventPtr = pq; OSEventWaitListInit(pevent); } else { pevent->OSEventPtr = (void *)OSEventFreeList; OSEventFreeList = pevent; pevent = (OS_EVENT *)0; } } return (pevent); }

Page 128: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35128

OSQPend() (1)void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err){ pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } *err = OS_NO_ERR; } else if (OSIntNesting > 0) { *err = OS_ERR_PEND_ISR; } else { OSTCBCur->OSTCBStat |= OS_STAT_Q; OSTCBCur->OSTCBDly = timeout; OSEventTaskWait(pevent); OSSched(); if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) { OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR;

Page 129: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35129

OSQPend() (2)

} else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { OSEventTO(pevent); msg = (void *)0; *err = OS_TIMEOUT; } else { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; *err = OS_NO_ERR; } } return (msg); }

Page 130: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35130

OSQPost() INT8U OSQPost (OS_EVENT *pevent, void *msg){ if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { *pq->OSQIn++ = msg; pq->OSQEntries++; if (pq->OSQIn == pq->OSQEnd) { pq->OSQIn = pq->OSQStart; } } return (OS_NO_ERR); } }

Page 131: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35131

OSQPostFront()

OSQPostFront() Is basically identical to OSQPost().

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

Page 132: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35132

OSQPostFront() (Cont.)INT8U OSQPostFront (OS_EVENT *pevent, void *msg){ if (pevent->OSEventGrp) { OSEventTaskRdy(pevent, msg, OS_STAT_Q); OSSched(); return (OS_NO_ERR); } else { pq = pevent->OSEventPtr; if (pq->OSQEntries >= pq->OSQSize) return (OS_Q_FULL); else { if (pq->OSQOut == pq->OSQStart) { pq->OSQOut = pq->OSQEnd; } pq->OSQOut--; *pq->OSQOut = msg; pq->OSQEntries++; } return (OS_NO_ERR); }}

Page 133: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35133

OSQAccept()

void *OSQAccept (OS_EVENT *pevent){ pq = pevent->OSEventPtr; if (pq->OSQEntries != 0) { msg = *pq->OSQOut++; pq->OSQEntries--; if (pq->OSQOut == pq->OSQEnd) { pq->OSQOut = pq->OSQStart; } } else { msg = (void *)0; } return (msg); }

Page 134: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35134

OSQFlush()

INT8U OSQFlush (OS_EVENT *pevent){ pq = pevent->OSEventPtr; pq->OSQIn = pq->OSQStart; pq->OSQOut = pq->OSQStart; pq->OSQEntries = 0; return (OS_NO_ERR);}

Page 135: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35135

OSQQuery()

Pass a OS_Q_DATA structure to query.

OS_Q_DATA contains following fieldsOSMsg

OSNMsgs

OSQSize

OSEventTbl[]

OSEventGrp

Page 136: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35136

OSQQuery() (Cont.)

INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata){ pdata->OSEventGrp = pevent->OSEventGrp; psrc = &pevent->OSEventTbl[0]; pdest = &pdata->OSEventTbl[0]; for (i = 0; i < OS_EVENT_TBL_SIZE; i++) { *pdest++ = *psrc++; } pq = (OS_Q *)pevent->OSEventPtr; if (pq->OSQEntries > 0) { pdata->OSMsg = pq->OSQOut; } else { pdata->OSMsg = (void *)0; } pdata->OSNMsgs = pq->OSQEntries; pdata->OSQSize = pq->OSQSize; return (OS_NO_ERR);}

Page 137: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35137

Using a Message Queue When Reading Analog Inputs

TaskADCMUX

Timeout

OSQPend()

OSQPost()

Queue

Analog Inputs

(1)

(2)

(3)

(4)

(5)

Page 138: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35138

Using a Queue as a Counting Semaphore

void main (void){ OSInit(); … QSem = OSQCreate(&QMsgTbl[0], N_RESOURCES); for (i = 0; i < N_RESOURCES; i++) { OSQPost(Qsem, (void *)1); } … OSTaskCreate(Task1, .., .., ..); … OSStart();}void Task1 (void *pdata){ for (;;) { OSQPend(&QSem, 0, &err); /* Obtain access to resource(s) */ Task has semaphore, access resource(s) OSMQPost(QSem, (void )1); /* Release access to resource(s) */ }}

Page 139: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35139

uC/OS-II

Real-Time Systems Concepts

Kernel Structure

Task Management

Time Management

Intertask Communication & Synchronization

Memory Management

Page 140: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35140

Memory Management

Overview

Memory Control Blocks

OSMemCreate()

OSMemGet()

OSMemPut()

OSMemQuery()

Examples

Page 141: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35141

ANSI C malloc() and free()

Dangerous in an embedded real-time system.

Fragmentation.

Non-deterministic.

Page 142: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35142

µC/OS-II malloc() and free()

Obtain a contiguous memory area.Memory blocks are the same size.Partition contains an integral number of blocks.Allocation and de-allocation is deterministic.

More than one memory partition can exist.Application can obtain memory blocks of different sizes. Memory block must always be returned to the partition from which it came from.

Page 143: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35143

Multiple Memory Partitions

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

Page 144: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35144

Memory Control Blocks

Keeps track of memory partitions through MCB.

Each memory partition requires its own memory control block.

Initialization is done by OSMemInit().

Number of memory partitions must be set to at least 2.

Page 145: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35145

Memory Control Block Data Structure

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

Page 146: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35146

List of Free Memory Control Blocks

OSMemAddr

OSMemFreeList

OSMemBlkSize

OSMemNBlks

OSMemNFree

OSMemAddr

OSMemFreeList

OSMemBlkSize

OSMemNBlks

OSMemNFree

OSMemAddr

OSMemFreeList

OSMemBlkSize

OSMemNBlks

OSMemNFree

0OSMemFreeList

OS_MAX_MEM_PART

Page 147: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35147

OSMemCreate() (1)

0

OSMemAddr = addr

OSMemFreeList= addr

OSMemBlkSize = blksize

OSMemNBlks = nblks

OSMemNFree = nblks

Contiguous memory

pmem

OSMemCreate() arguments

Page 148: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35148

OSMemCreate() (2)OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err){ pmem = OSMemFreeList; if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList>OSMemFreeList; } if (pmem == (OS_MEM *)0) { *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); } plink = (void **)addr; pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; pmem->OSMemAddr = addr; pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; *err = OS_NO_ERR; return (pmem); }

Page 149: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35149

OSMemGet()

void *OSMemGet (OS_MEM *pmem, INT8U *err) { if (pmem->OSMemNFree > 0) { pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = *(void **)pblk; pmem->OSMemNFree--; *err = OS_NO_ERR; return (pblk); } else { *err = OS_MEM_NO_FREE_BLKS; return ((void *)0); }}

Page 150: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35150

Returning a Memory Block

INT8U OSMemPut (OS_MEM *pmem, void *pblk) { if (pmem->OSMemNFree >= pmem->OSMemNBlks) return (OS_MEM_FULL); *(void **)pblk = pmem->OSMemFreeList; pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; return (OS_NO_ERR); }

Page 151: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35151

Obtaining Status about Memory Partition

Pass a OS_MEM_DATA structure to query.

OS_MEM_DATA contains following fieldsOSAddr

OSFreeList

OSBlkSize

OSNBlks

OSNFree

OSNUsed

Page 152: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35152

OSMemQuery()

INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata){ pdata->OSAddr = pmem->OSMemAddr; (1) pdata->OSFreeList = pmem->OSMemFreeList; pdata->OSBlkSize = pmem->OSMemBlkSize; pdata->OSNBlks = pmem->OSMemNBlks; pdata->OSNFree = pmem->OSMemNFree; pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2) return (OS_NO_ERR); }

Page 153: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35153

Using Dynamic Memory Allocation

ErrMsgPart

ErrMsgQ

ErrorHandler

AITask

0

OSMemGet() OSMemPut()

OSQPost() OSQPend()

OSTime

OSTimeGet()

(1)

AnalogInputs

(2)

(3)

(4)

(5) (6)

(7)

(8)

Page 154: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35154

Waiting for Memory Blocks (1)

Sometimes it’s useful to have a task wait for a memory block in case a partition runs out of blocks.

µC/OS-II doesn’t support ‘pending’ on a partitions.

Can support this requirement by adding a counting semaphore.

Page 155: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35155

Waiting for Memory Blocks (2)

void main (void){ … SemaphorePtr = OSSemCreate(100); PartitionPtr = OSMemCreate(Partition, 100, 32, &err); … OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); … OSStart(); }

Page 156: Introduction to uC/OS-II

資工系網媒所 NEWS實驗室嵌入式系統人才培訓班 02:37 /35156

Waiting for Memory Blocks (3)

void Task (void *pdata){ INT8U err; INT8U *pblock; for (;;) { OSSemPend(SemaphorePtr, 0, &err); pblock = OSMemGet(PartitionPtr, &err); /* Use the memory block */ OSMemPut(PartitionPtr, pblock); OSSemPost(SemaphorePtr); }}