Sei sulla pagina 1di 81

uCOS II

RTOS

Reference Book

Build Toolchain

Build Binary tools

Build GCC for the 1st time


(w ithout Glibc)
Build Glibc
(Need kernel head file)
Build GCC for the 2nd
time
(With Glibc)

Build uGlibc for embedded


development

Build GDB

Binutils
cd binutils-2.13.90.0.16
./configure --target=powerpc-linux --prefix=/opt/linuxppc
make
make install
/opt/linuxppc/bin
--prefix
/usr/local/usr

GCC

st
(1

Compile)

cd gcc-2.95.3
./configure --target=powerpc-linux prefix=/opt/linuxppc \
--enable-shared --enable-languages=c --with-newlib
make
make install

Extract Kernel
 tar

xvfz

GLIBC
Un-compress

GLIBC

&

glibc-linuxthreads

ln s include/asm-ppc /opt/powerpc-linux/include/asm
ln s include/linux /opt/powerpc-linux/include/linux
CC = powerpc-linux-gcc
AR=powerpc-linux-ar
RANLIB=powerpc-linux-ranlib
./configure --host=powerpc-linux enable-add-ons \
--with-headers=/opt/powerpc-linux/include\
--prefix=/opt/linuxppc
make
make install_root=/opt/powerpc-linux install

GCC

nd
(2

Compile)

make distclean
./configure --prefix=/opt/linuxppc target=powerpc-linux \
--enable-shared enable-threads
make && make install

Why RTOS?
 Learn

RTOS:

Fill the gap between Computer Science


Experts and Application Engineers
Understanding Computer more theoretically
 Using

RTOS:

Simplify the Application Programming


Higher the System Performance and
Reliability

Feature of Morden RTOS


 CPU(MMU

)


 C/C++ JAVA

Real Time Kernel

Advantage/Disadvantage of
Using RTOS


Advantage
Split application to multi tasks, simplify the
design, easy to be understand, expend and
maintenance
Time latency is guaranteed
Higher system reliability

Disadvantage
More RAM/ROM usage
2~5% CPU overhead
Adding additional cost, if commercial TROS is
used
About 80 RTOS vendors, cost from $70 to $30,000 some
are royalty free, some need $5 to $250 /MCU, MCU
dependent

What is uCOS II?


 Micro-Controller

Operating Systems,

Version 2
 A very small real-time kernel.
 Memory footprint is about 20KB for a
fully functional kernel.
 Source code is about 5,500 lines,
mostly in ANSI C.
 Its source is open but not free for
commercial usages.

Feature of uC/OSII






Preemptible priority-driven real-time


scheduling.
64 priority levels (max 64 tasks), 8 reserved
for uC/OS-II
Each task is an infinite loop.
Deterministic execution times for most
uC/OS-II functions and services.
Nested interrupts could go up to 256 levels.

Real Time Kernel on uCOS

C/OS is Widely Used in Many


Fields
 cameras
 medical

instruments
 Engine control
 musical instruments
 network adapter
 highway telephone call
box
 ATM machine
 industrial robots


Ports On Different CPUs


Manufacture MCU









AMD
Analog Device
ARM
Atmel
Fujitsu
Hitachi
Infineon
Intel

Motorola
M68HC16,

Philips
ST
TI
Automation
Zilog






80x86
SHARC (AD21065L)
ARM7
AVR, AT103
SPARC
64180, H8-300H, H8S,SH2,SH3
Tri.Core, 80C166/167
Strong ARM110,80C251,XC52, 80x86,
196K
M68HC08, M68HC11, M68HC12,
M68000, CPU32, DSP568xx, Cold.Fire,
M.Core, PowerPC8xx,MPC555
XA
80C166/167
TMS320-C40, TMS320-C6201
V8
Z-80, Z-180

Roadmap of Learning


Read the book and the C/OS-II source code


Understanding RTOS concepts

Compiler the C/OS-II with examples and run


on a PC
Add some codes to the examples

Porting the C/OS-II to a MCU, which you are


familiar with
Write the CPU.c and the CPU.a files

Do a project with a MCU board


Learn how to divide an application to several tasks
Communication and synchronization within tasks

uCOS II Architecture
Applications (Tasks)
CPU Independent Code
uCOS-II.h (Global Var)
uCOS_II.c Groups:
OS_Core.c OS_Task.c
OS_Time.c OS_Sem.c
OS_Mbox.c OS_Q.c
OS_Mem.c

Application
Configuration
Code
OS_CFG.h
Includes.h

CPU Dependent Code


