VX Worksproject 10
VX Worksproject 10
VX Worksproject 10
VxWORKS
-:BY:-
ABHAY KUMAR
AJAY KUMAR PANCHORE
REEP JYOTI DEKA
KAUSHIK DAS
SREEJITH S NAIR
ACKNOWLEGEMENT
It is a great privilege for us to express our deep sense of gratitude to our guide, Mr.
K.L. Baishnab of Electronics & Communication Engineering Department, NIT Silchar
for his stimulating guidance and profound assistance. I shall always cherish my
association with him for his constant encouragement and freedom to thought and
action that he rendered to me throughout this project.
Finally, I deem it a great pleasure to thank one and all those who helped me carry out
this project.
VxWorks
VxWorks is a real-time operating system(RTOS) made and sold by Wind River Systems of Alameda,
California, USA. Intel acquired Wind River Systems on July 17, 2009.
VxWorks is designed for use in embedded systems. Unlike "self-hosting" systems such as Unix,
VxWorks development is done on a "host" machine running Linux, Unix, or Windows, cross-
compiling target software to run on various "target" CPU architectures.
History
VxWorks started as an improvement on a primitive ROM chip with a 4K kernel sold by Ready
Systems, now a Mentor Graphics product. It contained VRTX, which lacked everything from a file
system to a development environment. Wind River created an accessory called VxWorks that turned
the VRTX kernel into an OS and a development environment. Fiddler and Wilner had negotiated an
agreement to sell VRTX with VxWorks. In 1987, anticipating that Ready Systems was going to cancel
its reseller contract, Wind River developed its own kernel and a smaller, faster, lighter OS – written
by an intern.
The name VxWorks is believed to be a pun (VRTX Works) on the VRTX real-time operating system.
OS overview
VxWorks has been ported to a number of platforms and now runs on practically any modern CPU
that is used in the embedded market. This includes the x86 family, MIPS, PowerPC, Freescale
ColdFire, Intel i960, SH-4 and the closely related family of ARM, StrongARM and xScale CPUs.
Multitasking kernel with preemptive and round-robin scheduling and fast interrupt response
Memory protection to isolate user applications from the kernel
SMP support
Fast, flexible inter-process communication including TIPC
Error handling framework
Binary, counting, and mutual exclusion semaphores with priority inheritance
Local and distributed message queues
POSIX PSE52 certified conformance
File system
IPv6 networking stack
VxSim simulator
INTRODUCTION ABOUT OUR PROJECT
In this project we explored the VxWorks software basics. First we studied a no. of
embedded system architecture and different types of OS like REAL-TIME OS NON
REAL-TIME OS and their difference.
Since we are new in this software so we have decided to learn the basics of software
like creating new functions , different controls like time control, multitasking, signals
handling etc.
Introduction
To understand and optimize the performance of a real-time system, it can be useful to time some of
the VxWorks and application functions. VxWorks provides a number of timing facilities to help with
this task.
The VxWorks execution timer can time any subroutine or group of subroutines. To time very fast
subroutines, the timer can also repeatedly execute a group of functions until the time of a single
iteration is known with reasonable certainty.
Objectives
The following are the primary objectives of this experiment:
To demonstrate how to time a single subroutine using the VxWorks timex() routine.
Description
The timex() routine times a single execution of a specified function with up to eight integer
arguments to be passed to the function. When execution us complete, timex() routine displays the
execution time and a margin of error in miliseconds. If the execution was so fast relative to the clock
rate that the time is meaningless(error > 50%), a warning message will appear. In such cases, use
timexN() which will repeatedly execute the function until the time of a single iteration is known with
reasonable certainty.
1. Syntax
2. Example This small example has two subroutines. The first subroutine "timing" makes a call to
timex() with the function name "printit" which is the subroutine to be timed. The arguments are all
NULL, so no parameters are being passed to "printit".
The second subroutine, "printit", which is being timed iterates 200 times while printing its task
id(using taskIdSelf()) and the increment variable "i".
Example Programs Codes
#include "vxWorks.h"
#include "timexLib.h"
#include "stdio.h"
int printit(void);
Note:-
The timings measure the execution time of the routine body, without the usual subroutine
entry and exit code. Also, the time required to set up the arguments and call the routines is
not included in the reported times. This is because the timing routines automatically
calibrate themselves by timing the invocation of a null routine, and thereafter subtracting
that constant overhead.
Experiment no 2.
Multi Tasking
Introduction
Modern real-time systems are based on the complementary concepts of multitasking and intertask
communications. A multitasking environment allows real-time applications to be constructed as a
set of independent tasks, each with a separate thread of execution and its own set of system
resources. The intertask communication facilities allow these tasks to synchronize and coordinate
their activities.
The VxWorks multitasking kernel, wind, uses interrupt-driven, priority- based task
scheduling. It features fast context switch time and low interrupt latency.
Objectives
The following are the primary objectives of this experiment:
Description
Multitasking creates the appearance of many threads of execution running concurrently when, in
fact, the kernel interleaves their execution on a basis of ascheduling algorithm. Each apparently
independent program is called a task. Each task has its own context, which is the CPU environment
and system resources that the task sees each time it is scheduled to run by the kernel.
On a context switch, a task's context is saved in the Task Control Block(TCB). A task's context
includes:
The routine taskSpawn creates the new task context, which includes allocating and setting up the
task environment to call the main routine(an ordinary subroutine) with the specified arguments. The
new task begins at the entry to the specified routine.
The arguments to taskSpawn() are the new task's name(an ASCII string), priority, an "options" word(also hex
value), stack size(int), main routine address(also main routine name), and 10 integer arguments to be passed
to the main routine as startup parameters.
2. Syntax
id = taskSpawn(name,priority,options,stacksize,function, arg1,..,arg10);
3. Example
This example creates ten tasks which all print their task Id once:
#define ITERATIONS 10
void print(void);
However, while shared address space simplifies the exchange of data, interlocking access to
memory is crucial to avoid contention. Many methods exist for obtaining exclusive access to
resources, and one of them is semaphores.
Objectives
The following are the primary objectives of this experiment:
Description
VxWorks semaphores are highly optimized and provide the fastest intertask communication
mechanisms in VxWorks. Semaphores are the primary means for addressing the requirements of
both mutual exclusion and task synchronization.
The are three types of Wind semaphores, optimized to address different classes of problems:
binary
The fastest, most general purpose semaphore. Optimized for synchronization and can also
be used for mutual exclusion.
mutual exclusion
A special binary semaphore optimized for problems inherent in mutual exclusion: priority
inheritance, deletion safety and recursion.
counting
Like the binary semaphore, but keeps track of the number of times the semaphore is given.
Optimized for guarding multiple instances of a resource.
1. Semaphore Control
Wind semaphores provide a single uniform interface for semaphore control. Only the creation
routines are specific to the semaphore type:
Please refer to the VxWorks Reference Manual for valid arguments in the above routines.
A binary semaphore can be viewed as a flag that is available or unavailable. When a task takes a
binary semaphore, using semTake(), the outcome depends on whether the semaphore is available
or unavailable at the time of the call. If the semaphore is available, then the semaphore becomes
unavailable and then the task continues executing immediately. If the semaphore is unavailable, the
task is put on a queue of blocked tasks and enters a state of pending on the availability of the
semaphore.
When a task gives a binary semaphore, using semGive(), the outcome depends on whether the
semaphore is available or unavailable at the time of the call.If the semaphore is already available,
giving the semaphore has no effect at all. If the semaphore is unavailable and no task is waiting to
take it, then the semaphore becomes available. If the semaphore is unavailable and one or more
tasks are pending on its availablity, then the first task in the queue of pending tasks is unblocked,
and the semaphore is left unavailable.
In the example below, two tasks(taskOne and taskTwo), are competing to update the value of a
global variable, called "global." The objective of the program is to toggle the value of the global
variable(1s and 0s). taskOne changes the value of "global" to 1 and taskTwo changes the value back
to 0.Without the use of the semaphore, the value of "global" would be random and the value of
"global" would be corrupted.
Example Programs Codes
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "semLib.h"
#include "stdio.h"
/* function prototypes */
void taskOne(void);
void taskTwo(void);
/* globals */
#define ITER 10
SEM_ID semBinary;
int global = 0;
void binary(void)
{
int taskIdOne, taskIdTwo;
/* create semaphore with semaphore available and queue tasks on FIFO basis */
semBinary = semBCreate(SEM_Q_FIFO, SEM_FULL);
Introduction
In VxWorks, the primary intertask communication mechanism within a single CPU is message
queues. Message queues allow a variable number of messages, each of variable length, to be
queued(FIFO or priority based). Any task can send a message to a message queue and any
task can receive a message from a message queue. Multiple tasks can send to and receive
from the same message queue. Two way communication between two tasks generally
requires two message queues, one for each direction.
Objectives
The following are the primary objectives of this experiment:
Description
Wind message queues are created and deleted with the following routines:
msgQCreate(int maxMsgs, int maxMsgLength, int options): Allocate and initialize a message
queue.
msgQSend(MSG_Q_ID msgQId, char *Buffer, UINT nBytes, int timeout, int priority): Send a
message to a message queue.
msgQReceive(MSG_Q_ID msgQId, char *Buffer, UINT nBytes, int timeout) Send a message to
a message queue.
This library provides messages that are queued in FIFO order, with a single exception: there are two
priority levels, and messages marked as high priority are attached to the head of the queue.
A message queue is created with msgQCreate(). Its parameters specify the maximum number of
messages that can be queued in the message queue and the maximum length in bytes of each
message.
A task sends a message to a message queue with msgQSend(). If no tasks are waiting for messages
on that queue, the message is added to the queue's buffer of messages. If any tasks are waiting for a
message from that message queue, the message is immediately delivered to the first waiting task.
A task receives a message from a message queue with msgQReceive(). If messages are already
available in the queue's buffer, the first message is immediately dequeued and returned to the
caller. If no messages are available, then the calling task blocks and is added to a queue of tasks
waiting for messages. The queue of waiting tasks can be ordered either by task priority or FIFO, as
specified when the queue is created.
Timeouts: Both msgQSend() and msgQReceive() take timeout parameters. The timeout
parameter specifies how many ticks(clock ticks per second) to wait for space to be available
when sending a message and to wait for a message to be available when receiving a
message.
Urgent Messages: The msgQSend() function can specify the priority of a message either as
normal MSG_PRI_NORMAL or urgent MSG_PRI_URGENT. Normal priority messages are
added to the tail of the message queue, while urgent priority messages are added to the
head of the message queue.
/* function prototypes */
void taskOne(void);
void taskTwo(void);
/* defines */
#define MAX_MESSAGES 100
#define MAX_MESSAGE_LENGTH 50
/* globals */
MSG_Q_ID mesgQueueId;
void message(void) /* function to create the message queue and two tasks
*/
{
int taskIdOne, taskIdTwo;
/* spawn the two tasks that will use the message queue */
if((taskIdOne =
taskSpawn("t1",90,0x100,2000,(FUNCPTR)taskOne,0,0,0,0,0,0,0,
0,0,0)) == ERROR)
printf("taskSpawn taskOne failed\n");
if((taskIdTwo =
taskSpawn("t2",90,0x100,2000,(FUNCPTR)taskTwo,0,0,0,0,0,0,0,0,0,0)) ==
ERROR)
printf("taskSpawn taskTwo failed\n");
}
/* send message */
if((msgQSend(mesgQueueId,message,MAX_MESSAGE_LENGTH, WAIT_FOREVER,
MSG_PRI_NORMAL)) == ERROR)
printf("msgQSend in taskOne failed\n");
}
/* receive message */
if(msgQReceive(mesgQueueId,msgBuf,MAX_MESSAGE_LENGTH, WAIT_FOREVER)
== ERROR)
printf("msgQReceive in taskTwo failed\n");
else
printf("%s\n",msgBuf);
msgQDelete(mesgQueueId); /* delete message queue */
}
Experiment no 5.
Round Robin Task Scheduling
Introduction
Task scheduling is the assignment of starting and ending times to a set of tasks, subject to certain
constraints. Constraints are typically either time constraints or resource constraints. On a time-
sharing operating system, running each active process in turn for its share of time (its "timeslice"),
thus creating the illusion that multiple processes are running simultaneously on a single processor.
Wind task scheduling uses a priority based preemptive scheduling algorithm as default, but it can
also accommodate round-robin scheduling.
Objectives
The following are the primary objectives of this experiment:
Description
Round-Robin Scheduling
A round-robin scheduling algorithm attempts to share the CPU fairly among all ready tasks of
the same priority. Without round-robin scheduling, when multiple tasks of equal priority
must share the processor, a single task can usurp the processor by never blocking, thus never
giving other equal priority tasks a chance to run.
Round-robin scheduling achieves fair allocation of the CPU to tasks of the same priority by an
approach known as time slicing. Each task executes for a defined interval or time slice; then
another task executes for an equal interval, in rotation. The allocation is fair in that no task
of a priority group gets a second slice of time before the other tasks of a group are given a
slice.
In the example below, three tasks with the same priority print their task ids and task names on the
console. Without round-robin scheduling, "taskOne" would usurp the processor until it was finished,
and then "taskTwo" and "taskThree" would do likewise. In the event that "taskOne" was looping
indefinitely, the other tasks would never get a chance to run.
To insure that the tasks get an equal share of the CPU time, a call is made to kernelTimeSlice(). This
sets the time slice interval value to TIMESLICE. The TIMESLICE value is the time slice interval in
terms of the number of clock ticks(which in the example and the M68040 is 60 ticks which is
equivalent to one second). The sysClkRateGet() can be used to determine the number of clock ticks
per second.
Having setup the time slice in the manner above, the three tasks are spawned. However, here a few
implementation details that should be noted:
Make sure that sched has a higher priority than the tasks it is spawning! Unless otherwise
specified, tasks have a default priority of 100. Notice that taskOne, taskTwo, and taskThree
all have priorities of 101, which makes them lower in priority than sched.
Yow must allow enough time for the context switches to occur. Thus the reason for -> for
(j=0; j < LONG_TIME; j++);
Using printf is not ideal in the example, because it can block .This will of course cause a task
transition which will upset the nice round robin picture. Instead use logMsg() (see vxWorks
reference manual for details). The latter won't block unless the log message queue is full.
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "kernelLib.h"
#include "sysLib.h"
#include "logLib.h"
/* function prototypes */
void taskOne(void);
void taskTwo(void);
void taskThree(void);
/* globals */
#define ITER1 100
#define ITER2 10
#define PRIORITY 101
#define TIMESLICE sysClkRateGet()
#define LONG_TIME 1000000
void sched(void) /* function to create the three tasks */
{
int taskIdOne, taskIdTwo, taskIdThree;
void taskOne(void)
{
int i,j;
for (i=0; i < ITER1; i++)
{
for (j=0; j < ITER2; j++)
logMsg("\n",0,0,0,0,0,0); /* log messages */
for (j=0; j < LONG_TIME; j++); /* allow time for context switch */
}
}
void taskTwo(void)
{
int i,j;
for (i=0; i < ITER1; i++)
{
for (j=0; j < ITER2; j++)
logMsg("\n",0,0,0,0,0,0); /* log messages */
for (j=0; j < LONG_TIME; j++); /* allow time for context switch */
}
}
void taskThree(void)
{
int i,j;
for (i=0; i < ITER1; i++)
{
for (j=0; j < ITER2; j++)
logMsg("\n",0,0,0,0,0,0); /* log messages */
for (j=0; j < LONG_TIME; j++); /* allow time for context switch */
}
}
Experiment no 6.
Preemptive Priority Based Task Scheduling
Introduction
Task scheduling is the assignment of starting and ending times to a set of tasks, subject to certain
constraints. Constraints are typically either time constraints or resource constraints. On a time-
sharing operating system, running each active process in turn for its share of time (its "timeslice"),
thus creating the illusion that multiple processes are running simultaneously on a single processor.
Wind task scheduling uses a priority based preemptive scheduling algorithm as default, but it can
also accommodate round-robin scheduling.
Objectives
The following are the primary objectives of this experiment:
To demonstrate the use of VxWorks preemptive priority based task scheduling facilities.
Description
Preemptive Priority Based Scheduling
With a preemptive priority based scheduler, each task has a priority and the kernel insures
that the CPU is allocated to the highest priority task that is ready to run. This scheduling
method is preemptive in that if a task that has a higher priority than the current task
becomes ready to run, the kernel immediately saves the current tasks's context and switches
to the context of the higher priority task.
The Wind kernel has 256 priority levels(0-255). Priority 0 is the highest and priority 255 is the
lowest. Tasks are assigned a priority when created; however, while executing, a task can
change its priority using taskPrioritySet().
1. Example: Preemptive Priority Based Scheduling
One of the arguments to taskSpawn() is the priority at which the task is to execute:
In addition a task's priority can be changed after its spawned using the following routine:
/* function prototypes */
void taskOne(void);
void taskTwo(void);
void taskThree(void);
/* globals */
#define ITER1 100
#define ITER2 1
#define LONG_TIME 1000000
#define HIGH 100 /* high priority */
#define MID 101 /* medium priority */
#define LOW 102 /* low priority */
void taskThree(void)
{
int i,j;
for (i=0; i < ITER1; i++)
{
for (j=0; j < ITER2; j++)
logMsg("\n",0,0,0,0,0,0);
for (j=0; j < LONG_TIME; j++);
}
}
Experiment no 7.
Priority Inversion
Introduction
Priority inversion occurs when a higher-priority task is forced to wait an indefinite period for the
completion of a lower priority task. For example, prioHigh, prioMedium,and prioLow are task of
high, medium, and low priority, respectively. prioLow has acquired a resource by taking its
associated binary semaphore. When prioHigh preempts prioLow and contends for the resource by
taking the same semaphore, it becomes blocked. If prioHigh would be blocked no longer than the
time it normally takes prioLow to finish with the resource, there would be no problem, because the
resource can't be preempted. However, the low priority task is vulnerable to preemption by the
medium priority task, prioMedium, which could prevent prioLow from relinquishing the resource.
This condition could persist, blocking prioHigh for an extensive period of time.
Objectives
The following are the primary objectives of this experiment:
Description
To address the problem of priority inversion, VxWorks provides an additional option when using
mutual exclusion semaphores. This option is SEM_INVERSION_SAFE which enables a priority
inheritance algorithm. This algorithm insures that the task that owns a resource executes at the
priority of the highest priority task blocked on that resource. When execution is complete, the task
relinquishes the resource and returns to its normal priority. Therefore, the inheriting task is
protected from preemption by an intermediate priority task. This option must be used in
conjunction with SEM_Q_PRIORITY:
The example below illustrates a typical situation in which priority inversion takes place. Here is the
what happens:
2. prioLow task gets preempted by prioMedium task which runs for a long time which results in the
blocking of prioLow.
3. prioHigh task preempts prioMedium task and tries to lock the semaphore which is currently
locked by prioLow.
Since both prioLow and prioHigh are both blocked, prioMedium runs to completion(a very long
time). By the time prioHigh runs it is likely that it has missed its timing requirements.
/* function prototypes */
void prioHigh(void);
void prioMedium(void);
void prioLow(void);
/* globals */
#define ITER 3
#define HIGH 102 /* high priority */
#define MEDIUM 103 /* medium priority */
#define LOW 104 /* low priority */
#define LONG_TIME 3000000
SEM_ID semMutex;
/* create semaphore */
semMutex = semMCreate(SEM_Q_PRIORITY); /* priority based semaphore */
void prioLow(void)
{
int i,j;
for (i=0; i < ITER; i++)
{
semTake(semMutex,WAIT_FOREVER); /* wait indefinitely for semaphore */
printf("Low priority task locks semaphore\n");
for (j=0; j < LONG_TIME; j++);
printf("Low priority task unlocks semaphore\n");
semGive(semMutex); /* give up semaphore */
}
printf("..................................Low priority task exited\n");
}
void prioMedium(void)
{
int i;
taskDelay(20);/*allow time for task with the low priority to seize semaphore */
for (i=0; i < LONG_TIME*10; i++)
{
if ((i % LONG_TIME) == 0)
printf("Medium task running\n");
}
printf("----------------------------------Medium priority task exited\n");
}
void prioHigh(void)
{
int i,j;
taskDelay(30);/* allow time for task with the lowe priority to seize semaphore */
for (i=0; i < ITER; i++)
{
printf("High priority task trys to lock semaphore\n");
semTake(semMutex,WAIT_FOREVER); /* wait indefinitely for semaphore */
printf("High priority task locks semaphore\n");
for (j=0; j < LONG_TIME; j++);
printf("High priority task unlocks semaphore\n");
semGive(semMutex); /* give up semaphore */
}
printf(".......................................High priority task exited\n");
}
Experiment no 8.
Signals
Introduction
A signal is a software notification to a task or a process of an event. A signal is generated when the
event that causes the signal occurs. A signal is delivered when a task or a process takes action based
on that signal. The lifetime of a signal is the interval between its generation and its delivery. A signal
that has been generated but not yet delivered is pending. There may be considerable time between
signal generation and signal delivery.
VxWorks supports a software signal facility. The signals asynchronously alter the control flow of
task. Any task can raise a signal for a particular task. The task being signaled immediately suspends
its current thread of execution and the task specified signal handler routine is executed the next
time the task is scheduled to run. The signal handler gets invoked even if the task is blocked on
some action or event. The signal handler is a user supplied routine that is bound to a specific signal
and performs whatever actions are necessary whenever the signal is received. Signals are most
appropriate for error and exception handling, rather than general intertask communication.
The Wind kernel has both BSD 4.3 and POSIX signal interface. The POSIX interface provides a
standardized interface which is more functional than BSD 4.3 interface. Your application should use
only one interface and not mix the two.
Objectives
The following are the primary objectives of this experiment:
Description
The signal facility provides a set of 31 distinct signals(see VxWorks Manual). A signal can be raised by
calling kill(), which is analogous to an interrupt or hardware exception. A signal is bound to a
particular signal with sigaction(). While the signal handler is running, other signals are blocked from
delivery. Tasks can block the occurence of certain signals with sigprocmask(); if a signal is blocked
when it is raised, its handler routine will be called when the signal becomes unblocked.
Signal handlers are typically defined as:
int sigaction(int signo, const struct sigaction *pAct, struct sigaction *pOact)
A data structure of type struct sigaction holds the handler information. The sigaction call has three
parameters: the signal number to be caught, a pointer to the new handler structure(of type struct sigaction),
and a pointer to the old structure(also of type struct sigaction). If the program does not need the value of the
old handler(*pOact), pass a NULL pointer for *pOact.
To direct a specific signal to a specific task, the kill(int, int) call is made where the first argument the task id
to send signal to, and the second argument is the signal to send to the task .
1. Example:
In the example below, the "sigGenerator" function generates the SIGINT or Ctrl-C signal, and directs the
signal to the "sigCatcher" task. When "sigCatcher" receives the signal, it suspends its normal execution and
branches to a signal hander that it has installed(catchSIGINT function).
/* function prototypes */
void catchSIGINT(int);
void sigCatcher(void);
/* globals */
#define NO_OPTIONS 0
#define ITER1 100
#define LONG_TIME 1000000
#define HIGHPRIORITY 100
#define LOWPRIORITY 101
int ownId;
if((taskId =
taskSpawn("signal",100,0x100,20000,(FUNCPTR)sigCatcher,0,0,0,0,0,0,0,
0,0,0)) == ERROR)
printf("taskSpawn sigCatcher failed\n");
printf("\n+++++++++++++++sigCatcher Exited+++++++++++++++\n");
}
Objectives
The following are the primary objectives of this experiment:
Description
The user may write an interrupt service routine (ISR) and attach it to a particular interrupt using the
intConnect routine provided by VxWorks. What basically happens when an interrupt to the system
occurs, is at the first non-critical code after the interrupt occured, guaranteed to be within musec by
WRS, the ISR is executed. This time span is generally knonw as interrupt latency. Because many
interrupts may occur within a short time of each other and a higher interrupt will block lower
priority interrupts, it is necessary to keep the ISR processing to a minimum. This is the responsibility
of the application writer.
The header files which relate to VxWorks interrupt management are, intLib.h - this is the interrupt
library header file; and ARCH/mc68k/ivMc68k.h. The ISR code does not run in the normal task
context. It has no task control block and all ISR's share a single stack. Because of these differences
there are restrictions to the type of routines that can be used in the ISR.
ISR's should not invoke functions which may cause ``blocking'' of the caller. For example, semTake.
malloc and free cannot be used because they call functions which may cause blocking and thus all
creation and deletion functions are forbidden since they use malloc and free. An ISR must not
perform I/O through the VxWorks I/O system. A call to a device driver may block the system if the
caller needs to wait for the device. However, the VxWorks pipe driver has been designed to permit
writes by interrupt service code.
The best way to print out messages from an ISR is to use the function logMsg or other functions
provided by the library logLib. ISRs should not use floating point instructions since these registers
are not saved on entry to the ISR. If floating point instructions are to be used the registers must be
saved using the functions in fppALib. However, floating point operations are time intensive and
should be avoided in ISRs.
Ideally, an ISR only contains a semGive system call. That is to say, the function of a ISR is to cause
the execution of a task to perform whatever processing is necessary. To improve cooperation
between VxWorks' ISRs and tasks, the best mechanism is semaphores.
1. Example:
SYNOPSIS
STATUS sysBusIntGen
(
int intLevel, /* bus interrupt level to generate */
int vector /* interrupt vector to generate (0-255) */
)
RETURNS
OK, or ERROR if intLevel is out of range or the board cannot generate
a bus interrupt.
interruptCatcher is able to handle this hardware interrupt by installing an interrupt handler,
interruptHandler.
SYNOPSIS
STATUS intConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
DESCRIPTION
This routine connects a specified C routine to a specified interrupt vector. The
address of routine is stored at vector so that routine is called with parameter when the
interrupt occurs. The routine is invoked in supervisor mode at interrupt level. A proper
C environment is established, the necessary registers saved, and the stack set up.
The routine can be any normal C code, except that it must not invoke certain
operating system functions that may block or perform I/O operations.
This routine simply calls intHandlerCreate( ) and intVecSet( ). The address of the
handler returned by intHandlerCreate( ) is what actually goes in the interrupt vector.
RETURNS OK, or ERROR if the interrupt handler cannot be built.
The run time scenario consists of interruptCatcher running and simulating normal processing until
interruptGenerator generates a hardware interrupt. Upon the generation of the interrupt,
interruptCatcher suspends its normal processing and branches to interruptHandler. Once the
interrupt handling code has been executed, control is passed back to interruptCatcher. This activity
is repeated multiple times.
/* function prototypes */
void interruptHandler(int);
void interruptCatcher(void);
/* globals */
#define INTERRUPT_NUM 2
#define INTERRUPT_LEVEL 65
#define ITER1 40
#define LONG_TIME 1000000
#define PRIORITY 100
#define ONE_SECOND 100
if((taskId =
taskSpawn("interruptCatcher",PRIORITY,0x100,20000,(FUNCPTR)interruptCatcher,0,0,0
,0,0,0,0,
0,0,0)) == ERROR)
logMsg("taskSpawn interruptCatcher failed\n",0,0,0,0,0,0);
logMsg("-------------------------------interrupt caught\n",0,0,0,0,0,0);
for (i=0; i < 5; i++)
logMsg("interrupt processing\n",0,0,0,0,0,0);
}
BIBLIOGRAPHY
vxworks_programmers_guide5.5_2 -----------------by wind river USA
vxworks_application_programmers_guide_6.6--- by wind river USA
Real-Time and Embedded guide --------------------by Herman Bruynincks
Programming Embedded System ---------------------by Michael J. Pont
Embedded Systems Architecture --------------------by Tammy Neorgaard
www.wikipedia.com
www.google.com
http://www.xs4all.nl/~borkhuis/vxworks/vxworks.html