Вы находитесь на странице: 1из 81

uCOS II

RTOS
Reference Book
Build Toolchain B u ild B in a r y t o o ls

B u ild G C C f o r t h e 1 s t t im e
( w it h o u t G lib c )

B u ild G lib c
( N e e d k e r n e l h e a d f il e )

B u ild G C C f o r t h e 2 n d
t im e
( W it h G lib c )

B u ild u G lib c f o r e m b e d d e d
d e v e lo p m e n t

B u ild G D B
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 (1 Compile) st

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 (2 Compile) nd

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.
 It’s 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 80x86
 Analog Device SHARC (AD21065L)
 ARM ARM7
 Atmel AVR, AT103
 Fujitsu SPARC
 Hitachi 64180, H8-300H, H8S,SH2,SH3
 Infineon Tri.Core, 80C166/167
 Intel Strong ARM110,80C251,XC52, 80x86,
196K
 Motorola M68HC08, M68HC11, M68HC12, M68HC16,
M68000, CPU32, DSP568xx, Cold.Fire,
M.Core, PowerPC8xx,MPC555
 Philips XA
 ST 80C166/167
 TI TMS320-C40, TMS320-C6201
 Automation V8
 Zilog 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 Application
uCOS-II.h (Global Var) Configuration
uCOS_II.c Groups:
OS_Core.c OS_Task.c Code
OS_Time.c OS_Sem.c OS_CFG.h
OS_Mbox.c OS_Q.c Includes.h
OS_Mem.c

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 task’s 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

} } }
Multi-
Tasking
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"

// Registers and data definition for our MX1 CPU


Sample #include "type.h"
#include "mx1.h"

Code (2) // 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