OS_CPU.H OS_CPU_A.ASM OS_CPU_C.C
CPU Startup Code

ISR (Timer and Other INT)

Feature of uCOSII
Portable :

portable C, minimum uC dependent ASM

ROMable & Scalable


Preemptive :

uC/OS-II is a fully preemptive real-time kernel

Multitasking : uC/OS-II can manage up to 64 tasks


Deterministic : Execution time of all uC/OS-II functions and
service are deterministic
Deterministic : Each task requires its own different stack size
Services :

Mailboxes, Queues, Semaphores, fixed-sized


memory partitions, time-related functions

Interrupt Management
Int. can be nested up to 255 levels deep
Robust and Reliable

OS Functions Provided by
uCOSII

Feature Not Supported by


uCOS
Not support priority inheritance.
With uC/OS-II, all tasks must have a unique
priority, (Cannot Change While Running)

Term (1)


Multitasking
The process of scheduling and switching the CPU
between several tasks

Task
A simple program which thinks it has the CPU all
to itself.

Kernel
The part of the multitasking system responsible for
the management of tasks and communication
between tasks

Task Switch
Kernel saves the current task's context (CPU
registers) onto the current task's stack.
Kernel load new task's context from the tasks
stack of new task

Term (2)


TCB
Task Control Block

Scheduler
Also called the dispatcher, is the part of the kernel
which is responsible for determining which task
will run next

Non-preemptive scheduling
Each task is required to explicitly give up control of
the CPU. (ex. System API Call)
cooperative multitasking; tasks cooperate with
each other to gain control of the CPU.

Term (3)
 Preemptive

Kernel

In it, when an event makes a higher priority


task ready to run, the current task is
immediately suspended and the higher
priority task is given control of the CPU
 Reentrancy

A reentrant function is a function which can


be used by more than one task without fear
of data corruption.

uC/OS II Overview
External
IRQ
TaskA() TaskB() TaskC()

Task Scheduler

IRQ1 IRQ2 IRQ3

Timer

MultiTasking
Overview

Sample Code (0)


Task0

Task1

MBox0

MBox1

Sample Code (1)


Global Variables
main()
{
init OS;
init Global Variables;
init Task0 and Task1
}
Task0()
{

Task1()
{

#include "includes.h"

Sample
Code (2)

// Registers and data definition for our MX1 CPU


#include "type.h"
#include "mx1.h"
// Basic IO operation function
extern void EUARTinit(void);
extern U8 EUARTgetData(void);
extern void EUARTputString(U8 *line);
// Define stacks for eack task (32-bit)
#define TASK_STK_SIZE 512
OS_STK TaskStk[2][TASK_STK_SIZE];
// Function prototypes of tasks
void Task0(void *data);
void Task1(void *data);
// Mail boxes (Just two points)
OS_EVENT* MBox0;
OS_EVENT* MBox1;

int main (void)


{
P_U32 temp;
// Init UART controller
EUARTinit(); EUARTputString("\nEntering main() now!\n");

Sample
Code (3)

// Init uCOS kernel


OSInit();
// Create Mailbox
MBox0 = OSMboxCreate((void*)0);
MBox1 = OSMboxCreate((void*)0);
// Create two task
OSTaskCreate(Task0,
// Task function
(void *)0,
// point to data struct for this task
&(TaskStk[0][TASK_STK_SIZE - 1]), // stacks for the task
1);
// priority
OSTaskCreate(Task1,
// Task function
(void *)0,
// no data transfered
&(TaskStk[1][TASK_STK_SIZE - 1]), // point to data struct for this task
2);
// priority
OSStart(); // Start multi-tasking now
return 0; // Never comes here
}

Sample Code (4)


void Task0 (void *data)
{
int n = 0;
int i;
void* msg;
INT8U err;

void Task1 (void *data)


{
int m = 0;
int i;
void* msg;
INT8U err;

while (1)
{
// Do something
for (i = 0; i < 10000; i++) n++;

while (1)
{
// Do something
for (i = 0; i < 1234; i++) m++;

// Tell people task0 is running


EUARTputString("Enter task0\n");

// Tell people task1 is running


EUARTputString("Enter task1\n");

// Send mail to mailbox 1 (to task 1)


err = OSMboxPost(MBox1, (void*)&n);

// Waiting for mail from mailbox 1 (mail


from task 0)
msg = OSMboxPend(MBox1, 100, &err);

// Waiting for mail from mailbox 0 (reply


from task1)
msg = OSMboxPend(MBox0, 100, &err);

// Get data attached in the mail


m = *((int*)msg);

// Get data attached in the mail


n = *((int*)msg);

// Reply the mail to mailbox 0 (to task 0)


err = OSMboxPost(MBox0, (void*)&m);

}
}

}
}

