Introduction to uc os ii
This presentation is the property of its rightful owner.
Sponsored Links
1 / 156

Introduction to uC/OS-II PowerPoint PPT Presentation


  • 44 Views
  • Uploaded on
  • Presentation posted in: General

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

Download Presentation

Introduction to uC/OS-II

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


Multitasking1

Multitasking

/35


Introduction to uc os ii

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


Task states

Task States

/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


Non preemptive kernel1

Non-Preemptive Kernel

/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


Preemptive kernel1

Preemptive Kernel

/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


Priority inversion problem

Priority Inversion Problem

/35


Priority inheritance

Priority Inheritance

/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


Using semaphore

Using Semaphore

/35


Synchronization

Synchronization

  • Synchronization mechanism is used between tasks or task to ISR.

    • Unilateral rendezvous

    • Bilateral rendezvous

/35


Unilateral rendezvous

Unilateral rendezvous

/35


Bilateral rendezvous

Bilateral rendezvous

/35


Event flags

Event Flags

/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 nesting

Interrupt Nesting

/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 preemptive kernel2

Non-preemptive Kernel

/35


Preemptive kernel2

Preemptive Kernel

/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 states1

Task States

/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


Ready list

Ready List

/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

76543210OSUnMapTbl[]

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


Statistics task

Statistics Task

/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


Servicing an interrupt

Servicing an Interrupt

/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


After calling osinit

After calling OSInit()

/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


Fragmentation

Fragmentation

/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


Stack checking

Stack Checking

/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


Ecb event control block

ECB (Event Control Block)

/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


List of free ecbs

List of Free ECBs

/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


Semaphore

Semaphore

/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


Message mailbox

Message Mailbox

/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


Message queues cont

Message Queues (Cont.)

/35


Data structures in a message queue

Data Structures in a Message Queue

/35


Queue control block

Queue Control Block

  • A queue control block contains following fields

    • OSQPtr

    • OSQStart

    • OSQEnd

    • OSQIn

    • OSQOut

    • OSQSize

    • OSQEntries

/35


List of free queue control blocks

List of Free Queue Control Blocks

/35


Message queue is a circular buffer

Message Queue Is a Circular Buffer

/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 message queue when reading analog inputs

Using a Message Queue When Reading Analog Inputs

/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


Multiple m emory p artitions

Multiple Memory Partitions

/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


List of free memory control blocks

List of Free Memory Control Blocks

/35


Osmemcreate 1

OSMemCreate() (1)

/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


Using d ynamic m emory a llocation

Using Dynamic Memory Allocation

/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


  • Login