Sample
EUARTinit(); EUARTputString("\nEntering main() now!\n");
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
}
void Task0 (void *data)
Sample Code (4)
void Task1 (void *data)
{
int n = 0; {
int i; int m = 0;
void* msg; int i;
INT8U err; void* msg;
INT8U err;
while (1)
{
// Do something while (1)
for (i = 0; i < 10000; i++) n++; {
// Do something
// Tell people task0 is running
for (i = 0; i < 1234; i++) m++;
EUARTputString("Enter task0\n");

// Send mail to mailbox 1 (to task 1) // Tell people task1 is running


err = OSMboxPost(MBox1, (void*)&n); EUARTputString("Enter task1\n");

// Waiting for mail from mailbox 0 (reply from task1) // Waiting for mail from mailbox 1 (mail
msg = OSMboxPend(MBox0, 100, &err); from task 0)
msg = OSMboxPend(MBox1, 100, &err);
// Get data attached in the mail
n = *((int*)msg);
} // Get data attached in the mail
} m = *((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 Wait mail from 0
Waiting reply from 1 Retrieve data from mail
Retrieve data from mail Reply 0

Calculate n Calculate m
Send mail to 1 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).
 Free pool. int main (void)
{
 Create housekeeping tasks. … OSInit();

 The idle task. OSTaskCreate(…);

 The statistics task. OSTaskCreate(…);

OSStart();
return 0; // Never return
}
OSInit OSRdyGrp Ready List

(2)
1 0 0 0 0 0 0 0 OSTCBPrioTbl[]
OSRdyTbl[] 0 [0]
0 [1]
0 [2]
0 0 0 0 0 0 0 0 0 [3]
0 [4]
0 0 0 0 0 0 0 0 0 [5]
0 [6]
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 1 0 0 0 0 0 0 0
0
[OS_LOWEST_PRIO - 1]
[OS_LOWEST_PRIO]

OSTaskStat() OSTaskIdle()
OS_TCB OS_TCB
OSTCBStk Ptr OSTCBStk Ptr
OSTCBExtP tr = NULL OSTCBExtPtr = NULL
OSTCBStk Botto m OSTCBStk Botto m
OSTCBStk Size = stack size OSTCBStk Size = stack size
OSTCBId = OS_LOWEST_PRIO OSTCBId = OS_LOWEST_PRIO
OSTCBList OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBEventPtr = NULL OSTCBEventP tr = NULL
OSPrioCur = 0 OSTCBMsg = NULL OSTCBMsg = NULL
OSPrioHighRdy = 0 0 OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
OSTCBDly = 0
OSTCBStat = OS_STAT_RDY
0
OSTCBCur = NULL OSTCBPrio = OS_LOWEST_PRIO-1
OSTCBX = 6
OSTCBPrio = OS_LOWEST_PRIO
OSTCBX = 7
OSTCBHighRdy = NULL OSTCBY = 7 OSTCBY = 7
OSTime = 0L OSTCBBitX = 0x40
OSTCBBitY = 0x80
OSTCBBitX = 0x80
OSTCBBitY = 0x80
OSIntNesting = 0 OSTCBDelReq = FALSE OSTCBDelReq = FALSE
OSLockNesting = 0
OSCtxSwCtr = 0
OSTaskCtr = 2
OSRunning = FALSE
OSCPUUsage = 0
OSIdleCtrMax = 0L
OSIdleCtrRun = 0L
OSIdleCtr = 0L Task Stack
OSStatRdy = FALSE Task Stack
OS_MAX_TASKS
OS_TCB OS_TCB OS_TCB OS_TCB
OSTCBStkPtr OSTCBStkPtr OSTCBStkPtr OSTCBStkPtr
OSTCBExtPtr OSTCBExtPtr OSTCBExtPtr OSTCBExtPtr
OSTCBStkBottom OSTCBStkBottom OSTCBStkBottom OSTCBStkBottom
OSTCBStkSize OSTCBStkSize OSTCBStkSize OSTCBStkSize
OSTCBId OSTCBId OSTCBId OSTCBId
OSTCBFreeList OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
OSTCBNext
OSTCBPrev
0
OSTCBEventPtr OSTCBEventPtr OSTCBEventPtr OSTCBEventPtr
OSTCBMsg OSTCBMsg OSTCBMsg OSTCBMsg
OSTCBDly OSTCBDly OSTCBDly OSTCBDly
OSTCBStat OSTCBStat OSTCBStat OSTCBStat

OSInit
OSTCBPrio OSTCBPrio OSTCBPrio OSTCBPrio
OSTCBX OSTCBX OSTCBX OSTCBX
OSTCBY OSTCBY OSTCBY OSTCBY
OSTCBBitX OSTCBBitX OSTCBBitX OSTCBBitX
OSTCBBitY OSTCBBitY OSTCBBitY OSTCBBitY
OSTCBDelReq OSTCBDelReq OSTCBDelReq OSTCBDelReq

(4) OS_EVENT OS_EVENT


OS_MAX_EVENTS
OS_EVENT OS_EVENT

OSEventFreeList OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
OSEventPtr
OSEventTbl[]
0
OSEventCnt OSEventCnt OSEventCnt OSEventCnt
OSEventType OSEventType OSEventType OSEventType
OSEventGrp OSEventGrp OSEventGrp OSEventGrp

OS_MAX_QS
OS_Q OS_Q OS_Q OS_Q

OSQFreeList OSQPtr
OSQStart
OSQPtr
OSQStart
OSQPtr
OSQStart
OSQPtr
OSQStart
0
OSQEnd OSQEnd OSQEnd OSQEnd
OSQIn OSQIn OSQIn OSQIn
OSQOut OSQOut OSQOut OSQOut
OSQSize OSQSize OSQSize OSQSize
OSQEntries OSQEntries OSQEntries OSQEntries

OS_MAX_MEM_PART
OS_MEM OS_MEM OS_MEM OS_MEM

OSMemAddr OSMemAddr OSMemAddr OSMemAddr


OSMemFreeList OSMemFreeList
OSMemBlkSize
OSMemFreeList
OSMemBlkSize
OSMemFreeList
OSMemBlkSize
OSMemFreeList
OSMemBlkSize 0
OSMemNBlks OSMemNBlks OSMemNBlks OSMemNBlks
OSNFree OSNFree OSNFree OSNFree
OSInit (3)
OSRdyGrp
7 6 5 4 3 2 1 0 OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]
Highest Priority Task

X
[0] 7 6 5 4 3 2 1 0
[1] 15 14 13 12 11 10 9 8
[2] 23 22 21 20 19 18 17 16
[3] 31 30 29 28 27 26 25 24
Y
[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 Priority #
Task's Priority
Lowest Priority Task
(Idle Task)
0 0 Y Y Y X X X

Bit position in OSRdyTbl[OS_LOWEST_PRIO / 8 + 1]

Bit position in OSRdyGrp and


Index into OSRdyTbl[OS_LOWEST_PRIO / 8 + 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 …
status. OSTaskCreate(…);

– Task never return; OSTaskCreate(…);

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) { /* Make sure priority is within allowable range */


return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority
*/
OSTCBPrioTbl[prio] = (OS_TCB *)1; /* 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); /* Initialize the task's stack */
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0);
if (err == OS_NO_ERR) {
OS_ENTER_CRITICAL();
OSTaskCtr++; /* Increment the #tasks counter */
OSTaskCreateHook(OSTCBPrioTbl[prio]); /* Call user defined hook */
OS_EXIT_CRITICAL();
if (OSRunning) { /* Find highest priority task if multitasking has started
*/
OSSched();
}
} else {
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* Make this priority available to others */
OS_EXIT_CRITICAL();
}
return (err);
} else {
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
}
}
OSStart
 Start multitasking of uC/OS-2.
 It never returns to main()
 The uC/OS-II picks up the highest-