Sample Code (5)


Task0

Task1

Calculate n

Calculate m

Send mail to 1
Waiting reply from 1

Wait mail from 0


Retrieve data from mail

Retrieve data from mail

Reply 0

Calculate n
Send mail to 1

Calculate m
Wait mail from 0

Waiting reply from 1


Retrieve data from mail

Retrieve data from mail


Reply 0

OSInit (1)









internal structures of uC/OS-2.


Task ready list.
Priority table.
Task control blocks (TCB).
int main (void)
Free pool.
{

Create housekeeping tasks. OSInit();

OSTaskCreate();
The idle task.

OSTaskCreate();
The statistics task.

OSStart();
return 0; // Never return
}

OSInit
(2)

Ready List

OSRdyGrp

OSTCBPrioTbl[]

1 0 0 0 0 0 0 0

OSRdyTbl[]
0
0
0
0
0
0
0
1

0
0
0
0
0
0
0
1

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0
0

0
0
0
0
0
0
0

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

0
0
0
[OS_LOWEST_PRIO - 1]
[OS_LOWEST_PRIO]

OSTaskStat()
OS_TCB

OSTCBList
OSPrioCur
OSPrioHighRdy
OSTCBCur
OSTCBHighRdy
OSTime
OSIntNesting
OSLockNesting
OSCtxSwCtr
OSTaskCtr
OSRunning
OSCPUUsage
OSIdleCtrMax
OSIdleCtrRun
OSIdleCtr
OSStatRdy

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

0
0
NULL
NULL
0L
0
0
0
2
FALSE
0
0L
0L
0L
FALSE

OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_LOWEST_PRIO
OSTCBNext
OSTCBPrev
OSTCBEventPtr = NULL
OSTCBMsg = NULL
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBPrio = OS_LOWEST_PRIO-1
OSTCBX = 6
OSTCBY = 7
OSTCBBitX = 0x40
OSTCBBitY = 0x80
OSTCBDelReq = FALSE

Task Stack

OSTaskIdle()
OS_TCB
OSTCBStkPtr
OSTCBExtPtr = NULL
OSTCBStkBottom
OSTCBStkSize = stack size
OSTCBId = OS_LOWEST_PRIO
OSTCBNext
OSTCBPrev
OSTCBEventPtr = NULL
OSTCBMsg = NULL
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBPrio = OS_LOWEST_PRIO
OSTCBX = 7
OSTCBY = 7
OSTCBBitX = 0x80
OSTCBBitY = 0x80
OSTCBDelReq = FALSE

Task Stack

OS_MAX_TASKS
OS_TCB

OSTCBFr

List

OSInit
(4)

OS_TCB

OS_TCB

OS_TCB

OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq

OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq

OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq

OSTCBStkPtr
OSTCBExtPtr
OSTCBStkBottom
OSTCBStkSize
OSTCBId
OSTCBNext
OSTCBPrev
OSTCBEventPtr
OSTCBMsg
OSTCBDly
OSTCBStat
OSTCBPrio
OSTCBX
OSTCBY
OSTCBBitX
OSTCBBitY
OSTCBDelReq

OS_MAX_EVENTS
OS_EVENT

OSEventFreeList

OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp

OS_EVENT

OS_EVENT

OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp

OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp

OS_EVENT

OSEventPtr
OSEventTbl[]
OSEventCnt
OSEventType
OSEventGrp

OS_MAX_QS
OS_Q

OSQFreeList

OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries

OS_Q

OS_Q

OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries

OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries

OS_Q

OSQPtr
OSQStart
OSQEnd
OSQIn
OSQOut
OSQSize
OSQEntries

OS_MAX_MEM_PART
OS_MEM

OSMemFreeList

OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree

OS_MEM

OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree

OS_MEM

OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree

OS_MEM

OSMemAddr
OSMemFreeList
OSMemBlkSize
OSMemNBlks
OSNFree

OSInit (3)
OSRdyGr
7

OSRdyTbl[OS_LOWEST_PRIO / 8
i

st ri rit Task

X
[0]

[1]

15 14 13 12 11 10

[2]

23 22 21 20 19 18 17 16

[3]

31 30 29 28 27 26 25 24

[4]

39 38 37 36 35 34 33 32

[5]

47 46 45 44 43 42 41 40

[6]

55 54 53 52 51 50 49 48

[7]

63 62 61 60 59 58 57 56

Task ri rit #

Task's Pri rity


0

Bit

siti

st ri rit Task
(I l Task)

i OSRdyTbl[OS_LOWEST_PRIO / 8

Bit siti i OSRdyGr and


Index int OSRdyTbl[OS_LOWEST_PRIO / 8

1]

1]

1]

