Sei sulla pagina 1di 142

UNIVERSITY OF GLAMORGAN

FACULTY OF ADVANCED TECHNOLOGY

Course name: Electronic Products Design


Student Signature:

Email: skalyd@hotmail.co.uk

Student: Mr Khaled Sobaihi

Academic Year: 2006-2007

Supervisor Signature:

ABSTRACT The Renesas M16C 16 bit microcontrollers are used extensively throughout our undergraduate and MSc courses. The main aim of this project consists of porting the C/OS-II Multitasking Real-Time Kernel to the Renesas M16C microcontrollers, which means make this RTOS operational on these microcontrollers, so it can be used by the students to develop multitask real time applications. The next step requires developing a Real Time Data Monitor, based on the ported C/OS-II; this application makes a demonstration tool to show the power and the benefits of this RTOS. To make the demonstration more attractive the Kernel Monitor of the C/OS-II called C/OS-View will be ported to the M16C microcontrollers, this viewer will show what is happening inside the C/OS-II in real time. As long the C/OS-II will be tested on the MSA0654 development board, the different peripherals drivers of this board need to be written and should be compatible with this RTOS regarding the used compiler.

Page 1

support of my supervisor, and the people who participated to make the project succeed

This project would not have been possible without the guidance and

ACKNOWLEDGEMENTS

Page 2

Introduction

INTRODUCTION Modern control systems applications are often built on top of a real time operating system (RTOS) which provides the multitask scheduling and the necessary hardware abstraction and other services as well. Several open source RTOS solutions are publicly available, which is very attractive, both from an economic (low licensing fees) as well as from technical (control over the source code) point of view. [8] The C/OS-II is priority based preemptive multitasking kernel, very scalable and highly portable, this RTOS has been ported to hundreds of microcontrollers, in addition, C/OS-II is very simple to use and to implement but very effective in terms of to price/performance ratio. The aim of this project consists of porting the C/OS-II to MSA0654MEAUST development board and interfacing daughter board which is widely used throughout the undergraduate and MSc courses. To achieve this goal, the C/OS-II should be first ported to the M16C62P microcontroller that makes the core of the MSA0654 development board. And secondly, various peripherals drivers should be written to be used for any C/OS-II application that targets this board. In order to finalize this project and make under test the ported C/OS-II, a Data Monitor application will be developed to demonstrate the multitasking mechanism and real time responsiveness of the C/OS-II. In addition, different features of the C/OS-II (inter-task communication and synchronization, memory management, etc.) will be used in this application.

Page 3

CHAPTER I

Real Time Operating System (RTOS)

CHAPTER I Real Time Operating System (RTOS)


INTRODUCTION This chapter will introduce brief notions of the operating system and especially the real the traditional programming and use the RTOS platform to develop a real time application. 1. The Operating System

time operating system (RTOS), in addition, we will make brief comparison between using An operating system (OS) is the program that, after being initially loaded into the computer

by a boot program, manages all the other programs in a computer. The other programs are user interface such as a command language or a graphical user interface (GUI). [9]

called applications or application programs. The application programs make use of the operating system by making requests for services through a defined application program

interface (API). In addition, users can interact directly with the operating system through a

Page 4

operating systems permit hundreds or even thousands of concurrent users.

Operating systems can be classified as follows:

CHAPTER I

Real Time Operating System (RTOS)

Multi-user: Allows two or more users to run programs at the same time. Some Multiprocessing: Supports running a program on more than one CPU. Multitasking: Allows more than one program to run concurrently. Multithreading: Allows different parts of a single program to run concurrently.

DOS and UNIX, are not real-time. 2.

Real time: Responds to input instantly. General-purpose operating systems, such as


The Real Time Operating System and embedded systems operate in constrained environments in which computer memory and processing power are limited. They must the use of real-time operating systems in embedded software. [6] provide their services within strict time deadlines to their users and to the surrounding world to which they interface. It is these memory, speed and timing constraints that dictate The kernel of the Real Time Operating System (RTOS) provides an "abstraction layer that to application software. Figure 1.1 shows these services. hides from application software the hardware details of the processor upon which the application software will run. In doing so, it supplies five main categories of basic services Real Time Operating System

Page 5

CHAPTER I Intertask communication & synchronization

Real Time Operating System (RTOS)

Timers

Task Management Dynamic memory allocation Device I/O Supervisor

The Task Management is the most important service provided by the RTOS, this allows to software developers to design their application as a number of separate tasks each one scheduling regarding the tasks priorities during the runtime of the embedded system.

Figure 1.1 Basic services provided by a Real Time Operating System

handles a distinct topic with its own deadline. In parallel, the RTOS provides the tasks can productively synchronize their activities or cooperate between each other, without the

help of these RTOS services, tasks might well communicate corrupted information or otherwise interfere with each other. [6] Timers timeouts. The third service is the Timing service; this service includes the task delay functions and can be allocated and freed in runtime. Some RTOS provides also Device I/O which provides are typical of an embedded system. [6]

The second service is inter-task communication and synchronization, this service allows

the tasks to exchange information without danger to be corrupted, in addition, the tasks

a uniform framework for organizing and accessing the many hardware device drivers that
Page 6

Some RTOS provide the dynamic allocation of the memory, in this case a memory partition can be used and reused many times by different tasks to store large size of data as long it

In addition of these basic services, RTOS can offer other optional services such as: File system management, Network communication, Database management, User Interface graphic etc. 2.1. Multitasking

CHAPTER I

Real Time Operating System (RTOS)

The multitasking concept was born from the observation that computers spent much of misusing the power of the processors as long waiting for an I/O is unproductive time. [2] task priority.

their time waiting for slow peripheral devices to either store or retrieve data; this leads to Multitasking is the process of scheduling and switching the CPU (Central Processing Unit) between several tasks; a single CPU switches execution from one task to another to ensure each task is given processing time when the respective task needs the CPU according to the applications. One of the most important aspects of multitasking is that it allows the Multitasking is like foreground/background with multiple backgrounds. Multitasking Application programs are typically easier to design and maintain if multitasking is used. [1] maximizes the utilization of the CPU and also provides for modular construction of

The multitasking is done by the kernel which is the principal part of an operating system that provides the most basic services to application software running on the processor. real time kernels:

application programmer to manage complexity inherent in real-time applications.

According to the manner in which the multitasking is achieved, we distinguish two types of

2.2. Non-Preemptive Kernel

Called also Cooperative Multitasking, In this case the tasks cooperate with each other to another task, in addition, when the interrupt service routine (ISR) interrupts the current
Page 7

share the CPU, hence, each task runs until it decides to gives up voluntary the CPU to

The advantage of the non-preemptive kernel is the safety when using the shared variables or non re-entrant functions (non re-entrant functions dont allow to be called more than manipulating the shared variables or when returns from a non re-entrant function. corrupting the shared variables as long each task gives up the CPU only when finished

running task it returns to the same task after accomplished, in this case this interrupt can be used to make the next task ready to run. Figure 1.2 shows the mechanism of the kernel.

CHAPTER I

Real Time Operating System (RTOS)

one task before the first caller achieve using this function), in this case there is no risk of

The most disadvantage of the non-preemptive kernel is their responsiveness, where the highest priority that has been made ready to run may wait for long time to run, waiting the current running task to give up the CPU.

Page 8

CHAPTER I
Task#2 High priority Task #1 gives control of the CPU to Task #2 Task#1 Low priority Task #1 interrupted by an ISR ISR Task #1 resumed after completion of the ISR

Real Time Operating System (RTOS)

Task #1 gives back control to Task #2

2.3. Preemptive Kernel

In this kernel the highest priority ready task is immediately re-launched when an interrupt run (not the interrupted task). Most of commercial RTOS use the preemptive kernel; therefore, the RTOS based on this kernel will be the subject of this thesis. ready to run is deterministic which leads to the best responsiveness time.

Figure 1.2 Non-Preemptive kernel

Time

occurs or when the current running task enters in waiting state, therefore, upon The advantage of this multitasking kernel is that the execution of the highest priority task manipulating such variables. Figure 1.3 shows the principle of this kernel.

completion of an ISR, the kernel will resume execution to the highest priority task ready to

In contrast, we should be careful when using the shared variables or non-reentrant

functions, to avoid any corruption that may occur the interrupts should be disabled before

Page 9

CHAPTER I
Task#2 High priority The highest priority ready Task #2 resumed after completion of the ISR Task#1 Low priority Task #1 interrupted by an ISR ISR

Real Time Operating System (RTOS)

Kernel gives control to Task#2 when Task#1 waiting for an event

Figure 1.3 Preemptive kernel 3. Context Switch

Time

The Context Switch called also Task Switch is achieved by the kernel when decides to give control to another task, which starts by saving the current tasks context (CPU registers) into the current tasks task, each task has its own stack area in memory. When this run into the CPU registers and gives control to this task by executing the return from interrupt instruction (REIT in case of M16C assembly language). The top pointer of each tasks stack is stored in a structure called Task Control Block (TCB) owned by each task, pointer, etc. operation performed the kernel restores the context of the highest priority task ready to

along with other information such as priority, name, next TCB pointer, previous TCB Figure 1.4 illustrates the context switch routine by taking an example of the M16C CPU stacks pointer of the high priority ready task to the stack pointer CPU register (ISP), the registers, when the Context Switch routine is called; which starts by storing all the registers onto stack memory area of Task #1 using the PUSHM instruction, after that it assigns the
Page 10

next step will restore the registers of this task to the CPU registers by using the POPM instruction.
/* Save all the registers into current Tasks Stack */ PUSHM R0,R1,R2,R3,A0,A1,SB,FB /* Assign the ready tasks stack pointer to stack pointer register (ISP) */ MOV.W OSTCBHighRdy, A0 LDC [A0], ISP /* Restore all register to the next Tasks Stack */ POPM R0,R1,R2,R3,A0,A1,SB,FB /* return from interrupt leads to resume task #2 */ REIT

CHAPTER I

Real Time Operating System (RTOS)

Task#2 High priority Task#1 Low priority

Figure 1.4 Context Switch mechanism (M16C Example)

Context Switch routine

Time

Page 11

CHAPTER I 4. RTOS Vs Infinite Loop

Real Time Operating System (RTOS)

An example is the best way to demonstrate the benefits brought by the real time operating system (RTOS) against the traditional infinite loop. Lets take an example of a data logger system; this example usually includes ADC converter, Keypad, LCD Display and RS232 Serial communication. configurations can be designed; the simplest solution is calling each function one by one achieved, executing all functions in one loop iteration will take too long time by calling functions that dont need to be called, short regular intervals by using a Timer interrupt, this timer should short enough to ensure be improved by calling more frequently the function that has the high priority. comparison when using an infinite loop and the RTOS. In the case of infinite loop each function is executed to completion, in this case many within the infinite loop, the first function gives control to the second function when More intelligence can be introduced by using the state machine; this method will make each loop shorter by calling one function by loop iteration, the loop can be called within In the other hand, using the RTOS platform begins by creating each task that performs the that function gets called at frequency the meets its timing requirements, this method can therefore, it seems that tasks are executed in same time. Table bellow makes structural

desired function, when the RTOS starts running, the CPU switches between all tasks,

Page 12

CHAPTER I

void TimerInterrupt(void) { TimerExpire = true; } void main(void) { State = 0; while(1) { if (TimerExpire){

Without using RTOS

Table 1.1 Using or not using RTOS structure comparison

Real Time Operating System (RTOS)

void ScanKeyPadTask() { while(1){ /* ScanKeyPadTask Code goes here */ Delay(); }}

Using RTOS

Switch(State){ case 0: if (KeyPressed) ScanKeyPad(); State = 1; break;

void ProcessRS232Task() { while(1){ /* ProcessRS232Task Code goes here */ Delay(); }} void ProcessADCTask() { while(1){ /* ProcessADCTask Code goes here */ Delay(); }}

When looking at both structures, the first thing we note is the total independences between tasks in case of RTOS structure, in contrast, we can see the interference that exists between tasks functions in case of infinite loop, this will lead to an important inertia to execute each function as long the previous should be entirely executed. trapped by the ScanKeyPad() function, this problem can be solved by using a complex Take an example if the user is typing command on the keypad, at this time an Analog input
Page 13

case 2: if (AdcReady) ProcessAdc(); State = 0; break; } TimerExpire = false; } else /* do something else */ } }

case 1: if (CharAvailable) ProcessRS232(); State = 2; break;

void main(void) { OSCreateTask(ScanKeyPadTask, KeyPadPrio); OSCreateTask(ProcessRS232Task, RS232Prio); OSCreateTask(ProcessADCTask, ADCPrio); OSRun(); }


/* Run the RTOS */

comes ready to be converted, this analog sample will be missed as long the infinite loop is

interrupt service routine for each function (Keypad ISR, Serial UART ISR, ADC ISR etc ), interrupt its optimal priority, in this case the system gets closer to an RTOS. that makes like all tasks are running in same time. CONCLUSION

CHAPTER I

Real Time Operating System (RTOS)

therefore, using an important number of interrupts would increase the system latency,

also, using such numbers of interrupts push to create a task scheduling to give each

In contrast case of using the RTOS, the user can continue uses the keypad while the

analogue samples are converted, this is the result of the high frequency tasks switching The RTOS provides an excellent and reliable solution to handle events within a rigorous communication, etc. deadline, especially when there are many events and tasks to manage with timing semaphores to access to shared resources, Mailboxes and Messages Queues for inter-task constraints. In addition, the RTOS provides additional features, such as Tasks priority,

Page 14

Chapter II

C/OS-II Real Time Operating System

CHAPTER II C/OS-II Real Time Operating System


INTRODUCTION C/OS-II (Micro-Controller Operating System Version II) is an open source preemptive medical products. management etc. 1.

multitasking real time operating system mainly intended for embedded systems written in

ANSI C. Highly portable, this RTOS can be ported on various microcontrollers. It is also very and how it can be used to develop a multitasking application. We will then focus on

robust and reliable and suitable for use in safety critical systems common to aviation and This chapter will introduce the latest version of C/OS-II V2.83, its multitasking strategy different features provided by this RTOS such as semaphores, mailboxes, memory The kernel of the C/OS-II performs the context switching or task switch in two levels, the Context Switch in C/OS-II

interrupt level task switch done by OSIntCtxSw() function.

first one is the task level context switch done by OSCtxSw() function, the second is the
Page 15

Chapter II

C/OS-II Real Time Operating System

1.1. Task Level Context Switch

The kernel calls the task level context switch function OSCtxSw() when the current running task enters in the waiting state or when suspended or even deleted by itself. Listing 2.1 shows the pseudo code of this function, the context switch function carries out the following steps: Save the CPU registers onto the current task stack; Save the stack pointer in the current TCB stack pointer;

users application whenever a context switch occurs, this function is useful to monitor task switching; assign its priority to the current task priority; priority ready task; Get the stack pointer of the task to resume, which is the stack pointer of the highest Reload the saved registers of this task onto the CPU registers; To resume this task, we simply call the return from interrupt instruction.

Call the user definable function OSTaskSwHook(), this function is called to inform the

Assign the TCB of the highest priority task and ready to run to the current task TCB, and

void OSCtxSw(void) { Save processor registers; Save the current tasks stack pointer into the current tasks OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new tasks stack; Execute a return from interrupt instruction; } Listing 2.1 OSCtxSw() routine Pseudo code

Page 16

Chapter II

C/OS-II Real Time Operating System

1.2. Interrupt Level Context Switch

as long as it has been called from an ISR, this ISR will perform the saving of the context when called. The listing 2.2 illustrates the pseudo code of this function, and we can distinguish the following steps: pointer to CPU stack pointer; 1) Save the stacks pointer to the current task stacks pointer; 2) Call the user definable function: OSTaskSwHook(); 4) Pop the current task registers to the CPU registers; 3) Transfer the TCB of the next ready to run task to the current TCB and assign its stack 5) Execute the return from interrupt instruction which resume the current task. void OSIntCtxSw(void) { Save the current tasks stack pointer into the current tasks OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new tasks stack; Execute a return from interrupt instruction; } Listing 2.2 OSIntCtxSw() Pseudo code 1.3. C/OS-II Tasks States

almost the same as OSCtxSw() exception in that, there is no need to save the CPUs context

The interrupt level context switch is performed by OSIntCtxSw(), this function is called by

OSIntExit() which determines the next ready task to run. The pseudo code of this function is

Figure 2.1 shows the five states that can be taken by a task, at the beginning when the multitasking starts, all tasks are in the ready state; hence the kernel executes the highest priority task.
Page 17

Chapter II

C/OS-II Real Time Operating System

When the running task wait for a delay to expire or for a message by calling OSTimeDly(), at this time the task placed in ready list waiting its turn to run. task is resumed otherwise the interrupted task is resumed. the idle task OSTaskIdle(). The running task can also be preempted by an ISR when interrupts enabled, therefore, an

Figure 2.1 The five possible states of the C/OS-II tasks

OSMboxPend() etc or even suspended by itself when calling OSTaskSuspend(), this task

will be placed in waiting state until the delay expires or the message waiting for is present, ISR may make one or more tasks ready to run, in this case before returning from the ISR the kernel checks if there is a higher priority task ready to run, then the new higher priority The Dormant state correspond to the deleted task by calling OSTaskDel() or not available to C/OS-II yet done by OSCreatTask() or OSCreatTaskExt(), in this case the task stays residing

in memory but without any effect. When there is no task ready to run the kernel executes

Page 18

Chapter II

C/OS-II Real Time Operating System

A task control block is a data structure that is used by C/OS-II to maintain the state of a task when it is preempted. When the task regains control of the CPU the task control block allows the task to resume execution exactly where it left off. All OS_TCBs reside in RAM. [1] V2.83: The following structure describes each field in the OS_TCB data structure in case C/OS-II
OS_TCB

1.4. Task Control Blocks (OS_TCBs)

typedef struct os_tcb { OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */ #if OS_TASK_CREATE_EXT_EN > 0 void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */ OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */ INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */ INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */ INT16U OSTCBId; /* Task ID (0..65535) */ #endif struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */ struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */ #if OS_EVENT_EN OS_EVENT *OSTCBEventPtr;/* Pointer to event control block */ #endif #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */ #endif #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) #if OS_TASK_DEL_EN > 0 OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */ #endif OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */ #endif INT16U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */ INT8U OSTCBStat; /* Task status */ BOOLEAN OSTCBPendTO; /* Flag indicating PEND timed out (OS_TRUE == timed out) */ INT8U OSTCBPrio; /* Task priority (0 == highest) */ INT8U OSTCBX; /* Bit position in group corresponding to task priority */ INT8U OSTCBY; /* Index into ready table corresponding to task priority */ #if OS_LOWEST_PRIO <= 63 INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */ INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */ #else INT16U OSTCBBitX; /* Bit mask to access bit position in ready table */ INT16U OSTCBBitY; /* Bit mask to access bit position in ready group */ #endif #if OS_TASK_DEL_EN > 0 INT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */ #endif #if OS_TASK_PROFILE_EN > 0 INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */ INT32U OSTCBCyclesTot; /*Total number of clock cycles the task has been running*/

Page 19

Chapter II

C/OS-II Real Time Operating System

INT32U OSTCBCyclesStart;/* Snapshot of cycle counter at start of task resumption */ OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */ INT32U OSTCBStkUsed; /* Number of bytes used from the stack */ #endif #if OS_TASK_NAME_SIZE > 1 INT8U OSTCBTaskName[OS_TASK_NAME_SIZE]; #endif } OS_TCB;

OSTCBExtPtr: This pointer is used for user extension of the TCB without changing the whole structure of the C/OS-II TCB. This field is used only when the task created by OSTaskCreateExt() with OS_TASK_CREATE_EXT_EN = 1, OSTCBStkSize: This is variable that holds the size of the stack in number of elements instead of bytes. This means that if a stack contains 1000 entries and each entry is 32-bit wide then the actual size of the stack is 4000 bytes. OSTCBStkSize is used by OSTaskStkChk(), this field is valid when OS_TASK_CREATE_EXT_EN set to 1. OSTCBOpt: This Variable holds options passed to OSTaskCreateExt() when a task is created by the extended task create function, OSTCBId: Variable used to hold an identifier for the task. This field is currently not used and has only been included for future expansion.

OSTCBStkPtr: Contains a pointer to the top of the respective task stack pointer, C/OS-II allows to each task to have its own stack with any size, this will lead to minimize the ram area allocated to stacks, OSTCBStkBottom: This pointer points on the bottom valid stack location OSTCBStkBottom is used by OSTaskStkChk() to check the size of a tasks stack at run-time in order to determine the amount of free stack space available for each stack. This field is used only when the task created by OSTaskCreateExt() with OS_TASK_CREATE_EXT_EN = 1,

OSTCBPendTO: Indicates if the task is no more pending on an event (semaphore, messagebox etc...), =OS_TRUE if true (timed out);
Page 20

OSTCBStat: contains the state of the task. When equals to 0, the task is ready to run;

OSTCBEventPtr, OSTCBMsg: Contain pointers to an Event Control Block and to the message sent to the task respectively, these will be described in inter-task communication;

OSTCBDly: This variable contains how many clock ticks left to get ready to run when the task delayed for a certain number of clocks ticks or waits for event with certain a timeout;

OSTCBNext, OSTCBPrev: Contains pointers to previous and next TCB, because the tasks TSBs are doubly linked nodes this will make easy the update of each field of the TCBs.

OSTCBDelReq: Indicates if the task has been requested to delete itself, used to free the resources owned by this task before deletion; OSTCBCtxSwCtr, OSTCBCyclesTot, OSTCBCyclesStart, OSTCBStkBase and OSTCBStk are used to profile the respective task, useful to keep track of each status of each task by the debugger programs; OSTCBTaskName: String to hold the tasks name, length = OS_TASK_NAME_SIZE;

OSTCBPrio: Contains the task priority. A high priority task has a low OSTCBPrio;

Chapter II

C/OS-II Real Time Operating System

OSTCBX, OSTCBY, OSTCBBitX and OSTCBBitY: These variables are used to accelerate the process of making a task ready to run, or to make a task wait for an event (to avoid computing these values at runtime). The values for these fields are computed when the task is created or when the task's priority is changed. The values are computed as follows: Table 2.1 OSMapTbl[8] values Index Bit mask (Binary) 0 00000001 1 00000010 2 00000100 3 00001000 4 00010000 5 00100000 6 01000000 7 10000000

OSTCBY = priority >> 3; OSTCBBitY = OSMapTbl[priority >> 3]; OSTCBX = priority & 0x07; OSTCBBitX = OSMapTbl[priority & 0x07];

1.5. Ready list

C/OS-II is a priorities based RTOS, therefore, each task is assigned a unique priority used has the lowest priority.

as identifier in many functions, the C/OS-II V2.83 allows up to 255 tasks fixed by the RAM it is preferable to fix this variable to the number of used tasks plus the idle task which

variable OS_LOWEST_PRIO = Number of tasks - 1, in order to optimize the size of the used The ready tasks are placed in the ready list consisting of two variables; OSRdyTbl and
Page 21

OSRdyGrp. OSRdyTbl is 8x8 bits or 16x16 bits to support up to 63 Tasks or 255 tasks respectively, this table contains states bits of each task (0:Not ready, 1:Ready task).

The tasks priorities are grouped in OSRdyGrp (8 tasks per group or 16 tasks in case of 63 belongs to this group is ready. The state of each task is easily located in the OSReadyTbl with X equals to the first 3 or 4

Chapter II

C/OS-II Real Time Operating System

and 255 tasks respectively), each bit in this variable is set to 1 when at least one task that LSB bits, and Y equals to the remaining 3 or 4 MSB bits, again depends to the numbers of supported tasks (63 or 255). Figure 2.2 illustrates the bits map of these variables.
8-Bits length OSRdyGrp 7 6 5 4 3 2 1 0 [0] 7 6 Highest priority Task 4 3 2

1 9

0 8

[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 8-Bits length Task's Priority Byte X Bits Position in OSRdyTbl Y Y Y X [6] 55 54 53 52 51 50 49 48 [7] 63 62 61 60 59 58 57 56 X X Lowest priority Task

Figure 2.2 Ready to run tasks table and ready group bits map

X Bits Position in OSRdyTbl

Page 22

The following code place a task in the ready list: To remove a task from the ready list: OSRdyGrp OSRdyTbl[prio >> 3]

task from ready list or get the highest ready to run task. |= OSMapTbl[prio >> 3]; |= OSMapTbl[prio & 0x07];

This configuration allows C/OS-II to accelerate the operations of make task ready, remove

Chapter II

C/OS-II Real Time Operating System

if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0) OSRdyGrp &= ~OSMapTbl[prio >> 3]; y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; prio = (y << 3) + x;

In order to get the priority of the highest priority task ready to run: OSUnMapTbl is a lookup table to find the highest priority task ready to run rather than scanning through the table starting with OSRdyTbl[0], OSUnMapTbl[256] is declared is follow:
INT8U 0, 4, 5, 4, 6, 4, 5, 4, 7, 4, 5, 4, 6, 4, 5, 4, }; const 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, OSUnMapTbl[256] = { 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0, 0, 2, 0, 1, 0, 3, 0,

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

/* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /*

0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xA0 0xB0 0xC0 0xD0 0xE0 0xF0

to to to to to to to to to to to to to to to to

0x0F 0x1F 0x2F 0x3F 0x4F 0x5F 0x6F 0x7F 0x8F 0x9F 0xAF 0xBF 0xCF 0xDF 0xEF 0xFF

*/ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */

Page 23

For example, if OSRdyGrp contains 01101000 then: Y = OSUnMapTbl[OSRdyGrp] = 3; Assume that OSRdyTbl[3] = 11100100; X = = OSUnMapTbl[OSRdyTbl[3]] = 2;

Chapter II

C/OS-II Real Time Operating System

The highest priority task ready to run (prio) would then be 26 (3 * 8 + 2). OSTCBPrioTbl[] using the task's priority.[1] 2. Task Scheduling

Getting a pointer to the OS_TCB for the corresponding task is done by indexing into The scheduler, also called the dispatcher, is the part of the kernel responsible for assigned a priority based on its importance. In a priority-based kernel, control of the CPU will always be given to the highest priority task ready-to-run. [1] by OSSched() function and interrupt level performed by OSIntExit(). 2.1. OSSched() Context Switch function

determining which task will run next. C/OS-II kernel is priority based. Each task is As we have seen before, C/OS-II makes the context switch in two levels; task level, done

Listing 2.3 illustrates the OSShed() code, the scheduling starts by disabling all interrupts by accept to be interrupted. The test statement tests if the scheduling enabled (OSLockNesting

calling OS_ENTER_CRITICAL() macro (1), the next code is a critical section and doesnt == false) and if the OSShed() was not called from an interrupt (OSIntNesting == false) (2), if the both conditions are true then the priority of the highest priority task ready to run is current running task (4), if the case no need to make an useless context switch, if not the TCBs pointer of this task is assigned to the highest priority task ready to run OSTCBHighRdy TCB (5). Next, OSSched() increments the context switch counter OSCtxSwCtr computed using the part of code (3), the next if statement tests if this task is not the which keeps track the number of the performing context switch (6), finally, the context calling OS_EXIT_CRITICAL().
Page 24

switch achieved by calling the macro OS_TASK_SW() (7) and re-enable the interrupts by

Chapter II

C/OS-II Real Time Operating System

void OSSched (void) { INT8U y; OS_ENTER_CRITICAL(); (1) if ((OSLockNesting | OSIntNesting) == 0) { (2) y = OSUnMapTbl[OSRdyGrp]; (3) OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); if (OSPrioHighRdy != OSPrioCur) { (4) OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; (5) OSCtxSwCtr++; (6) OS_TASK_SW(); (7) } } OS_EXIT_CRITICAL(); (8) }