priority task to run on context-switching.
– Tightly coupled with RTC ISR.
int main (void)
{

OSInit();

OSTaskCreate(…);

OSTaskCreate(…);

OSStart();
return 0; // Never return
}
Task
Management
WAITING

OSMBoxPost() OSMBoxPend()
OSQPost() OSQPend()
OSQPostFront()
OSTaskDel() OSSemPost() OSSemPend()
OSTaskResume() OSTaskSuspend()
OSTimeDlyResume() OSTimeDly()
OSTimeTick() OSTimeDlyHMSM()

OSTaskCreate()
OSTaskCreateExt() OSStart()
OSIntExit() Interrupt
OS_TASK_SW()
DORMANT READY 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
INT32U
*OSTCBStkBottom;
OSTCBStkSize;
TCB
Structure
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
void *OSTCBMsg; // Point to message list
#endif
INT16U OSTCBDly; // Task call delay()
INT8U OSTCBStat;
INT8U OSTCBPrio; // Lower value  higher prio.
INT8U OSTCBX; // For fast task schedule
INT8U OSTCBY; OSTCBY = priority >> 3;
OSTCBBitY = OSMapTbl[priority >> 3];
INT8U OSTCBBitX;
OSTCBX = priority & 0x07;
INT8U OSTCBBitY;  OSTCBBitX = OSMapTbl[priority &
#if OS_TASK_DEL_EN 0x07];
BOOLEAN OSTCBDelReq;
#endif
TCB Structure (contd.)

OSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS-1]

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

OSTCBFreeList OSTCBNext OSTCBNext OSTCBNext OSTCBNext 0

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
0
with real memory
OSMemAddr OSMemAddr OSMemAddr
partition info.
OSMemFreeList OSMemFreeList OSMemFreeList OSMemFreeList 0
OSMemBlkSize OSMemBlkSize OSMemBlkSize

Only empty OSMemNBlks OSMemNBlks OSMemNBlks

data structs OSMemNFree OSMemNFree OSMemNFree

after init OS_MAX_MEM_PART