OSTaskCreate (1)




Create tasks with the given arguments.


Tasks become ready after they are created.
Task
An active entity which could do some
computations.
int main (void)
{
Priority, CPU registers,

OSInit();
stack, text, housekeeping

OSTaskCreate();
status.

OSTaskCreate();
Task never return;

OSStart();
return 0; // Never return

OSTaskCreate (2)

Task Function

INT8U OSTaskCreate (void (*task)(void *pd),


void *pdata,
Private Data
OS_STK *ptos,
For Task
INT8U prio)
Priority of
created task

Stack For Task

Note that OSTaskCreate can be called by


main when OSStart is not invoked, but it
can also be called in tasks when more
task should be created at the run time

Creating Task, OSTaskCreate()


INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
{
void *psp;
INT8U err;

if (prio > OS_LOWEST_PRIO) {


return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) {
OSTCBPrioTbl[prio] = (OS_TCB *)1;

/* Make sure priority is within allowable range

*/

/* Make sure task doesn't already exist at this priority */


/* Reserve the priority to prevent others from doing ...

*/
/* ... the same thing until task is created.
OS_EXIT_CRITICAL();
psp = (void *)OSTaskStkInit(task, pdata, ptos, 0);
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0);
if (err == OS_NO_ERR) {
OS_ENTER_CRITICAL();
OSTaskCtr++;
OSTaskCreateHook(OSTCBPrioTbl[prio]);
OS_EXIT_CRITICAL();
if (OSRunning) {

/* Initialize the task's stack

/* Increment the #tasks counter


/* Call user defined hook

*/

*/

*/
*/

/* Find highest priority task if multitasking has started

*/
OSSched();
}
} else {
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *)0;
OS_EXIT_CRITICAL();
}
return (err);
} else {
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
}
}

/* Make this priority available to others

*/

OSStart
 Start

multitasking of uC/OS-2.
 It never returns to main()
 The uC/OS-II picks up the highestpriority task to run on context-switching.
Tightly coupled with RTC ISR.
int main (void)
{

OSInit();

OSTaskCreate();

OSTaskCreate();

OSStart();
return 0; // Never return
}

WAITING

OSTaskDel()

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

OSTaskCreate()
OSTaskCreateExt()

DORMANT

READY

Task
Management

OSMBoxPend()
OSQPend()
OSSemPend()
OSTaskSuspend()
OSTimeDly()
OSTimeDlyHMSM()

OSStart()
OSIntExit()
OS_TASK_SW()

Interrupt

RUNNING

ISR
OSIntExit()

OSTaskDel()
Task is Preempted
OSTaskDel()

Task is created by calling OSTaskCreate()


Task is deleted by calling OSTaskDel() (After calling the
function OS will never touch the task)
Task is in waiting when request a system resource or singal
(OSSemPend(),OSMboxPend(),OSQPend(), OSTimeDly() or
OSTimeDlyHMSM() )

Task Management (contd.)


uC/OS-II can manage up to 64 tasks
- two task are used for system use.
- Reserve prorities 0, 1, 2, 3,
OS_LOWEST_PRIO-3, 2, 1, 0

Use 56 application task

Task Control Block (TCB)


When a task is created, it is assigned a Task
Control Block, OS_TCB
OS_TCB is a data structure that is used by
uC/OS-II to maintain the state of a task when it
is preempted.
All OS_TCB reside in RAM
An OS_TCB is initialized when a task is
created.

typedef struct os_tcb {


OS_STK
*OSTCBStkPtr; // Can be accessed by ASM
#if OS_TASK_CREATE_EXT_EN
// Data for advanced task
void
*OSTCBExtPtr; // (record more info.)
OS_STK
*OSTCBStkBottom;
INT32U
OSTCBStkSize;
INT16U
OSTCBOpt;
INT16U
OSTCBId;
#endif
struct os_tcb *OSTCBNext;
// 2 dir link
struct os_tcb *OSTCBPrev;
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN
OS_EVENT
*OSTCBEventPtr; // Point to event list for
#endif
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
// Point to message list
void
*OSTCBMsg;
#endif
INT16U
OSTCBDly;
// Task call delay()
INT8U
OSTCBStat;
// Lower value
higher prio.
INT8U
OSTCBPrio;
INT8U
OSTCBX;
// For fast task schedule
INT8U
OSTCBY;
= priority >> 3;
INT8U
OSTCBBitX; OSTCBY
OSTCBBitY = OSMapTbl[priority >> 3];
INT8U
OSTCBBitY; OSTCBX
= priority & 0x07;
#if OS_TASK_DEL_EN
OSTCBBitX = OSMapTbl[priority &
BOOLEAN
OSTCBDelReq;
0x07];
#endif
} OS_TCB;