Listing 2.3 Task level Scheduling function OSSched()

2.2. OSIntExit() Context Switch function

OSIntCtxSw() firstly because the ISR has already saved the CPU registers, secondly because OSIntExit().

OSIntExitY is declared as global variable to avoid allocating a local variable on the stack which needs to be accounted for in interrupt level context switch OSIntCtxSw(). Instead of calling OSCtxSw() to perform the context switching, OSIntExit() calls

decrement which means that this interrupt has interrupted a task rather than another interrupt, in the case and if the scheduling enabled (OSLockNesting == false) then the same procedures are performed as in OSSched() (3), (4) and (5) except that in this case

called at the entry of each interrupt code, OSIntExit() verifies that OSIntNesting = 0 after a

Listing 2.4 shows the code of this function, as we can note OSIntExit() looks like OSSched() nesting variable OSIntNesting, this variable was incremented by OSIntEnter() function

except for some differences, the first one is that OSIntExit() should decrement the interrupt

OSIntCtxSw() should do some stack adjustment to remove the return address to itself and

Page 25

Chapter II

C/OS-II Real Time Operating System

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

(1) (2) (3)

(4) (5) (6) (7)

Listing 2.4 Interrupt level Scheduling function OSIntExit()


(8)

3.

The C/OS-II requires to write the ISRs in assembly language to get access to CPU registers, unless the compiler support the inline assembly, listing 2.5 shows the pseudo code of an ISR under C/OS-II.
ISR identifier: 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; (1) (2) (3) (4) (5) (6)

Interrupts Under C/OS-II

The first that should be done is saving all CPU registers (1), next, calling OSIntEnter() or

increment OSIntNesting directly in order to notify that an ISR has occurred (2), at this moment the ISR routine can be serviced by calling the respective call-back function (3), interrupt or the highest priority ready task (depends of what OSIntExit() has performed) by

Listing 2.5 Pseudo code of an interrupt service routine under C/OS-II

when the ISRs call-back function achieved the ISR calls OSIntExit() to perform the context switching and decrementing the interrupt nesting variable OSIntNesting (4), the next step restores the saved CPU registers (5) in order to return to the interrupted task, ISR
Page 26

executing the return from interrupt instruction (6). The listing bellow illustrates an example of an ISR code in case of M16C microcontroller:
TIMER_A1_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB INC.B OSIntNesting JSR TIMER_A1_CALLBACK JSR OSIntExit POPM R0,R1,R2,R3,A0,A1,SB,FB REIT

Chapter II

C/OS-II Real Time Operating System

4.

C/OS-II needs a temporal reference source in order to keep track of the time delays and timeouts, this can be achieved by hardware timer or an extern pulses (Ex. 50/60Hz main frequency can be between 50 and 100Hz. supply frequency), The faster the tick rate, the higher the overhead imposed on the system. serviced by this interrupt should be OSTimeTick(), the listing bellow shows the pseudo code of this ISR interrupt: ISR identifier: Depends of the microcontroller performance and desired tick resolution, the ticks

Listing 2.6 Sample of an interrupt service routine ISR in case of M16C under C/OS-II Clock Ticks

;Save current CPU context registers ;OSIntNesting++ ;Call the interrupt call-back function ;Call OSIntExit() ;Restore the CPU context registers ;Return from the interrupt

As described before the Clock Ticks Timer is serviced like any ISR, The call-back function

Save all CPU registers; Call OSIntEnter() or, increment OSIntNesting directly; Execute user code to service ISR; Call OSTimeTick ; Restore all CPU registers; Execute a return from interrupt instruction;

Listing 2.8 shows the code that services OSTimeTick() call-back function. OSTimeTick() the functionality of OSTimeTick() (1).

starts by calling a user definable function OSTimeTickHook() which can be used to extend

Listing 2.7 Pseudo code of the Clock Ticks ISR

Page 27

decremented to zero, the task is made ready to run (4). The task is not readied, however, if it was explicitly suspended by OSTaskSuspend() (5). The execution time of OSTimeTick() is directly proportional to the number of tasks created in an application. [1]
void OSTimeTick (void) { OS_TCB *ptcb; OSTimeTickHook(); ptcb = OSTCBList; while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { OS_ENTER_CRITICAL(); if (ptcb->OSTCBDly != 0) { if (--ptcb->OSTCBDly == 0) { if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { ptcb->OSTCBDly = 1; } } } ptcb = ptcb->OSTCBNext; OS_EXIT_CRITICAL(); } OS_ENTER_CRITICAL(); OSTime++; OS_EXIT_CRITICAL(); }

Most of the work done by OSTimeTick() basically consist of decrementing the OSTCBDly

Chapter II

C/OS-II Real Time Operating System

field for each OS_TCB (if its nonzero). OSTimeTick() follows the chain of OS_TCB starting at

OSTCBList (2) until it reaches the idle task. When the OSTCBDly field of a task's OS_TCB is

(1) (2) (3)

(5) (4)

(7) (6)

Listing 2.8 OSTimeTick() Code

5.

infinite loop otherwise deletes itself before exiting the tasks void, listings bellow show the template of any task:

C/OS-IIs Task has the format of any C void with no return value, also it should be an

Task Management

Page 28

Chapter II

C/OS-II Real Time Operating System

void TASK (void *pdata) { /* Task code */ while(1) /* infinite loop */ { /* Task code */ } }

void TASK (void *pdata) { /* user code */

Listing 2.9 C/OS-II Task template in case of infinite loop code

/* delete task */ }

pdata argument contains the data pointer passed to the task when executed first time. 5.1. Creating C/OS-II Task

Listing 2.10 C/OS-II Task template without infinite loop code

C/OS-II or during the runtime. There are two functions that can be used to create a task, one simple OSTaskCreate() or the extended version OSTaskCreateExt():
INT8U OSTaskCreate(void(*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio) /* Arguments: Task is a pointer to the task's code p_arg is a pointer to an optional data area which can be used to pass parameters to the task when the task first executes. ptos is a pointer to the task's top of stack. prio is the task's priority. A unique priority MUST be assigned to each task and thenlower the number, the higher the priority. Returns: OS_NO_ERR if the function was successful. OS_PRIO_EXIT if the task priority already exist (each task MUST have a unique priority). OS_PRIO_INVALID if the priority you specify is higher than the maximum allowed (i.e. >= OS_LOWEST_PRIO) OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR.*/

Before C/OS-II carries out a declared task it should be created in other word assign a TCB to this task and place it in ready task list. A task can be created before launching the

Listing 2.11 C/OS-II Create Task function

Page 29

Chapter II

C/OS-II Real Time Operating System

INT8U OSTaskCreateExt (void(*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio, INT16U id, OS_STK *pbos, INT32U stk_size, void *pext, INT16U opt) /* Arguments : Task is a pointer to the task's code p_arg is a pointer to an optional data area which can be used to pass parameters to the task when the task first executes. ptos is a pointer to the task's top of stack. prio is the task's priority. A unique priority MUST be assigned to each task and then lower the number, the higher the priority. id is the task's ID (0..65535) pbos is a pointer to the task's bottom of stack. stk_size is the size of the stack in number of elements. If OS_STK is set to INT8U, 'stk_size' corresponds to the number of bytes available. If OS_STK is set to INT16U, 'stk_size' contains the number of 16-bit entries available. pext is a pointer to a user supplied memory location which is used as a TCB extension. opt contains additional information (or options) about the behaviour of the task. * OS_TASK_OPT_STK_CHK Stack checking to be allowed for the task OS_TASK_OPT_STK_CLR Clear the stack when the task is created OS_TASK_OPT_SAVE_FP If the CPU has floating-point registers, save them during a context switch. Returns: OS_NO_ERR if the function was successful. OS_PRIO_EXIT if the task priority already exist (each task MUST have a unique priority). OS_PRIO_INVALID if the priority you specify is higher than the maximum allowed (i.e. >= OS_LOWEST_PRIO) OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR. */

In C/OS-II a task can be deleted, suspended, and resumed etc..., by using the task manipulation functions summarised in Table 2.1.

Listing 2.12 Extended version of the C/OS-II create task function

Page 30

Chapter II

Tasks manipulation functions

OSTaskChangePrio (INT8U oldprio, INT8U newprio) OSTaskDel (INT8U prio) OSTaskdelreq (INT8U prio) OSTaskNameSet (INT8U prio, INT8U *pname, INT8U *err) OSTaskNameGet (INT8U prio, INT8U *pname, INT8U *err) OSTaskSuspend (INT8U prio) OSTaskResume (INT8U prio)

Table 2.1 Task Manipulation functions

C/OS-II Real Time Operating System

Change the priority of a task to newprio Delete the task with priority prio Request that a task delete itself Set a name to the task with priority prio Suspend a task with priority prio Resume a suspended task with priority prio

Description

Get the name of a task with priority prio

By default C/OS-II creates the Idle Task (OSTaskIdle()) which is executed when no task is ready to run, C/OS-II creates another task when enabled, called performs every second the computing of the percentage of CPU usage .

Statistic Task(OSTaskStat()) which

6.

When variables are shared among two or more tasks can allows to these tasks to interact for one task to read a value written by another task.

Inter-task Communication & Synchronization

between each other. For example, one way to communicate information between tasks is In order to get exclusive access to shared variables and avoid that more than one task get access to the resource in same time which leads to corrupt these variables, C/OS-II these will disable interrupts and leads to stop the multitasking. Another method can be OSSchedUnlock() respectively the multitasking can be stopped as well. provides the two macros OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() which are called respectively before starting and after finishing the manipulation of the shared resource,

used, by Locking and unlocking C/OS-IIs scheduler with OSSchedLock() and

Page 31

In a real time system this could lead to performance problems due to the disruption of the protection based on a construct known as a semaphore (a word which means signal or alternatively a device which is used to send signals). [2] semaphore to synchronize tasks, messages mailbox or messages queues to make the intertask communication. The listing bellow shows the data structure of an ECB.
typedef struct { void *OSEventPtr; /* Pointer 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;

Chapter II

C/OS-II Real Time Operating System

precision of the timing. For these reasons a different technique is used for critical section a shared structure called ECB (Event Control Blocks) which can take the form of a

In order to perform the inter-task communication and synchronization, C/OS-II provides

*/

OSEventPtr: This pointer is used when the ECB is assigned to a mailbox or a messages states respectively except that they contain a list of tasks waiting on the event instead of being a list of tasks ready-to-run. semaphore. to a message queue data.

queue. In this case, OSEventPtr points to the message when used for a mailbox or a pointer

Listing 2.13 OS_EVENT Structure members

OSEventCnt is used to hold the semaphore count when the ECB is used for a

OSEventTbl[] and OSEventGrp are similar to OSRdyTbl[ ] and OSRdyGrp used in tasks

OSEventType contains the type associated with the ECB and can have the following values: OS_EVENT_SEM, OS_EVENT_TYPE_MBOX or OS_EVENT_TYPE_Q. This field is used to objects through C/OS-IIs service calls. [1]. make sure you are accessing the proper object when you perform operations on these

Page 32

Chapter II

C/OS-II Real Time Operating System

A semaphore is a key that your code acquires in order to continue its execution. If the someone else is using it, I am willing to wait for it!. [1]

6.1. Semaphores

semaphore is already in use, the requesting task is suspended until the semaphore is In order to use the C/OS-IIs semaphore we need to create it first using the function OSSemCreate (Assign an ECB to this semaphore) as follow:
OS_EVENT *MySemaphore;

released by its current owner. In other words, the requesting task says: "Give me the key. If

MySemaphore = OSSemCreate (INT16U cnt) /* Argument : cnt : Is the initial value for the semaphore. If the value is 0, no resource is available (or no event has occurred). You initialize the semaphore to a non-zero value to specify how many resources are available (e.g. if you have 10 resources, you would initialize the semaphore to 10) */ /* Returns: != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the created semaphore == (void *)0 if no event control blocks were available */

OSSemPend is called, this function will make the called task in waiting list until the prototype of this function:
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

semaphore is available or the specified timeout finished, the listing bellow show the
/* Arguments : pevent is a pointer to the event control block associated with the desired semaphore. timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for the resource up to the amount of time specified by this argument. If you specify 0, however, your task will wait forever at the specified semaphore or, until the resource becomes available (or the event occurs). err is a pointer to where an error message will be deposited. Possible error messages are: OS_NO_ERR The call was successful and your task owns the resource or, the event you are waiting for occurred. OS_TIMEOUT The semaphore was not received within the specified timeout. OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.

Wait for a semaphore, when a task requesting access to a semaphore the function

Listing 2.13 Function to create a semaphore

Page 33

Chapter II

C/OS-II Real Time Operating System

OS_ERR_PEND_ISR If you called this function from an ISR and the result would lead to a suspension. OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. Returns: none */

Signal a semaphore (release a semaphore), after get access to a semaphore and we want follow:

release it, the OSSemPost function is called, this will signal to the task waiting for this

semaphore that the semaphore is free to be taken, the prototype of this function is as
INT8U OSSemPost (OS_EVENT *pevent) /* Arguments: pevent is a pointer to the event control block associated with the desired semaphore. Returns: OS_NO_ERR The call was successful and the semaphore was signaled. OS_SEM_OVF If the semaphore count exceeded its limit. In other words, you have signaled the semaphore more often than you waited on it with either OSSemAccept() or OSSemPend(). */ /* Return: OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer. */

Listing 2.14 Function to wait on semaphore to be released

Another interesting function which checks if a semaphore is available or not without this function:

waiting, OSSemAccept(), unlike OSSemPend(), OSSemAccept() does not suspend the calling

task if the resource is not available or the event did not occur. The listing bellow illustrates

Listing 2.15 Function to release a semaphore

INT16U OSSemAccept (OS_EVENT *pevent) /* Arguments: pevent is a pointer to the event control block Returns: > 0 if the resource is available or the event did not occur the semaphore is decremented to obtain the resource. == 0 if the resource is not available or the event did not occur or if 'pevent' is a NULL pointer or, if you didn't pass a pointer to a semaphore */

Listing 2.16 Function to check the availability of a semaphore

Page 34

Chapter II

C/OS-II Real Time Operating System

task is the first task that calls OSSemPend() function, this resource is available to task 1 until it release it by calling OSSemPost(), at this moment the task 2 which was waiting for the semaphore to be signalled takes the control of this semaphore or in other word the LCD Display until it releases it to the Task 1 when calling OSSemPost().
OS_EVENT* LcdSem ; /* ECB to be assigned to semaphore */ void Task_1(void *pdata) {INT8U err; LcdSem = OSSemCreate(1); /* Create the LCD semaphore with one access */ while(1) { OSSemPend (LcdSem, 0, &err);/* Waite until the Lcd display available */ LcdWrite(Task 1: Hello!); /* Display the task 1s message */ OSTimeDly(2000); /* keep the message for 2000 clock ticks */ OSSemPost(LcdSem); /* Release the Lcd Display to other tasks */ OSTimeDly(1000); /* Make a delay of 1000 ticks */ } } Calling OSSemPost in Task 1 releases the LcdSem semaphore and OSSemPend terminates the waiting time of Task 2

Figure 2.3 illustrates an example when using the semaphore as key to get exclusive access to a resource, Task 1 starts by creating the semaphore by assigning an ECB to it, when this

6.1.1. Get exclusive access to a resource using semaphore

Calling OSSemPost in Task 2 releases the LcdSem semaphore and OSSemPend terminates the waiting time of Task 1

void Task_2(void *pdata) { INT8U err; while(1) { OSSemPend (LcdSem, 0, &err); /* Wait until the Lcd display available */ LcdWrite(Task 2: Hello!); /* Display the task 1s message */ OSTimeDly(2000); /* keep the message for 2000 clock ticks */ OSSemPost(LcdSem); /* Release the Lcd Display to other tasks */ OSTimeDly(1000); /* Make a delay of 1000 ticks */ } }

Figure 2.3 Semaphore used to get exclusive access to LCD Display resource

Page 35

Chapter II

C/OS-II Real Time Operating System

6.1.2. Using A Semaphore To Synchronize Two Tasks

A Semaphore can be used also to synchronize a task with another task or an ISR, in this case the semaphore is initialized to zero (no resource), depends on whether one task or an ISR signals to another task unilateral rendezvous or two tasks signal to each other bilateral semaphore is represented as flag; Figure 2.4 illustrates different synchronization cases. Semaphore Semaphore

rendezvous, two tasks can synchronize their activities with each other. In this case the

OSSemPost()

OSSemPend()

TASK2

OSSemPost()

OSSemPend()

OSSemPend()

OSSemPost()

TASK1 ISR

TASK1

TASK2

Unilateral rendezvous

Bilateral rendezvous

Figure 2.4 Semaphore used for: Unilateral synchronization (Unilateral rendezvous), Bilateral synchronization (Bilateral rendezvous)

Page 36

Chapter II

C/OS-II Real Time Operating System

void Task_1(void *pdata) { Sem = OSSemCreate(0);/* Create a semaphore with no shared resource*/ while(1) { OSSemPost(Sem); /* Send semaphores Signal to task 2 */ OSTimeDly(1000); /* Make a delay of 1000 ticks */ }} Task 1 sends signal to task 2 by calling OSSemPost(), this signal will be detected by OSSemPend in Task 2.

void Task_2(void *pdata) { while(1) { OSSemPend(Sem, 0, &err);/* Wait until signal received from Task 1 */ /* Perform the operations waiting for the signal */ /*.*/ OSTimeDly(1000); /* Make a delay of 1000 ticks */ }}

Figure 2.5 Two Tasks synchronization example, Task 1 signals Task 2 to perform the waiting instructions. 6.2. Mutual Exclusion Semaphores Mutual Exclusion Semaphores (Mutex) are used by tasks to gain exclusive access to a resource. Mutexes have additional features beyond the normal semaphores in order to resolve the problem of priority inversion. lowest priority gets access to the semaphore, at (2) this task preempted by Task 1 (because The priority inversion problem is illustrated by Figure bellow, at (1) Task 3 that has the Task 1 has the higher priority). At (3), Task 1 requests the semaphore, but this semaphore
Page 37

is still owned by Task 3, therefore, Task 1 will be placed in waiting list until the semaphore is released, at this time Task 3 takes the control of the CPU and continues manipulating the semaphores resources, at (4) Task 2 preempts Task 3 and runs until (5), where the CPU

will be given to Task 3 instead of Task 1 (Highest priority) which still awaits for the obtains it after a long waiting.

Chapter II

C/OS-II Real Time Operating System

semaphore to be released by Task 3. At (6) Task 3 releases this semaphore and Task 1 This situation makes a virtual reduction of the Task 1 priority to Task 2 and Task 3, because it was waiting for a semaphore which has been owned by lowest priority task (Task 3), this would lead to an important execution delay of the Task 1. (1) (2) (3) (4)
Priority inversions problem Task 1 (Highest priority) wait for Task 2 or Task 3 (Lowest priority)

TASK 2 (Medium priority)

TASK 1 (Highest priority) TASK 3 (Lowest priority)

(5)

(6)

SEM

Task 1 Gets Semaphore

Task 3 preempted by Task 1

Task 3 Gets Semaphore

SEM

SEM

To avoid this problem, we can raise the priority of Task 3 over the others Tasks and restore this Task, therefore, the semaphore will be released more quickly and task 1 does not have using the mutual exclusion semaphore instead of the normal semaphore. to wait for a long time for the semaphore. These Operations will be done automatically by
Page 38

the original priority when releases the semaphore, this will lead to give more CPU cycles to

Figure 2.6 Priority inversions problem when using semaphores.

Task 3 resumed

Task 3 pre-empted by Task 2

Task 3 preempted by Task 2

SEM

Task 3 releases the Semaphore

Chapter II

C/OS-II Real Time Operating System

Like the normal semaphores, the Mutex should be created before its using, almost the same function as the normal semaphores are used to wait for, release or check the status of the Mutex. The table bellow summarizes these functions in the case of the Mutexes: Table 2.2 Mutual Exclusion semaphores functions Mutexes functions Description

OSMutexCreate (INT8U prio, INT8U *err)

OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) OSMutexPost (OS_EVENT *pevent) OSMutexAccept (OS_EVENT*pevent, INT8U *err) OSMutex_RdyAtPrio (OS_TCB *ptcb, INT8U prio)

creates a mutual exclusion semaphore prio is the priority to use when accessing the mutual exclusion semaphore. In other words, when the semaphore is acquired and a higher priority task attempts to obtain the semaphore then the priority of the task owning the semaphore is raised to this priority. It is assumed that you will specify a priority that is LOWER in value than ANY of the tasks competing for the mutex. Pend on mutual exclusion semaphore. Post signal to a mutual exclusion semaphore Checks the mutual exclusion semaphore is available.

6.3.

C/OS-II allows tasks to exchange messages between each other by using the Mailbox ECB, the message has the form of pointer which points on any type of messages (string, it, to create a mailbox the following function is requested:

Message Mailboxes

Restore a task back to its original priority Arguments: ptcb is a pointer to OS_TCB of the task to make ready, prio is the desired priority,

numbers, structures etc), as for any ECB object, the Mailbox should be created before use
OS_EVENT *OSMboxCreate (void *msg) /* Arguments : msg is a pointer to a message that you wish to deposit in the mailbox. Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the created mailbox == (OS_EVENT *)0 if no event control blocks were available */

Listing 2.17Function to create a Mailbox

Page 39

Chapter II

C/OS-II Real Time Operating System

After created the Mailbox, a message can be posted into it by using the following function:

INT8U OSMboxPost (OS_EVENT *pevent, void *msg) /* Arguments: pevent is a pointer to the event control block associated with the desired mailbox msg is a pointer to the message to send. You MUST NOT send a NULL pointer. Returns: OS_NO_ERR: The call was successful and the message was sent OS_MBOX_FULL: If the mailbox already contains a message. You can can only send one message at a time and thus, the message MUST: be consumed before you are allowed to send another one. OS_ERR_EVENT_TYPE: If you are attempting to post to a non mailbox. OS_ERR_PEVENT_NULL: If 'pevent' is a NULL pointer OS_ERR_POST_NULL_PTR: If you are attempting to post a NULL pointer */

To read the message sent, two functions can be used depend if we want pending on execution of the program by using OSMboxAccept(), the following listings illustrate these functions:
/* Pend on the mailbox within a timeout if specified until a message is available */ void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err); /* Get the message if exists without waiting */ void *OSMboxAccept (OS_EVENT *pevent); /* Arguments : pevent is a pointer to the event control block associated with the desired mailbox timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a message to arrive at the mailbox up to the amount of time specified by this argument. If you specify 0, however, your task will wait forever at the specified mailbox or, until a message arrives. err is a pointer to where an error message will be deposited. Possible error messages are: OS_NO_ERR The call was successful and your task received a message. OS_TIMEOUT A message was not received within the specified timeout OS_ERR_EVENT_TYPE Invalid event type OS_ERR_PEND_ISR If you called this function from an ISR and the result would lead to a suspension. OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer Returns : != (void *)0 is a pointer to the message received == (void *)0 if no message was received or, if 'pevent' is a NULL pointer or, if you didn't pass the proper pointer to the event control block.*/

mailbox until the message is sent, in this case the OSMboxPend() is used, or we can check if

there is message in the mailbox, if exists then read the massage otherwise continue the

Listing 2.18 Function to post a message into a Mailbox

Listing 2.19 Functions to pickup the sent message

Page 40

Chapter II

C/OS-II Real Time Operating System

Mailbox
TASK

OSMboxPost()

OSMboxPend()

TASK

ISR

OSMboxPost()

OSMboxAccept()

TASK ISR

Figure 2.7 Inter-task communication using Mailbox


void Task_1 (void *data) { char SentMsg = HELLO!; INT8U err; MailBox = OSMboxCreate(TextMsgPtr); while(1) { OSMboxPend(MailBox, 0, &err); /* Wait until the Mailbox is empty */ OSMboxPost(Mailbox, (void *)&SentMsg);/* send the text message */ OSTimeDly(1000); /* Make a delay of 1000 ticks */ }} Task 1 sends Text Message to MailBox by OSMboxPost(), Task 2 receives this message by calling OSMboxPend(). void Task_2 (void *data) { char* ReceivedMsg; INT8U err; while(1) { /* Pend on Mailbox until the message available then read it */ ReceivedMsg = (char*)OSMboxPend(MailBox, 0, &err); printf(%s \n, ReceivedMsg); /* Print the received message */ OSTimeDly(1000); /* Make a delay of 1000 ticks */ }}

Figure 2.8 Task 1 sends Text Message to task 2 through a mailbox

Page 41

Chapter II

C/OS-II Real Time Operating System

6.4. Messages Queues

A Message Queue is built as chain of Mailboxes organized in queue, therefore, a messages queue can hold more than one message, these messages are sent and received in FIFO (first queue should be created using the following function: input first output) priority. As we have seen in Semaphores and Mailboxes the messages
*OSQCreate (void **start, INT16U size)

OS_EVENT

/* Arguments: start is a pointer to the base address of the message queue storage area. The storage area MUST be declared as an array of pointers to 'void' as follows: void *MessageStorage[size] size is the number of elements in the storage area Return: != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the created queue == (OS_EVENT *)0 if no event control blocks were available or an error was detected */

if we want to send the message at the front of the message queue OSQPostFront() function is called, the following listing illustrates the prototypes of these functions:
/* post message at the end of the queue */ INT8U OSQPost (OS_EVENT *pevent, void *msg); /* post message at the front instead of the end of the queue */ INT8U OSQPostFront (OS_EVENT *pevent, void *msg); /* Arguments: pevent is a pointer to the event control block associated with the desired queue msg is a pointer to the message to send. Returns: OS_NO_ERR The call was successful and the message was sent OS_Q_FULL If the queue cannot accept any more messages because it is full. OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue. OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer */

To send (inject) a message at the end of the massage queue, OSQPost() is called, otherwise

Listing 2.20 Function to create a Messages Queue

Listing 2.21 Function to post message into messages queue

Page 42

check if there is a message in the queue, if the case, read this message or leave the function, the following listing shows these functions:
/* Wait for a message to be sent to a queue */ void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) /* pickup the message if available or leave if not */ void *OSQAccept (OS_EVENT *pevent, INT8U *err) /* Arguments: pevent is a pointer to the event control block associated with the desired queue timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a message to arrive at the queue up to the amount of time specified by this argument. If you specify 0, however, your task will wait forever at the specified queue or, until a message arrives. err is a pointer to where an error message will be deposited. Possible error messages are: OS_NO_ERR The call was successful and your task received a message. OS_TIMEOUT A message was not received within the specified timeout OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer OS_ERR_PEND_ISR If you called this function from an ISR and the result would lead to a suspension. OS_ERR_PEND_LOCKED If you called this function with the scheduler is locked Returns: != (void *)0 is a pointer to the message received == (void *)0 if you received a NULL pointer message or, if no message was received or, if 'pevent' is a NULL pointer or, if you didn't pass a pointer to a queue.*/