typedef struct {
Memory void *OSMemAddr;
void *OSMemFreeList;

Management in INT32U OSMemBlkSize;


INT32U OSMemNBlks;
INT32U
uCOS (contd.) 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 AI OSQPost() OSQPend() Error


Inputs Task (5) (6) Handler
(1)

(4) (7)

OSMemGet() OSMemPut()
(2) (8)

ErrMsgPart 0
Time Management
10m s

T ic k In t e rru p t
(2 ) (1 ) (5 )
O S T ic k IS R ( )

(3 )
A ll H P T

(6 )
L o w - P r io r it y T a s k

T a s k c a lls (4 )
5m s
O S T im e D ly ( 1 ) h e re !
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 A Task A sleep now
Task B
Find the highest
priority ready task
B, and activate it
 This ISR is called
every time tick to
advance the clock
OSTickISR
Hooks
 A hook function will be called by uC/OS-
when 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 OS’s 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)
OSMboxPend
 Step 1
– If mail box is empty,
empty pending the task by calling
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 task’s 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 box’s 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.
S ig n a l W a it IS R S ig n a l Task
W a it
IS R EC B Task

T im e EC B
ou t

Task S ig n a l W a it
Task

T im e
W a it / ou t
Task S ig n a l
S ig n a l
W a it
Task EC B Task EC B
T im e
ou t W a it /
Task T im e
S ig n a l
ou t
typedef struct {
void *OSEventPtr;
INT8U OSEventTbl[OS_EVENT_TBL_SIZE];
INT16U OSEventCnt;
INT8U OSEventType;
INT8U OSEventGrp;
} OS_EVENT;
•OSEventPtr Event Control
ECB is assigned to a mailbox or a queue
Blocks
•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
.OSEventTbl[OS_LOWEST_PRIO/8+1]
7 6 5 4 3 2 1 0 x
[0 ] 7 6 5 4 3 2 1 0
[1 ] 15 14 13 12 11 10 9 8
[2 ] 23 22 21 20 19 18 17 16
[3 ] 31 30 29 28 27 26 25 24
y
[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’s Priority Priority of task waiting
0 0 Y Y Y X X X for the event to occur

Lowest Priority Task


Bit position in .OSEventTbl[]
Bit posion in .OSEventGrp
and Index into .OSEventTbl[]
Making a task wait for an event
pevent->OSEvebtGrp |= OSMapTbl[prio >> 3];
pevent->OSEventTbl[prio>>3] |= OSMapTbl[prio & 0x07];
Content of OSMapTbl[]
Index Bit Mask(Binary)
0 0000 0001
1 0000 0010
2 0000 0100
3 0000 1000
4 0001 0000
5 0010 0000
6 0100 0000
7 1000 0000

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
- OSSemCreate() O S S e m C re a te ( )

- OSSemPend()
O S S e m P o s t( )
- OSSemPost() O S S em P en d ()
Task O S S e m A c c e p t( )
- OSSemAccept() N O S S e m Q u e ry ( )
- OSSemQuery()
O R Task

IS R
N
O S S e m P o s t( )
O S S e m A c c e p t( )
OSSemCreate() OSSemPend()
: Creates and initializes a semaphore : When a task wants exclusive access to
a resource, needs to synchronize its
OS_EVENT *DispSem;
activities with an ISR or a task, or is
void main(void) waiting until an event occurs
{
...
void DispTask(void *pdata)
OSInit();
... {
DispSem = OSSemCreate(1);
INT8U err;
...
pdata = pdata;
OSStart();
for (;;) {
} ...
OSSemPend(DispSem, 0, &err);
...
}
}
OSSemPost() OSSemQuery()
: A semaphore is signaled by calling : Obtain information about a semaphore
OSSemPost().

void Task (void *pdata)


void TaskX(void *pdata) {
{
OS_SEM_DAT sem_data:
INT8U err; INT8U err, highest, x, y;
pdata = pdata; pdata = pdata;

for (;;) { for (;;) {


...
...
err = OSSemPost(DispSem);
err = OSSemQuery(DispSem,&sem_data);
if (err == OS_NO_ERR) {
if (err==OS_NO_ERR) {
/* Semaphore signaled */
y=OSUnMapTbl[sem_data.OSEventGrp];
} else { x=OSunMapTbl[sem_data.OSEventTbl[y]];

/* Semaphore has overflowed */ 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
O S M b o x C re a te ( )
- OSMboxCreate()
- OSMboxPend() O S M b o x P o s t( )
O S M b o xP en d ()
- OSMboxPost() Task O S M b o x A c c e p t( )
O S M b o x Q u e ry ( )
- OSMboxAccept()
- OSMboxQuery() Task

IS R M a ilb o x
M essage
O S M b o x P o s t( )
O S M b o x A c c e p t()
OSMboxCreate() OSMboxPend()
: Creates and initializes a mailbox : When a task task expects to receive a
message.

OS_EVENT *CommMbox;
void main(void) void CommTask(void *pdata)
{ {
... INT8U err;
OSInit(); void *msg;
...
CommMbox = OSMboxCreate((void *)0); pdata = pdata;
... for (;;) {
OSStart(); ...

} msg=OSMboxPend(CommMbox, 10, &err);

if (err==OS_NO_ERR) {
/* Code for received message */
} else {
/* Code for message not received within
time out */
OSMboxPost() OSMboxQuery()
: Send a message to a task through : Obtain information about a message
a mailbox mailbox

OS_EVENT *CommMBox
void Task (void *pdata)
INT8U CommRxBuf[100];
{
OS_MBOXDATA mbox_data:
void CommTaskRx(void *pdata) INT8U err;
{ pdata=pdata;
for (;;) {
INT8U err;
... ...
err = OSMboxQuery(CommMbox,
pdata = pdata;
&mbox_data);
for (;;) {
if (err==OS_NO_ERR) {
...
/* Mailbox contains a message if
err = OSMboxPost(CommMbox, (void *)
mbox_data.OSMsg is not NULL */ }
&CommRxbuf[0]);
...
...
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.
uC/OS-II provides seven services to Queues
O S Q C re a te ( )
- OSQCreate()
- OSQPend() O S Q P o s t( )
O S Q P o s tF ro n t( )
- OSQPost() Task O S Q F lu s h ( ) O S Q P en d ()
N O S Q A c c e p t( )
- OSQPostFront() O S Q Q u e ry ( )

- OSQAccept() Task

- OSQFlush() IS R Q ueue

- OSQQuery() M essage
O S Q P o s t( )
O S Q P o s tF ro n t( )
O S Q F lu s h ( )
O S Q A c c e p t( )
OSQCreate() OSQPend()
: Creates a message queue : 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;


OSInit(); for (;;) {
... ...
msg=OSQPend(CommQ, 100, &err);
CommQ=OSQCreate(&CommMsg[0],10); if (err==OS_NO_ERR) {

... /* Message received wihin 100 ticks! */ }


OSStart(); else {

} /* Message not received, must have


timed out */
...
OSQPost() OSQPostFront()
: Send a message to a task through : Send a message to a task through a
a queue queue

OS_EVENT *CommQ; OS_EVENT *CommQ;


INT8U CommRxBuf[100]; INT8U CommRxBuf[100];

void CommTaskRx(void *pdata) void CommTaskRx(void *pdata)


{ {
INT8U err; INT8U err;
... ...
pdata = pdata; pdata = pdata;
for (;;) { for (;;) {
... ...
err = OSQPost(CommQ, (void *) err = OSQPostFront(CommQ, (void *)
&CommRxBuf[0]); &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 Interrupt
codes on a
Startup.s
uCOS box?
OS_CPU_a.s
uCOS core

All of them
TaskA(){…}
TaskB(){…}
are
TaskC(){…} compiled
TaskD(){…} 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;

Вам также может понравиться