TCB
Structure

TCB Structure (contd.)


OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS-1]
OSTCBTbl[0]

OSTCBFreeList

OSTCBTbl[1]

OSTCBTbl[2]

OSTCBNext

OSTCBNext

OSTCBNext

OSTCBNext

OS_MAX_TASKS is specified in OS_CFG.H

Task Scheduling
Task-level scheduling is performed by OSSched().
ISR-level scheduling is handled by OSIntExit().
void OSSched (void)
{
INT8U y;
OS_ENTER_CRITICAL();
if ((OSLockNesting | OSIntNesting) == 0) {/* Task scheduling must be enabled and not ISR level */
y = OSUnMapTbl[OSRdyGrp];
/* Get pointer to highest priority task ready to run */
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur) {
/* No context switch if current task is highest ready */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
/* Increment context switch counter
*/
OS_TASK_SW();
/* Perform a context switch
*/
}
}
OS_EXIT_CRITICAL();
}

Memory Management in uCOS




malloc() and free() is dangerous in Embedded


real-time system
Unable to obtain a single contiguous memory area
due to fragmentation

Execution time of malloc() and free() are also


nondeterministic
Algorithms used to locate a contiguous block of free
memory
Time for de-fragmentation

Fixed-sized memory blocks from a partition


made of a contiguous memory area.
All memory blocks are the same size and the
partition contains an integral number of blocks
Allocation and deallocation of these memory blocks
is done in constant time and is deterministic

Memory Management in uCOS


(contd.)

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

pmem

OSMemAddr

= addr

OSMemFreeList= addr
OSMemBlkSize = blksize
OSMemNBlks

= nblks

OSMemNFree

= nblks

Contiguous memory
OSMemCreate() arguments

Get one node from


OSMemFreeList, & fill
with real memory
partition info.

Only empty
data structs
after init

OSMemAddr

OSMemAddr

OSMemFreeList

OSMemFreeList

OSMemFreeList

OSMemBlkSize

OSMemFreeList

OSMemAddr

OSMemBlkSize

OSMemBlkSize

OSMemNBlks

OSMemNBlks

OSMemNBlks

OSMemNFree

OSMemNFree

OSMemNFree

OS_MAX_MEM_PART

Memory
Management in
uCOS (contd.)

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

OS_MEM *CommTxBuf;
INT8U CommTxPart[100][32];
void main(void)
{
INT8U err;
...
OSInit();
...
CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err);
...
OSStart();
}

Memory Management Functions




OSMemCreate (void *addr, INT32U nblks,


INT32U blksize, INT8U *err)
Format a memory partition

OSMemGet (OS_MEM *pmem, INT8U *err)


Get a memory block from one of the created
memory partitions

OSMemPut (OS_MEM

*pmem, void *pblk)

Returning a Memory Block to the appropriate


partition


OSMemQuery()
Obtaining status of a Memory partition

Memory Management Example


OSTime
OSTimeGet()

(3)
ErrMsgQ
Analog
Inputs

AI
Task

OSQPost()

OSQPend()

(5)

(6)

Error
Handler

(1)
(4)
OSMemGet()

(2)

ErrMsgPart

(7)
OSMemPut()

(8)

Time Management
10m s

Tic k Inte rrupt

(2)

(1)

(5)

O S Tic kIS R()


(3)
All HPT
(6)
Lo w- Prio rity Ta s k
Ta s k c a lls
O S Tim e Dly(1) he re !

(4)

5m s

Time Management Function




 OSTimeDly()
Delay for a user-specified

number of clock ticks

 OSTimeDlyHMSM()
hours(H), minutes(M), seconds(S),
milliseconds(m), Maximum Delay 256hours (11days)
OSTimeDlyHMSM( 0, 0, 1, 500);

 OSTimeDlyResume()
Resuming a Delayed Task

 OSTimeGet() & OSTimeSet()


32-bit counter

Time Management Function


(contd.)
1

Task A

Task A call

OSTimeDly(100)
2
3
Task B
Find the highest
priority ready task
B, and activate it