The same situation as in mailboxes, there are two function to get message from the queue,

Chapter II

C/OS-II Real Time Operating System

OSQPend() to pend on the message queue until a message is present or OSQAccept() to

Listing 2.22 Functions to pickup a message from a queue


OSQPostFront()

TASK ISR TASK ISR

OSQPost()

Messages Queue
End of the queue

OSQPend() OSQAccept()
Front of the queue

TASK ISR

Figure 2.9 Messages posting and receiving in queue structure


Page 43

Chapter II

C/OS-II Real Time Operating System

void Task_1 (void *data) { char* SentMsg = Task 1 Message; while(1) { /* send SentMsg message to the Queue */ OSQPost(MsgQ, (void *)SentMsg); OSTimeDly(1000); /* Make a delay of 1000 ticks */

}}

void Task_2 (void *data) { char* SentMsg = Task 2 Message; while(1) { /* send SentMsg message to the Queue */ OSQPost(MsgQ, (void *)SentMsg); OSTimeDly(1000); /* Make a delay of 1000 ticks */ }} Task 2 sends Text Message to MsgQ by OSQPost()

Task 1 sends Text Message to MsgQ by OSQPost()

const QSize = 64;/* Messages queues size */ void* TxtPtr[QSize]; /* Pointers that hold messages */ /* this task gets messages from queue and print them */ void Task_3 (void *data) { Char* ReceivedMsg;/* Pointer to contain the Received Message */ INT8U err; /* Create the queue size = QSize */ MsgQ = OSQCreate(&TxtPtr[0], QSize); while(1) { /* Pend on Messsage Queue until a message available */ ReceivedMsg = (char*)OSQPend(MsgQ, 0, &err); printf(%s \n, ReceivedMsg); /* Print the received message */ OSTimeDly(1000); /* Make a delay of 1000 ticks */

Figure 2.10 Messages Queue example, Task 1 and Task 2 send Messages to the queue every 1000 Clock Ticks, Task 3 reads these messages and prints them

}}

Page 44

Chapter II

C/OS-II Real Time Operating System

6.5. Event Flags (C/OS-II V2.51 and higher)

Event flags are used when a task needs to synchronize with the occurrence of multiple have occurred. This is called conjunctive synchronization (logical AND). [4] TASK TASK
TASK/ISR

events. The task can be synchronized when any of the events have occurred. This is called disjunctive synchronization (logical OR). A task can also be synchronized when all events Figure bellow shows the Disjunctive and Conjunctive synchronization using Flag Events:
Post Events

TASK
Pend on Events

Post Events

AND (ALL)

TASK
TASK/ISR

Pend on Events OR (ANY)

TASK

TASK

ISR

Conjunctive synchronization

ISR

In C/OS-II the flags are grouped in a set of 8, 16 or 32 flags (fixed in compile time) called Event Flags Group, each event flag is represented by a bit which can be Set or Clear by a check these Event flags states. TASK ISR
Set/Clear Event Flags OSFlagPost()
Event Flags Group 0 1 1 1 0 0 1 1

Figure 2.11 Conjunctive and Disjunctive synchronization

Disjunctive synchronization

task or an ISR, in the other side a task can synchronize its activities by waiting (Pend) on or
Wait Events OSFlagPend()

TASK ISR
Check Events OSFlagAccept()

Set/Clear Event Flags OSFlagPost()

Figure 2.12 C/OS-II Event Flags service

Page 45

Chapter II

C/OS-II Real Time Operating System

OSFlagCreate(), described as follow:

Before using C/OS-II Event Flags a group of flags should be created by using
OS_FLAG_GRP *OSFlagCreate (OS_FLAGS flags, INT8U *err) /* Arguments: flags Contains the initial value to store in the event flag group. err is a pointer to an error code which will be returned to your application: OS_NO_ERR if the call was successful. OS_ERR_CREATE_ISR if you attempted to create an Event Flag from an ISR. OS_FLAG_GRP_DEPLETED if there are no more event flag groups Returns: A pointer to an event flag group or a NULL pointer if no more groups are available.*/

To Set/Clear some bits in the Event Flags Group, the function OSFlagPost() is called as
OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err) /* Arguments: pgrp is a pointer to the desired event flag group. flags If 'opt' (see below) is OS_FLAG_SET, each bit that is set in 'flags' will set the corresponding bit in the event flag group. e.g. to set bits 0, 4 and 5 you would set 'flags' to: 0x31 (note, bit 0 is least significant bit) If 'opt' (see below) is OS_FLAG_CLR, each bit that is set in 'flags' will CLEAR the corresponding bit in the event flag group. e.g. to clear bits 0, 4 and 5 you would specify 'flags' as: 0x31 (note, bit 0 is least significant bit) opt indicates whether the flags will be Set(OS_FLAG_SET)or Cleared (OS_FLAG_CLR) err is a pointer to an error code and can be: OS_NO_ERR The call was successful OS_FLAG_INVALID_PGRP You passed a NULL pointer OS_ERR_EVENT_TYPE you are not pointing to an event flag group OS_FLAG_INVALID_OPT You specified an invalid option Returns: The new value of the event flags bits that are still set. */

follow:

Listing 2.23 Functions to create the Event Flags

Listing 2.24 Functions to post (Set) some flags bits

Page 46

Chapter II

C/OS-II Real Time Operating System

In order to synchronize another Task the function OSFlagPend() is used to wait for a combination of bit to be set or clear, the listing bellow describe how to use this function:
OS_FLAGS OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *err) /* Arguments: pgrp is a pointer to the desired event flag group flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to wait for. The bits you want are specified by setting the corresponding bits in 'flags'. e.g. if your application wants to wait for bits 0 and 1 then 'flags' would contain 0x03. wait_type specifies whether you want ALL bits to be set or ANY of the bits to be set. You can specify the following argument: OS_FLAG_WAIT_CLR_ALL You will wait for ALL bits in 'mask' to be clear (0) OS_FLAG_WAIT_SET_ALL You will wait for ALL bits in 'mask' to be set (1) OS_FLAG_WAIT_CLR_ANY You will wait for ANY bit in 'mask' to be clear (0) OS_FLAG_WAIT_SET_ANY You will wait for ANY bit in 'mask' to be set (1) NOTE: Add OS_FLAG_CONSUME if you want the event flag to be 'consumed' by the call. Example, to wait for any flag in a group AND then clear the flags that are present, set 'wait_type' to: OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME timeout is an optional timeout (in clock ticks) that your task will wait for the desired bit combination. If you specify 0, however, your task will wait forever at the specified event flag group or, until a message arrives. err is a pointer to an error code and can be: OS_NO_ERR The desired bits have been set within the specified 'timeout'. OS_ERR_PEND_ISR If you tried to PEND from an ISR OS_FLAG_INVALID_PGRP If 'pgrp' is a NULL pointer. OS_ERR_EVENT_TYPE You are not pointing to an event flag group OS_TIMEOUT The bit(s) have not been set in the specified 'timeout'. OS_FLAG_ERR_WAIT_TYPE You didn't specify a proper 'wait_type' argument. Returns: The flags in the event flag group that made the task ready or, 0 if a timeout or an error occurred.*/

The task that watches the risen Flags (Watch_Flags_Task) wait until the event occurs by sticking (Pend) on the OSFlagPend() function until the task Hold_Flag_Task signals the flag.

The example bellow shows a demonstration of the Event Flags, firstly the task

Hold_Flag_Task create the Flags group, when it is time to rise the flag, this task calls

Listing 2.25 Functions to pend on the flags to be Set/Clear

OSFlagPost() and specifies that the first flag (Flags = 0x01) equal to one (OS_FLAG_SET).

Page 47

Chapter II

C/OS-II Real Time Operating System

void Hold_Flag_Task(void *pdata) { INT8U err; OS_FLAG_GRP * Flag; /* Create the Flags */ Flag = OSFlagCreate(0x00, &err); while(1) { /* Test if is Time to rise the flag If yes, rise the first Flag (Set to 1 first bit)*/ OSFlagPost(Flag, 0x01, /*First Flag */ OS_FLAG_SET,/*Set the flag to 1 */ &err); } }

Figure 2.13 Flag Events application example 7. Time Management

void Watch_Flags_Task(void *pdata) { INT8U err; OS_FLAG_GRP * Flag; while(1) { /* Wait until the Flag raised */ OSFlagPend( Flag, /* Flags Pointer */ 0x01, /* Watch the first flag */ /* Consume the Flag (Decline it) */ OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0, /* Wait forever, until the flag rises */ &err); } }

Table 2.3 Different Time Management functions TASK DELAYING FUNCTION DESCRIPTION Delay the currently running task until the number of ticks OSTimeDly(INT16U ticks) expires OSTimeDlyHMSM(INT8U Delay the currently running task until the Time specified hours, INT8U minutes, INT8U (Hours:Min:Sec:MSec) expires seconds, INT16U milli) Resume a task that has been delayed by OSTimeDly() or OSTimeDlyResume (INT8U OSTimeDlyHMSM(), or task waiting for an event with prio) timeout. This would make the task look like a timeout occurred. Get the current value of the 32-bit counter which keeps OSTimeGet (void) track of the number of clock ticks. Set the 32-bit counter which keeps track of the number of OSTimeSet (INT32U ticks) clock ticks.

C/OS-II provides a set of timing functions to delay a task a certain amount of time, the OS_TICKS_PER_SEC, the table bellow summarizes the Task delaying functions:

time resolution depends of the Clock Tick frequency fixed by the constant

Page 48

Chapter II

C/OS-II Real Time Operating System

8.

Instead of using the hardware Timers which can affects the responsiveness of the C/OS-II the latest versions of C/OS-II provides timers facilities, managed by the Timers task a Timer we should create it by using the function described by the following listing:

Timers Management

OSTmr_Task, C/OS-IIs Timers can be settled in repeat or in one-shout mode, before using
OS_TMR *OSTmrCreate (INT32U dly, INT32U period, INT8U opt, OS_TMR_CALLBACK callback, void *callback_arg, INT8U *pname, INT8U *perr) /* Arguments: dly Initial delay. If the timer is configured for ONE-SHOT mode, this is the timeout used, If the timer is configured for PERIODIC mode, this is the first timeout to wait for before the timer starts entering periodic mode, period The 'period' being repeated for the timer. If you specified 'OS_TMR_OPT_PERIODIC' as an option, when the timer expires, it will automatically restart with the same period. opt Specifies either: OS_TMR_OPT_ONE_SHOT The timer counts down only once OS_TMR_OPT_PERIODIC The timer counts down and then reloads itself callback Is a pointer to a callback function that will be called when the timer expires. The callback function must be declared as follows: void MyCallback (OS_TMR *ptmr, void *p_arg); callback_arg Is an argument (a pointer) that is passed to the callback function when it is called. pname Is a pointer to an ASCII string that is used to name the timer. Names are useful for debugging. perr Is a pointer to an error code. '*perr' will contain one of the following: OS_NO_ERR OS_ERR_TMR_INVALID_DLY you specified an invalid delay OS_ERR_TMR_INVALID_PERIOD you specified an invalid period OS_ERR_TMR_INVALID_OPT you specified an invalid option OS_ERR_TMR_ISR if the call was made from an ISR OS_ERR_TMR_NON_AVAIL if there are no free timers from the timer pool OS_ERR_TMR_NAME_TOO_LONG if the timer name is too long to fit Returns: A pointer to an OS_TMR data structure. This is the 'handle' that you application will use to reference the timer created/started. */

Listing 2.26 Functions to create a Timer

Page 49

To start the created Timer, OSTmrStart() is used as follow:

Chapter II

C/OS-II Real Time Operating System

OSTmrStart (OS_TMR *ptmr, INT8U *perr) /* Arguments: ptmr Is a pointer to an OS_TMR perr Is a pointer to an error code. '*perr will contain one of the following: OS_NO_ERR OS_ERR_TMR_INVALID OS_ERR_TMR_INVALID_TYPE ptmr is not pointing to an OS_TMR OS_ERR_TMR_ISR if the call was made from an ISR OS_ERR_TMR_INACTIVE if the timer was not created OS_ERR_TMR_INVALID_STATE the timer is in an invalid state Returns: OS_TRUE if the timer was started OS_FALSE if an error was detected */

This Timer can be stopped and deleted if requested by using the following function:
OSTmrStop (OS_TMR *ptmr, INT8U opt, void *callback_arg, INT8U *perr) /* Arguments: ptmr Is a pointer to the timer to stop and delete. opt Allows you to specify an option to this functions which can be: OS_TMR_OPT_NONE Do nothing special but stop the timer OS_TMR_OPT_CALLBACK Execute the callback function, pass it the callback argument specified when the timer was created. OS_TMR_OPT_CALLBACK_ARG Execute the callback function, pass it the callback argument specified in THIS function call callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function instead of the timer's callback argument. In other words, use 'callback_arg' passed in THIS function INSTEAD of ptmr>OSTmrCallbackArg perr Is a pointer to an error code. '*perr' will contain one of the following: OS_NO_ERR OS_ERR_TMR_INVALID 'ptmr' is a NULL pointer OS_ERR_TMR_INVALID_TYPE 'ptmr' is not pointing to an OS_TMR OS_ERR_TMR_ISR if the function was called from an ISR OS_ERR_TMR_INACTIVE if the timer was not created OS_ERR_TMR_INVALID_OPT if you specified an invalid option for 'opt' OS_ERR_TMR_STOPPED if the timer was already stopped OS_ERR_TMR_INVALID_STATE the timer is in an invalid state OS_ERR_TMR_NO_CALLBACK if the timer does not have a callback function defined Returns: OS_TRUE If the call was successful (if the timer is already stopped, we also return OS_TRUE) OS_FALSE If not */

Listing 2.27 Function to start the created Timer

Listing 2.28 Functions to stop the Timer

Page 50

Chapter II

C/OS-II Real Time Operating System

9.

In order to exploit dynamically a memory partition, C/OS-II provides dynamic memory allocation and releasing functions of a fixed size partition made of a contiguous memory area with fixed blocks size. To achieve this and to manage the partition, a memory control block data structure is associated to each created partition, the figure bellow shows the structure of the Memory partition with the respective Control Block: Memory Partition
Memory Block

Memory Management

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

Total blocks OSMemNBlks

Free blocks OSMemNFree

OSMemAddr: Points to the first block (base) of the memory partition, it contains the partition handle as well. block or to the next free memory block. OSMemBlkSize: The size of each memory blocks in the partition.

Figure 2.14 Memory partition and its Memory Control Blocks

OSMemFreeList: pointer used by C/OS-II to point to either the next free memory control OSMemNBlks: Total number of memory blocks that the partition contains. OSMemNFree: Number of the available blocks from the memory partition.

Page 51

Before using a memory partition we should create a partition from an array type and assign following declaration:

Chapter II

C/OS-II Real Time Operating System

it to the Partition Control Blocks, to achieve this OSMemCreate() is called regarding the
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err) /* Arguments: addr is the starting address of the memory partition nblks is the number of memory blocks to create from the partition. blksize is the size (in bytes) of each block in the memory partition. err is a pointer to a variable containing an error message which will be set by this function to either: OS_NO_ERR if the memory partition has been created correctly. OS_MEM_INVALID_ADDR you are specifying an invalid address for the memory storage of the partition or, the block does not align on a pointer boundary OS_MEM_INVALID_PART no free partitions available OS_MEM_INVALID_BLKS user specified an invalid number of blocks (must be >= 2) OS_MEM_INVALID_SIZE user specified an invalid block size - must be greater than the size of a pointer - must be able to hold an integral number of pointers Returns: != (OS_MEM *)0 is the partition was created == (OS_MEM *)0 if the partition was not created because of invalid arguments or no free partition is available. */

Upon the memory partition created, we can dynamically allocate and freed each block of the partition by calling OSMemGet() and OSMemPut() functions.
/* Allocate a memory block from a partition */ void *OSMemGet (OS_MEM *pmem, INT8U *err); /* Arguments: pmem is a pointer to the memory partition control block err is a pointer to a variable containing an error message which will be set by this function to either: OS_NO_ERR if the memory partition has been created correctly. OS_MEM_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller OS_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' Returns: A pointer to a memory block if no error is detected A pointer to NULL if an error is detected */

Listing 2.29 Functions to create a memory partition

Listing 2.30 Functions to allocate a memory block

Page 52

Chapter II

C/OS-II Real Time Operating System

/* free a memory block to a partition */ INT8U OSMemPut (OS_MEM *pmem, void *pblk) /* Arguments: pmem is a pointer to the memory partition control block blk is a pointer to the memory block being released. Returns: OS_NO_ERR if the memory block was inserted into the partition OS_MEM_FULL if you are returning a memory block to an already FULL memory partition (You freed more blocks than you allocated!) OS_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem' OS_MEM_INVALID_PBLK if you passed a NULL pointer for the block to release.*/

The following listing illustrates the memory management example, the memory partition is these data are sending and no longer need to save them:

used to store the converted analogue data, and the partition blocks will be freed when
INT16U Data[128][32];/*128 blocks with 32bytes each, devoted for the memory partition */ OS_MEM* DataMem; /* Memory Control Blocks to manage the partition */ void* MemBlkPtr; /* Pointer contains a partition block */ void DataStore_Task(void *pdata) { INT8U err; /* Create the Memory Control Blocks associated with the declared partition */ DataMem = OSMemCreate(Data, 128, 32, &err); while(1) { MemBlkPtr = OSMemGet(DataMem, &err); /* Allocate a block memory */ if (err == OS_NO_ERR) /* if the block allocated successfully */ GetData(MemBlkPtr); /* Store the data into the allocated block */ if (SendReq) { SendData(MemBlkPtr); /* Send the block of the stored data */ OSMemPut(DataMem, MemBlkPtr); /* freed the allocated block */ } OSTimeDly(100); }}

Listing 2.31 Functions to free the allocated block

Listing 2.32 Dynamic memory allocation example

Page 53

Chapter II

C/OS-II Real Time Operating System

CONCLUSION

Therefore, the C/OS-II stills useless without making the next bottom layer, this layer this operation is called Porting the C/OS-II to the specific microcontroller, this will be the topic of the next chapter.

interfaces between the C/OS-II functions and the hardware of the target microcontroller,

management, Inter-task synchronization and communication, memory management etc.

In this chapter we have seen all the features provided by the C/OS-II, these includes Tasks

Page 54

Chapter III

Porting C/OS-II to the M16C Microcontrollers

CHAPTER III Porting C/OS-II to the M16C Microcontrollers


INTRODUCTION C/OS-II is a real time operating system that can work on several Processors and Microcontrollers. However, C/OS-II needs to write some processors specific codes in C

Porting the C/OS-II to a given processor consists of defining the specific types length, write the context switch routines and the Time track ticks generator (Timer). produce reentrant code. 1. 2. 3. 4. 5. You must be able to disable and enable interrupts. A processor can run C/OS-II if it satisfies the following general requirements [1]:

and assembly language, especially codes that manipulate CPU registers and interrupts.

You must have a C compiler for the processor and the C compiler must be able to The processor must support interrupts and you need to provide an interrupt that The processor must support a hardware stack, and the processor must be able to store

occurs at regular intervals (typically between 10 to 100 Hz). a fair amount of data on the stack (possibly many Kbytes). CPU registers either on the stack or in memory.

The processor must have instructions to load and store the stack pointer and other
Page 55

Chapter III

C/OS-II Source files C/OS-II specific application file Processor independent files File Function File Function os_core.c Real-time kernel functions Include/exclude the ucos_ii.h C/OS-II functions prototype C/OS-II functions, keep os_mbox.c Message mailbox management only the function needed <os_cfg.h> by the application to os_q.c Message queue management optimize the output code os_sem.c Semaphore management size os_task.c Tasks management os_time.c Time management <app_cfg.h> Application configuration os_flag.c Event flag management This file includes all the os_mutex.c Mutual exclusion semaphore <includes.h> header files needed by the os_tmr.c Timer management application os_mem.c Memory management Ported C/OS-II files Processor dependent files File Function os_cpu.h Redefining data type and macros os_cpu_c.c Tasks frame stack initialization function OSTaskStkInit() os_cpu_a.asm C/OS-II assembly functions

Table 3.1 C/OS-II Hardware and Software structures

Porting C/OS-II to the M16C Microcontrollers

COS-II Application

Table 3.1 shows the different files that constitute the C/OS-II RTOS, the C/OS-II source

Hardware

<os_cpu_a.asm>, these files are specific to each processor.

provided by the C/OS-II. The files to be programmed are <os_cpu.h>, <os_cpu_c.c> and

files are processors independent and work on any suitable processor. There is no subject to modify these file, the specific application header files can be modified depends on the application needs, <os_cfg.h> contains the options to include or exclude different service

Page 56

Chapter III

Porting C/OS-II to the M16C Microcontrollers

1.

OS_EXIT_CRITICAL() macros definitions to enable and disable the interrupts, it contains also OS_TASK_SW() macro which performs the task level context switch and should be referred to vector #0 interrupt. <OS_CPU.H> Listing 3.1 shows the implementation of this file in case of M16C microcontroller:

that represent the INT8U, INT8S, INT16U etc., it contain also the OS_ENTER_CRITICAL() and

inherently non-portable. Instead, the file <os_cpu.h> contains the processor specific type

C/OS-IIs code never makes use of Cs short, int and, long data types because they are

Compiler Specific Data Types and Macros, <OS_CPU.H>

/***************************************************************************/ /******* DATA TYPES ******/ /******* (Compiler Specific) *******/ /***************************************************************************/ typedef typedef typedef typedef typedef typedef typedef typedef typedef unsigned unsigned signed unsigned signed unsigned signed float double char char char int int long long BOOLEAN; INT8U; /* INT8S; /* INT16U;/* INT16S;/* INT32U;/* INT32S;/* FP32; /* FP64; /*

Unsigned 8 bit quantity Signed 8 bit quantity Unsigned 16 bit quantity Signed 16 bit quantity Unsigned 32 bit quantity Signed 32 bit quantity Single precision floating point Double precision floating point

*/ */ */ */ */ */ */ */ */ */

typedef unsigned int typedef INT16U

OS_STK; /* Each stack entry is 16-bit wide OS_CPU_SR; /* Type of CPU status register

/***************************************************************************/ /******* INTERRUPTS ENABLE/DISABLE MACROS ******/ /******* (processors Specific) *******/ /***************************************************************************/ #define OS_ENTER_CRITICAL() asm("FCLR I") /* Disable interrupts */ #define OS_EXIT_CRITICAL() asm("FSET I") /* Enable interrupts */ /***************************************************************************/ /******* STACK GROWTH, CONTEXT SWITCH INTERRUPT MAPPING ******/ /******* (processors Specific) *******/ /***************************************************************************/ #define #define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory */ OS_TASK_SW() asm("INT #0") /* Mapped to the software interrupt 0

Listing 3.1 os_cpu.h, Compiler specific data types

*/

Page 57

Chapter III

Porting C/OS-II to the M16C Microcontrollers

2.

function will be called when a task is created in order to simulate an interrupt call and all the processor registers were pushed onto the stack. the tasks priority. this function the start address of the task, a pointer called pdata, Tasks top-of-stack and case of M16C microcontroller.

When a task created by either OSTaskCreate() or OSTaskCreateExt(), we should pass to

This file contains the body of the stack frame initialization function (OSTaskStkInit()), this

Stack Initialization And User Hook Function, OS_CPU_C.C

shows the stack frame configuration that should be achieved by OSTaskStkInit() function in
Low memory
Stack pointer SP

