introduction to uc os ii
Download
Skip this Video
Download Presentation
Introduction to uC/OS-II

Loading in 2 Seconds...

play fullscreen
1 / 156

Introduction to uC/OS-II - PowerPoint PPT Presentation


  • 66 Views
  • Uploaded on

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Introduction to uC/OS-II' - dong


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
introduction to uc os ii

Introduction to uC/OS-II

http://www.micrium.com/

uc os ii
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

real time systems concepts
Real-Time Systems Concepts
  • Multitasking
  • Kernel
  • Scheduling
  • Mutual Exclusion
  • Message Passing
  • Interrupt

/35

foreground background systems
Foreground/Background Systems

Interrupt Level

Task Level

/35

multitasking
Multitasking
  • Multitasking
    • A process of scheduling and switching CPU between several tasks.
  • Related issues
    • Context Switch (Task Switch)
    • Resource Sharing
    • Critical Section

/35

slide7
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

/35

kernel
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

/35

non preemptive kernel
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.

/35

preemptive kernel
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.

/35

function reentrancy
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()

/35

function reentrancy1
Non-Reentrant Function

static int Temp;

void swap(int *x, int *y)

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

}

Reentrant Function

void strcpy(char *dest, char *src)

{

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

}

Function Reentrancy

/35

scheduling
Scheduling
  • Round-Robin Scheduling
    • Tasks executed sequentially
  • Task Priority Assignment
    • Static priority
      • Rate Monotonic (RM)
    • Dynamic priority
      • Earliest-Deadline First (EDF)
  • Time-Derived Scheduling
    • Pinwheel

/35

round robin
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-II
    • O(1) priority preemptive scheduling

/35

mutual exclusion
Mutual Exclusion
  • Protected shared data of processes.
  • Exclusive access implementation
    • Disabling and enabling interrupts
    • Test-and-Set
    • Disabling and enabling scheduler
    • Semaphores
      • Simple Semaphore
      • Counting Semaphore
  • Deadlock – set timeout for a semaphore

/35

synchronization
Synchronization
  • Synchronization mechanism is used between tasks or task to ISR.
    • Unilateral rendezvous
    • Bilateral rendezvous

/35

message passing
Message Passing
  • Intertask Communication
    • Using 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.

/35

message mailboxes
Message Mailboxes
  • A Message Mailbox, also called a message exchange, is typically a pointer size variable.
  • Operations
    • Initial
    • POST
    • PEND
      • necessary to wait for the message being deposited
    • ACCEPT
      • Acknowledgement

/35

message queues
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).

/35

interrupt
Interrupt
  • An interrupt is a hardware mechanism used to inform the CPU that an asynchronous event has occurred.
  • Interrupt Latency
  • Interrupt Response
  • Interrupt Recovery

/35

interrupt latency
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.

/35

interrupt response
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 forinterrupt response is adopted.

/35

interrupt recovery
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.

/35

non maskable interrupts nmis
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 ISR
  • Interrupt response = Interrupt latency + Time to save CPU context
  • Interrupt recovery = Time to restore CPU context + time of executing return-from-interrupt

/35

clock tick
Clock Tick
  • A periodical interrupt
    • Be 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.

/35

delaying a task for 1 tick
Delaying a Task for 1 Tick

20 mS

Tick Interrupt

Tick ISR

All higher priority tasks

Call to delay 1 tick (20 mS)

Call to delay 1 tick (20 mS)

Call to delay 1 tick (20 mS)

Delayed Task

t3

t1

t2

(27 mS)

(19 mS)

(6 mS)

/35

clock tick1
Clock Tick
  • Solve 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.

/35

memory requirement
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

/35

real time kernels
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.

/35

uc os ii1
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

kernel structure
Kernel Structure
  • Task Control Blocks
  • Ready List
  • Task Scheduling
  • Interrupt under uC/OS-II

/35

critical sections
Critical Sections
  • Archive this by disabling interrupt
  • OS_CPU.H
    • OS_ENTER_CRITICAL()
    • OS_EXIT_CRITICAL()

/35

tasks
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.

/35

task control blocks
Task Control Blocks

typedef 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;

/35

os tcb lists
OS_TCB Lists
  • TCBs store in OSTCBTbl[]
  • All TCBs are initialized and linked when uC/OS-II is initialized

/35

osrdygrp and osrdytbl
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.

/35

making a task ready to run
Making a Task Ready to Run

OSRdyGrp |= OSMapTbl[prio >> 3];

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

/35

removing a task from the ready list
Removing a Task from the Ready List

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

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

/35

finding the highest priority task
Finding the Highest Priority Task

76543210 OSUnMapTbl[]

00000000 0

00000001 0

00000010 1

00000011 0

00000100 2

00000101 0

00000110 1

00000111 0

00001000 3

00001001 0

00001010 1

00001011 0

00001100 2