Task A

Task A sleep now

This ISR is called


every time tick to
advance the clock
OSTickISR

Hooks


A hook function will be called by uC/OSwhen the corresponding event occurs.


Event handlers could be in user programs.
For example, OSTaskSwHook () is called every
time when context switch occurs.

The hooks are specified in the compiling time


in uC/OS-II:
uC/OS-II is an embedded OS.
OS_CFG.H (OS_CPU_HOOKS_EN = 0)

Many OSs can register and un-register hooks.

Hook Functions Empty function, can be


overridden by user










void OSInitHookBegin (void)


void OSInitHookEnd (void)
void OSTaskCreateHook (OS_TCB *ptcb)
void OSTaskDelHook (OS_TCB *ptcb)
void OSTaskIdleHook (void)
void OSTaskStatHook (void)
void OSTaskSwHook (void)
void OSTCBInitHook (OS_TCB *ptcb)
void OSTimeTickHook (void)

Mail Box


A mailbox is for data exchanging between


tasks.
A mailbox consists of a data pointer and a wait-list.

OSMboxPend():
The message in the mailbox is retrieved.
If the mailbox is empty, the task is immediately
blocked and moved to the wait-list.
A time-out value can be specified.

OSMboxPost():
A message is posted in the mailbox.
If there is already a message in the mailbox, then
an error is returned (not overwritten).
If tasks are waiting for a message from the mailbox,
then the task with the highest priority is removed
from the wait-list and scheduled to run.

Mail Box Operation


OS_EVENT* MBox0;
OS_EVENT* MBox1;

MBox0 = OSMboxCreate((void*)0);
MBox1 = OSMboxCreate((void*)0);

err = OSMboxPost(MBox1, (void*)&n);

msg = OSMboxPend(MBox0, 100, &err);

OSMboxCreate


Step 1
Get a OS_EVENT node from OSEventFreeList

Step 2
Assign type OS_EVENT_TYPE_MBOX to the OS_EVENT
node

Step 3
Attach the message (given from caller) to the OS_EVENT
node




Step 4
Return the point of the OS_EVENT node to the caller
Note
Mail box is an event in the view of uCOS
Mail box is not attach to specific task when created
The mail box has a table to record the tasks that are waiting
on the mail box.

OSMboxPost


Step 1
If there has some Task waiting on the mail box,
wake up it and give the message to it directly

Step 2 (Step 1 is not run)


If the mail box is full return error
OS_MBOX_FULL

Step 3 (Step 2 is not run)


Attach mail message to the mail box (mail box is
a special event)

Step 1

OSMboxPend

If mail box is empty pending the task by calling


empty,
OSEventTaskWait() (This function will register the
task on the event table of the mail box, so that when
mail box receive a message, it can check its table to
wake up those tasks)


Step 2 (Step 1 is not run)


This step is run either because mail box get new
email or timeout event occur
The mail will be sent to task directly
Note:
The message can be found by tasks message pointer. If
there are already tasking waiting for mail in the mailbox, the
arriving mail is given to task directly instead of storing to
mailbox and then inform the task
The message can be found in mail boxs pointer if the mail
is sent when no tasking is pending for mail of the mail box.

Message Qeue






A message queue consists of an array of


elements and a wait-list.
Different from a mailbox, a message queue
can hold many data elements (in a FIFO
basis).
As same as mailboxes, there can be multiple
tasks pend/post to a message queue.
OSQPost(): a message is appended to the
queue. The highest-priority pending task (in
the wait-list) receives the message and is
scheduled to run, if any.
OSQPend(): a message is removed from the
array of elements. If no message can be
retrieved, the task is moved to the wait-list
and becomes blocked.

Intertask Comm. & Synch.


Sign al

IS R

IS R

W ait

EC B

EC B
Ta s k

Ta s k
Ta s k

EC B

W ait

Ta s k
T im e
ou t

Sign al

Ta s k

Sign al

W ait

T im e
ou t

Sign al

W ait/
Sign al

Ta s k

W ait

T im e
ou t

EC B
Ta s k

W ait/
Sign al

T im e
ou t

Ta s k

typedef struct {
void *OSEventPtr;
INT8U OSEventTbl[OS_EVENT_TBL_SIZE];
INT16U OSEventCnt;
INT8U OSEventType;
INT8U OSEventGrp;
} OS_EVENT;

Event Control
ECB is assigned to a mailbox or a queue
Blocks

OSEventPtr

OSEventTbl[] & .OSEventGrp