OSTaskStkInit() needs the Tasks address, pdata pointer and Task top-of-stack, Figure 3.1

FLG(H) PC(H) PC(L) FB SB

FLG(L)

Stack growth

A1 A0 R3 pdata(H) (R2) pdata(L) (R1)

Task address

ptos (R0) High memory

The configuration of the figure 3.1 done by OSTaskStkInit(), firstly the address of the task is
Page 58

Figure 3.1 Stack frame initialization of the M16C

pushed at beginning of the stack, next steps will simulate a task call like any other function, start by pushing the argument pdata, the following would be pushing the return address if it was normal function, but as the task doesnt return and considered as infinite loop, there

is no need to push the return address of the caller, the next step pushes all the remaining of the stack which represents the stack pointer or the stack handle. The listing 3.2 shows the OSTaskStkInit() function that performs this configuration. os_cpu_c.c

Chapter III

Porting C/OS-II to the M16C Microcontrollers

CPU registers R3, A0, A1, SB, FB and PC(L), FLG(L), PC(H) and FLH(H) are pushed at the top

OS_STK *OSTaskStkInit(void(*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { INT16U *pstk16; INT16U flag; flag = 0x0040; pstk16 = (INT16U *)ptos; pstk16--; /* Simulate ISR entry */ *pstk16-- = (flag & 0x00FF)/* The lowest byte of the FLAG register */ INT32U)task >> 8) & 0x00000F00)/*The highest nibble of the PC register */ | ((flag << 4) & 0xF000); /* The highest nibble of the FLAG register */ *pstk16-- =(((INT32U)task)&0x0000FFFF);/* The lowest bytes of the PC register */ /* Save registers onto stack frame */ *pstk16-- = (INT16U)0xFBFB; /* ... FB register */ *pstk16-- = (INT16U)0x3B3B; /* ... SB register */ *pstk16-- = (INT16U)0xA1A1; /* ... A1 register */ *pstk16-- = (INT16U)0xA0A0; /* ... A0 register */ *pstk16-- = (INT16U)0x3333; /* ... R3 register */ *pstk16-- = (INT32U)pdata >> 16L /* ... Pass argument in R2 register */ *pstk16-- = (INT32U)pdata & 0x0000FFFFL; /*... Pass argument in R1 register*/ *pstk16 = (INT16U)0x0000; /* ... R0 register */ return ((OS_STK *)pstk16); }

which monitors all the activities of the kernel, these function are:

In addition of the OSTaskStkInit, C/OS-II porting requires to write the some user functions, these functions are used by the C/OS-II kernel awareness called COS-VIEW

Listing 3.2 Stack initialization function, OSTaskStkInit

/* Return the top address of the Stack */

Page 59

Chapter III

calls OSView_TaskCreateHook() owned by the OS-VIEW module, OSTaskDelHook(), called when a task going to be deleted,

OSTaskCreateHook(), this function is called whenever a task is created, therefore, it OSTaskSwHook(), called when a context switch performed, allows the user to perform OSTaskStatHook(), This function is called every second by C/OS-II's statistics task, OSTaskIdleHook(), Called by the idle task, this hook has been added to allow the user to OSTCBInitHook(), Called by OS_TCBInit() after setting up most of the TCB. OSTimeTickHook(), This function is called every tick, used to call OSView_TickHook, this Assembly Language Functions File, OS_CPU_A.ASM

Porting C/OS-II to the M16C Microcontrollers

other operations during a context switch, this function should calls OSView_TaskSwHook() to aware the OS-VIEW that a context switch has occurred. this allows to add new functionality to the statistics task. do such things as STOP the CPU to conserve power.

3.

function is also used to increment the C/OS-II V2.83 Timers counter. C/OS-II, these functions are: 3.1. OSStartHighRdy()

This file contains the functions written in assembly language and the interrupt table of the

called by the C/OS-II when starts running, this function load the stack of the highest priority ready to run task, assumed that OSTCBHighRdy points on the TCB of the highest the user that the multitasking has just starting before making OSRunning = TRUE. priority ready to run task, this function call the hook function OSTaskSwHook() to inform

Page 60

The listing below show the assembly code of this function in case of the M16C microcontroller: OS_CPU_A.ASM

Chapter III

Porting C/OS-II to the M16C Microcontrollers

;';;;;;;;;;;;;;;;;;; Run the highest priority task ready to run ;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;; void OSStartHighRdy(void);;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OSStartHighRdy: JSR OSTaskSwHook ;'Call OSTaskSwHook() FCLR U ;'Software interrupt knowledge ;'Point on the stack pointer of the highest priority ready task... MOV.W OSTCBHighRdy, A0 ;'ISP = OSTCBHighRdy->OSTCBStkPtr LDC [A0], ISP MOV.B #01H, OSRunning ;'OSRunning = TRUE ;'Load the highest priority ready task registers into CPU registers POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ;'Launch the highest priority ready task

3.2. OSCtxSw(),

This function performs the task level context switch, as we have seen in chapter II this task and launches this task, the listing bellow shows the pseudo code of this function:
void OSCtxSw(void) { Save processor registers; Save the current tasks stack pointer into the current tasks OS_TCB: OSTCBCur->OSTCBStkPtr = Stack pointer; Call user definable OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; Restore all processor registers from the new tasks stack; Execute a return from interrupt instruction; }

Listing 3.3 Function called when C/OS-II start to run the highest priority ready to run task

routine starts by saving the context registers, loads the context of the highest priority ready

Listing 3.4 Pseudo code of the function that performs Context Switch function
Page 61

The implementation of this function in case of M16C microcontroller is shown by listing called by INT#O assembly instruction symbolized by OSCtxSw() macro. OS_CPU_A.ASM
;';;;;;;;;;;;;;;; Performs the task level context switch ;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;; void OSCtxSw(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OSCtxSw: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Push the CPU Regs onto current task stack MOV.W OSTCBCur, A0 ;'OSTCBCur->OSTCBStkPtr = SP STC ISP, [A0] JSR OSTaskSwHook ;'Call OSTaskSwHook() MOV.W OSTCBHighRdy, OSTCBCur ;'OSTCBCur = OSTCBHighRdy MOV.W OSPrioHighRdy, OSPrioCur;'OSPrioCur = OSPrioHighRdy MOV.W OSTCBHighRdy, A0 ;'SP = OSTCBHighRdy->OSTCBStkPtr LDC [A0], ISP ;'Restore all processor registers from the new tasks stack POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ;'Launch the highest priority ready task

Chapter III

Porting C/OS-II to the M16C Microcontrollers

3.5, we should note that this routine is mapped in interrupt vector number 0, thus it will be

3.3. OSIntCtxSw(),

This function performs the interrupt level context switch, which means that is called when an interrupt occurs, therefore, no need to save the current context as long it has been function. already done by the calling interrupt, this what makes difference with the OSCtxSw()

Listing 3.5 Assembly code of the function that performs task level Context Switch function

Page 62

The listing bellow shows the assembly code of this function: OS_CPU_A.ASM

Chapter III

Porting C/OS-II to the M16C Microcontrollers

;';;;;;;;;;;;;; Performs the interrupt level context switch ;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;; void OSIntCtxSw(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OSIntCtxSw: JSR OSTaskSwHook ; 'Call OSTaskSwHook() MOV.W OSTCBHighRdy, OSTCBCur ; 'OSTCBCur = OSTCBHighRdy MOV.W OSPrioHighRdy, OSPrioCur ; 'OSPrioCur = OSPrioHighRdy MOV.W OSTCBHighRdy, A0 ; 'SP = OSTCBHighRdy->OSTCBStkPtr LDC [A0], ISP ;'Restore all processor registers from the new tasks stack POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ; 'Launch the highest priority ready task

Listing 3.6 Assembly code of the function that performs the interrupt level Context Switch function

3.4. OSTickISR(),

This ISR is considered as Clock Ticks generator, required by C/OS-II to keep track of delays and timeout, any hardware Timer or external pulses can be used to invoke this decrease the reactivity of the C/OS-II application. The listing below show the pseudo code of this routine [1]:
Call OSTimeTick();

routine periodically, the frequency of these pulses should be between 10 and 100Hz, making too high this frequency would overhead the CPU, in contrast, making it too low will

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

Listing 3.7 Pseudo code of the Clock Ticks interrupt


Page 63

In case of M16C microcontroller, this function can be implemented as the following assembly code: OS_CPU_A.ASM
;';;;;;;;;;;;;;;;;;;;; Clock Ticks Generator Timer ;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;; void OSTickISR (void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; OSTickISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ; 'Save current task registers INC.B OSIntNesting ; 'OSIntNesting++ ;' Make sure that this ISR does not interrupt another ISR... CMP.B #1,OSIntNesting ; 'if (OSIntNesting == 1) JNE OSTickISR1 ;'If yes assign the highest priority ready task stack pointer to the current TCB stack pointer MOV.W OSTCBCur, A0 ; 'OSTCBCur->OSTCBStkPtr = SP STC ISP, [A0] OSTickISR1: JSR OSTimeTick ; 'Call OSTimeTick() JSR OSIntExit ; 'Call OSIntExit() to achieve the context switch POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers from the new tasks stack REIT

Chapter III

Porting C/OS-II to the M16C Microcontrollers

Listing 3.8 Assembly code of the Clock Tick ISR

Page 64

To achieve the os_cpu_a.asm file we need to add the interrupt vectors table for OSCtxSw and OSTickISR ISR, the listing shows such interrupts table in case of IAR C Compiler for M16C: OS_CPU_A.ASM

Chapter III

Porting C/OS-II to the M16C Microcontrollers

;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;; INTERRUPT VECTOR TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .COMMON INTVEC ;'Context Switch Interrupt Vector ORG 0 .LWORD OSCtxSw ;'Clock Ticks Generator TIMER A0 ORG 21*4 .LWORD OSTickISR ;'Tx UART Interrupt vector, Used by COS-VIEW Module (Optional) .ORG 17*4 .LWORD OSView_TxISR ;'Rx UART Interrupt vector, Used by COS-VIEW Module (Optional) .ORG 18*4 .LWORD OSView_RxISR .END

Listing 3.9 Interrupts vector table of the os_cpu_a.asm file

CONCLUSION

in the next chapter.

applications that targets the M16C can be built upon this RTOS. These applications will get

the benefits and the facilities that characterize the COS-II. This will be the topic addressed

Once the porting of the COS-II to the M16C microcontrollers achieved, any real time

Page 65

Chapter IV

C/OS-II Demonstration Example

CHAPTER IV C/OS-II Demonstration Example


INTRODUCTION In this chapter we will use the C/OS-II operating system to develop a real time embedded application, in order to demonstrate the way how to use the features brought by the C/OS-II, this application needs to be a multitask system with inter-task communication using Mailboxes, Message Queues and Events Flag etc. this application displays in real time the Temperatures, Pressure and the Gates status alarm and display the nature of the emergency on the LCD Display. To achieve this goal I have chosen a data acquisition system of a hermitically closed area, (Open/Close) of this area, if the temperature exceeds or the pressure is bellow a certain predefined values or one of the gates are open, the application makes visual and audible Before start programming this application, I have made a C/OS-II V2.83 Template Project

targets the M16C Microcontrollers, in all programs that follow the IAR Embedded Workbench for Mitsubishi V1.36 Compiler and Linker are used.

which should be the start point of our application or any C/OS-II based application that

Page 66

Chapter IV

C/OS-II Demonstration Example

1.

Figure bellow shows the IAR Project of the template, we can see that the projects files are C/OS-II core which contain all its features grouped by categories, these file are: Table 4.1 C/OS-II Source file Functions C/OS-II Core functions (Required) Tasks management functions (Required) Mailboxes management functions (Optional) Semaphores management functions (Optional) Mutual exclusion semaphore functions (Optional) Message queues management functions (Optional) Memory management functions (Optional) Events Flag management functions (Optional) Delay Time functions (Ex. OSTimeDly()) (Optional) Timers management functions (Optional)

C/OS-II Project Template

grouped in the project file structure and the folders structure as well in four groups, the

first group contains C/OS-II sources files (Chip independent files), these file constitute the

C/OS-II Source file OS_CORE.C OS_TASK.C OS_MBOX.C OS_SEM.C OS_MUTEX.C OS_Q.C OS_MEM.C OS_FLAG.C OS_TIME.C OS_TMR.C

The file os_cfg.h contains the directives to include or exclude different features provided by The next important group of files is the C/OS-II port files; these files are chip specific and depend of the microcontroller, the first file os_cpu_a.asm contains the functions written in assembly language, these functions perform the context switch operations (OSCtxSw, to the users hook functions. the needed functions.

the C/OS-II; these directives are useful to optimize the application code by keeping only

All the C/OS-II variables, data structures and all the prototypes functions are declared in ucos_ii.h file, this file should be included in any C/OS-II application.

OSIntCtxSw etc) which require to access to CPUs registers. The second file ported to the

M16C Microcontrollers is os_cpu_c.c which contains the Tasks Stack initialization and calls

Page 67

Chapter IV

C/OS-II Demonstration Example

C/OS-II Application directory files

M16C target Port Files C/OS-II Source directory files

COS-View Module directory files

Communication Setup for the MSA0654 board

The C/OS-II project need to be compiled under far memory model, therefore, this model project as shown in Figure 4.3.

Figure 4.1 C/OS-II Template project and its directories structures

has been chosen within the IAR Embedded Workbench Options as shown in the Figure 4.2. In addition, we should include the directory paths that contain the header files of the

Page 68

Chapter IV

C/OS-II Demonstration Example

Far memory model

Figure 4.2 Far memory model used to compile the project

Page 69

Chapter IV

C/OS-II Demonstration Example

Extra include directories of the C/OS-II Project

The third group contains the embedded part of the C/OS-View software; this embedded View provides an important GUI tool to debug the C/OS-II RTOS by showing the status of each managed Task, the name of each task, CPU cycles consumed by each task etc. OS_VIEW.C makes the core of C/OS-View and it is independent of the processor. all the header files used by the application and <ucos_ii.h> file.

module communicates with a Microsoft Windows application via RS232 serial port. C/OSOS_VIEWa.ASM and OS_VIEWc.C files depend of the microcontroller and contain the serial The files that belong to the application are grouped in same folder named C/OS communication interrupts declaration and UARTs registers initialization respectively. Application, depend of the size of the application all the tasks can be written in same file or make to each task its own file, this folder contains also the file <includes.h> which contains
Page 70

Figure 4.3 Include directories added to the project

Another header file included by C/OS-II anyway is <app_cfg.h>, this file can be used to define the constants or data structures for the application (Ex. Tasks priorities, Tasks Stacks size etc) without creating another application header file. <includes.h> The following listing shows the previous file of the project template:
#define Chip_3062x #include <iom16c62.h>

Chapter IV

C/OS-II Demonstration Example

/* Define the Target Chip */ /* include the Target Chip file */

/* Add your application need header file Here */ /* Ex.. #include <string.h> */ /* uCOS-II Header File */ #include <uCOS_II.H> /* uCOS-II OS Viewer header files */ #include <OS_VIEWc.H> #include <OS_VIEW.H>

<app_cfg.h>
/* Define Tasks priorities here */ #define STARTUP_PRIO 40 #define TASK1_PRIO 5 #define TASK2_PRIO 10 /* Tasks Stack size */ #define TASK_STK_SIZE /* CPU Clock frequency */ #define CPU_CLK_FREQ

128

16000000

/* Timer initialization of the C/OS-II Clock Ticks Generator */ void InitTick(void);

Page 71

The following listing contains the template of a C/OS-II application: Main.C


/* include the global header file */ #include <includes.h> /* Startup Tasks Stack declaration */ OS_STK STARTUP_STK[TASK_STK_SIZE]; /* Other Tasks Stacks declaration go here */ OS_STK TASK1_STK[TASK_STK_SIZE]; /* Task1s Stack */ OS_STK TASK2_STK[TASK_STK_SIZE]; /* Task2s Stack */ /* Tasks Core Go Here */ /*********************** Task 1 ************************/ void TASK1(void *pdata) { INT32U X = 1, Y = 0; /* Task 1 Core */ while(1) { Y += sqrt(X++^2+2); OSTimeDlyHMSM(0, 0, 0, 100); } } /*********************** Task 2 ***********************/ void TASK2(void *pdata) { INT32U Z = 0, W = 1; /* Task 2 Core */ while(1) { W += sqrt(Z++) + 1; OSTimeDlyHMSM(0, 0, 0, 200); } }

Chapter IV

C/OS-II Demonstration Example