00001101 0

00001110 1

00001111 0

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

};

/35

task scheduler
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();

}

/35

locking the scheduler
Locking The Scheduler

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

/35

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

/35

idle task
Idle Task
  • OSTaskIdle()
  • Lowest priority, OS_LOWEST_PRIO

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

/35

initializing the statistic task
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! */ }}

/35

initializing the statistic task1
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();

}

/35

statistics task1
Statistics Task

void OSTaskStat (void *pdata)

{

INT32U run;

INT8S usage;

pdata = pdata;

while (OSStatRdy == FALSE) { (1)

OSTimeDly(2 * OS_TICKS_PER_SEC);

}

for (;;) {

OS_ENTER_CRITICAL();

OSIdleCtrRun = OSIdleCtr;

run = OSIdleCtr;

OSIdleCtr = 0L;

OS_EXIT_CRITICAL();

if (OSIdleCtrMax > 0L) {

usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); (2)

if (usage > 100) {

OSCPUUsage = 100;

} else if (usage < 0) {

OSCPUUsage = 0;

} else {

OSCPUUsage = usage;

}

} else {

OSCPUUsage = 0;

}

OSTaskStatHook(); (3)

OSTimeDly(OS_TICKS_PER_SEC);

}

}

/35

interrupts under uc os ii
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;

/35

beginning an isr
Beginning an ISR

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

/35

leaving an isr
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();

}

/35

pseudo code for tick isr
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;}

/35

service a tick
Service a Tick

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

/35

uc os ii initialization
uC/OS-II Initialization
  • Initialize variables and data structures
  • Create the idle task OSTaskIdle()
  • Create the statistic task OSTaskStat()

/35

starting uc os ii
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) }}

/35

uc os ii2
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

task management
Task Management
  • Task prototype
  • Create a task
  • Task stacks
  • Stack checking
  • Delete a task
  • Change a task’s priority
  • Suspend a task
  • Resume a task
  • Query task information

/35

task prototype
Task Prototype

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

/35

ostaskcreate
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

/35

ostaskcreate1

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

}

}

OSTaskCreate()

/35

ostaskcreateext
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

/35

ostaskcreateext1

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

}

}

OSTaskCreateExt()

/35

task stacks
Task Stacks

Static OS_STK MyTaskStack[stack_size];

or

OS_STK MyTaskStack[stack_size];

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;

}

/35

ostaskstkchk
OSTaskStkChk()
  • Computes the amount of free stack space by “walking” from the bottom of the stack until a nonzero value is found

/35

ostaskdel
OSTaskDel()
  • Return to the DORMANT state
  • The code for the task will not be deleted
  • Procedures
    • Prevent from deleting and idle task
    • Prevent from deleting a task from within an ISR
    • Verify that the task to be deleted does exist
    • Remove the OS_TCB
    • Remove the task from ready list or other lists
    • Set .OSTCBStat to OS_STAT_RDY
    • Call OSDummy()
    • Call OSTaskDelHook()
    • Remove the OS_TCB from priority table
    • Call OSSched()

/35

ostaskdelreq
OSTaskDelReq()
  • Tell the task that owns memory buffers or semaphore to delete itself
  • Procedures
    • Check the task’s priority
    • If the task’s priority is OS_PRIO_SELF
      • Return the flag of OSTCBDelReq
    • Otherwise
      • Set OSTCBDelReq of the task to OS_TASK_DEL_REQ

/35

ostaskdelreq example
OSTaskDelReq() Example

void 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 */ } }}

/35

ostaskchangeprio
OSTaskChangePrio()
  • Cannot change the priority of any idle task
  • Procedures
    • Reserve 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()

/35

ostasksuspend
OSTaskSuspend()
  • Procedures
    • Check the input priority
    • Remove the task from the ready list
    • Set the OS_STAT_SUSPEND flag in OS_TCB
    • Call OSSched()

/35

ostaskresume
OSTaskResume()
  • Procedures
    • Check the input priority
    • Clear the OS_STAT_SUSPEND bit in the OSTCBStat field
    • Set OSTCBDly to 0
    • Call OSSched()

/35

ostaskquery
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);

}

/35

uc os ii3
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

time management
Time Management
  • OSTimeDly()
  • OSTimeDlyHMSM()
  • OSTimeDlyResume()
  • OSTimeGet()
  • OSTimeSet()

/35

ostimedly
OSTimeDly()

void OSTimeDly (INT16U ticks) {

if (ticks > 0) {

if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {

OSRdyGrp &= ~OSTCBCur->OSTCBBitY; }

OSTCBCur->OSTCBDly = ticks;

OSSched(); }

}

/35

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

}

/35

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

}

/35

ostimeget ostimeset
OSTimeGet() & OSTimeSet()

INT32U OSTimeGet (void) {

ticks = OSTime;

return (ticks);

}