Contains a list of tasks waiting on the event
OSEventCnt
Hold the semaphore count
OSEventType
The type associated with the ECB
OS_EVENT_SEM, OS_EVENT_TYPE_MBOX, OS_EVENT_TYPE_Q

Event Control Blocks


Highest Priority Task Waiting

.OSEventGrp
7 6

4 3

1 0

.OSEventTbl[OS_LOWEST_PRIO/8+1]

[0]

15 14 13 12 11 10 9

[2]

23 22 21 20 19 18 17 16

[3]

31 30 29 28 27 26 25 24

[4]

39 38 37 36 35 34 33 32

[5]

47 46 45 44 43 42 41 40

[6]

[1]

Tasks Priority

55 54 53 52 51 50 49 48

[7]

63 62 61 60 59 58 57 56

0 Y Y Y X X X
Bit position in .OSEventTbl[]

Bit posion in .OSEventGrp


and Index into .OSEventTbl[]

Priority of task waiting


for the event to occur
Lowest Priority Task

Making a task wait for an event


pevent->OSEvebtGrp
|= OSMapTbl[prio >> 3];
pevent->OSEventTbl[prio>>3] |= OSMapTbl[prio & 0x07];
Content of OSMapTbl[]
Ind ex
0
1
2
3
4
5
6
7

it M ask(B inary)
0 0 0 0 0 0 01
0 0 0 0 0 0 10
0 0 0 0 0 1 00
0 0 0 0 1 0 00
0 0 0 1 0 0 00
0 0 1 0 0 0 00
0 1 0 0 0 0 00
1 0 0 0 0 0 00

Removing a task from a wait list


if ((pevent->OSEventTbl[prio>>3] &= ~OSMapTbl[prio & 0x07]) == 0) {
pevent->OSEventGrp &= ~OSMapTbl[prio >> 3]; }
Finding the highest priority task waiting for the event
y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEvenTbl[y]];
prio = (y<<3) + x;

OSEventWaitListInit()
: a function called when a semaphore, message mailbox, message queue is created
initializing an ECB

OSEventTaskRdy()
: Removes the highest priority task(HPT) from the wait list of the ECB and make
this task ready to run
called by OSSemPost(), OSMboxPosr(), OSQPost(), OSQPostFront()

OSEventTaskWait()
: called by OSSemPend(), OSMboxPend(), OSQPend() when a task must wait on
an ECB
Removes the current task from the ready list and places it in the wait list of the
ECB

Semaphores
16-bit unsigned integer used to hod the semaphore count (0 to 65535)
a list of tasks waiting for the semaphore count to be greater than 0
uC/OS-II provides five services to semaphores
OS S e m Cre a te ()

- OSSemCreate()
- OSSemPend()

OS S e m Po s t()

- OSSemPost()
- OSSemAccept()

OS S e m Pe n d ()
OS S e m Ac c e p t()
OS S e m Que ry()

Ta s k
N

- OSSemQuery()
OR
SR
OS S e m Po s t()
OS S e m Ac c e p t()

Ta s k