/* Startup Tasks Core */ void STARTUP_TASK(void *pdata) { INT8U err; InitTick(); /* Initialize the Clock Ticks Timer */ OSStatInit(); /* Initialize the Statistic Task (Optional) */ OSView_Init(); /* Initialize the OS Viewer Module (Optional) */ /* Use OS-View function to send text to the UART Terminal */ OSView_TxStr( UCOS-II V2.83\n DEMONSTRATION\n PROGRAM\n ,0); /* Other initialization functions go here... */ /* Create Other Tasks Here */ /* Create Task 1 */ OSTaskCreateExt(TASK1, (void *)0, &TASK1_STK[TASK_STK_SIZE-1], TASK1_PRIO, TASK1_PRIO, &TASK1_STK[0], TASK_STK_SIZE,(void*)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to the created Task (TASK1) */ OSTaskNameSet(TASK1_PRIO, TASK1, &err); /* Create Task 2 */

Page 72

Chapter IV

C/OS-II Demonstration Example

OSTaskCreateExt(TASK2, (void *)0, &TASK2_STK[TASK_STK_SIZE-1], TASK2_PRIO, TASK2_PRIO, &TASK2_STK[0], TASK_STK_SIZE,(void*)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to the created Task (TASK2) */ OSTaskNameSet(TASK2_PRIO, TASK2, &err); while(1) { /* Startup Tasks Core */ /*.....................*/ OSTimeDlyHMSM(0, 0, 1, 0); /* Delay the Task for 1 Sec */ } } /* Timer initialization of the C/OS-II Clock Ticks Generator */ void InitTick(void) { /* Make reload value to generate OS_TICKS_PER_SEC Ticks/Sec */ TA0 = (INT16U)(( 2000000 / OS_TICKS_PER_SEC 1)); TA0MR = 0x40; /* F8 as clock source = 500ns */ TA0IC = 0x01; /* Timer interrupt register, priority 1 (lowest)*/ TABSR |= 0x01; /* Set Timer count start flag */ PRCR = 0x01; /* Enable write to Processor mode */ CM0 &= 0x1F; /* main clock division register: no division */ CM1 &= 0x3F; PRCR = 0x00; /* Disable access to processor and clock mode */ } void main (void) { OSInit(); /* Initialize the uC/OS-II */ /********** Create the StartUp Task ***********/ OSTaskCreateExt(STARTUP_TASK, /* Tasks Void */ (void *)0, /* No value passed to the task */ &STARTUP_STK[TASK_STK_SIZE 1],/* Top of the Tasks Stack */ STARTUP_PRIO, /* Task Priority */ STARTUP_PRIO, /* Task ID */ &STARTUP_STK[0], /* Bottom of the Tasks Stack */ TASK_STK_SIZE, /* Tasks Stack Size */ (void*)0, /* No TCB Extension */ /* Enable stack checking + clear stack */ OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /*Give a Name to the Startup Task */ OSTaskNameSet(STARTUP_PRIO,STARTUP TASK, (void*)0); OSStart(); } /* Start running the operating system */

Page 73

Ticks Timer and create Task1 and Task2, Task1 and Task2 make some mathematical operations to consume some CPU cycles. 2. C/OS-View Module The C/OS-View is a combination of an embedded module that resides in the target

In the previous application I have used the low priority Startup Task to initialize the Clock

Chapter IV

C/OS-II Demonstration Example

following information: [7]

microcontroller with C/OS-II application and a Windows application, the Windows the status of the tasks managed by the C/OS-II. The C/OS-View V1.10 allows to shows the The address of the TCB of each task; The name of each task;

application communicate with the embedded module via the rs232 port and allows to view

The status (Ready, delayed, waiting on event) of each task; The amount of stack space used and left for each task; The number of times each task has been switched to; The execution profile of each task; be processed.

The number of ticks remaining for a timeout if a task is delayed or wait on timed events; The percentage of CPU time used by each task relative to all the tasks;

Suspend the tick interrupt from decrementing delays and timeouts of tasks. However, you can step on tick at a time by pressing the F8 key from the Windows application. The F6 key cancels this mode, the F7 key enables this mode and the F8 key enables one tick to the command structure. Pass keystrokes to your application from the Terminal window. In other words, you target specific and thus you can define those specific to your product.

can now send commands to your product from the Windows application. You determine Output ASCII strings from the target to the Terminal window. These ASCII strings are
Page 74

To use the C/OS-View terminal, these two functions are used to send or receive ASCIL character respectively: To send data:

Chapter IV

C/OS-II Demonstration Example

OSView_TxStr(char *s, INT16U dly);/* Send ASCII string to terminal window */ /* dly: Time delay to send the string s */

To receive data:

/* Install the function that receive the data */ OSView_TerminalRxSetCallback(TerminalCallback); /* The code for the callback looks as follows: */ void TerminalCallback (INT8U data) { /* The received data will be carried by data variable */ }

After many experiences, I have noted that writing all interrupts as described in Chapter II the interrupt level context switch, the other interrupts notify the C/OS-II that an interrupt shows the new format to write an interrupt (Ex. Serial Port data reception interrupt Tx).
;'Save the current running task registers ;'OSIntNesting++, ;'Call OSView_TxISRHandler() ;'OSIntNesting-;'Restore registers from the new task stack

causes the crash of the application when these interrupt are often triggered, therefore, I has occurred without making the context switch by incrementing OSIntNesting when enter

have kept this format only in the case of Clock Ticks Timer (OSTickISR) in order to perform to interrupt and decrements this variable when excite the interrupt, the listing bellow

OSView_TxISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB INC.B OSIntNesting JSR OSView_TxISRHandler DEC.B OSIntNesting POPM R0,R1,R2,R3,A0,A1,SB,FB REIT

Page 75

consumed by each task, we can show also how often the context switches performed to a located in <os_cfg.h>).

certain task. C/OS-View displays the Tasks stack size and the amount left, Figure 4.4 shows the C/OS-View windows that provide Tasks status for the previous sample. In this

By using the C/OS-View application we can show the Tasks status and the CPUs cycles example the number of Clock Ticks has been fixed to 100 (OS_TICKS_PER_SEC = 100,

Chapter IV

C/OS-II Demonstration Example

COS-View Terminal window

Figure 4.4 Tasks Status and C/OS-II running information given by C/OS-View

Number of Context Switches to each task so far Page 76

Time remain to task to be ready

Events address waited for

Stack used /Stack Size and Stack address

Tasks priority

Tasks Status

Tasks TCB Address Tasks Name

CPUs Time consumed

C/OS-II CPU Load graph (very low compared to the idle tasks CPU load), I have multiplied the CPU load of each task by 100 in os_view.c file as follow: os_view.c
OSView_TxStoINT32U((INT32U)ptcb->OSTCBEventPtr);/*Pointer to event task is waiting for*/ OSView_TxStoINT32U((INT32U)ptcb->OSTCBDly);/*Timeout (i.e. ticks of delayed task)*/ OSView_TxStoINT32U(ptcb->OSTCBCyclesTot*100);/* ExecTime */ OSView_TxStoINT32U(ptcb->OSTCBCtxSwCtr); /* NumActivations */ ..

In order to make the CPU load of the Task1, Task2 and Startup Task visible on the

Chapter IV

C/OS-II Demonstration Example

TASK2s Activity

TASK1s Activity Startup Tasks Activity Figure 4.5 Graph of the CPU percentage consumed by each task across the time
Page 77

The graph of the figure 4.5 provides useful information about the CPU consumption of each task, the first note we can see is that 98.53% of the time is spent in the idle Task which statistics proves the benefit of the C/OS-II regarding the CPU load optimization. 3. C/OS-II Demonstration Example means the rest time of the C/OS-II, in contrast, Task1 and Task2 consume only 0.63 time to add more Tasks and Codes without the risk to overload the CPU. Therefore, these and 0.65% of CPU time respectively which is very low, this means that still plenty of CPU

Chapter IV

C/OS-II Demonstration Example

The previous project template will be used to develop the data acquisition system feature of the C/OS-II, which is the multitasking, the whole system will be divided into in order to achieve the main functions of this system. Figure 4.6 shows the block diagram of this system: C/OS-II Inter-task communications tools to make different tasks interact with each other

described briefly at the beginning of this chapter, to get benefit of the most important

tasks, each task performs its job independently of other tasks, therefore, the system uses

Page 78

Chapter IV

C/OS-II Demonstration Example

LEDS ALARM TASK


Mailbox

SOUND ALARM TASK


Mailbox

Buzzer

LCD Semaphore

CONFIG MENU TASK


Event Flag

LCD MESSAGES TASK


Mails Queue Emergency Mailbox

Messages Store Memory

1 4 7 A

2 5 8 0

3 6 9 B

F E

Emergency Messages

Messages contain system status (Temperature, Pressure, Gates Close/Open)

Message to make Leds blink when emergency

Sent Audible Message when emergency

DATA CAPTURE TASK

Keypad RS232

Mails Queue

Computer

Suspend /Resume

SERIAL COM TASK

Resume sending the stored messages when memory 90% full Stored Messages to be sent to PC

Temperature Gates Sensor Open/Close Sensors

Figure 4.6 Block diagram of the developed system

Pressure Sensor

Page 79

2. LEDs Alarm Task: To pay the intention of the user when the system in emergency, I have added a visual alarm to the previous audio alarm, therefore, the Leds Alarm Task performs this job by controlling the eight Leds of the board, this task contains a mailbox to receive the emergency message which contains the pattern of the Leds that should be bright and if these Leds blink or bright in permanence.

sounds, this tasks program contains a Mailbox to receive messages from outside, and this message carries the code pattern of the desired sound.

The data acquisition system of the precedent block diagram contains the following tasks:

Chapter IV

C/OS-II Demonstration Example

1. Sound Alarm Task: This task drives the Buzzer to generate the warning alarm

3. LCD Messages Task: This task drives the LCD Display in order to show the received messages, thus, this task contains a Messages Queue as long these messages are displayed one by one with certain time between each two messages. I have added to this task an Emergency Mailbox in which this task receives the emergency messages that they cant Display. These messages will be stored on a Memory Partition with limited size, therefore, Serial Com Task. wait on the queue and should be displayed immediately. The messages posted to this task stored in the freed area wont be lost, but send to the Personal Computer via the Serial Port where they can be stored on files, this is will be the mission of the next Task which is 4. Serial Com Task: The job of this task is to send the stored messages to the PC via

contain two text lines of 16 characters each to be displayed on the 2-Line 16-Charaters LCD this partition should be used dynamically and freed each time it is 90% full, the messages

Serial Port when the memory area is 90% full, each block sent of the memory partition will be freed by this task, to achieve this a messages queue is used by this task which contain a when 90% of the memory is free.

pointer to each stored message, this task will be suspended by the LCD Message Task until the time to freed the memory comes in which it will be resumed and suspended again

Page 80

5. Config Menu Task: The role of this task is to manage different configuration menus of

Chapter IV

C/OS-II Demonstration Example

this application, this menu contain two major items, the Setup menu; in this menu the user

can setup different parameters of the system (Ex. Maximum allowed Temperature, the View item, by selecting this menu the user can display the status of the C/OS-II, the items that can be displayed are: CPU Usage (%), Free Messages Memory (%), Number of the Menus items.

Minimum allowed Pressure, Alarmed/Disarmed gates, Time and Date). The second menu is Clock Tick and Context Switches, Time/Date. This task waits for an Event Flag to be signaled by the keypads interrupt when any button pressed, at this time this task becomes

ready to run and ask for the LCD Display via the LCD Display Semaphore in order to display responsiveness of the system depends of the responsiveness of this task, thus, this task was given the highest priority among all tasks. By the means of Temperature and Pressure sensors and the eight switches, this task picks up the Temperature, Pressure and Status of Message Task into its Messages Queue in order to be displayed one by one on the LCD 6. Data Capture Task: This task is the most important task in the system and the

the eight gates, these values are stamped by the Time and Date and send to the LCD Display, in case when the Temperature is above the predefined value or the pressure is bellow the minimum pressure or either one gate or more are open, this task posts an emergency message into the emergency Mailbox of the LCD Message Task to notify the the emergency will more severe. user about the nature of the emergency problem (Temperature too high, Pressure too low or which gate is open). In addition, this task sends messages to Leds Alarm Task and

Sound Alarm Task to their Mailboxes in order to make a visual and an audible alarm, so

Page 81

the mixture of the displayed characters (Menus items and Messages) of both tasks. 4. MSA0654 Development Board

The LCD Semaphore will be used to get exclusive access to the LCD Display, This Display is

Chapter IV

C/OS-II Demonstration Example

shared by the Config Menu Task and the LCD Message Task, therefore, when one task of

them gets access to this resource the other task should wait until released. This will avoid

MEAUST) development board with its daughter board; this board contains the M16C62 microcontroller as core. In addition, this board was built with many Input/Output development board connected with its daughter board.

peripherals (LCD Displays, LEDs, Keypad, and Buzzer etc.). Figure 4.7 shows this

The application designed in this chapter will be tested on the MITSUBISHI (MSA0654-

Page 82

Chapter IV

C/OS-II Demonstration Example

Main board M16C62P

Daughter board

Figure 4.7 MSA0654 development board, used to run the application


Page 83

Chapter IV

C/OS-II Demonstration Example

Figure 4.8 shows the Applications project designed with the IAR IDE V1.36, the previous project template was used to develop this application.

5.

Test and Demonstration

Applications directory

MSA0654 Board Drivers

Figure 4.8 The C/OS-II Application project

Page 84

Chapter IV

C/OS-II Demonstration Example

In addition of the tasks shown by the Figure 4.8, the Clock Task has been added to provide any archiving process.

Figure 4.9 Tasks and C/OS-II status viewed by C/OS-View

Real Time Clock in order to stamp the stored messages by the time, which is a necessity in provides the routines to use different peripherals of this board (Ex. LCD, Keypad, Leds, AD Converters etc). The assembly file uCOS-II-MSA0654-DRIVERS-ASM.ASM contains the Drivers and should be written in assembly language.

C/OS-II MSA0654 DRIVERS directory contains the MSA0654 board driver functions, and interrupt service routines and the interrupt vectors table needed by MSA0654 Board

Page 85

Chapter IV

C/OS-II Demonstration Example

5.1. Normal Running of the Application

of the application, Figures bellow shows that profile when the Application runs in the usual time (Temperature, Pressure and Gates status displayed on the LCD, no emergency, no message sent via RS232 Port, no menus).

By using the C/OS-View kernel debugger, we can monitor the profile of the C/OS-II and each task

CPU Overload when LCDs functions called

Figure 4.10 Graphs shows Tasks CPU load in normal operation of the application

Page 86

From the Tasks information given by Figure 4.9 and Figure 4.10 we can comment on the small amount of CPU cycles when picking up the data or sending messages; status of each task as follow:

Chapter IV

C/OS-II Demonstration Example

Data Capture Task: This task spend the majority of time delayed and consumes a LCD Message Task: This is the most one that loads the CPU; this is caused by LCD Displays functions that should call the dummy function to simulate a short delay to follow emergency Mailbox if a message was posted to display it on the LCD display; the LCD module responsiveness. In addition, this task checks the Message Queue and the was sent in case of emergency to light the LEDs according the message content;

LEDS Alarm Task: By lighting the LEDs one by one to show which gates are alarmed, the LCD Message Task; this task loads slightly the CPU (0.01%), in addition, this task check its Mailbox if a message Serial Com Task: Suspended until the memory is 90% full where will be resumed by

the keypads interrupt when the user presses any button. Therefore, this task spends all its time in waiting state and it doesnt load the CPU while in this state. for this message; Sound Alarm Task: This task waits for a message to be posted in its Mailbox, which therefore, this task doesnt consume too much CPU time. the C/OS-II parameters and different Tasks profiles. carries the emergency sound Alarm, this task doesnt consume any CPU time while waiting

Config Menu Task: This task waits for an Event Flags to be signaled by the means of

By observing the CPU load of the whole system, we can note that the great CPU time (99.63%) is consumed by the Idle Task; the statistic task consumes 0.32% used to compute be added to the C/OS-II without overload the CPU or miss the deadline of each task. From these results we can conclude that CPU stills not full used and many other tasks can

Clock Task: This task delays it self by one second to generate the time and date,

Page 87

Chapter IV

C/OS-II Demonstration Example

5.2. When Keypads button pressed

CPU as long the LCD is not available to call its functions. The graphs of the figure bellow demonstrate this case:

When Config Menu task takes over the LCD Display, the LCD Message task loads less the

menus items and the user can navigates through different items to change the system parameters or view some information about the C/OS-II or display time and date.

In this case the Event Flags which waited to be set by the Config Menus Task will be signaled by the Keypads interrupt, this will lead to make ready to run this task, after asking

for the LCD Display via the LCD Display Semaphore the Config Menu Task displays the

Config Menu Task goes back to wait state when exit menu Config Menu Task comes active when keypad pressed

Figure 4.11 Config Menu Task comes active to manage the menus items when keypad pressed
Page 88

Chapter IV

C/OS-II Demonstration Example

5.3. When the Messages memory is full

Messages Task, the graphs of the figure bellow shows this scenario.

When the memory partition where all messages are stored is 90% full. These messages should be sent to the Computer via the RS232 port in order to be saved in files, this will be achieved by the Serial Com Task which will be resumed after was suspended by the LCD

Messages sent by the Serial Com Task Serial Com Suspended when memory emptied Serial Com Resumed when memory full

Figure 4.12 Serial Com Task resumed to empty the memory when it is 90% full

Page 89

Chapter IV

C/OS-II Demonstration Example

5.4. In Case of emergency

The Emergency case happened when the temperature is too high or the pressure is too low or either any of the eight gates is open, in this case the system emits loud alarm sound Figures 4.13 shows the activities of each task involved in the Emergency state. in addition, the LCD Messages Task sends to the LCD the nature of the emergency. The

along with LEDs blinking done by the Alarm Sound and LEDs Alarm Tasks respectively,

LCD Messages and DATA Capture Tasks load more the CPU Sound Alarm Task comes active and plays the Emergency Alarm sound

Figure 4.13 CPU load of the involved Tasks in case of emergency

Page 90

Figure 4.13 shows what is happened in the case of emergency regarding the activities of

Chapter IV

C/OS-II Demonstration Example

different tasks. The Sound Alarm Task which was waiting for a message starts running frequently as long the emergency state stills present.

and emits the Alarm sound; at that time this task loads the CPU slightly while emitting this sound. The DATA Capture and LCD Messages Tasks consume much more CPUs cycles When there is no emergency the LCD Displays shows the temperature, pressure and the 4.2 shows the messages displayed and LEDs status for different cases. because the Emergency message will be sent and received by these tasks respectively more gates status (Open/Close). Otherwise, in case of emergency it displays the nature of this emergency (Temperature too high, Pressure too low or which gate has been broken), Table

Page 91

Chapter IV

Table 4.2 LCDs Messages displayed Messages displayed Description and LEDs status

C/OS-II Demonstration Example

Message to display the actual Pressure Value Status of the all Gates of the closed area

Message to display the actual Temperature degree Value

Emergency Message when the Temperature is higher than the maximum temperature preset value. All LEDs blinking and Alarm sound emitted Emergency Message when the Pressure is lower than the minimum preset value, four LEDs blinking and Alarm Sound emitted

Emergency Message when any of the armed gate is open, the number of the gate displayed, the respective LED blinking and Alarm Sound emitted

Page 92

The LCD Display can show other parameters of the C/OS-II or the application (CPU usage, parameters can be shown by selecting the View item of the Main Menu. By selecting the parameters. Table 4.3 Setup and View Menu items

Chapter IV

C/OS-II Demonstration Example

Amount of the free memory, number Clock ticks and Context Switches etc). These

setup menu the user can set different parameters of the application (Max Temperature, Min

Pressure, Alarms/Disarms each gate, set Time/Date). Table 4.3 summarizes the displayed Setup or View Menu Items Description

Setup Menu to change the Maximum Allowed Temperature Setup Menu to change the Minimum Allowed Pressure

Setup Menu to Enable/Disable the desired Gates Time/Date View Menu item, view the Real Time Clock

Clock Ticks/Context Switches View Menu item, Display the number of Clock Ticks and Context Switches Free Mem View Menu item, Display the amount of the remaining memory, used to store the messages

CPU Usage View Menu item, Display the global CPU Load of the application

Page 93

Chapter IV

C/OS-II Demonstration Example

CONCLUSION

The application built in this chapter has well demonstrated the advantages of the C/OS-II advantages can be summarized as follow: no limit made by other tasks when developing a task, especially regarding the waiting time or the inertia made by other tasks; means provided by C/OS-II (Mailbox, Messages Queue, Event flags, etc.), the functions that manipulate these services are very trivial and easy to use;

and the facilities brought by this RTOS to design a real time multitasking application, these

1. Total independence between different programmed Tasks, in other word, there is 2. Tasks can easily interact with each other or exchange information using different problem can be resolved efficiently by using the semaphore or mutual exclusion semaphore and they are manipulated with very simple functions.

3. No more worries about the resources sharing and the risk of corruption, this The robustness and the reliability of the developed application have been tested as well, by keeping this application running for many hours. Therefore, no crash was noted along with trying different circumstances that may occur.

Page 94

Conclusion

Conclusion
full success. to illustrate this; I have developed and tested the ported files by developing a real time Data Monitor on the C/OS-II platform that targets the M16C62P microcontroller. provided by the C/OS-II (Semaphore, Mailbox, Event flags etc) to give a practical demonstration on how to use these features. In addition to the real time responsiveness of this application, I have used all the features Further more, in order to make the ported files useful for future works or for students who wish to develop C/OS-II applications I have created on the joint CD a fully commented template project to make it easy to use. Two templates have been designed to be compiled under M16C IAR Workbench for V1.36 and V2.12. demonstrated, by observing the delay between an action made on the input (Keypad, measured were very short and imperceptible by humans and were therefore, acceptable. developing board, the real time responsiveness of the C/OS-II has been well With the different Input/Output (LCD, LEDs, Switches etc) built within the MSA0654 In this project, porting the C/OS-II to the M16C microcontrollers has been achieved with

Potentiometer that simulates the temperature or pressure, switches to simulate the Gates status) and the reaction that results from these actions which can be observed on the LCD, To achieve this work, I felt the necessity to make an attractive demonstration about what is has a Monitor called C/OS-View, made from a windows application and an embedded LEDS and the Buzzer speaker, and this in different experimental conditions The delays

microcontrollers by writing the hardware initialization of the serial communication and the Transmission/Reception interrupts for a specific microcontroller.
Page 95

happening inside the C/OS-II and the status of each application task. Luckily, the C/OS-II module built within the C/OS-II project, the embedded files should be ported to the M16C

Conclusion

The C/OS-View works along with its graphical windows, and provides the status (Ready, each task.

Wait for a delay to expire or Semaphore or Message etc) and shows graphically the activity The global CPU load of the developed application which doesnt exceed 9% demonstrates

(CPU Load) of each task, this makes an excellent tool to debug the C/OS-II application by the step-by-step execution and to optimize the global CPU load by knowing the CPU load of the major benefit gained when using the C/OS-II thanks to the optimized way that C/OS-

II uses the CPU, where tasks can be added without affecting the responsiveness of other the traditional way to develop a medium or large applications, because of the new attractive structure of this RTOS, and very easy to use functions provided. The disadvantage that maybe considered when using the C/OS-II is the extra memory needed to run this RTOS, which is about 20Kb when all the features are enabled. tasks. In other word, someone who uses the C/OS-II for the first time will never go back to use

Page 96

References

REFERENCES [1] Microc/OS-II: The Real-Time Kernel, Second Edition, 2002, Jean J. Labrosse [2] Introduction to Real-Time operating systems (2001) Robert Betz [4] C/OS-II and Event Flags, Application Note AN-1007A Jean J. Labrosse

[6] Introduction to Real-Time Operating Systems, David Kalinsky, Ph.D. Enea Embedded USA Technology, San Jose, California USA [7] C/OS-View V1.10 Users Manual, Micrim, Inc.

[5] C/OS-II and Mutual Exclusion Semaphores, Application Note AN-1002 Jean J. Labrosse

[3] C/OS-II and the Renesas M16C Processors, Application Note AN-1019 Jean J. Labrosse

[8] Open Source Real Time Operating Systems Overview T. Straumann, SSRL, Menlo Park, [9] http://www.whatis.com/ [10] C/OS-View V1.10 Users Manual, Micrim, Inc.

Page 97

Appendix I

Appendix I Programs listings of the Project Application

Main.C /****************************************************************************/ /* Main.C */ /* This file contains the "Startup" Task to create all of the other tasks */ /* initialize the MSA0654 board hardware and the Ticks Timer */ /* */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ /* void pointer to each Task managed by uCOS-II */ extern void LCDMESSAGES_TASK(void *pdata); extern void DATACAPTURE_TASK(void *pdata); extern void LEDSALARM_TASK(void *pdata); extern void SERIALCOM_TASK(void *pdata); extern void CONFIGMENU_TASK(void *pdata); extern void SOUNDALARM_TASK(void *pdata); extern void CLOCK_TASK(void *data); /* uCOS-II's Clock Tick Timer initialization */ void InitTick(void); /* Stack of each Task managed by uCOS-II */ OS_STK STARTUP_STK[TASK_STK_SIZE]; OS_STK DATACAPTURE_STK[TASK_STK_SIZE]; OS_STK LEDSALARM_STK[TASK_STK_SIZE]; OS_STK SERIALCOM_STK[TASK_STK_SIZE]; OS_STK CONFIGMENU_STK[TASK_STK_SIZE]; OS_STK SOUNDALARM_STK[TASK_STK_SIZE]; OS_STK LCDMESSAGES_STK[TASK_STK_SIZE]; OS_STK CLOCK_STK[TASK_STK_SIZE];

Page 98

Appendix I

/* Startup Task */ /* This Task initializes the Clock Tick timer and different MSA0654 board peripherals and ceates the other tasks, at the end it deletes itself */ static void STARTUP_TASK(void *pdata) { INT8U err; InitTick(); /* Initialize the Clock Tick Timer */ LcdDspInit(); /* Initialize the LCD Display */ ADCInit(); /* Initialize the ADC Converter */ OSStatInit(); /* Initialize the Statistic Task */ OSView_Init(); /* Initialize the uCOS-VIEW Module */ /* Dispplay the Welcome Screen */ LcdDspChars(0, 0, " uC/OS-II V2.83 ", 16); LcdDspChars(1, 0, " DATA MONITOR ", 16); /* Create the "DATA Capture" Task */ OSTaskCreateExt(DATACAPTURE_TASK, (void *)0, &DATACAPTURE_STK[TASK_STK_SIZE - 1], DATACAPTURE_PRIO, DATACAPTURE_PRIO, &DATACAPTURE_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "Data Capture" Task */ OSTaskNameSet(DATACAPTURE_PRIO, "DATA CAPTURE", &err); /* Create the "LCD Messages" Task */ OSTaskCreateExt(LCDMESSAGES_TASK, (void *)0, &LCDMESSAGES_STK[TASK_STK_SIZE - 1], LCDMESSAGES_PRIO, LCDMESSAGES_PRIO, &LCDMESSAGES_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "LCD Messages" Task */ OSTaskNameSet(LCDMESSAGES_PRIO, "LCD MESSAGES", &err); /* Create the "LEDs Alarm" Task */ OSTaskCreateExt(LEDSALARM_TASK, (void *)0, &LEDSALARM_STK[TASK_STK_SIZE - 1], LEDSALARM_PRIO, LEDSALARM_PRIO, &LEDSALARM_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "LEDs Task" Task */ OSTaskNameSet(LEDSALARM_PRIO,"LEDS ALARM", &err); /* Create the "Serial Com" Task */ OSTaskCreateExt(SERIALCOM_TASK, (void *)0, &SERIALCOM_STK[TASK_STK_SIZE - 1], SERIALCOM_PRIO, SERIALCOM_PRIO,

Page 99

Appendix I

&SERIALCOM_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "Serial Communicator" Task */ OSTaskNameSet(SERIALCOM_PRIO,"SERIAL COM", &err); /* Create the "Config Menu" Task */ OSTaskCreateExt(CONFIGMENU_TASK, (void *)0, &CONFIGMENU_STK[TASK_STK_SIZE - 1], CONFIGMENU_PRIO, CONFIGMENU_PRIO, &CONFIGMENU_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "Config Menus" Task */ OSTaskNameSet(CONFIGMENU_PRIO,"CONFIG MENUS", &err); /* Create the "Sound Alarm" Task */ OSTaskCreateExt(SOUNDALARM_TASK, (void *)0, &SOUNDALARM_STK[TASK_STK_SIZE - 1], SOUNDALARM_PRIO, SOUNDALARM_PRIO, &SOUNDALARM_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Give a name to "Sound Alarm" Task */ OSTaskNameSet(SOUNDALARM_PRIO,"SOUND ALARM", &err); /* Create the "Clock" Task */ OSTaskCreateExt(CLOCK_TASK, (void *)0, &CLOCK_STK[TASK_STK_SIZE-1], CLOCK_PRIO, CLOCK_PRIO, &CLOCK_STK[0], TASK_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); OSTaskNameSet(CLOCK_PRIO,"CLOCK", &err); /* Give a name to "Startup" Task */ OSTaskNameSet(STARTUP_PRIO, "STARTUP", &err); OSTaskDel(OS_PRIO_SELF);/* Delete the Startup task */ } /* Timer initialization of the COS-II Clock Ticks Generator */ void InitTick(void) /* Make reload value to generate OS_TICKS_PER_SEC Ticks/Sec */ { TA0 = (INT16U)(( 2000000 / OS_TICKS_PER_SEC - 1)); TA0MR = 0x40; /* F8 as clock source = 500ns TA0IC = 0x01; /* Timer interrupt register, priority 1 (lowest) TABSR |= 0x01; /* Set Timer count start flag PRCR = 0x01; /* Enable write to Processor mode CM0 &= 0x1F; /* main clock division register: no division

Page 100

*/ */ */ */ */

Appendix I

CM1 PRCR }

&= 0x3F; = 0x00;

/* Disable access to processor and clock mode

*/

void main (void) { OSInit(); /* Initialize the uCOS-II */ /********** Create the StartUp Task ***********/ OSTaskCreateExt(STARTUP_TASK, /* Task's Void */ (void *)0, /* No value passed to the task */ &STARTUP_STK[TASK_STK_SIZE - 1], /* Top of the Task's Stack */ STARTUP_PRIO, /* Task Priority */ STARTUP_PRIO, /* Task ID */ &STARTUP_STK[0], /* Bottom of the Task's Stack */ TASK_STK_SIZE, /* Task's Stack Size */ (void*)0, /* No TCB Extension */ OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear stack */ OSTaskNameSet(STARTUP_PRIO,"STARTUP TASK", (void*)0); /* Give a name to Startup Task */ OSStart(); /* Start running the operating system */ }

Main.h /* Message Format received by "LCD Messages" Task */ typedef struct { char TimeStamp[21];/* Time Stamp */ char Line_0[18]; /* First line of the LCD Display */ char Line_1[18]; /* Second line of the second line */ } LcdMsg; /* Message Format received by "LEDs Alarm" Task */ typedef struct { INT8U Pattern; /* LEDs pattern to be light */ BOOLEAN Blink; /* Specify if LEDs blink or not */ } LedMsg; /* Decimal to String conversion function prototype */ void DecToStr (INT8U *Str, INT32U Dec, INT8U digits); /* String to Decimal conversion function prototype */ INT32U StrToDec(INT8U *Str, INT8U Digits); /* Picking up the time function prototype */ char* GetTime(char* Time); /* Picking up the date function prototype */ char* GetDate(char* Date);

include.h #define Chip_3062x #include <iom16c62.h> /* Define the Target Chip */ /* include the Target Chip file */

Page 101

Appendix I

/* Application needded header file Here */ #include <string.h> /* uCOS-II Header File */ #include <uCOS_II.H> /* MSA0654 board drivers */ #include "uCOS-II-MSA0654-DRIVERS.H" /* Application header file */ #include "main.h" /* uCOS-II OS Viewer header files */ #include "OS_VIEWc.H" #include "OS_VIEW.H"

app_cfg.h /* Priority of each Task */ #define STARTUP_PRIO #define DATACAPTURE_PRIO #define LCDMESSAGES_PRIO #define LEDSALARM_PRIO #define SERIALCOM_PRIO #define CONFIGMENU_PRIO #define SOUNDALARM_PRIO #define CLOCK_PRIO 8 10 20 30 35 40 45 50

#define TASK_STK_SIZE 128 /* Same stack size for all task */ #define CPU_CLK_FREQ 16000000 /* CPU Frequency */ /* memory management constant */ #define MsgLogNBlk 64 /* # of the memory partition block */ #define MsgLogMinNBlk 10 /* # of minimum free blks */ #define MsgLogMaxNBlk 60 /* # of maximum used blks */ #define MsgLogBlkSize 64 /* Size of each block in byte */ /* Sound code for each emergency */ #define HighTempSoundAlarm 0 #define LowPressSoundAlarm 1 #define GateOpenSoundAlarm 2 #define SoundPaternSize 4 /* numbers of tones in sound pattern */ /* LCD Messages message displaying period */ #define MsgPeriod 40 /* number of messages that can wait on LCD Queue */ #define LcdQueueSize 8 /* number of memory blocks that can stored in the Queue to be sent via rs232 */ #define SerialComQueueSize MsgLogNBlk

uCOS-TASK1-LCDMESSAGES.C /****************************************************************************/ /* uCOS-TASK1-LCDMESSAGES.C */

Page 102

Appendix I

/* This file contains the "Lcd Message" Task, "Lcd Message" receives */ /* LCD Messages, display them on the LCD and stores them in the */ /* memory partition. */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ void* LcdMsgQPTR[LcdQueueSize]; /* Queue of pointers to the queued Messages */ OS_EVENT *LcdDspSem; /* LCD Semaphore to access to LCD Display */ OS_EVENT *LcdMsgQ; /* Messages Queue to queue the messages received by this task */ OS_EVENT *LcdEmergMBox; /* Emergency Mailbox to receive the emergency messages */ OS_MEM *MsgLogMem; /* Memory partition to store the received messages */ extern OS_EVENT *SerialComMsgQueue; /* Pointer to Messages Queue of serial Com Task */ /* Memory area to be managed by the "MgLogMem" memory partition */ static char MsgLog[MsgLogNBlk][MsgLogBlkSize]; void *MsgLogBlkPTR; /* Pointer used to allocate a memory block to store messages */ extern char CLOCK[19]; /* String that holds Time and Date */ /********* "LCD Message" Task Core ***********/ void LCDMESSAGES_TASK(void *pdata) { LcdMsg* Msg; /* Variable to hold the LCD Message format */ INT8U err; /* Create the LCD Semaphore and give it a Name */ LcdDspSem = OSSemCreate(1); OSEventNameSet (LcdDspSem, "LCD Semaphore", &err); /* Create the Messages Queue and give it a Name */ LcdMsgQ = OSQCreate(&LcdMsgQPTR[0], LcdQueueSize); OSEventNameSet (LcdMsgQ, "LCD Msg Queue", &err); /* Create the Emergency Messagebox and give it a Name */ LcdEmergMBox = OSMboxCreate((void*)0); OSEventNameSet (LcdEmergMBox, "LCD Mailbox", &err); /* Create the Memory partition and give it a Name, MsgLogNBlk: #Blocks, MsgLogBlkSize: Block size */ MsgLogMem = OSMemCreate(MsgLog, MsgLogNBlk, MsgLogBlkSize, &err); OSMemNameSet(MsgLogMem, "MsgLog Memory", &err); /* LCD Messages Task's infinit loop */ while(1) { /* Wait for an Emegency message within OS_TICKS_PER_SEC/10 secs */ Msg = (LcdMsg*)OSMboxPend(LcdEmergMBox, OS_TICKS_PER_SEC/10, &err); if (Msg != (void*)0){ /* If Emergency message received... Request the LCD Display within OS_TICKS_PER_SEC/50 secs */ OSSemPend(LcdDspSem, OS_TICKS_PER_SEC/50, &err); if (err == OS_NO_ERR){ /* If the LCD Display aquired by this task... /* Display the Emergency Message */ LcdDspChars(0, 0, Msg->Line_0, 16); LcdDspChars(1, 0, Msg->Line_1, 16); /* Release the LCD Display */ OSSemPost(LcdDspSem);} } else {/* if there is no emergency message.... Check the Messages Queue within OS_TICKS_PER_SEC/10 if any message waits */ Msg = (LcdMsg*)OSQPend(LcdMsgQ, OS_TICKS_PER_SEC/10, &err); if (Msg != (void*)0) {/* If a message was picked...

Page 103

Appendix I

Request the LCD Display within OS_TICKS_PER_SEC/50 secs */ OSSemPend(LcdDspSem, OS_TICKS_PER_SEC/50, &err); if (err == OS_NO_ERR){/* If the LCD Display aquired by this task... /* Display the Emergency Message */ LcdDspChars(0, 0, Msg->Line_0, 16); LcdDspChars(1, 0, Msg->Line_1, 16); /* Release the LCD Display */ OSSemPost(LcdDspSem);} }} /* Messages storing code */ if (Msg != (void*)0) {/* if any messages has been received... Allocate a memory partition block */ MsgLogBlkPTR = OSMemGet(MsgLogMem, &err); if (err == OS_NO_ERR){/* if the allocation succeed... copy the message to the allocated memory block */ memcpy(MsgLogBlkPTR, Msg, sizeof(LcdMsg)); /* Send the block pointer to the Serial Com task Msg queue to be sent */ OSQPost(SerialComMsgQueue, (void*)MsgLogBlkPTR); } if (MsgLogMem->OSMemNFree < MsgLogMinNBlk)/*if the#memory blocks<minimal #block /* Resume the "Serial Com" task to send the messages via the rs232 port */ OSTaskResume(SERIALCOM_PRIO); else if(MsgLogMem->OSMemNFree > MsgLogMaxNBlk)/*when #free blocks>#Max free blocks Suspend the "Serial Com" task */ OSTaskSuspend(SERIALCOM_PRIO); } } } /********* END of the "LCD Messages" Task *******************/

uCOS-TASK2-DATACAPTURE.C /****************************************************************************/ /* uCOS-TASK2-DATACAPTURE.C */

Page 104

Appendix I

/* Containts "DATA Capture" Task */ /* "DATA Capture" Task picks up the Temperature, Pressure and Gates' */ /* Statues and send these info bto other Tasks within messages. */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ INT8U INT8U INT8U MaxTemperature MinPressure GatesMask = 150; /* Maximum Allowed Temperature */ = 20; /* Minimum Allowed Pressure */ = 0xFF; /* Gates Enabled/Disabled Mask */

extern OS_EVENT* LcdMsgQ; /* Pointer to LCD Messages Task Queue */ extern OS_EVENT* LcdEmergMBox; /* Emergency Mailbox of the LCD Messages Task */ extern OS_EVENT* LedMbox; /* Pointer to Mailbox of the LEDs Task */ extern OS_EVENT* SoundMbox; /* Pointer to Mailbox of the Sound Task */ /***************************************************************************/ /************** Different Messages come out from this task *****************/ LcdMsg TempNormalLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n", /* Temperature Values */ "==TEMPERATURES==\r\n", /* Message */ "=== XXX Degs ===\r\n"}, TempEmergeLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n",/* High Temperature */ "=== WARNINGS ===\r\n", /* Emergency Message */ " TEMPS TOO HIGH \r\n"}, PressureNormalLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n",/* Pressure Values */ "====PRESSURE====\r\n", /* Message */ "=== XXX Bars ===\r\n"}, PressureEmergeLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n",/* Low pressure */ "=== WARNINGS ===\r\n", /* Emergency Message */ "PRESSURE TOO LOW\r\n"}, GatesNormalLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n",/* Gates Open/Close */ "==GATES STATUS==\r\n", /* Message */ "== ALL CLOSED ==\r\n"}, GatesEmergeLcdMsg = {"YYYY-MM-DD HH:MM:SS\r\n",/* Gates Penetration */ "====WARNINGS====\r\n", /* Emergency Message */ "= GATE #X OPEN =\r\n"}; LedMsg */ GatesEmergeLedMsg = {0x00 ,OS_TRUE}; /* Gate Message sent to LEDs Task */ void { DATACAPTURE_TASK(void *pdata) INT16U TEMPERATURE = 0; INT16U PRESSURE = 0; INT8U GATES, OPENGATE = 1; INT8U SoundMsg = 1; INT16U MsgCount = 0; ADCInit(); /* Initialize the ADC Converter */ while(1) { TEMPERATURE = ADCGetValue(0); /* Pick Up the temperature through the ADC */ if (TEMPERATURE > MaxTemperature)/* If the Temperature > Preset Max temp... */ {/* Stamp the Hight Temp Emergency Message with Time and Date */ GetDate(&TempEmergeLcdMsg.TimeStamp[0]); GetTime(&TempEmergeLcdMsg.TimeStamp[11]); /* Post the Emergency Message into the LCD Messages Task's Emergency Mailbox */ TempEmergeLedMsg = {0xFF, OS_TRUE},/* High Temp Message sent to LEDs Task */ PressureEmergeLedMsg = {0xF0, OS_TRUE},/* Low Press Message sent to LEDs Task

Page 105

Appendix I

OSMboxPost(LcdEmergMBox, (void*)&TempEmergeLcdMsg); /* Post an Emergency Message into the LEDs Task's Mailbox */ OSMboxPost(LedMbox, (void*)&TempEmergeLedMsg); SoundMsg = HighTempSoundAlarm; /* Select the nature of the sound Alarm... Post the Alarm Emergency Message into the Sound Task's Mailbox */ OSMboxPost(SoundMbox, (INT8U*)&SoundMsg); } else /* Else, if the Temperature in the normal limits... */ if (MsgCount == MsgPeriod)/* is it time to post message to LCD Messages Task?*/ {/* Stamp the Message with Time and Date */ GetDate(&TempNormalLcdMsg.TimeStamp[0]); GetTime(&TempNormalLcdMsg.TimeStamp[11]); /* Convert the Temperature value to string */ DecToStr(&TempNormalLcdMsg.Line_1[4], TEMPERATURE, 3); /* Post the Message to LCD Messages Task's Queue */ OSQPost(LcdMsgQ, (void*)&TempNormalLcdMsg); } /* Pick up the pressure (Simulated by dividing Ad value / 3 ) */ PRESSURE = ADCGetValue(0) / 3; if (PRESSURE < MinPressure) /* if the pressure < Presete value... */ {/* Stamp the Emergency message with Time and Date */ GetDate(&PressureEmergeLcdMsg.TimeStamp[0]); GetTime(&PressureEmergeLcdMsg.TimeStamp[11]); /* Post the Message into the LCD messages Task's Emergency Mailbox */ OSMboxPost(LcdEmergMBox, (void*)&PressureEmergeLcdMsg); /* Post an Emergency Message into the LEDs Task's Mailbox */ OSMboxPost(LedMbox, (void*)&PressureEmergeLedMsg); SoundMsg = LowPressSoundAlarm; /* Select the sound Alarm... Post the Alarm Emergency Message into the Sound Task's Mailbox */ OSMboxPost(SoundMbox, (INT8U*)&SoundMsg); } else /* Else, if the Pressure in the normal limits... */ if (MsgCount == 2*MsgPeriod)/* is it time to post message to LCD Messages Task?*/ {/* Stamp the Message with Time and Date */ GetDate(&PressureNormalLcdMsg.TimeStamp[0]); GetTime(&PressureNormalLcdMsg.TimeStamp[11]); /* Convert the Pressure value to string */ DecToStr(&PressureNormalLcdMsg.Line_1[4], PRESSURE, 3); /* Post the Message to LCD Messages Task's Queue */ OSQPost(LcdMsgQ, (void*)&PressureNormalLcdMsg); } /**********************************************************************/ GATES = SwGetStatus() & GatesMask; /* Get the Gates' switches status */ if (GATES != 0x00) /* If Any gate is open... */ { GatesEmergeLedMsg.Pattern = GATES; /* Save the gates' switches status */ OPENGATE = 1; /* Detect which gate is open By... */ while(GATES = GATES >> 1) OPENGATE++; /*..decoding the Gates' Switches status */ /* Convert the open gate number to char and insert it in the LCD Messages */ GatesEmergeLcdMsg.Line_1[8] = OPENGATE%10 + '0'; /* Stamp the Message with Time and Date */ GetDate(&GatesEmergeLcdMsg.TimeStamp[0]); GetTime(&GatesEmergeLcdMsg.TimeStamp[11]); /* Post the Message into the LCD messages Task's Emergency Mailbox */ OSMboxPost(LcdEmergMBox, (void*)&GatesEmergeLcdMsg);

Page 106

Appendix I

/* Post an Emergency Message into the LEDs Task's Mailbox */ OSMboxPost(LedMbox, (void*)&GatesEmergeLedMsg); SoundMsg = GateOpenSoundAlarm;/* Select the sound Alarm... Post the Alarm Emergency Message into the Sound Task's Mailbox */ OSMboxPost(SoundMbox, (INT8U*)&SoundMsg); } else /* Else, if All gate are close...*/ if (MsgCount > 3*MsgPeriod)/* is it time to send message about gates status */ {/* if yes Stamp the LCD messages with time and date */ GetDate(&GatesNormalLcdMsg.TimeStamp[0]); GetTime(&GatesNormalLcdMsg.TimeStamp[11]); /* Post the Gates' status message into the LCD Messages Task's Queue */ OSQPost(LcdMsgQ, (void*)&GatesNormalLcdMsg); MsgCount = 0; /* initialize the Massages periode variable */ } MsgCount++;/* increment the Massages periode variable */ OSTimeDly(OS_TICKS_PER_SEC/10); /* Make delay of 100ms */ } } /********* END of the "DATA CAPTURE" Task *******************/

uCOS-TASK3-CONFIGMENU.C /****************************************************************************/ /* uCOS-TASK3-CONFIGMENU.C */ /* Containts "Config Menus" Task */ /* "Config Menus" Manages different configuration Menus' Items */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ typedef struct { INT8U ItemState[3][10]; INT8U MaxItems[3]; INT8U XPos, YPos; char *MenuName[3]; char *ItemName[3][10]; } MenuMap; /* /* /* /* /* /* Menu's Map Structure */ Munu's Items States Machine */ Maximum Items of each Submenu */ X, Y Position in the Menu's Map */ SubMenus' Names */ SubMenus' Items Names */

MenuMap MainMenu = { /* Instance of the used Menu */ /* State Machine's State of each menu's item */ 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, /* Max Items of the respective Submenu */ 3, 6, 5, /* Initial X and Y position in Menu */ 0, 0, /* SubMenus' Names */ "|MAIN| E:ENTER ", "|SETUP| E:ENTER ", "|VIEW| E:ENTER ", /* SubMenus' Items Names */ {"<B SETUP C>", "<B VIEW C>", "<B EXIT C>", "", "", "", "", "", "", "",

Page 107

Appendix I

"<B MAX TEMP C>", "<B MIN PRESS C>", "<B EN/DI GATE C>", "<B SET DATE C>","<B EXIT C>", "", "","","", "<B CPU USAGE C>", "<B FREE MEM C>", "<B Tick/CtxSw C>", "<B EXIT C>", "","","","",""} };

SET TIME

C>", "<B

TIME/DATE C>", "<B

extern INT8U MaxTemperature;/* Link to Maximum Temperature */ extern INT8U MinPressure; /* Link to Minimum Pressure */ extern INT8U GatesMask; /* Link to Gates Alarme/Disarme Mask */ extern INT8U SEC, MIN, HR, DAY, MONTH; /* Link to Clock's parametres */ extern INT16U YEAR; extern OS_MEM *MsgLogMem; /* link to Memory partition used to store Messages */ extern OS_EVENT *LcdDspSem; /* Semaphore to access LCD Display */ OS_FLAG_GRP *MenuFlag; /* Event Flags, Sigaled when keypad pressed */ /* User interface Text Input function via Keypad and LCD */ INT16U GetInputValue(char* Label, INT8U Lenght); /* User interface function to Enable/Disable gates via keypad and LCD */ INT8U EnableDisableGates(void); INT8U SetTime(); /* User interface function to set Time */ INT8U SetDate(); /* User interface function to set Date */ void KeyPadPressed(void)/* Function called when keypad pressed */ { INT8U err; /* Set the bit 0 of the "MenuFlag" Event flag */ OSFlagPost(MenuFlag, 0x01, OS_FLAG_SET, &err); } /************************** CONFIGURATION MENU TASK *****************************/ void CONFIGMENU_TASK(void *pdata) { INT8U err, Key, TextMsg[16]; INT32U InValue = 0; BOOLEAN QuitMenu = OS_TRUE; INT8U State = 1; /* Initialize Keypad hardware with "KeyPadPressed" callback function */ KeyPadInit(KeyPadPressed); MenuFlag = OSFlagCreate (0x00, &err); /* Create the Menu Event Flag */ OSFlagNameSet(MenuFlag, "Menu Flag Evants", &err);/* Give it name */ while(1) {/* Pend on the Event Flag until set, consume it when setted */ OSFlagPend(MenuFlag, 0x01, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0, &err); OSSemPend(LcdDspSem, 0, &err);/* Ask Access for the LCD via LCD Semaphore */ QuitMenu = OS_FALSE; /* we have just enter to Menu... */ State = 1; /*...in the first State */ GetKey();/* Consume the pressed key */ while(!QuitMenu){ /* while user didn't exit menu */ switch (State) /* Menu's State Machine */ { case 0 : QuitMenu = OS_TRUE;/* User quites Menu... then Clear the 1st bit of the Event Flag */ OSFlagPost(MenuFlag, 0x01, OS_FLAG_CLR, &err); OSSemPost(LcdDspSem);/*... and release the LCD Display */ break; case 1 :{ /* Display the Selected Submenu's Item */ LcdDspChars(0, 0, MainMenu.MenuName[MainMenu.YPos], 16); LcdDspChars(1, 0, MainMenu.ItemName[MainMenu.YPos][MainMenu.XPos], 16);

Page 108

Appendix I

/* wait until any key pressed */ while ((Key = GetKey()) == 0xFF) OSTimeDly(OS_TICKS_PER_SEC / 50); switch(Key) /* regarding the key pressed...*/ { case 'E' : /* E: User select to Enter into the submenu then... Set the next state to state of the slected Item */ State = MainMenu.ItemState[MainMenu.YPos][MainMenu.XPos];break; case 'B' : /* B: User select to shift left the Menu */ if (MainMenu.XPos == 0) MainMenu.XPos = MainMenu.MaxItems[MainMenu.YPos] - 1; else MainMenu.XPos--; State = 1; break; case 'C' : /* C: User select to shift right the Menu */ if (MainMenu.XPos == MainMenu.MaxItems[MainMenu.YPos] - 1) MainMenu.XPos = 0; else MainMenu.XPos++; State = 1; break; default:break; }}break; case 10 : MainMenu.XPos MainMenu.YPos State = 1; /* break; MainMenu.XPos MainMenu.YPos State = 1; /* break; State = 0; /* break; = 0;/* Set X and Y to "Setup" submenu Position */ = 1; Go to "Setup" submenus */ = 0;/* Set X and Y to "View" submenu Position */ = 2; Go to "View" submenus */ User slected to quit menus */

case 11 :

case 12 :

case 20 :

/* User selects to change the Max Temperature... Call the User interface Function to capture the input data */ InValue = GetInputValue("MAX TEMP:", 3); if (InValue != -1) {/* if the user valadates typed value */ LcdDspCls(); /* Clear LCD Display */ MaxTemperature = (INT8U)InValue; /* Change the Max Temp */ LcdDspChars(0, 2, "DATA UPDATED", 12); /* Data Updated */ LcdDspChars(1, 2, "WITH SUCCESS", 12); OSTimeDlyHMSM(0, 0, 1, 0); } State = 1; /* Go back the previous menu */ break; /* User selects to change the Min Pressure... Call the User interface Function to capture the input data */ InValue = GetInputValue("MIN PRESS:", 3); if (InValue != -1) {/* if the user valadates typed value */ LcdDspCls();/* Clear LCD Display */ MinPressure = (INT8U)InValue; /* Change the Min Pressure */ LcdDspChars(0, 2, "DATA UPDATED", 12); /* Data Updated */ LcdDspChars(1, 2, "WITH SUCCESS", 12); OSTimeDlyHMSM(0, 0, 1, 0); }

case 21 :

Page 109

Appendix I

State = 1; /* Go back the previous menu */ break; case 22 : /* User selects to Enable/Disable some gates... Call the function that manages this */ GatesMask = EnableDisableGates(); State = 1;/* Go back the previous menu */ break; SetTime(); /* Call the function that allows the user to Set time State = 1; /* Go back the previous menu */ break; SetDate(); /* Call the function that allows the user to Set date State = 1; /* break; MainMenu.XPos MainMenu.YPos State = 1; /* break; Go back the previous menu */ = 0; /* Select to root of the Menu */ = 0; Go to the selected Munu's item */

case 23 : */

case 24 : */

case 25 :

case 30 : /* User select to View the CPU Usage */ LcdDspCls(); /* Clear LCD */ strncpy(TextMsg, "XXX%", 4); LcdDspChars(0, 0, "== CPU USAGE: ==", 16); while (Key = GetKey() == 0xFF){ /* while no key pressed */ /* Get CPU Usage computed by Statistic Task */ InValue = (INT32U)OSCPUUsage; /* Convert the value to string */ TextMsg[0] = (InValue / 100) + '0'; TextMsg[1] = (InValue % 100)/10 + '0'; TextMsg[2] = (InValue % 10) + '0'; LcdDspChars(1, 6 ,TextMsg, 4); /* Display CPU Usage */ OSTimeDly(OS_TICKS_PER_SEC / 2); /* Update value each 500ms */ } State = 1; /* go to previous menu */ break; case 31 : /* User select to View the Free Memory used to Store messages */ LcdDspCls(); /* Clear LCD */ TextMsg[3] = '%'; LcdDspChars(0, 1, "FREE MEMORY(%)", 14); while (Key = GetKey() == 0xFF){ /* while no key pressed */ /* Get exclusive access to MsgLogMem->OSMemNBlks */ OS_ENTER_CRITICAL(); /* Compute the % of the remaining memory in the partition */ InValue = (100 * MsgLogMem->OSMemNFree)/MsgLogMem->OSMemNBlks; OS_EXIT_CRITICAL(); /* Convert it to string */ TextMsg[0] = (InValue / 100) + '0'; TextMsg[1] = (InValue % 100)/10 + '0'; TextMsg[2] = (InValue % 10) + '0'; LcdDspChars(1, 6, &TextMsg[0], 4); /* Display that value */

Page 110

Appendix I

OSTimeDly(OS_TICKS_PER_SEC);}; /* Update value each 1sec */ State = 1; /* go to previous menu */ break; case 32 : /* View the number of Clock Ticks and Context switches */ LcdDspCls();/* Clear LCD */ while (Key = GetKey() == 0xFF){/* while no key pressed */ strncpy(TextMsg, "#Ticks:", 7);/* Copy the #Ticks label */ InValue = (INT32U)OSTime; /* Pickup the # Clock Ticks */ DecToStr(&TextMsg[7], InValue, 8);/* Convert it to string */ LcdDspChars(0, 0, TextMsg, 15);/* display it on LCD */ strncpy(TextMsg, "#CtxSw:", 7);/* Copy the #Ctx Sw label */ InValue = (INT32U)OSCtxSwCtr;/* Pickup the # Cntx Sw */ DecToStr(&TextMsg[7], InValue, 8);/* Convert it to string */ LcdDspChars(1, 0, TextMsg, 15);/* display it on LCD */ OSTimeDly(OS_TICKS_PER_SEC);} /* Update value each 1sec */ State = 1;/* go to previous menu */ break; case 33 : /* User select to View the Time/Date */ LcdDspCls();/* Clear LCD */ while (Key = GetKey() == 0xFF){/* while no key pressed */ GetTime(TextMsg); /* Pickup the time */ LcdDspChars(0, 4, TextMsg, 8); /* Display the time */ GetDate(TextMsg); /* Pickup the date */ LcdDspChars(1, 3, TextMsg, 10); /* Display the date */ OSTimeDlyHMSM(0, 0, 1, 0); }; /* Update value each 1sec */ State = 1;/* go to previous menu */ break; case 34 :MainMenu.XPos = 2;/* Select the View submenu */ MainMenu.YPos = 0; State = 1; /* Go back to SubMenu */ break; default: State = 1; break; } } } } /********* user interface text input function *******************/ INT16U GetInputValue(char* Label, INT8U Lenght) { INT8U Text[8] = " ", Key; INT8U indx = 0; INT32U InputValue = 0; LcdDspCls();/* Clear LCD Display */ LcdDspChars(0, 0, "E:Go|F:Exit|D:<-", 16); LcdDspChars(1, 0, Label, strlen(Label)); LcdDspMoveTo(1, strlen(Label)); LcdDspCursorBlink(); while (1) { switch(Key = GetKey()) {/* When 0..9 key pressed */ case '0':case'1':case'2':case'3':case'4': case '5':case'6':case'7':case'8':case'9':

Page 111

Appendix I

if (indx < Lenght) { Text[indx] = Key;/* Store the pressed # in buffer*/ LcdSendData(Text[indx]);/* make an echo on the LCD of number */ indx++;} /* increment the buffer position */ break; case 'D':/* Backspace key pressed */ if (indx > 0) { LcdDspBackSpace(); /* send Back the LCD cursor */ indx--;}/* decrement the buffer position */ else indx = 0;/* we got the limit */ break; case 'E': /* user presses Enter key to validate the input value...*/ InputValue = StrToDec(Text, Lenght);/*..Convert it to decimal */ LcdDspCursorOff();/* Hide LCD cursor */ return InputValue; /* return the typed value */ case 'F': /* user wants exit without validate the typed value */ LcdDspCursorOff();/* Hide LCD cursor */ return -1;/* indicate the used didnt validate the typed value */ default:break; } OSTimeDly(OS_TICKS_PER_SEC / 50); } } /********* user interface Enable/Disable Gates function *******************/ INT8U EnableDisableGates(void) { char Key, GatesCheckBox[10] = "|XXXXXXXX|"; INT8U indx, Mask = 0xFE; LcdDspCls(); for (indx = 1; indx < 9; indx++)/* Initialize the checkbox regarding...*/ { if ((Mask | GatesMask) == 0xFF) /*...the enabled or disabled gates */ GatesCheckBox[indx] = 'X'; else GatesCheckBox[indx] = ' '; Mask = (Mask <<= 1)|0x01; } LcdDspChars(0, 0, "Gate#:|12345678|", 16);/* display gate order */ LcdDspChars(1, 0, "En/Di:", 6); LcdDspChars(1, 6, GatesCheckBox, 10);/* Display the check box */ while (1) { switch(Key = GetKey()) {/* When key 1...8 pressed... */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': indx = Key - '0';/* Convert the pressed number to decimal */ if (GatesCheckBox[indx] == 'X') /* if the checkbox checked before then...*/ GatesCheckBox[indx] = ' '; /* uncheck it */ else GatesCheckBox[indx] = 'X'; /* else check it */ LcdDspChars(1, 6, GatesCheckBox, 10);/* display the new checkbox status */ break; case 'E': /* User has activated the entered configuration */ for (indx = 1; indx < 9; indx++)/* Transfer the checkbox config to...*/ {Mask = Mask >>= 1; /*...the Enable/Disable Gates */ if (GatesCheckBox[indx] == 'X') Mask |= 0x80; else Mask &= 0x7F;

Page 112

Appendix I

} return Mask; /* return the entered Mask */ case 'F': /* The user has canceled the entered Mask */ return GatesMask; /* return the old Mask */ default:break; } OSTimeDly(OS_TICKS_PER_SEC / 50); } } /********* user interface Set Time function *******************/ INT8U SetTime(void) { INT8U Key, indx = 0, Time[8]; LcdDspCls();/* Clear the LCD */ LcdDspChars(0, 0, "E:Go|F:Exit|D:<-", 16);/* Display the Menu */ GetTime(Time); /* import the current Time */ LcdDspChars(1, 4, Time, 8); /* Display the current Time */ LcdDspMoveTo(1, 4); /* Move LCD cursor to begining of the Time string */ LcdDspCursorBlink(); /* Make Cursor blinking */ while (1) { switch(Key = GetKey()) {/* When a number pressed...*/ case '0':case'1':case'2':case'3':case'4': case '5':case'6':case'7':case'8':case'9': if (indx < 8) {/* Capture the lcd cursor inside the displayed Time string */ Time[indx] = Key; /* Buffer the pressed number */ LcdSendData(Time[indx]); /* Make an echo of the prssed number */ if (Time[indx+1] == ':') { indx++; LcdSendData(':');} /* rewrite : as well */ indx++; } /* go to next digit */ break; case 'D': /* Backspace key pressed */ if (indx > 0) { LcdDspBackSpace();/* Backspace the LCD cursor */ if (Time[indx-1] == ':') { indx--; LcdDspBackSpace();}/* Skip the : character */ indx--;} /* decrement the buufer's cursor */ else indx = 0; /* freez the cursor when we get the left limit */ break; case 'E': /* user presses Enter key to validate the input value...*/ OS_ENTER_CRITICAL();/* Get exclusive access to clock (Sec,Min,Hr)(stop interrupt)*/ HR = (Time[0] - 48)*10 + (Time[1] - 48); MIN = (Time[3] - 48)*10 + (Time[4] - 48); SEC = (Time[6] - 48)*10 + (Time[7] - 48); OS_EXIT_CRITICAL();/* Release the interrupt clock (Sec, Min, Hr) */ LcdDspCursorOff();/* Hide cursor */ return 0;/* return 0 to indicates that the user has validate the time */ case 'F': /* user wants exit without validate the typed value */ LcdDspCursorOff(); /* Hide LCD cursor */ return -1;/* indicate the used didnt validate the typed value */ default:break; } OSTimeDly(OS_TICKS_PER_SEC / 50);

Page 113

Appendix I

} } /********* user interface Set Date function *******************/ INT8U SetDate(void) { INT8U Key, indx = 0, Date[10]; LcdDspCls();/* Clear LCD Display */ LcdDspChars(0, 0, "E:Go|F:Exit|D:<-", 16);/* Display the top Menu */ GetDate(Date); /* import the current Date */ LcdDspChars(1, 3, Date, 10); /* Display the current Date */ LcdDspMoveTo(1, 3); /* Move LCD cursor to begining of the Time string */ LcdDspCursorBlink(); /* Make Cursor blinking */ while (1) { switch(Key = GetKey()) {/* When a number pressed...*/ case '0':case'1':case'2':case'3':case'4': case '5':case'6':case'7':case'8':case'9': if (indx < 10) {/* Capture the lcd cursor inside the displayed Time string */ Date[indx] = Key; /* Buffer the pressed number */ LcdSendData(Date[indx]); /* Make an echo of the prssed number */ if (Date[indx+1] == '-') { indx++; LcdSendData(':');}/* rewrite : as well */ indx++; } /* go to next digit */ break; case 'D': /* Backspace key pressed */ if (indx > 0) { LcdDspBackSpace();/* Backspace the LCD cursor */ if (Date[indx-1] == '-') { indx--; LcdDspBackSpace();}/* Skip the '-' character */ indx--;} /* decrement the buufer's cursor */ else indx = 0; /* freez the cursor when we get the left limit */ break; case 'E': /* user presses Enter key to validate the input value...*/ OS_ENTER_CRITICAL(); /* Get exclusive access to clock (Sec,Min,Hr)(stop interrupt)*/ YEAR = (Date[0] - 48)*1000+(Date[1] - 48)*100+(Date[2] 48)*10+(Date[3] - 48); MONTH = (Date[5] - 48)*10+(Date[6] - 48); DAY = (Date[8] - 48)*10+(Date[9] - 48); OS_EXIT_CRITICAL();/* Release the interrupt clock (Sec, Min, Hr) */ LcdDspCursorOff();/* Hide cursor */ return 0;/* return 0 to indicates that the user has validate the time */ case 'F':/* user wants exit without validate the typed value */ LcdDspCursorOff(); /* Hide LCD cursor */ return -1;/* indicate the used didnt validate the typed value */ default:break; } OSTimeDly(OS_TICKS_PER_SEC / 50); } } /********* Decimal to string conversion function *******************/ void DecToStr(INT8U *Str, INT32U Dec, INT8U Digits) { INT8U indx;

Page 114

Appendix I

INT32U Mult; Mult = 1; /* Convert each digit one by one, regarding its order */ for (indx = 0; indx < (Digits - 1); indx++) Mult *= 10; while (Mult > 0) { *Str++ = Dec / Mult + '0'; Dec %= Mult; Mult /= 10; } } /********* String to Decimal conversion function *******************/ INT32U StrToDec(INT8U *Str, INT8U Digits) { INT8U indx; INT32U Mult, Dec; Mult = 1; Dec = 0; for (indx = 0; indx < (Digits - 1); indx++) Mult *= 10; /* Convert each digit one by one, regarding its order */ for (indx = 0; indx < (Digits); indx++) { Dec += (Str[indx] - '0')*Mult; Mult /= 10; } return Dec; }

uCOS-TASK4-SERIALCOM.C /****************************************************************************/ /* uCOS-TASK4-SERIALCOM.C */ /* Containts "SERIALCOM" Task */ /* "SERIALCOM" Sends the stored Messages via the RS232 Port to the PC */ /* and free the memory block where the message was stored */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ /* Pointers to carry the received messages */ void* SerialComMsgQueuePTR[SerialComQueueSize]; OS_EVENT* SerialComMsgQueue; /* Serial Com Task Messages Queue */ extern OS_MEM *MsgLogMem; /* Link to Memorry Partition */ void { SERIALCOM_TASK(void *pdata) INT8U err; LcdMsg *MsgLog; /* Create the Messages Queue, and Give it a name */ SerialComMsgQueue = OSQCreate(&SerialComMsgQueuePTR[0], SerialComQueueSize); OSEventNameSet(SerialComMsgQueue, "Serial Queue", &err); /* super loop of the "Serial Com" Task */ while(1) {/* Check if there is message on the queue */ MsgLog = (void*)OSQAccept(SerialComMsgQueue, &err); if (MsgLog != (void*)0){ /* if yes ...*/ OSView_TxStr("\n", 10); /* insert line on the terminal */ OSView_TxStr((char*)MsgLog, 10); /* Send the message to the terminal */

Page 115

Appendix I

/* Free the memory block carried the sent message */ OSMemPut(MsgLogMem, MsgLog); } OSTimeDly(OS_TICKS_PER_SEC/50); /* 50ms delay between each message sent */ } }

uCOS-TASK5-SOUNDALARM.C /****************************************************************************/ /* uCOS-TASK5-SOUNDALARM.C */ /* This file contains the "Sound Alarm" Task, "Sound Alarm" Plays Alarm */ /* Sound when it receives Emergency Messages */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ OS_EVENT* SoundMbox; /* "Sound Alarm" Task's Mailbox */ /* the Played note typedef by the Buzzer */ typedef struct {INT16U Periode; /* Period of the emited signal */ INT16U Delay; /* for how long this signal emited */ } SoundNote; /* Sound Alarm Pattern, Table of Consecutive Notes */ static const SoundNote AlarmSound[SoundPaternSize] = {{0x2FFF, OS_TICKS_PER_SEC/4}, {0x1FFF, OS_TICKS_PER_SEC/4}, {0x0FFF, OS_TICKS_PER_SEC/4}, {0x0EFF, OS_TICKS_PER_SEC/4}}; /************ Sound Alarm Task ****************/ void SOUNDALARM_TASK(void *pdata) { INT8U Cnt, err, *SoundTypeMsg; /* Create the Soun Alarm MessageBox and give it a Name */ SoundMbox = OSMboxCreate((void*)0); OSEventNameSet(SoundMbox, "Sounds Mailbox", &err); /* Initialize the Sound timer connected to the Buzzer */ SoundInit(); /* Task infinit loop */ while(1) { /* Wait forever for a Message to be posted */ SoundTypeMsg = (INT8U*)OSMboxPend(SoundMbox, 0, &err); /* When getting the Message, depends of Sound's ID sent ...*/ switch (*SoundTypeMsg){ case HighTempSoundAlarm:/* if High temperature emergency */ case LowPressSoundAlarm:/* if low pressure emergency */ case GateOpenSoundAlarm:/* if a gate is open */ for (Cnt=0; Cnt<SoundPaternSize; Cnt++) /* Play the Sound Alarm Pattern */ Sound(AlarmSound[Cnt].Periode, AlarmSound[Cnt].Delay); break;

Page 116

Appendix I

default: break; } }} /************ Sound Alarm Task End **************/

uCOS-TASK6-LEDSALARM.C /****************************************************************************/ /* uCOS-TASK6-LEDSALARM.C */ /* This file contains the "Leds Alarm" Task, "Leds Alarm" indicates which */ /* gates are Alarmed and Makes visual Alarm by leds when emergency */ /****************************************************************************/ #include <includes.h> /* Include the globale header file */ extern INT8U GatesMask; /* Alarmed/Disarmed gates Mask */ OS_EVENT *LedMbox; /* LEDs Task's Mailbox */ void { LEDSALARM_TASK(void *pdata) INT8U err, Count = 0, LedPattern = 0x01; LedMsg* Msg; /* Leds Message format received by LEDs Mailbox */ LedsInit(); /* initialize the eight LEDs hardware */ LedMbox = OSMboxCreate((void*)0); /* Create the LEDs Mailbox */ OSEventNameSet(LedMbox, "LEDs Mailbox", &err);/* Give name to this Mailbox */ while(1) {/* Wait for message to be posted within 100ms (OS_TICKS_PER_SEC/10) */ Msg = (LedMsg*)OSMboxPend(LedMbox, OS_TICKS_PER_SEC/10, &err); if (Msg != (void*)0) /* if Message received ...*/ { LedPattern = Msg->Pattern; /* read the light LEDs pattern */ while(Count++ < 10){/* within certain time...*/ if(Msg->Blink) /* if we should blink the LEDs...*/ LedPattern = (~LedPattern) & Msg->Pattern; /* blink LEDs */ else LedPattern = Msg->Pattern; /* permanent light LEDs */ LedsLight(LedPattern); /* Light LEDs */ OSTimeDly(OS_TICKS_PER_SEC/10);/* Make delay of 100ms */ } Count = 0; } else { /* else, If no message received ...*/ LedPattern = LedPattern << 1; /* Shift left the Leds Pattern */ if (LedPattern == 0x00) LedPattern = 0x01; LedsLight(GatesMask & LedPattern); /* Light the LEDs regarding the Mask*/ } }

} /************ LEDS ALARM Task End **************/ uCOS-TASK7-CLOCK.C /****************************************************************************/ /* uCOS-TASK7-CLOCK.C */ /* This file contains the "Clock" Task, "Clock" Task provides a Real Time */ /* Clock to the system to be used as Stamp when store messages */ /****************************************************************************/

Page 117

Appendix I

#include <includes.h> /* Include the globale header file */ char CLOCK[19] = "YYYY-MM-DD HH:MM:SS"; /* String to hld Date and Time */ INT8U SEC = 0, MIN = 58, HR = 23, DAY = 20, MONTH = 8; INT16U YEAR = 2007; /* Number of day of each month */ static INT8U MONTHDAYS[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; BOOLEAN UpdateClock(void); void UpdateDate (void); /* Clock Task (increment seconds using the OSTimeDlyHMSM delay function */ void CLOCK_TASK (void *pdata) { while(1) { if (UpdateClock()) UpdateDate();/* if 24Hours occured Update the Date */ OSTimeDlyHMSM(0, 0, 1, 0); } } static BOOLEAN UpdateClock(void) { BOOLEAN NEWDAY; NEWDAY = OS_FALSE; /* Still not completed one day yet */ if (SEC >= 59) { /* One minute completed ? */ SEC = 0; /* Yes, clear seconds */ if (MIN >= 59){/* One hour completed ? */ MIN = 0; /* Yes, clear minutes */ if (HR >= 23) { /* One day Completed */ HR = 0; /* Yes, clear hours */ NEWDAY = OS_TRUE; /* we have New day */ } else HR++; /* No, increment hours */ } else MIN++; /* No, increment minutes */ } else SEC++; /* No, increment seconds */ return (NEWDAY); } static BOOLEAN IsLeapYear(INT16U YEAR) {/* The year not dividable by 4 and dividable by 100 or not dividable by 400 ...*/ if (!(YEAR % 4) && (YEAR % 100) || !(YEAR % 400)) { return OS_TRUE; /* We have leap year */ } else { return OS_FALSE;/* else we have normal year */ } } static void UpdateDate (void) { BOOLEAN newmonth; newmonth = OS_TRUE; if (DAY >= MONTHDAYS[MONTH]) { /* Last day of the month? */ if (MONTH == 2) { /* Is this February? */ if (IsLeapYear(YEAR) == OS_TRUE) {/* Yes, Is this a leap year? */ if (DAY >= 29) { /* Yes, Last day in february? */ DAY = 1; /* Yes, Set to 1st day in March*/ } else { DAY++; newmonth = OS_FALSE; }

Page 118

Appendix I

} else { DAY = 1; } } else { DAY = 1; } } else { DAY++; newmonth = OS_FALSE; } if (newmonth == OS_TRUE) { /* We have completed a month */ if (MONTH >= 12) { /* Yes, Is this december ? */ MONTH = 1; /* Yes, set month to january */ YEAR++; /* we have a new year */ } else { MONTH++; /* No, increment the month */ } } } char* GetTime(char* Time) { OS_ENTER_CRITICAL();/* Disable interrupts to get exclusive access to SEC, MIN, HR */ CLOCK[18] = SEC%10 + '0'; /* Convert Time to String format */ CLOCK[17] = SEC/10 + '0'; CLOCK[15] = MIN%10 + '0'; CLOCK[14] = MIN/10 + '0'; CLOCK[12] = HR %10 + '0'; CLOCK[11] = HR /10 + '0'; OS_EXIT_CRITICAL(); /* Enable interrupt again */ return (strncpy(Time, &CLOCK[11], 8)); /* Copy the Time into the Clock variable */ } char* GetDate(char* Date) { INT16U YEAR1 = YEAR; OS_ENTER_CRITICAL();/* Disable interrupts to get exclusive access to Year, Month,Day*/ CLOCK[0] = YEAR1 / 1000 + '0';/* Convert Date to String format */ YEAR1 = YEAR1 % 1000; CLOCK[1] = YEAR1 / 100 + '0'; YEAR1 = YEAR1 % 100; CLOCK[2] = YEAR1 / 10 + '0'; CLOCK[3] = YEAR1 % 10 + '0'; CLOCK[5] = MONTH / 10 + '0'; CLOCK[6] = MONTH % 10 + '0'; CLOCK[8] = DAY / 10 + '0'; CLOCK[9] = DAY % 10 + '0'; OS_EXIT_CRITICAL();/* Enable interrupt again */ return (strncpy(Date, &CLOCK[0], 10));/* Copy the Time into the Clock variable */ } /************ Clock Task End **************/