void OSTimeSet (INT32U ticks) {

OSTime = ticks;

}

/35

uc os ii4
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

intertask communication synchronization
Intertask Communication & Synchronization
  • OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()
  • OSSchedLock()OSSchedUnlock()
  • SemaphoreMessage mailboxMessage queue

/35

os enter critical os exit critical
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

/35

linux example
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()

/35

locking and unlocking the scheduler
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(); }

}

}

}

/35

event control block
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;

/35

wait queue functions
Wait Queue Functions

void 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; }

}

/35

wait queue functions1
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;

}

/35

creating a semaphore
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);

}

/35

waiting for a semaphore
Waiting for a Semaphore

void 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; }

}

}

/35

signaling a semaphore
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); }

}

}

/35

getting a semaphore without waiting
Getting a Semaphore without Waiting

INT16U OSSemAccept (OS_EVENT *pevent) {

cnt = pevent->OSEventCnt;

if (cnt > 0) {

pevent->OSEventCnt--;

}

return (cnt);

}

/35

obtaining the status of a semaphore
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);

}

/35

creating a mailbox
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);

}

/35

waiting for a message to arrive at a mailbox
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);

}

/35

depositing a message in a mailbox
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); }

}

}

/35

getting a message without waiting
Getting a Message without Waiting

void *OSMboxAccept (OS_EVENT *pevent) {

msg = pevent->OSEventPtr;

if (msg != (void *)0) {

pevent->OSEventPtr = (void *)0; }

return (msg);

}

/35

obtaining the status of a mailbox
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);

}

/35

using a mailbox as a binary semaphore
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) */

}

}

/35

using a mailbox as a time delay
Using a Mailbox as a Time Delay

void 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 */

.

.

}

}

/35

message queues1
Message Queues
  • OSQCreate()
  • OSQPend()
  • OSQPost()
  • OSQPostFront()
  • OSQAccept()
  • OSQFlush()
  • OSQQuery()

/35

message queues2
Message Queues
  • A message queue
    • Allows 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.

/35

queue control block
Queue Control Block
  • A queue control block contains following fields
    • OSQPtr
    • OSQStart
    • OSQEnd
    • OSQIn
    • OSQOut
    • OSQSize
    • OSQEntries

/35

creating a queue
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.

/35

osqcreate
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);

}

/35

osqpend 1
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;

/35

osqpend 2
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);

}

/35

osqpost
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);

}

}

/35

osqpostfront
OSQPostFront()
  • OSQPostFront()
    • Is basically identical to OSQPost().
    • Uses OSQOut instead of OSQIn as the pointer to the next entry.

/35

osqpostfront cont
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);

}

}

/35

osqaccept
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);

}

/35

osqflush
OSQFlush()

INT8U OSQFlush (OS_EVENT *pevent)

{

pq = pevent->OSEventPtr;

pq->OSQIn = pq->OSQStart;

pq->OSQOut = pq->OSQStart;

pq->OSQEntries = 0;

return (OS_NO_ERR);

}

/35

osqquery
OSQQuery()
  • Pass a OS_Q_DATA structure to query.
  • OS_Q_DATA contains following fields
    • OSMsg
    • OSNMsgs
    • OSQSize
    • OSEventTbl[]
    • OSEventGrp

/35

osqquery cont
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);

}

/35

using a queue as a counting semaphore
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) */

}

}

/35

uc os ii5
uC/OS-II
  • Real-Time Systems Concepts
  • Kernel Structure
  • Task Management
  • Time Management
  • Intertask Communication & Synchronization
  • Memory Management

/35

memory management
Memory Management
  • Overview
  • Memory Control Blocks
  • OSMemCreate()
  • OSMemGet()
  • OSMemPut()
  • OSMemQuery()
  • Examples

/35

ansi c malloc and free
ANSI C malloc() and free()
  • Dangerous in an embedded real-time system.
    • Fragmentation.
    • Non-deterministic.

/35

c os ii malloc and free
µ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.

/35

memory control blocks
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.

/35

memory control block data structure
Memory Control Block Data Structure

typedef struct {

void *OSMemAddr;

void *OSMemFreeList;

INT32U OSMemBlkSize;

INT32U OSMemNBlks;

INT32U OSMemNFree;

} OS_MEM;

/35

osmemcreate 2
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);

}

/35

osmemget
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);

}

}

/35

returning a memory block
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);

}

/35

obtaining status about memory partition
Obtaining Status about Memory Partition
  • Pass a OS_MEM_DATA structure to query.
  • OS_MEM_DATA contains following fields
    • OSAddr
    • OSFreeList
    • OSBlkSize
    • OSNBlks
    • OSNFree
    • OSNUsed

/35

osmemquery
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);

}

/35

waiting for memory blocks 1
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.

/35

waiting for memory blocks 2
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();

}

/35

waiting for memory blocks 3
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);

}

}

/35

ad