OSSemCreate()
: Creates and initializes a semaphore
OS_EVENT *DispSem;
void main(void)
{
...
OSInit();
...
DispSem = OSSemCreate(1);
...
OSStart();

OSSemPend()
: When a task wants exclusive access to
a resource, needs to synchronize its
activities with an ISR or a task, or is
waiting until an event occurs

void DispTask(void *pdata)


{
INT8U err;
pdata = pdata;
for (;;) {
...
OSSemPend(DispSem, 0, &err);

...
}
}

OSSemPost()
: A semaphore is signaled by calling
OSSemPost().

OSSemQuery()
: Obtain information about a semaphore

void Task (void *pdata)

void TaskX(void *pdata)


{
INT8U err;
pdata = pdata;
for (;;) {
...
err = OSSemPost(DispSem);
if (err == OS_NO_ERR) {
/* Semaphore signaled */
} else {
/* Semaphore has overflowed */
.

{
OS_SEM_DAT sem_data:
INT8U err, highest, x, y;
pdata = pdata;
for (;;) {
...
err = OSSemQuery(DispSem,&sem_data);
if (err==OS_NO_ERR) {
y=OSUnMapTbl[sem_data.OSEventGrp];
x=OSunMapTbl[sem_data.OSEventTbl[y]];
highest = (y<<3)+x;
...

Message Mailboxes
A message mailbox is a uC/OS-II object that allows a task or an ISR to send a
pointer sized variable to another task
uC/OS-II provides five services to mailboxes

OS Mb o xC e a te ()

- OSMboxCreate()
OS Mb o xPo s t()

- OSMboxPend()
- OSMboxPost()

Ta s k

OS Mb o xPe n d ()
OS Mb o xAc c e p t()
OS Mb o xQue y()

- OSMboxAccept()
- OSMboxQuery()

Ta s k
IS R

Ma ilb o x
Me s s a g e

OS Mb o xPo s t()
OS Mb o xAc c e p t()

OSMboxCreate()
: Creates and initializes a mailbox

OSMboxPend()
: When a task task expects to receive a
message.

OS_EVENT *CommMbox;
void main(void)
{
...
OSInit();
...
CommMbox = OSMboxCreate((void *)0);
...
OSStart();
}

void CommTask(void *pdata)


{
INT8U err;
void *msg;
pdata = pdata;
for (;;) {
...
msg=OSMboxPend(CommMbox, 10, &err);
if (err==OS_NO_ERR) {
/* Code for received message */
} else {
/* Code for message not received within
time out */
...

OSMboxPost()
: Send a message to a task through
a mailbox
OS_EVENT *CommMBox
INT8U CommRxBuf[100];

void CommTaskRx(void *pdata)


{
INT8U err;
...
pdata = pdata;
for (;;) {
...
err = OSMboxPost(CommMbox, (void *)
&CommRxbuf[0]);
...

OSMboxQuery()
: Obtain information about a message
mailbox

void Task (void *pdata)


{
OS_MBOXDATA mbox_data:
INT8U err;
pdata=pdata;
for (;;) {
...
err = OSMboxQuery(CommMbox,
&mbox_data);
if (err==OS_NO_ERR) {
/* Mailbox contains a message if
mbox_data.OSMsg is not NULL */ }
...

Message Queues
A message queue is a uC/OS-II object that allows a task or an ISR to send pointer
sized variables to another task.

- OSQCreate()

- OSQPostFront()
- OSQAccept()

Ta s k

u u

IS R

OS
s t()
OS
s tFr t()
OS Flus h()
OS A
t()

M s s ag

- OSQQuery()

- OSQFlush()

()
OS
OS A
t()
OS
u r ()

Ta s k

s t()
OS
OS
s tFr t()
OS Flus h()

- OSQPost()

- OSQPend()

r a t ()

OS

uC/OS-II provides seven services to Queues

OSQCreate()
: Creates a message queue

OSQPend()
: When a task task expects to receive a
message from a queue

OS_EVENT *CommQ;
void *CommMsg[10];

void CommTask(void *pdata)


{

void main(void)
{

INT8U err;
void *msg;

pdata = pdata;
...
for (;;) {
OSInit();
...
...
CommQ=OSQCreate(&CommMsg[0],10); msg=OSQPend(CommQ, 100, &err);
...
if (err==OS_NO_ERR) {
OSStart();
/* Message received wihin 100 ticks! */ }
}
else {
/* Message not received, must have
timed out */
...

OSQPost()
: Send a message to a task through
a queue

OSQPostFront()
: Send a message to a task through a
queue

OS_EVENT *CommQ;

OS_EVENT *CommQ;

INT8U CommRxBuf[100];

INT8U CommRxBuf[100];

void CommTaskRx(void *pdata)

void CommTaskRx(void *pdata)

{
INT8U err;
...
pdata = pdata;
for (;;) {
...
err = OSQPost(CommQ, (void *)
&CommRxBuf[0]);
...

INT8U err;
...
pdata = pdata;
for (;;) {
...
err = OSQPostFront(CommQ, (void *)
&CommRxBuf[0]);
...

Semaphore

How to Transplant to ARM?




MMU?
Not implemented

Startup.s
Basic init before main is run

OS_CPU_a.s
System code for task swapping & IRQ (FIQ)

OS_CPU.c, OS_CPU.h
Hooks and the C extention of IRQ (FIQ)
handler

OS_CFG.h
Which modules are compiled into code?

How Many Codes on uCOS Box


Reset
How many
codes on a
uCOS box?

Interrupt
Startup.s
OS_CPU_a.s
uCOS core
TaskA(){}
TaskB(){}
TaskC(){}
TaskD(){}

All of them
are
compiled
into a large
binary file

Interrupts under uC/OS-II


uC/OS-II requires that an Interrupt Service Routine(ISR) be
written in assembly language.
Pseudocode for an ISR
YourISR:
Save all CPU registers;
Call OSIntEnter() or, increment OSIntNesting
directly;
Execute user code to service ISR;
Call OSIntExit();
Restore all CPU registers;
Execute a return from interrupt instruction;

Potrebbero piacerti anche