Page 119

Appendix II

Appendix II MSA0654 Development Board Drivers


uCOS-II-MSA0654-DRIVERS.H /********************************************************************************/ /* FILE: uCOS-II-MSA0654-DRIVERS.H */ /* CREATED: 19/07/07 */ /* LAST MODIFICATION: 19/07/07 */ /* CREATED BY: Khaled Sobaihi */ /********************************************************************************/ /* Derective to include/exclude the needed drivers */ #define SevSegEn 1 #define LcdDspEn 1 #define LedsEn 1 #define SwitchesEn 1 #define KeyPadEn 1 #define ADCEn 1 #define SwitchesIntEn 1 #define SoundEn 1 #define TenBitAdcEn 0 #define SevenSegScanDly 10 /* Seven Seg digits scan delay (ms) */ #define SevenSegDigitNb 2 /* Number of seven segments Digits MSA0654 case = 2 */ /* Ports names redefinition */ #define PORT_0 P0 #define PORT_0D PD0 #define PORT_1 P1 #define PORT_1D PD1 #define PORT_2 P2 #define PORT_2D PD2 #define PORT_3 P3 #define PORT_3D PD3 #define PORT_4 P4 #define PORT_4D PD4 #define PORT_5 P5 #define PORT_5D PD5 #define PORT_10 P10

Page 120

Appendix II

#define PORT_10D PD10 /* LCD Command values */ #define LcdCmd_Cfg 0x3B #define LcdCmd_Cls 0x01 #define LcdCmd_Inc 0x06 #define LcdCmd_Set 0x0C #define LcdCmd_CursorOn #define LcdCmd_CursorOff #define LcdCmd_CursorBlink #define LcdCmd_On #define LcdCmd_Off

/*Cfg: 8-bit data, 1/16 duty, 5x8 dots */ /*Clear Display, Cursor Home */ /*Set Incrument Mode */ /*Set LCD: Dsp: ON, Cursor OFF, Blink: Off */ 0x0E 0x0C 0x0D 0x0C 0x08

#define LcdCmd_BckSpace 0x10 #define LcdCmd_FwdSpace 0x14 #define LcdCmd_PanLeft 0x18 #define LcdCmd_PanRight 0x1C /* LCD Macros for quick execution */ #define LcdDspCls() LcdSendCmd(LcdCmd_Cls) #define LcdDspOn() LcdSendCmd(LcdCmd_On) #define LcdDspOff() LcdSendCmd(LcdCmd_Off) #define LcdDspBackSpace() LcdSendCmd(LcdCmd_BckSpace) #define LcdDspFwdSpace() LcdSendCmd(LcdCmd_FwdSpace) #define #define #define #define #define #define #define LcdDspMoveScrLeft() LcdDspMoveScrRight() LcdDspCursorOn() LcdDspCursorOff() LcdDspCursorBlink() KeyRptStartDly KeyRptDly LcdSendCmd(LcdCmd_PanLeft) LcdSendCmd(LcdCmd_PanRight) LcdSendCmd(LcdCmd_CursorOn) LcdSendCmd(LcdCmd_CursorOff) LcdSendCmd(LcdCmd_CursorBlink) 1000 400 /* x 976.56us */ /* x 976.56us */

#if SevSegEn > 0 void SevenSegInit(void); /* Initialize 7-Segs display */ /* Display DIG_0 and DIG_1 on the 7-Segs Display */ void SevenSegDsp(INT8U DIG_0, INT8U DIG_1); /* Light specific segements on DIG_0 and DIG_1 */ void SevenSegActive(INT8U SEG_0, INT8U SEG_1); #endif #if LcdDspEn > 0 void LcdDspInit(void);/* initialize LCD Display hardware */ /* Move cursor to specified position */ void LcdDspMoveTo(INT8U Row, INT8U Col); /* Display the String in Row, Col position with Chars Nb length */ void LcdDspChars(INT8U Row, INT8U Col, char* String, INT8U CharsNb); void LcdSendCmd(INT8U Cmd);/* Send command to LCD routine */ void LcdSendData(INT8U DATA);/* Send displayed char to LCD routine */ #endif #if LedsEn > 0 void LedsInit(void); /* initialize LEDs hardware */ void LedsLight(INT8U Pattern);/* Light the leds with the pettern */ #endif

Page 121

Appendix II

#if SwitchesEn > 0 void SwitchesInit(void); /* initialize Switches hardware */ INT8U SwGetStatus(void); /* Get the status of the Switches */ #endif #if KeyPadEn > 0 void KeyPadInit(void(*CallBack)(void)); /* initialize keypad hardware */ INT8U GetKey(void); /* pickup the pressed function */ #endif #if ADCEn > 0 void ADCInit(void); INT16U ADCGetValue(INT8U Channel); #endif #if SwitchesIntEn > 0 void SwIntInit(); #endif #if SoundEn > 0 void SoundInit(void); void Sound(INT16U SoundPeriod, INT16U Dly); #endif

uCOS-II-MSA0654-DRIVERS.C /*************************************************************************/ /* */ /* FILE: uCOS-II-MSA0654-DRIVERS.C */ /* CREATED: 19/07/07 */ /* LAST MODIFICATION: 30/08/07 */ /* CREATED BY: Khaled Sobaihi */ /*************************************************************************/ /* This File contains the MSA0654 Board hardware Drivers functions */ /*************************************************************************/ #include <includes.h> #include "uCOS-II-MSA0654-DRIVERS.H" void dummy(void){}/* Dummy void to simulate short delay */ /*******************************************************************************/ /* KEYPAD DRIVER */ /*******************************************************************************/ #if SevSegEn > 0 const INT8U SevenSegCode[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80, 0x90}; INT8U SevenSegDigit[SevenSegDigitNb]; INT8U DigitIndex; void SevenSegInit(void) /* Initialize 7-Segs display and timer used to scan 2 digits */ { PORT_0D = 0xFF; PORT_1D = 0xFF; TA2IC = 0x02; /* Setup Timer A2 interrupt reg */ TA2MR = 0x80; /* Timer A2 Moder Register: f1 * 32 = 2 us. */

Page 122

Appendix II

TA2 = SevenSegScanDly * 500; /* Timer A2: Initialize to wait SevenSegScanDly msec*/ TABSR |= 0x04; /* Start timer A2. */ } /* Display DIG_0 and DIG_1 on the 7-Segs Display */ void SevenSegDsp(INT8U DIG_0, INT8U DIG_1) { SevenSegDigit[0] = SevenSegCode[DIG_0]; SevenSegDigit[1] = SevenSegCode[DIG_1]; } /* Light specific segements on DIG_0 and DIG_1 */ void SevenSegActive(INT8U SEG_0, INT8U SEG_1) { SevenSegDigit[0] = ~SEG_0; SevenSegDigit[1] = ~SEG_1; } #endif /* Timer A2 Callback function to scan the 2 7-Segs digits */ void TIMER_A2_CALLBACK(void) { #if SevSegEn > 0 PORT_3D = 0xFF; PORT_0 = SevenSegDigit[DigitIndex];/* Get to pattern of the digit */ if (DigitIndex == SevenSegDigitNb-1) { DigitIndex = 0; PORT_1 = 0xFE;/* Active the first digit */ } else { DigitIndex = 1; PORT_1 = 0xFD;/* Active the second digit */ } #endif } /********************************************************************************/ /* KEYPAD DRIVER */ /********************************************************************************/ #if KeyPadEn > 0 BOOLEAN KeyDown = OS_FALSE; BOOLEAN KeyHot = OS_FALSE; BOOLEAN KeyUnRead = OS_FALSE; INT8U KeyCode = 0xFF; /* keypad interrupt callback function */ void(*KeyCallBack)(void) = (void*)0; INT8U GetKey(void) /* pickup the pressed function */ { INT8U KeyChar; /* Convert the code of pressed key to the respective char */ if (KeyUnRead) { switch (KeyCode){ case 0xEE : KeyChar = '1'; break; case 0xDE : KeyChar = '4'; break; case 0xBE : KeyChar = '7'; break; case 0x7E : KeyChar = 'A'; break;

Page 123

Appendix II

case case case case case case case case

0xED 0xDD 0xBD 0x7D 0xEB 0xDB 0xBB 0x7B

: : : : : : : :

KeyChar KeyChar KeyChar KeyChar KeyChar KeyChar KeyChar KeyChar

= = = = = = = =

'2'; '5'; '8'; '0'; '3'; '6'; '9'; 'B';

break; break; break; break; break; break; break; break;

case 0xE7 : KeyChar = case 0xD7 : KeyChar = case 0xB7 : KeyChar = case 0x77 : KeyChar = default : KeyChar = } } else KeyChar = 0xFF; KeyUnRead = OS_FALSE; return KeyChar;

'F'; break; 'E'; break; 'D'; break; 'C'; break; 0xFF; break;

} /* initialize keypad hardware */ void KeyPadInit(void(*CallBack)(void)) { PORT_10D = 0x0F; PORT_10 = 0x00; PUR2 = 0x20; /* PULL UP resistors enabled on P10.4-P10.7 */ KUPIC = 0x04; /* Enable interrupt on keypad with priority = 4 */ PD8 &= 0x3F; /* Xc pins as input */ PRCR = 0x01; CM0 |= 0x10; CM0 &= 0xF7; PRCR = 0x00; TA3 = TA3MR = TA3IC = TABSR|= 0x01; 0xC2; 0x02; 0x08; /* Enable write to Processor mode /* Xc Circuit Enabled */ */

/* Disable access to processor and clock mode */ /* /* /* /* initial reload = 976.56us */ One shoot mode timer, fc32 src =976.56us */ Priority = 2 */ Enable TA3 Timer */

KeyCallBack = CallBack; /* Assign the callback function */ } void KEYPAD_CALLBACK(void)/* when any key pressed */ { TA3 = 40; KeyDown = OS_TRUE; ONSF |= 0x08; /* Start Timer A3 */ /* Call the keypad callback if not null */ if ((void*)(KeyCallBack) != (void*)0) KeyCallBack(); } #endif /* Timer A3 callback function, used for the auto repeat */ void TIMER_A3_CALLBACK(void) { INT8U Shift; static INT8U Code; KeyHot = OS_TRUE;

Page 124

Appendix II

if (KeyDown){ KeyDown = OS_FALSE; TA3 = KeyRptStartDly; Shift = 0; PORT_10 = 0x0E; /* Decode the pressed key from X and Y positions */ while(((PORT_10 | 0x0F) == 0xFF) & Shift++ < 4) PORT_10 = ((PORT_10 << 1) | 0x01) & 0x0F; Code = PORT_10; } else {PORT_10 = Code; if (PORT_10 == Code) { TA3 = KeyRptDly;} else { KeyHot = OS_FALSE; ONSF &= 0xF7; }} KeyCode = Code; PORT_10 = 0x00; KUPIC &= 0xF7; if (KeyHot) { KeyUnRead = OS_TRUE; ONSF |= 0x08; } } /********************************************************************************/ /* LEDS DRIVER */ /********************************************************************************/ #if LedsEn > 0 void LedsInit(void)/* initialize LEDs hardware */ { PORT_3D = 0xFF;} void { #endif LedsLight(INT8U Pattern) /* Light the leds with the pettern */ PORT_3 = Pattern;}

/********************************************************************************/ /* EIGHT SWITCHES DRIVER */ /********************************************************************************/ #if SwitchesEn > 0 void SwitchesInit(void)/* initialize Switches hardware */ { PORT_1D = 0x00;} INT8U { SwGetStatus(void)/* Get the status of the Switches */ INT8U Pattern; Pattern = ~PORT_1; return Pattern;

} #endif

Page 125

Appendix II

/********************************************************************************/ /* LCD DISPLAY DRIVER */ /********************************************************************************/ #if LcdDspEn > 0 void LcdDspInit(void) /* initialize LCD Display hardware */ { PORT_0D = 0xFF; PORT_5D = 0xFF; PORT_0 = 0x00; PORT_5 = 0x00; LcdSendCmd(LcdCmd_Cfg); LcdSendCmd(LcdCmd_Inc); LcdSendCmd(LcdCmd_Set); LcdSendCmd(LcdCmd_Cls); } /* Move cursor to specified position */ void LcdDspMoveTo(INT8U Row, INT8U Col) { switch(Row) {case 0 : LcdSendCmd(0x80 | Col); break; case 1 : LcdSendCmd(0xC0 | Col); break; } } /* Display the String in Row, Col position with Chars Nb length */ void LcdDspChars(INT8U Row, INT8U Col, char* String, INT8U CharsNb) { LcdDspMoveTo(Row, Col); while(CharsNb-- > 0) LcdSendData(*String++);} /* Send command to LCD routine */ void LcdSendCmd(INT8U Cmd) { PORT_5 &= 0xDF; /* Select Write Mode rw = 0 */ PORT_5 &= 0xBF; /* Select command register rs = 0 */ PORT_0 = Cmd; /* Put data on Port 0 */ /* Clock Cmd into LCD... */ PORT_5 |= 0x80; /* Enable = 1 */ asm("nop"); PORT_5 &= 0x7F; /* Enable = 0 */ OSTimeDly(1); } /* Give time to LCD to get the command */ /* Send displayed char to LCD routine */ void LcdSendData(INT8U DATA) { INT16U Cnt; PORT_5 &= 0xDF; /* Select Write Mode rw = 0 */ PORT_5 |= 0x20; /* Select DATA register rs = 1 */ PORT_0 = DATA; /* Put data on Port 0 */ /* Clock DATA into LCD... */ PORT_5 |= 0x80; /* Enable = 1 */ asm("nop"); PORT_5 &= 0x7F; /* Enable = 0 */ for(Cnt = 0; Cnt < 40; Cnt++) dummy(); /* Give short delay to LCD to display the char */ } #endif /********************************************************************************/

Page 126

Appendix II

/* ADC DRIVER */ /********************************************************************************/ #if ADCEn > 0 OS_EVENT *ADCSem; /* Semaphore to prevent multiaccess to adc in same time */ void ADCInit(void)/* initialize the ADC Hardware */ { INT8U err; ADCSem = OSSemCreate(1); /* Create the ADC Semaphore */ OSSemPend(ADCSem, 0, &err); /* wait until semaphore released */ ADCON0 = 0x80; /* Cannel 0, one-shoot mode, Software trigger */ ADCON1 = 0x20; /* 8-bits conversion, vref connected */ #if TenBitAdcEn > 0 ADCON1 = 0x28; /* 10-bits conversion if selected */ #endif ADCON2 = 0x06; /* Port 2 selected */ OSSemPost(ADCSem);/* release the semaphore */ } /* Pickup the Analog value of the specified channel */ INT16U ADCGetValue(INT8U Channel) { INT16U ADCValue = 0; INT8U err; OSSemPend(ADCSem, 0, &err); /* ask for exclusive access to ADC */ ADCON0 &= (Channel | 0xF8); /* Select the channel */ ADCON0 |= 0x40; /* Start the conversion */ while(ADCON0 & 0xBF != 0xFF);/* wait until conversion done */ /* Depend of the selected channel pickup the ADC value frome the right register */ switch (Channel) { case 0 : ADCValue = AD0H; ADCValue <<= 8; ADCValue |= AD0L; break; case 1 : ADCValue = AD1H; ADCValue <<= 8; ADCValue |= AD1L; break; case 2 : ADCValue = AD2H; ADCValue <<= 8; ADCValue |= AD2L; break; case 3 : ADCValue = AD3H; ADCValue <<= 8; ADCValue |= AD3L; break; case 4 : ADCValue = AD4H; ADCValue <<= 8; ADCValue |= AD4L; break; case 5 : ADCValue = AD5H; ADCValue <<= 8; ADCValue |= AD5L; break; case 6 : ADCValue = AD6H; ADCValue <<= 8; ADCValue |= AD6L;

Page 127

Appendix II

break; ADCValue = AD7H; ADCValue <<= 8; ADCValue |= AD7L; break; default : ADCValue = AD0H; ADCValue <<= 8; ADCValue |= AD0L; break; } OSSemPost(ADCSem); /* release the semaphore */ return ADCValue; } case 7 : #endif /********************************************************************************/ /* INTERRUPT SWITCHES DRIVER */ /********************************************************************************/ #if SwitchesIntEn > 0 void (*SW1_CallBack)(void) = (void*)0; void (*SW2_CallBack)(void) = (void*)0; void (*SW3_CallBack)(void) = (void*)0; /* initialize the interrupts hardwares by giving the callback function of each interrupt */ void SwIntInit(void(*SW1_CallBck)(void), void(*SW2_CallBck)(void), void(*SW3_CallBck)(void)) { INT0IC = 0x06; INT1IC = 0x06; ADIC = 0x06; SW1_CallBack = SW1_CallBck; SW2_CallBack = SW2_CallBck; SW3_CallBack = SW3_CallBck; } #endif void INT_0_CALLBACK(void)/* Switch 1 interrupt */ { if ((void*)(SW1_CallBack) != (void*)0) SW1_CallBack(); } void INT_1_CALLBACK(void)/* Switch 2 interrupt */ { if ((void*)(SW2_CallBack) != (void*)0) SW2_CallBack(); } void ADtrg_CALLBACK(void)/* Switch 3 interrupt */ { if ((void*)(SW3_CallBack) != (void*)0) SW3_CallBack(); } /********************************************************************************/ /* SOUND DRIVER */ /********************************************************************************/ #if SoundEn > 0 void SoundInit(void) /* Initialize Timer A1 used to ring the buzzer */ { TA1MR = 0x00; TA1 = 0x0E9F; TABSR|= 0x02; } /* Produce sound with SoundPeriod period for Dly clock ticks */ void Sound(INT16U SoundPeriod, INT16U Dly)

Page 128

Appendix II

TA1 = SoundPeriod; TA1MR |= 0x04; OSTimeDly(Dly); TA1MR &= 0xFB; }

/* /* /* /*

load the period */ Start the Timer */ Wait for Dly clock ticks */ Stop the timer */

#endif uCOS_II_MSA0654_DRIVERS-ASM.ASM ;'*******************************************************************************; ;'FILE: uCOS-II-MSA0654-DRIVERS-ASM.ASM ;'CREATED : 18/08/07 ;'CREATED BY : Khaled Sobaihi ;'LAST MODIFICATION : 30/08/07 ;'*******************************************************************************; MODULE uCOS_II_MSA0654_DRIVERS ;'******************************************************************************** RSEG RSEG EXTERN RSEG EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN CSTACK ISTACK OSIntNesting CODE(1) TIMER_A2_CALLBACK TIMER_A3_CALLBACK KEYPAD_CALLBACK OSView_TxISRHandler OSView_RxISRHandler INT_0_CALLBACK INT_1_CALLBACK ADtrg_CALLBACK OSView_TxISR OSView_RxISR

; declared as INT8U,8-bit long

PUBLIC DUMMY ;******************************************************************************** .EVEN DUMMY: REIT ;'******************************************************************************** .EVEN TIMER_A2_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current CPU context registers INC.B OSIntNesting ;'OSIntNesting++ JSR TIMER_A2_CALLBACK ;'Call the interrupt callback function DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore the CPU context registers REIT ;'******************************************************************************** .EVEN TIMER_A3_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current task registers INC.B OSIntNesting ;'OSIntNesting++ JSR TIMER_A3_CALLBACK ;'Call the TIMER Callback function DEC.B OSIntNesting ;'OSIntNesting--

Page 129

Appendix II

POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers of the new Task Stack REIT ;'******************************************************************************** .EVEN KEYPAD_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current task registers INC.B OSIntNesting ;'OSIntNesting++ JSR KEYPAD_CALLBACK ;'Call the Keypad Callback function DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers REIT ;'******************************************************************************** .EVEN INT_0_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current tasks registers INC.B OSIntNesting ;'OSIntNesting++ JSR INT_0_CALLBACK ;'Call the INT0 Callback function DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers REIT ;'******************************************************************************** .EVEN INT_1_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current tasks registers INC.B OSIntNesting ;'OSIntNesting++ JSR INT_1_CALLBACK ;'INT_1_CALLBACK() DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers REIT ;'******************************************************************************** .EVEN ADtrg_ISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current tasks registers INC.B OSIntNesting ;'OSIntNesting++ JSR ADtrg_CALLBACK ;'AD Trigger interrupt callback DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers REIT ;'******************************************************************************** .EVEN TxISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current task registers INC.B OSIntNesting ;'OSIntNesting++ JSR OSView_TxISRHandler ;'OSView_RxISRHandler() DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers REIT ;'******************************************************************************** .EVEN RxISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ;'Save current task registers INC.B OSIntNesting ;'OSIntNesting++ JSR OSView_RxISRHandler ;'OSView_RxISRHandler() DEC.B OSIntNesting ;'OSIntNesting-POPM R0,R1,R2,R3,A0,A1,SB,FB ;'Restore registers

Page 130

Appendix II

REIT ;'******************************************************************************** ;'* INTERRUPT VECTOR TABLE ;'******************************************************************************** .COMMON .ORG .LWORD .ORG .LWORD .ORG .LWORD .ORG .LWORD .ORG .LWORD .ORG .LWORD .ORG .LWORD .ORG .LWORD .END INTVEC 13*4 KEYPAD_ISR 14*4 ADtrg_ISR 23*4 TIMER_A2_ISR 24*4 TIMER_A3_ISR 29*4 INT_0_ISR 30*4 INT_1_ISR 17*4 TxISR 18*4 RxISR

Page 131

Appendix III

Appendix III C/OS-II M16C Port Listing Programs


os_cpu.h
#ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif /* ********************************************************************************** * DATA TYPES * (Compiler Specific) ********************************************************************************** */ #define typedef typedef typedef typedef typedef typedef typedef typedef typedef OS_TASK_TMR_PRIO unsigned unsigned signed unsigned signed unsigned signed float double char char char int int long long BOOLEAN; INT8U; INT8S; INT16U; INT16S; INT32U; INT32S; FP32; FP64; OS_STK; OS_CPU_SR; 0

/* /* /* /* /* /* /* /*

Unsigned 8 bit quantity Signed 8 bit quantity Unsigned 16 bit quantity Signed 16 bit quantity Unsigned 32 bit quantity Signed 32 bit quantity Single precision floating point Double precision floating point

*/ */ */ */ */ */ */ */ */ */

typedef unsigned int typedef INT16U

/* Each stack entry is 16-bit wide /* Type of CPU status register

#define

OS_CRITICAL_METHOD

Page 132

Appendix III

#if #define #define #endif

OS_CRITICAL_METHOD == 1 OS_ENTER_CRITICAL() asm("FCLR I") OS_EXIT_CRITICAL() asm("FSET I")

/* Disable interrupts /* Enable interrupts

*/ */

/* ********************************************************************************** * RENESAS M16C FAMILY MISCELLANEOUS ********************************************************************************** */ #define #define OS_STK_GROWTH OS_TASK_SW() 1 /* Stack grows from HIGH to LOW memory */ asm("INT #0") /* Mapped to the software interrupt 0 */

/* ********************************************************************************** * PROTOTYPES ********************************************************************************** */ void void void void OSCtxSw OSIntCtxSw OSStartHighRdy OSTickISR (void); (void); (void); (void);

os_cpu_a.asm
;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;' PUBLIC FUNCTIONS ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RSEG RSEG EXTERN EXTERN EXTERN EXTERN EXTERN EXTERN RSEG EXTERN EXTERN EXTERN CSTACK ISTACK OSTCBCur ; 'Current Running Task TCB, 32-bit long OSTCBHighRdy ;'Highest Priority Task TCB ready to run,32-bitlong OSPrioCur ;'Current running Task Priority, 8-bit long OSPrioHighRdy ;'Priority of the Highest Priority Task ready to run, ;8-bit long OSIntNesting ; 'Interrupts nesting variable, 8-bit long OSRunning ; 'Is C/OS-II Running?, 8-bit long CODE OSIntExit ; 'Exit from interrupt, called when finish with the ISR OSTimeTick ; 'Function called every Clock Tick of the uCOS-II OSTaskSwHook ; 'User hook function, Called at each context switch

Page 133

Appendix III

;' Tx/Rx UART Callback functions, declared in OSVIEW Module (Optional) EXTERN OSView_TxISR EXTERN OSView_RxISR EXTERN DUMMY ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PUBLIC PUBLIC PUBLIC OSStartHighRdy OSCtxSw OSIntCtxSw ; 'Start the OS, Run the Highest Priority Task ; 'Task Level Context Switch routine ; 'Interrupt Level Context Switch routine

;';;;;;;;;;;;;;;;; Run the highest priority task ready to run ;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;; void OSStartHighRdy(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .EVEN OSStartHighRdy: JSR OSTaskSwHook ; 'Call OSTaskSwHook() FCLR U ; 'Software interrupt knowledge ; 'Point on the stack pointer of the highest priority ready task... MOV.W OSTCBHighRdy, A0 ; 'ISP = OSTCBHighRdy->OSTCBStkPtr LDC [A0], ISP MOV.B #01H, OSRunning ; 'OSRunning = TRUE ; 'Load the highest priority ready task registers into CPU registers POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ; 'Launch the highest priority ready task ;';;;;;;;;;;;;;;;;;;; Performs the task level context switch ;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;; void OSCtxSw(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .EVEN OSCtxSw: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ; 'Push the CPU Regs onto current task stack MOV.W OSTCBCur, A0 ; 'OSTCBCur->OSTCBStkPtr = SP STC ISP, [A0] JSR OSTaskSwHook ; 'Call OSTaskSwHook() MOV.W OSTCBHighRdy, OSTCBCur ; 'OSTCBCur = OSTCBHighRdy MOV.W OSPrioHighRdy, OSPrioCur; 'OSPrioCur = OSPrioHighRdy MOV.W OSTCBHighRdy, A0 ; 'SP = OSTCBHighRdy->OSTCBStkPtr LDC [A0], ISP ; 'Restore all processor registers from the new tasks stack POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ; 'Launch the highest priority ready task ;';;;;;;;;;;;;;;; Performs the interrupt level context switch ;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;; void OSIntCtxSw(void) ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .EVEN OSIntCtxSw: JSR OSTaskSwHook ; MOV.W OSTCBHighRdy, OSTCBCur ; MOV.W OSPrioHighRdy, OSPrioCur; MOV.W OSTCBHighRdy, A0 ; LDC [A0], ISP

'Call OSTaskSwHook() 'OSTCBCur = OSTCBHighRdy 'OSPrioCur = OSPrioHighRdy 'SP = OSTCBHighRdy->OSTCBStkPtr

Page 134

Appendix III

; 'Restore all processor registers from the new tasks stack POPM R0,R1,R2,R3,A0,A1,SB,FB REIT ; 'Launch the highest priority ready task ;';;;;;;;;;;;;;;;;;;;;;;;;; Clock Ticks Generator Timer ;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;; void OSTickISR (void) ;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .EVEN OSTickISR: PUSHM R0,R1,R2,R3,A0,A1,SB,FB ; 'Save current task registers INC.B OSIntNesting ; 'OSIntNesting++ ;' Make sure that this ISR does not interrupt another ISR... CMP.B #1,OSIntNesting ; 'if (OSIntNesting == 1) JNE OSTickISR1 ; 'If yes assign the highest priority ready task stack pointer to the current TCB stack pointer MOV.W OSTCBCur, A0 ; 'OSTCBCur->OSTCBStkPtr = SP STC ISP, [A0] OSTickISR1: JSR OSTimeTick ; 'Call JSR OSIntExit ; 'Call POPM R0,R1,R2,R3,A0,A1,SB,FB REIT

OSTimeTick() OSIntExit() to achieve the context switch ; 'Restore registers from the new tasks stack ; 'Launch the highest priority ready task

;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;; INTERRUPT VECTOR TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .COMMON INTVEC ;'Context Switch Interrupt Vector ORG 0 .LWORD OSCtxSw ;'Clock Ticks Generator TIMER A0 ORG 21*4 .LWORD OSTickISR ;'Tx UART Interrupt vector, Used by OSVIEW Module (Optional) .ORG 17*4 .LWORD OSView_TxISR ;'Rx UART Interrupt vector, Used by OSVIEW Module (Optional) .ORG 18*4 .LWORD OSView_RxISR ;TIMER A2 Vector .ORG 22*4 .LWORD DUMMY .END

Page 135

Appendix III

os_cpu_c.c
#define OS_CPU_GLOBALS #include <ucos_ii.h> #if OS_VIEW_MODULE > 0 #include <os_viewc.h> #include <os_view.h> #endif /********************************************************************************* * LOCAL VARIABLES *********************************************************************************/ #if OS_TMR_EN > 0 static INT16U OSTmrCtr; #endif /********************************************************************************* * OS INITIALIZATION HOOK * (BEGINNING) * Description: This function is called by OSInit() at the beginning of OSInit(). * Arguments : none * Note(s) : 1) Interrupts should be disabled during this call. *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203 void OSInitHookBegin (void) { #if OS_TMR_EN > 0 OSTmrCtr = 0; #endif } #endif /********************************************************************************* * OS INITIALIZATION HOOK * (END) * Description: This function is called by OSInit() at the end of OSInit(). * Arguments : none * Note(s) : 1) Interrupts should be disabled during this call. *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203 void OSInitHookEnd (void) { } #endif /******************************************************************************** * TASK CREATION HOOK * Description: This function is called when a task is created. * Arguments : ptcb is a pointer to the task control block of the task being created.* Note(s) : 1) Interrupts are disabled during this call. *********************************************************************************/

Page 136

Appendix III

#if OS_CPU_HOOKS_EN > 0 void OSTaskCreateHook (OS_TCB *ptcb) { #if OS_VIEW_MODULE > 0 OSView_TaskCreateHook(ptcb); #else (void)ptcb; /* Prevent compiler warning #endif } #endif

*/

/********************************************************************************** * TASK DELETION HOOK * Description: This function is called when a task is deleted. * Arguments : ptcb is a pointer to the task control block of the task being deleted. * * Note(s) : 1) Interrupts are disabled during this call. *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 void OSTaskDelHook (OS_TCB *ptcb) { ptcb = ptcb; /* Prevent compiler warning */ } #endif /********************************************************************************** IDLE TASK HOOK * Description: This function is called by the idle task. This hook has been added to allow you to do such things as STOP the CPU to conserve power. * * Arguments : none * * Note(s) : 1) Interrupts are enabled during this call. ********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251 void OSTaskIdleHook (void) { } #endif /********************************************************************************* * STATISTIC TASK HOOK * Description: This function is called every second by uC/OS-II's statistics task. This allows your application to add functionality to the statistics task. * Arguments : none *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 void OSTaskStatHook (void) { } #endif

Page 137

Appendix III

/******************************************************************************** * INITIALIZE A TASK'S STACK ********************************************************************************/ OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { INT16U *pstk16; INT16U flag; flag = 0x0040; pstk16 = (INT16U *)ptos; pstk16--; /* Simulate ISR entry */ *pstk16-- = (flag & 0x00FF) /*... The lowest byte of the FLAG register */ | (((INT32U)task >> 8) & 0x00000F00) /*..The highest nibble of the PC register*/ | ((flag << 4) & 0xF000);/* ... The highest nibble of the FLAG register */ *pstk16-- = (((INT32U)task ) & 0x0000FFFF);/*..The lowest bytes of the PC register*/ /* Save registers onto stack frame */ *pstk16-- = (INT16U)0xFBFB; /* ... FB register */ *pstk16-- = (INT16U)0x3B3B; /* ... SB register */ *pstk16-- = (INT16U)0xA1A1; /* ... A1 register */ *pstk16-- = (INT16U)0xA0A0; /* ... A0 register */ *pstk16-- = (INT16U)0x3333; /* ... R3 register */ *pstk16-- = (INT32U)pdata >> 16L; /* ... Pass argument in R2 register */ *pstk16-- = (INT32U)pdata & 0x0000FFFFL; /*..Pass argument in R1 register */ *pstk16 = (INT16U)0x0000; /*..R0 register */ return ((OS_STK *)pstk16); } /********************************************************************************* * TASK SWITCH HOOK * * Description: This function is called when a task switch is performed. This allows you to perform other * operations during a context switch. * * Arguments : none * * Note(s) : 1) Interrupts are disabled during this call. * 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the TCB of the task that * will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the * task being switched out (i.e. the preempted task). *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 void OSTaskSwHook (void) { #if OS_VIEW_MODULE > 0 OSView_TaskSwHook(); #endif } #endif

Page 138

Appendix III

/********************************************************************************* * OSTCBInit() HOOK * Description: This function is called by OS_TCBInit() after setting up most of the TCB. * Arguments : ptcb is a pointer to the TCB of the task being created. * Note(s) : 1) Interrupts may or may not be ENABLED during this call. ********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203 void OSTCBInitHook (OS_TCB *ptcb) { (void)ptcb; /* Prevent Compiler warning */ } #endif

/********************************************************************************* * TICK HOOK * Description: This function is called every tick. * Arguments : none * Note(s) : 1) Interrupts may or may not be ENABLED during this call. *********************************************************************************/ #if OS_CPU_HOOKS_EN > 0 void OSTimeTickHook (void) { #if OS_VIEW_MODULE > 0 OSView_TickHook(); #endif #if OS_TMR_EN > 0 OSTmrCtr++; if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { OSTmrCtr = 0; OSTmrSignal(); } #endif } #endif

Page 139

Table of Contents

CHAPTER I ...............................................................................................................................................................................4 REAL TIME OPERATING SYSTEM (RTOS) .......................................................................................................................4

ABSTRACT ......................................................................................................................................................................................................... 1 ACKNOWLEDGEMENTS .......................................................................................................................................................................... 2 INTRODUCTION.......................................................................................................................................................................................... 3 INTRODUCTION.......................................................................................................................................................................................... 4 1. THE OPERATING SYSTEM .................................................................................................................................................................... 4 2. REAL TIME OPERATING SYSTEM ....................................................................................................................................................... 5 2.1. Multitasking.................................................................................................................................................................................. 7 2.2. Non-Preemptive Kernel ........................................................................................................................................................... 7 2.3. Preemptive Kernel...................................................................................................................................................................... 9 3. CONTEXT SWITCH ..............................................................................................................................................................................10 4. RTOS VS INFINITE LOOP ..................................................................................................................................................................12 CONCLUSION...................................................................................................................................................................................................14 INTRODUCTION ..............................................................................................................................................................................................15 1. CONTEXT SWITCH IN C/OS-II .......................................................................................................................................................15 1.1. Task Level Context Switch ....................................................................................................................................................16 1.2. Interrupt Level Context Switch ..........................................................................................................................................17 1.3. C/OS-II Tasks States .............................................................................................................................................................17 1.4. Task Control Blocks (OS_TCBs) ..........................................................................................................................................19 1.5. Ready list ......................................................................................................................................................................................21 2. TASK SCHEDULING .............................................................................................................................................................................24 2.1. OSSched() Context Switch function ..................................................................................................................................24 2.2. OSIntExit() Context Switch function ................................................................................................................................25 3. INTERRUPTS UNDER C/OS-II .......................................................................................................................................................26 4. CLOCK TICKS .......................................................................................................................................................................................27 5. TASK MANAGEMENT ..........................................................................................................................................................................28 5.1. Creating C/OS-II Task..........................................................................................................................................................29 6. INTER-TASK COMMUNICATION & SYNCHRONIZATION .................................................................................................................31 6.1. Semaphores .................................................................................................................................................................................33 6.2. Mutual Exclusion Semaphores ...........................................................................................................................................37 6.3. Message Mailboxes ..................................................................................................................................................................39 6.4. Messages Queues ......................................................................................................................................................................42 6.5. Event Flags (C/OS-II V2.51 and higher) ......................................................................................................................45 7. TIME MANAGEMENT ..........................................................................................................................................................................48 8. TIMERS MANAGEMENT......................................................................................................................................................................49 9. MEMORY MANAGEMENT ...................................................................................................................................................................51 CONCLUSION .............................................................................................................................................................................................54

TABLE OF CONTENTS

CHAPTER II ........................................................................................................................................................................... 15 C/OS-II REAL TIME OPERATING SYSTEM ................................................................................................................. 15

CHAPTER III ......................................................................................................................................................................... 55

Table of Contents
PORTING C/OS-II TO THE M16C MICROCONTROLLERS ...................................................................................... 55 INTRODUCTION........................................................................................................................................................................................55 1. COMPILER SPECIFIC DATA TYPES AND MACROS, <OS_CPU.H> ...............................................................................................57 2. STACK INITIALIZATION AND USER HOOK FUNCTION, OS_CPU_C.C ........................................................................................58 3. ASSEMBLY LANGUAGE FUNCTIONS FILE, OS_CPU_A.ASM ........................................................................................................60 3.1. OSStartHighRdy() ....................................................................................................................................................................60 3.2. OSCtxSw(), ...................................................................................................................................................................................61 3.3. OSIntCtxSw(), .............................................................................................................................................................................62 3.4. OSTickISR(), ................................................................................................................................................................................63 CONCLUSION .............................................................................................................................................................................................65 INTRODUCTION ..............................................................................................................................................................................................66 1. C/OS-II PROJECT TEMPLATE ........................................................................................................................................................67 2. C/OS-VIEW MODULE .....................................................................................................................................................................74 3. C/OS-II DEMONSTRATION EXAMPLE ..........................................................................................................................................78 4. MSA0654 DEVELOPMENT BOARD ................................................................................................................................................82 5. TEST AND DEMONSTRATION ............................................................................................................................................................84 5.1. Normal Running of the Application .................................................................................................................................86 5.2. When Keypads button pressed ..........................................................................................................................................88 5.3. When the Messages memory is full ...................................................................................................................................89 5.4. In Case of emergency ..............................................................................................................................................................90 CONCLUSION .............................................................................................................................................................................................94 REFERENCES ..................................................................................................................................................................................................97

CHAPTER IV.......................................................................................................................................................................... 66 C/OS-II DEMONSTRATION EXAMPLE......................................................................................................................... 66

CONCLUSION ........................................................................................................................................................................ 95

APPENDIX I ........................................................................................................................................................................... 98 PROGRAMS LISTINGS OF THE PROJECT APPLICATION .......................................................................................... 98 APPENDIX II ...................................................................................................................................................................... 120 MSA0654 DEVELOPMENT BOARD DRIVERS ........................................................................................................... 120 APPENDIX III ..................................................................................................................................................................... 132 C/OS-II M16C PORT LISTING PROGRAMS ............................................................................................................. 132

Potrebbero piacerti anche