Sei sulla pagina 1di 52

Bâtiment EARHART

ZAC Grenoble Air Parc Real-time kernel for PIC18


38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

Pragmatec
Products and services dedicated to real time embedded systems

PICos18
Real time kernel for PIC18

Tutorial & Developer Guide

15th March 2005 – Rev 2.00

1 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

2 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

TO ANY PICos18 USER

Distribution:

PICos18 is free software; you can redistribute it and/or modify it under the terms of the GNU General License
as published by the Free Software Foundation; either version 2, or (at your option) any later version.

PICos18 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License along with PICOS18; see the file
COPYING.txt. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-
1307, USA.

PICos18 is a product of the PRAGMATEC S.A.R.L. company distributed freely under the GPL
licence. This licence is the warranty PICos18 will be always available for free.

PICos18 is a real time kernel based on the OSEK/VDX standard for the automotive industry and is
dedicated to the PIC18 family of Microchip Technology Inc.

This document is the property of PRAGMATEC S.A.R.L. It is a tutorial and a user’s guide to help
people to use the PICos18 operating system. For technical and practical reasons it has been realized
for MPLAB and compiled with the C18 compiler for the PIC18F452 target.

3 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

TABLE DES MATIERES

1. PREAMBLE .........................................................................................................................................................................5
A MULTI- TASK KERNEL ...............................................................................................................................................................5
PICOS18 : A REAL TIME KERNEL FOR PIC18 ..............................................................................................................................6
THE OSEK/VDX STANDARD..................................................................................................................................................6
THE PIC OS18 FEATURES .............................................................................................................................................................7
THE GPL LICENCE .......................................................................................................................................................................8
THE MICROCHIP COMPILER TOOLSUITE ......................................................................................................................................9
THE PRAGMATEC COMPANY......................................................................................................................................................10
2. PICOS18 : TUTORIAL ....................................................................................................................................................11
DEVELOPMENT TOOLS ...............................................................................................................................................................11
THE FIRST TASK ..........................................................................................................................................................................11
THE PRE-EMPTION ......................................................................................................................................................................11
A MULTI- TASK APPLICATION .....................................................................................................................................................11
INTERRUPTS ................................................................................................................................................................................11
USING DRIVERS ..........................................................................................................................................................................12
APPLICATION EXAMPLE .............................................................................................................................................................12
3. DEVELOPMENT TOOLS...............................................................................................................................................13

4. THE FIRST TASK ............................................................................................................................................................18

5. THE PREEMPTION .........................................................................................................................................................24

6. A MULTI-TASK APPLICATION..................................................................................................................................31

7. THE INTERRUPTS ..........................................................................................................................................................35

8. USING DRIVERS ..............................................................................................................................................................42

9. APPLICATION EXAMPLE............................................................................................................................................47

10. BOOK AND INTERNET REFERENCES................................................................................................................52

4 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

1. Preamble
A multi-task kernel

In the embedded world we hear so many people talking about real time kernels without knowing
exactly what it is. Actually to understand easily what a multi-task real time kernel is, we need to talk
about 3 different aspects:

A kernel...

A kernel is a set of functionalities, regroup under the term SERVICES for most of them. In the case of
Linux for instance the kernel is composed of the task manager, the hardware access manager, the
file system manager... The shell is a program and then is not included on the kernel itself. The malloc
function that reserve memory dynamically calls a kernel service because the kernel is in charge of the
resource management, and memory is a resource.
One of the most famous functionality of the kernel (without being a service) is the SCHEDULER in
charge of the task processing in parallel.

... multi-task ...

So the kernel controls the resources and lets the applications use them safety and efficiently through
a set of SERVICES. Because the kernel warranty the stability of the system many independent
applications can be ready to run, when the kernel decide it. This MULTI-PROGRAMMING capability
let many developers create its own program without thinking about what is developed in the other
tasks of the system. Each developer has the feeling to be alone to develop.
If the kernel can do it, it’s also possible to make different programs running in parallel with the feeling
each task is alone (but is slower than if the task will be really alone).
When the kernel is a perfect task manager (the task scheduling is the job of the kernel) we say the
kernel is a MULTI-TASK AND PREEMPTIVE kernel. If not, each task needs to manage itself this
process scheduling by calling the kernel scheduler some time to time. We say the kernel is a MULTI-
TASK AND COOPERATIVE kernel.

PICos18 is a multi-task and preemptive kernel.

... in real time

The multi-task kernel can just manage the task parallelism by splitting the global time into small time
slices for each task present in memory. The problem is that each task doesn’t need the same CPU
availability and some task running very seldom needs all the CPU capability when they are running.
The tasks then have different PRIORITIES and need to start immediately if necessary. Rather than
warranty a null time (that is not possible), the kernel has to warranty a constant LATENCY TIME: that
is called the DETERMINISM.

The latency time of PICos18 is 50 us.

5 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
PICos18 : a real time kernel for PIC18

With the old PIC16 family it was not possible to create such a kernel with PICmicros. Indeed the main
feature of a multi-task kernel is to make run different tasks together that means we need to control
the function call stack [cf datasheet of the PIC18F452 DS39564A, page 37, chapter 4.2 « Return
Address Stack »]. Imagine what would append if all the task presents in the system share the same
stack: the kernel would stop the current task to activate another one and at the next RETURN
instruction the address pointer will jump in the first task where the previous task stopped!

The PIC18 can manage the hardware stack dedicated to the function calls (thanks to the PUSH and
POP instructions and the free motion of the stack pointer), so it is possible now to put the stack in a
proper state before jumping to the next task.

It was just needed then to define the list of kernel services and how the kernel manages the tasks
and the resources. Rather than designing the kernel as a proprietary solution, the Pragmatec
company decided to base the kernel on a standard: the OSEK/VDX standard.

The OSEK/VDX standard

PICos18 is based on the OSEK-VDX standard (www.osek-vdx.org).


OSEK-VDX is a wide project from the automotive industry supported by the most French and
German car manufacturers. The project goal is to define a standard for the control and process of
embedded architectures in modern vehicles. The actual vehicles can use up to 30 calculators (motor
control, onboard computer, door controller, ABS, ESP…) that transfer data through a global network
(CAN, VAN, LIN, MOST buses…).

Describe the way these calculators are working all together is:

Ø Define the same development platform, same development process and same
validation process;
Ø Specify a common language for manufacturers, subcontractors et third parties;
Ø To use a common architecture for the development, validation and intergation
sequences in a project.

The term OSEK means « Offene Systeme und deren Schnittstellen für die Elektronik im
Kraftfahrzeug » (Open system and related interfaces for embedded automotive electronic »). The
term VDX means « Vehicle Distributed eXecutive ».

The OSEK operating system standard is included now in VDX.

Nowadays this standard is used in the automotive and the robotic industries and defines the kernel
features around 3 axes: Operating System (OS), Communication (COM) and Network Management
(NM). At this moment only the OS specifications has been implemented in PICos18.

The OSEK-VDX standard is really suitable for a PIC18 kernel. A PICos18 application is composed
of many tasks symbolized by circles on the following picture.

The major feature is that only one task can have access to the PIC18 to run (more precisely to the
processor, to the RAM memory and to the stack).

6 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

In order to decide which task is allowed to run at a certain time the PICos18 kernel inspects all the
task of the application and chooses the task in a ready
state with the highest priority.

After being activated a task can wait for a specific event


and then falls asleep temporarily to let another task with
a smallest priority to run. When the event will be
detected the kernel will wake up the task previously put
in a waiting state.

The different states of a PICos18 task are: READY,


SUSPENDED, WAITING and RUNNING.

The PICos18 features

The PICos18 kernel is composed of different layers:

ü The kernel core (Init + Scheduler + Task Manager) in charge of managing the tasks present in
the application and so decide the next task to activate function to the state and the priority oif the
tasks.
ü The alarm and counter manager (Alarm Manager). Attached to the kernel core it uses the
TIMER0 interrupt in order to update periodically the alarms and counters used by the application.
ü The Hook routines are partially included in the kernel core and let the developer to jump into
additional land personal routines. Doing so it is possible to take the control of the kernel process
during a short time to debug the application for instance.
ü The task manager (Process Manager) is a set of kernel services which proposes the necessary
functions to manage the task state (to change the state of a task, chain two tasks, activate a
task...).
ü The event manager (Event Manager) is a set of kernel services which proposes the necessary
function to manage the events waited or posted by/to a task (to wait for an event, to post an
event, to clear an event, to read the set of events received..).
ü The interrupt manager (INT Manager) is a set of kernel services to enable or disable the
interrupts (high and low interrupts).

PICos18 is a modular kernel that means the access to the PIC18 peripherals (drivers, file system
manager, etc.) are written as a task independent of the kernel.

Then it is possible for you to customize your PICos18 application by using different software layers
(different tasks and libraries like those proposed by Pragmatec) to obtain something specific to your
needs and also fast and easy to design.

7 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
The GPL licence

The PICos18 kernel is distributed in open-source under the GPL licence (General Public Licence). It
means all of the sources of the kernel written in C code and assembling language is always available
without any limitation. It means also it is totally free and you don’t have to pay for any royalties to the
authors.

At the top of each PICos18 source file you will find the same text with a GPL banner. If you need to
modify or to use one of the PICos18 file you have to keep this banner or eventually to complete it:

/**********************************************************************/
/* */
/* File name: filename of the source file */
/* */
/* Since: date of creation */
/* */
/* Version: 2.xx (current release of PICos18) */
/* */
/* Author: Designed by Pragmatec S.A.R.L. www.pragmatec.net */
/* MONTAGNE Xavier [XM] xavier.montagne@pragmatec.net */
/* LASTNAME Firstname [xx] */
/* */
/* Purpose: file content explanation */
/* */
/* The GPL licence from Boston (USA)(cf « Free Software Foundation) */
/* Distribution: This file is part of PICos18. */
/* PICos18 is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2, or (at your option) */
/* any later version. */
/* */
/* PICos18 is distributed in the hope that it will be */
/* useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with gpsim; see the file */
/* COPYING.txt. If not, write to the Free Software */
/* Foundation, 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/* > A special exception to the GPL can be applied should */
/* you wish to distribute a combined work that includes */
/* PICos18, without being obliged to provide the source */
/* code for any proprietary components. */
/* */
/* History: */
/* 2004/09/20 [XM] Create this file. */
/* */
/**********************************************************************/

The GPL licence warranty the PICos18 sources can be get freely without any restriction or patent of
any company or organisation. Moreover the PRAGMATEC company which has created PICos18
accepts to maintain the kernel and to update as often as possible always with the respect to the GPL
licence. Of course anybody can modify the PICos18 sources for its own needs or can participate to
the kernel evolution.

8 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
A special paragraph has been added to the GPL licence in then banner. This paragraph written in
English specify it is possible to add any files to PICos18 without being forced to apply the GPL
licence to these new files, it means that you don’t have to provide your own sources. But keep in
mind you have to provide the kernel sources itself because it is still protected by the GPL licence.

The Microchip compiler toolsuite

You’re going to program your first application in C with PICos18. The kernel itself is composed of C
files and a file in assembling language (kernel.asm).

These different files will be compiled and link all together in order to get a unique file: the HEX file that
can be loaded into your PIC18.

The Microchip compiler toolsuite is composed of 3 elements:

Ø The MPASM assembler to transform the ASM files into O files


Ø The MCC18 compiler to transform C files into O files
Ø The MPLINK linker to link all the O files to a unique HEX file

The file called “linker script” (File.lkr above) is very important to generate the HEX file. Indeed the O
files can not place the code and variables into memory. For instance the main() function has been
translated into assembling instructions that the PIC18 can interprete but is not located at a specific
place.

9 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

It is the goal of the linker script to specify the position of the variables and code into memory (into
RAM and RAM). PICos18 is provided with some linker script for the most famous PIC of the PIC18
family. You can adapt them to a specific application or port one file to manage a new PIC18.

There are different other files generated after the compilation process and the link of the project
(*.map, *.lst, *.cod). Have a look at the Microchip documentation for more detail about these files.

This tutorial has been written to help the users to understand and use properly the PICos18 real-time
kernel. For technical reasons it has been done with MPLAB and compiled with the C18 compiler in
free version for a PIC18F452 target.

This tutorial has been tested with the Microsoft Windows 98/NT/2K/XP and the MPLAB v7.00
development environment and the C18 v2.40 compiler from Microchip.

The Microchip toolsuite can be download for free from the Microchip Technology Inc. web site:
www.microchip.com.

The Pragmatec company

This tutorial is the property of PRAGMATEC S.A.R.L.

PICos18 is a product of the PRAGMATEC company an dis distributed freely under the GPL licence.

The PRAGMATEC company develops and proposes PICos18 extensions to let the developer design
their own application based on free software layers (RS232 driver, CAN bus driver to transfer data
with the PIC18F458 CAN bus peripheral, USB, I2C, etc.).

PRAGMATEC provides also a set of additional software and hardware tools to use with PICos18 and
the PIC18 to let the user debug and control the application from a Windows application, program the
PIC18, convert data on a CAN bus…

10 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

2. PICOS18 : Tutorial
The goal of this tutorial is to show how it is simple to program with PICos18. The OSEK standard
defines the main features of the kernel itself and defines also the interface between the kernel and
the application.
Follow this tutorial to learn how to configure MPLAB®, to use PICos18 and to program multi-task
applications for PIC18.

Development tools

In this first chapter you will create an entire project based on PICos18. To do so you will use the
MPLAB® development environment from Microchip and the C18 compiler.

The first task

Now you have successfully compiled the PICos18 project under MPLAB® it's time to create and
simulate your first task. You will learn how to write a such task and what is the system tick at 1ms.

The pre-emption

You've just designed an application with only one task, but this application is not really useful! By
adding a new task you will discover all the mechanisms of the pre-emption from one task to the
others.

A multi-task application

This chapter introduces the synchro mechanisms between the tasks in PICos18. A third task comes
to complete the application and post an event to another task in order to activate it. We will learn to
use the events posted from a task or to share the resources.

Interrupts

By using the PIC18 uC you probably expect to use the internal peripherals. To do it you have to
consider the interrupts.
You will learn how works interrupts under PICos18 and how to write your own interrupt routines.

11 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

Using drivers

You want to communicate through the serial port or the CAN interface? Now you know how to write
interrupts and tasks and you know how to manage alarms and events it will be easy to use and to
write a real driver for PICos18.

Application example

The tutorial is terminated with this last chapter about PICos18 development. The sources of this
typical application are located in the Project/Tutorial directory of PICos18. This example is here to
show you how easy it is to develop a complex application with PICos18.

12 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

3. Development tools
In this first chapter you will create an entire project based on PICos18. To do so you will use the
MPLAB® development environment from Microchip and the C18 compiler.

> Project sources


Before executing MPLAB®, download here the sources of PICos18, including kernel sources and the
tutorial's application. Here is the meaning of each file:

13 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

This directory contains all the PICos18 kernel headers. The headers dedicated to
the application and drivers are located in the appropriate directories (under
Include Project). One header exists for each sub-system of the kernel: alarms, events,
interruption and process. The file device.h contains the generic definition of the
kernel like the values returned by the PICos18 services (the API).
You will found here all the kernel sources. The C files are dedicated to a group of
kernel services (the API), and the kernel.asm file, the only one coded in
assembling language, stores all the basic features of the kernel : scheduler
algorithms, task priority and order and error management.
The sources are provided for your information or if you wish to modify them for a
specific need. TO let you use PICos18 more easily we have added the PICos18
Kernel
library: picos18.lib.
Moreover the startup codes (runtime) provided by Microchip are not well adapted
to PICos18, then we have chosen to modify them. The new startup codes are
provided with PICos18 like .o files (PICos18iz.o for example).
You don't have to take care of the picos18.lib library and the startup code
because they are automatically included in your PICos18 project!
When you build your application with PICos18 you write your application in a C
language. Then you have to compile your application with C18 (to build each .o
file corresponding to one .c file) and to link them thanks to MPLINK. The way you
are linking the .o files can be set with linker scripts, the .lkr files included in this
Linker
directory. For each major microcontroller of the PIC18 family a LKR script is
present under this directory to avoid to let you manage by yourself this complex
part of the build process. For each new PIC18 manage by PICos18 a new script
will be added to this directory in the future.
This directory contains all the files dedicated to a basic project with PICos18. As
you can notice there are very few files: the main.c file which is the first file of your
application executed by PICos18, the int.c file that contains all the interrupt and
Project/MyApp
fast interrupt routines, the taskdesc.c file which describes precisely all the
features of your application (alarms, counters, task features, ...), and a C file for
each task of the application.
The tutorial is based on a typical PICos18 application. Through the different
chapters you will discover how to program with PICos18 and to build your own
Project/Tutorial application. The files presents under this directory are those of the final
application when the tutorial is finished. This brings something more practical to
this tutorial with a base composed by source code.

Unzip the PICos18_v2_xx.zip file directly under C:\. All the tutorial chapters assume the PICos18
directory is located under C:\. If not modify by yourself what is necessary.

14 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

At this moment the tutorial is validated under MPLAB® / Windows™ development environment
(MPLAB® v6.62 and v7.00 with C18 compiler from Microchip release 2.40. You can download the
free versions of these tools from the Microchip web site. The free version of C18 is the same as the
full version but without the optimization management. In fact you have to disable such options with
PICos18, some are not well adapted for a multi-task application.

Then the free version of C18 suits well for PICos18 and PIC18, le assembling code generated is very
good compared to other commercial compiler.

The target is a PIC18F452 (don't forget to select it under MPLAB®).

> C18 compiler

Start by installing MPLAB® and the Microchip® C


compiler for PIC18 family. By default we assume the
path would be "C:\mcc18\".

Under MPLAB® click on "Project / Set Language Tool


Location..." and set up MPASM, MPLAB C18 and
MPLINK location.

> Project creation

Then create a new project under MPLAB®. Click on


"Project / New..." et name the project with a length
minus than 8 characters. I've chosen "picos.pjt" for
the next. Take care to have the filename path without
any space character!

Then click on "Project / Select Language Toolsuite..."


and select the "Microchip C18 Toolsuite".

15 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> Project options


Click on "Project / Build Options..." and set
the Include and Library directories for C18
and for the compiler. Be careful: you
cannot place a space character between
the directory paths.

Then click on the "MPLAB® C18" sheet


and check the "Use alternate settings"
options and add the "-On" option in the
command line.

This force the compiler to disable the bank


selection optimization, not efficient with
PICos18.

> Adding files

Then right click on the project window to add what follows :

- int.c, main.c, tascdesc.c et tsk_task0.c presents under


MyApp
- define.h present under MyApp
- 18f452.lkr present under the Linker directory

The picos18.lib and PICos18iz.o files are automatically


included by the compiler tool suite.

> Compiling project

16 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
Finally compile the project with F10 button.

The compile compiles all the files of the


application one by one. It won't build any file of
the kernel itself, because the PICos18 library is
added to your project.

Then the linker put together all the .o file to build


the files necessary to the simulation and the
PIC18 programming sequence.

> Disable the Watchdog

The MPLAB® simulation is based on the settings


of the PIC18 config bits.

Setup your simulation as described on the


screenshot.
The watchdog must be disabled.

> Project simulation


Finalement lancez la simulation en cliquant sur "Debugger / Select Tool / MPLAB® SIM", puis F9
(Run). Attendez quelques secondes avant d'appuyez sur F5 (Stop).

Start the simulation by selecting “Debugger /


Select Tool / MPLAB® SIM” then F9 (Run). Wait
for few seconds and stop with the F5 button
(Stop).

The simulation is stopped on the "while(1)"


instruction of the task 1. But this instruction does
not block the PIC18 by an infinite loop, because
the kernel can be called if necessary: try few
more times to stop in one part of the kernel.

The kernel source in which you're stopped will be


displayed, but the kernel sources have never
been added to your project!
Actually you have unzipped the PICos18 sources
under C:\ and the library has been build
according to this path...

17 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

4. The first task


Now you have successfully compiled the PICos18 project under MPLAB® it's time to create and
simulate your first task. You will learn how to write a such task and what is the system tick at 1ms.

> Requirements

First of all it is necessary to create a new project under MPLAB® from the PICos18 sources.

Then you have to install the Microchip C18 compiler and to setup the software (previous chapter).

> State of one task

In our application there is only one task defined in the "tsk_led.c" file :

TASK(TASK0)
{
while(1);
}

We understand easily the goal of the state is to create a infinite loop.


Under MPLAB® place a breakpoint on the line with the "while(1);" statement then start the simulation
(F9).

You can notice the simulation stops on the breakpoint. But how the kernel knows the presence of the
task, to execute its code up to the infinite loop ... without being fully blocked by this instruction?

Actually the task has been declared to the kernel in the "tascdesc.c" file.

/**********************************************************************
* ----------------------------- task 0 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task0 = {
TASK0_PRIO, /* prioinit from 0 to 15 */
stack0, /* stack address (16 bits) */
TASK0, /* start address (16 bits) */
READY, /* state at init phase */
TASK0_ID, /* id_tsk from 1 to 15 */
sizeof(stack0) /* stack size (16 bits) */
};

18 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
On the bold line you can specify the state of the task at the start time. In fact when a task exists in the
project (it has been compiled by the compiler) it is not necessarily enabled by the kernel.

With PICos18, as specified by the OSEK standard, a task has 4 possible states:

SUSPENDED: the task is present in


the application but is not taken into
account by the kernel.

READY: the task is available to be


executed by the kernel then is taken
into account by the scheduler.

WAITING: the task is sleeping and so


is temporarily SUSPENDED and will
be READY as soon as an event
occurs.

RUNNING: : there is only one task


running at a certain time : this is the
task in a REAYD state with the highest
priority.

Speaking of our application the task is in a READY state. While in this state the kernel will be allowed
to execute it...
Replace READY by SUSPENDED in the taskdesc.c file then rebuild and restart the simulation: you
can notice the simulation does not stop anymore on the breakpoint.

> Task description


Like the state of the task a lot of features are described in the tascdesc.c file. Actually everything
related to your application are located in this file as an example: the ID of the task, its priority, its
software stack, the alarms used by the project, ...
We find at first the alarms of the application:

AlarmObject Alarm_list[] =
{
/*******************************************************************
* -------------------------- First task ---------------------------
*******************************************************************/
{
OFF, /* State */
0, /* AlarmValue */
0, /* Cycle */
&Counter_kernel, /* ptrCounter */
TASK0_ID, /* TaskID2Activate */
ALARM_EVENT, /* EventToPost */
0 /* CallBack */
},
};

19 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
This table is the list of the alarms, each one is represented by a structure. An alarm is a kind of
TIMER object managed by software by the kernel. In fact PICos18 has a timer reference of 1 ms,
built from hardware and software drivers. So it is possible to create a software timer based on this 1
ms tick: the alarms.

An alarm is connected to a counter (here Counter_kernel which is the 1ms reference) and a task
(with the TASK0_ID identifier). When the alarm reaches a certain value it can post an event to this
task (ALARM_EVENT in our example) or call a C function (CallBack mechanism).

We find then the list of resources of the application:

/**********************************************************************
* --------------------- COUNTER & ALARM DEFINITION -------------------
**********************************************************************/
Resource Resource_list[] =
{
{
10, /* priority */
0, /* Task prio */
0, /* lock */
}
};

A resource is another object managed by the kernel. A resource is in general a peripheral shared by
different tasks, for instance a 8 bits port of the PIC18. It has its own priority (priority field) and can be
locked (lock field) by a task (Task prio field). Then when a task want to grant access to the 8 bits port
it can have a secure access through the resource and lock the other tasks to an access during a
short time. The resource management will be introduced in the multi-task chapter.

Now we find the software stack list:

There are 2 kinds of variables: the static ones and the automatic ones...but to be more
understandable it should be said there are global variables and local variables, even if it is not totally
correct. The global variables (it means the variable declared out a C function) are placed in RAM at
an absolute address, an address that never change.

The local variables (declared in a C function) are compiled by C18 so that they are stored in a
specific memory buffer called the software stack. A software stack is a dynamic memory area,
something alive from a certain point of view. When you enter in a C function the PIC18 starts to push
the local variables and when it leaves this C function it pops (removes) the area reserved to local
variables then freeing memory. This mechanism lets you spare a lot of memory when you need a lot
of C function, and the additional code necessary is not significant.

PICos18 is compliant with the C18 software stack management. Each task has its own software stack
so that each task of the application can work as alone in its own private space without disturbing the
other processing. Moreover PICos18 has an automatic stack overflow detection that occurs when a
software stack becomes bigger than expected (kernelpanic flag).

20 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
/**********************************************************************
* ----------------------- TASK & STACK DEFINITION --------------------
**********************************************************************/
#define DEFAULT_STACK_SIZE 128
DeclareTask(TASK0);

volatile unsigned char stack0[DEFAULT_STACK_SIZE];

Every time you add a task to your application do not forget to add a software stack by copying the line
above and changing the name of the stack (by stack1 for example).

• A minimum software stack is 64.

• A maximum software stack is 256.

• A typical stack size is 128.

Only the 3 above values are correct. Do not try to setup a different value, the C18 compiler cannot
manage a such value. Moreover a software stack has to be always in a same bank and not on 2
pieces of bank. If you don’t know let all the stack size to 128.

Then we find the task list of the application:

/**********************************************************************
* ----------------------------- task 0 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task0 = {
TASK0_PRIO, /* prioinit from 0 to 15 */
stack0, /* stack address (16 bits) */
TASK0, /* start address (16 bits) */
READY, /* state at init phase */
TASK0_ID, /* id_tsk from 1 to 15 */
sizeof(stack0) /* stack size (16 bits) */
};

You have already seen this task descriptor but here is some additional details:

• prioinit: it's the task priority from 1 to 15 included. 1 is the lowest priority, 15 the highest. The
priority 0 is reserved to the kernel and should not be used for your application.

• stack address: is the software stack of the task. Each task has its own software stack where
are stored the local variables when the task is executed but also all the PIC18 context
(registers, hardware stack) when the task is not executed.

• start address: it is the task name it means the function name of the task entry. The compiler
translates it into an address used by the kernel to start the task the first time.

• state init: is the initial state of the task. In our application it is READY that means the task will
be started as soon as the kernel is finished to boot.
• stack size: is the software stack size. The kernel uses this value to control there is no
software stack overflow trashing another one.

21 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> 1ms interrupt

Even if your application does not need to manage interrupts you will probably need the internal
software timer. To do so the "int.c" file has some definitions and one is a kind of software IT vector
table.

In fact the function is very light and lets you manage IT without reading first the heavy PIC18
datasheet :

#pragma code _INTERRUPT_VECTORL = 0x003000


#pragma interruptlow InterruptVectorL save=section(".tmpdata"), PROD
void InterruptVectorL(void)
{
EnterISR();

if (INTCONbits.TMR0IF == 1)
AddOneTick();
/*Here is the next interrupts you want to manage */
/*if (INTCONbits.RBIF == 1) */
/* MyOwnISR(); */

LeaveISR();
}
#pragma code

As you can imagine when the TIMER0 overflow occurs (TMR0IF flag) the AddOneTick function is
called to add 1 ms to every alarms present in the application. When an alarm reaches a critical value
it sends some actions to the dedicated task with the kernel help, the only one entity to be able to
activate a task.

You can notice then the kernel is always enable and that no task can stop it even with an infinite
"while(1)" loop.

To verify it setup your simulation to 40MHZ (Debugger/Settings..), place a breakpoint face to the
AddOneTick() call, and display the MPLAB stopwatch (Debbuger/Stopwatch) :

22 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> Application start

Finally your application has a file called "main.c" needed by the compiler.

According to the OSEK standard this main file is not a part of the OS but from the application itself,
and the job of this main file is to start the kernel (because it is possible to start and to stop the kernel
from the main file).

In the main file you will find an Init() function that lets you setup your application frequency without
open the PIC18 datasheet :

void Init(void)
{
FSR0H = 0;
FSR0L = 0;

/* User setting : actual PIC frequency */


Tmr0.lt = _40MHZ;

/* Timer OFF - Enabled by Kernel */


T0CON = 0x08;
TMR0H = Tmr0.bt[1];
TMR0L = Tmr0.bt[0];
}

The bold line is necessary to setup the INTERNAL frequency of the PIC28 chip. Indeed the PIC18
has got a PLL by 4 you can enable or not. A typical PIC18 application should need an external
10MHz crystal with two 15 pF capacitors and with the PLL enable in order to run to 40 MHz.
The internal pipeline of the processor is at level 4, then the worst case of the PIC18 is 10 MIPS, it
means 10 millions of instructions par seconds (see the PIC18 datasheet). So the PIC18 is a small 8
bits microcontroller cheap and very powerful with a lot of peripheral for your applications.

If you wish to use a different frequency have a look at the "define.h" file to get the available
frequencies.

23 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

5. The preemption

You've just designed an application with only one task, but this application is not really useful! By
adding a new task you will discover all the mechanisms of the preemption from one task to the
others. Furthermore we'll manipulate alarms to understand their functionalities and how to use them.

> Periodic wake up of a task

It is still difficult to understand what is the interest of such a kernel when you have only one task... to
do an infinite loop!

So we’re going to start to bring a little bit more interesting our task by modifying the code to make a
LED blinking at a certain frequency.
Modify the task code as follows:

TASK(TASK0)
{
TRISBbits.TRISB4 = 0;
LATBbits.LATB4 = 0;

SetRelAlarm(ALARM_TSK0, 1000, 200);

while(1)
{
WaitEvent(ALARM_EVENT);
ClearEvent(ALARM_EVENT);

LATBbits.LATB4 = ~LATBbits.LATB4;
}
}

Our task is composed here by 2 phases: the first one has a "while(1)" which correspond to an init
phase and a second one that is in the while core.

The 2 first instructions let you manipulate the IO ports of the PIC18 chip. The key word "TRISx" is
used to setup a port as an input or an output and the key word "TRISxbits" is a structure to let you
modify the state of a port bit.

Here we have a RB4 port as an output (the "0", a "1" meaning "input") and the output value to "0"
(key word LATxbits).
Then the SetRelAlarm function is used to program the alarm of the task. In the previous chapter we
have seen what is an alarm: a TIMER object based on a software tick at 1ms. In the "tascdesc.c" file
the alarm ID is 0 (ALARM_TSK0) and has been connected to the task TASK0:

24 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

AlarmObject Alarm_list[] =
{
/*******************************************************************
* -------------------------- First task ---------------------------
*******************************************************************/
{
OFF, /* State */
0, /* AlarmValue */
0, /* Cycle */
&Counter_kernel, /* ptrCounter */
TASK0_ID, /* TaskID2Activate */
ALARM_EVENT, /* EventToPost */
0 /* CallBack */
},
};

The SetRelAlarm has 3 important fields:

• Alarm ID : alarm index in the table Alarm_list


• TIMER 1: millisecond number before the first time the event is posted
• TIMER 2: millisecond number between 2 consecutive events
In our application it means the alarm 0 waits for 1000ms before posting the event ALARM_EVENT
then will post periodically the event every 200 ms.

Once the alarm is programmed the task can go on. In the "while(1)" the first function called is the
WaitEvent function that permits to put to sleep the task until the event ALARM_EVENT is posted.

You can put to sleep your task on any event but keep in mind the event must be defined as a power
of 2 in the "define.h" file. The allowed values are : 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02 et 0x01.

> Task 0 simulation


To verify we have a blinking task with a period of 200ms it is possible to simulate the application by
placing a breakpoint face to the line that toggles the RB4 bits:

25 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
Moreover you can spy the PIC18 peripherals or the PICos18 global variables, particularly the
"global_counter" variable which is decimal counter of the milliseconds occurred. To get a decimal
value at screen click with the right button of the mouse on the variable and choose "Dec".

Start many time your simulation (F9) to see the PORTB toggle between 0x00 and 0x10 and the
value of global_counter incremented by 200. The variable starts from the value 1001 (the kernel
needs 1ms to boot so you get the value 1001 instead of the value expected of 1000).

That means the RB4 port is ON after 1 second then toggles periodically every 200ms.

Modify now the last two parameters of the SetRelAlarm function to see what appends. For instance
put a 0 in the last parameter to see RB4 stay at 1 and you never go back in the task.

Have a look at the PDF related to the PICos18 API to learn much more about these functions.

> Creating a second task


Now you have design a periodic task you’re going to create a second one and synchronize the both
of them.
1) Under MPLAB® save the "tsk_task0.c" file to "tsk_task1.c"
2) Modify the references of the new task in the taskdesc.c file:

#define DEFAULT_STACK_SIZE 128


DeclareTask(TASK0);
DeclareTask(TASK1);

volatile unsigned char stack0[DEFAULT_STACK_SIZE];


volatile unsigned char stack1[DEFAULT_STACK_SIZE];

/**********************************************************************
* ---------------------- TASK DESCRIPTOR SECTION ---------------------
**********************************************************************/
#pragma romdata DESC_ROM
const rom unsigned int descromarea;
/**********************************************************************
* ----------------------------- task 0 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task0 = {
TASK0_PRIO, /* prioinit from 0 to 15 */
stack0, /* stack address (16 bits) */
TASK0, /* start address (16 bits) */
READY, /* state at init phase */
TASK0_ID, /* id_tsk from 1 to 15 */
sizeof(stack0) /* stack size (16 bits) */
};
/**********************************************************************
* ----------------------------- task 1 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task1 = {
TASK1_PRIO, /* prioinit from 0 to 15 */
stack1, /* stack address (16 bits) */
TASK1, /* start address (16 bits) */
READY, /* state at init phase */
TASK1_ID, /* id_tsk from 1 to 15 */
sizeof(stack1) /* stack size (16 bits) */
};

26 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
3) Then change the function core of the task 1:
unsigned char hour, min, sec;

/**********************************************************************
* ------------------------------ TASK1 -------------------------------
*
* Second task of the tutorial.
*
**********************************************************************/
TASK(TASK1)
{
hour = min = sec = 0;

while(1)
{
WaitEvent(TASK1_EVENT);
ClearEvent(TASK1_EVENT);

sec++;
if (sec == 60)
{
sec = 0;
min++;
if (min == 60)
{
min = 0;
hour++;
}
}
}
}

As you probably guessed this task manages a kind of software swatch with hour/minute/second:
every time the task wakes up the sec variable is incremented by 1and the hour and min variables are
updated if necessary.

4) So the task needs to be called every 1000ms. Modify the task 0 to let it post an event every
second to our new task:

SetRelAlarm(ALARM_TSK0, 1000, 1000);

while(1)
{
WaitEvent(ALARM_EVENT);
ClearEvent(ALARM_EVENT);

LATBbits.LATB4 = ~LATBbits.LATB4;
SetEvent(TASK1_ID, TASK1_EVENT);
}

27 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
5) Now we need to update the symbols present in the "define.h" file :
/***********************************************************************
* ----------------------------- Events --------------------------------
**********************************************************************/
#define ALARM_EVENT 0x80
#define TASK1_EVENT 0x10

/***********************************************************************
* ----------------------------- Task ID -------------------------------
**********************************************************************/
#define TASK0_ID 1
#define TASK1_ID 2

#define TASK0_PRIO 7
#define TASK1_PRIO 6

6) Finally you can add the new file to the project ("Project/Add files to Project...").

Rebuild the project (F10).

> Task 1 simulation

In order to verify the hour, min and sec variables are updated properly every second start the
simulation with a breakpoint:

A simulation of 1 second needs a lot of time for MPLAB® so if you wish to test the min and hour
variables up to 60 you need to modify the alarm ALARM_TASK0 to go faster just for the simulation of
course.

28 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> Preemption

Now your application is composed of 2 tasks, it is now a multi-task application. But it does not mean
the both tasks are running at the same time because it is not possible for the PIC18 processor that
can execute only one instruction at a time. At the maximum we can say the tasks are running in
parallel it means one after the other function to a set of rules described in the kernel core... like the
priorities.

To understand properly the preemption, the multi-task and the real-time terms add some breakpoints
and start the simulation:

The pointer runs through the breakpoints in this order:

• WaitEvent in the task 0


• SetEvent in the task 0
• WaitEvent in the task 0
• ClearEvent in the task 1

Actually the task 0 has a priority higher than the task 1 then when it post an event to the task 1 it
continue to run until it falls asleep by the WaitEvent function. Then the task 1 is free to run and the
pointer stops on the ClearEvent breakpoint.

Now modify the priority of the task 1 in the "define.h" file to put it as the task with the highest priority:

/***********************************************************************
* ----------------------------- Task ID -------------------------------
**********************************************************************/
#define TASK0_ID 1
#define TASK1_ID 2

#define TASK0_PRIO 7
#define TASK1_PRIO 10

29 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
Rebuild and start the simulation: now the new breakpoint order is what follows :

• WaitEvent in the task 0


• SetEvent in the task 0
• ClearEvent in the task 1
• WaitEvent in the task 0

Because the task 1 is now the task with the highest priority, when an event occurs the current task is
stopped immediately to let the task with the highest priority to run: it can be said there is preemption
(that means to hang).

The preemption is one of the most major features of the multi-task and real-time kernels. Indeed with
a non preemptive kernel the task 0 will continue to run until it falls asleep by itself to let the task 1 to
run. We say such a kernel is a cooperative kernel that means the current task has the responsibility
to decide when to give back hand to the rest of the application. The SALVO kernel which manages
also the PIC18 is a good example of a cooperative kernel.
Of course in our application it is not very important because it seams to run by the same way finally.
Anyway when we have to manage complex protocol or when the application is composed by a lot of
task a preemptive kernel is much safer for the application whichever the code size.

But the preemption is not a sufficient reason to say that a kernel is a real-time kernel or not. To do it
we have to talk about the determinism, it means the fact a kernel is able to warranty the time
necessary to switch from one task to another one is a constant. With PICos18 the time is 50 µs then
each time the task 0 sends an event to the task 1 the time to switch from task 1 to task 0 is 50 µs.
PICos18 is a preemptive, a multi-task and a real-time kernel that does what is necessary to switch to
a task with a highest priority immediately if an event occurs and needs only 50 µs to do it, whatever
the application is composed. You can understand now that the infinite "while(1);" loop in the task with
the highest priority will block the rest of the application. Try to do it with the simulator!

30 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

6. A multi-task application

This chapter introduces the synchro mechanisms between the tasks in PICos18. A third task comes
to complete the application and post an event to another task in order to activate it. We will learn to
use the events posted from a task or an alarm.

> Building an idle task


In the previous chapters we have designed an application composed by 2 tasks that manage a kind
of software swatch with 3 variables: hour, min and sec.

The PICos18 multi-task does not only let you split your project into separated task to reduce the
complexity of the application but also to code different independent sub-system. For instance we’re
going to create 2 additional tasks to inspect the RB0 and RB1 port permanently like 2 push buttons.

A push button is not a typical signal that goes from the 0 state
to the 1 state and stay at 1 up to the next change.

When you press a push button (something mechanic) there


are some rebounds during few milliseconds before getting a
stable signal at 1. Then we have to write a code that wait for
this stable state before reading the push button state.

First of all we start to create a first task that inspects the RB0 port where is located the BNT0 push
button.

1) Under MPLAB® save the "tsk_task0.c" file to "tsk_task2.c"


2) Modify the definition related to the new task in the taskdesc.c file:

#define DEFAULT_STACK_SIZE 128


DeclareTask(TASK0);
DeclareTask(TASK1);
DeclareTask(TASK2);

volatile unsigned char stack0[DEFAULT_STACK_SIZE];


volatile unsigned char stack1[DEFAULT_STACK_SIZE];
volatile unsigned char stack2[DEFAULT_STACK_SIZE];

/**********************************************************************
* ---------------------- TASK DESCRIPTOR SECTION ---------------------
**********************************************************************/
#pragma romdata DESC_ROM
...

31 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
/**********************************************************************
* ----------------------------- task 1 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task2 = {
TASK2_PRIO, /* prioinit from 0 to 15 */
stack2, /* stack address (16 bits) */
TASK2, /* start address (16 bits) */
READY, /* state at init phase */
TASK2_ID, /* id_tsk from 1 to 15 */
sizeof(stack2) /* stack size (16 bits) */
};

3) Then change the task 2 core as follows:


extern unsigned char hour;

/**********************************************************************
* ------------------------------ TASK2 -------------------------------
*
* Third task of the tutorial.
*
**********************************************************************/
TASK(TASK2)
{
unsigned int i;

while(1)
{
while(PORTBbits.RB0 == 0);
for (i = 0; i < 10000; i++)
Nop();
if (PORTBbits.RB0 == 1)
hour++;
}
}

The task has an infinite loop without waiting for an event with a WaitEvent function. So the task can
block the rest of the application, more precisely the task with a lowest priority... Then its priority has to
be the smallest one of the application: we say the task id the idle task.
It starts to inspect the RB0 port and stay in an infinite loop as long as the BTN0 button is not pressed.
As soon as the button is pressed the task waits for the end of the rebound thanks to a FOR loop.
Then if the RB0 is ON the "hour" variable is incremented. It can update the software clock for
instance.

4) Now you need to update the definition related to the new task in the "define.h" file.
/***********************************************************************
* ----------------------------- Task ID -------------------------------
**********************************************************************/
#define TASK0_ID 1
#define TASK1_ID 2
#define TASK2_ID 3

#define TASK0_PRIO 7
#define TASK1_PRIO 10
#define TASK2_PRIO 1

32 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
5) Finally you have to add the new task to the project ("Project/Add files to Project...").

You can rebuild and start the simulation (F10).

> Round robin


Now we can create a second idle task. Indeed PICos18 lets you design many different tasks with the
same priority. In our application we wonder which one is able to run... Actually the PICos18 scheduler
uses a 'Round Robin" algorithm.
With such an algorithm the idle tasks can share the PIC18 processor during a time slice of 1ms.
Because the task have a very low priority they run only when not any task needs to run and during a
maximum time of 1 ms. After this time another task with the same priority will run during the same
time slice.

Design a task 3 with the same code (Except that the port inspected is the port RB1) and with the
same priority :

/***********************************************************************
* ----------------------------- Task ID -------------------------------
**********************************************************************/
#define TASK0_ID 1
#define TASK1_ID 2
#define TASK2_ID 3
#define TASK3_ID 4

#define TASK0_PRIO 7
#define TASK1_PRIO 10
#define TASK2_PRIO 1
#define TASK3_PRIO 1

33 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

Do not forget to add the new file to the project and rebuild (F10).

Place some breakpoints in front of the "while(PORTBbits.RBx == 0);" instructions and start the
simulation. You will see the pointer to be stopped in the task2. Disable the breakpoint where the
pointer is and run the simulation: the pointer stops now in the task 3 after 1ms...
If now you place breakpoints in task 0 and 1 you will see the pointer to be stopped after 1 second in
one of the 2 tasks: there is preemption because of the highest priorities of the both tasks.

> Simulation
To simulate the push button is ON you can use the Watch window:

Start the simulation until the pointer stops on the first breakpoint of the task2. Click on the Watch
window to set the PORTB at 0x01. Then start the simulation and check the breakpoint in the task 3 is
still enabled.

You will see the pointer stops at first in the task 3 before reaching the second breakpoint in the task
2. In fact after 1 ms, the scheduler has decided to run the other task...

34 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

7. The interrupts

By using the PIC18 uC you probably expect to use the internal peripherals. To do it you have to
consider the interrupts.

You will learn how works interrupts under PICos18 and how to write your own interrupt routines.

> Présentation du fichier int.c


Now we're going to connect the both buttons on the external interrupt pins of the PIC18 that let us
treat the button rebound only when one button is pressed.
First of all we're going to see what is the "int.c" file in charge of the interrupt management. The PIC18
manages 2 kinds of interrupts: the low priority interrupts (IT_vector_low) and the high priority
interrupts (IT_vector_high). But what for...?!
Actually you have to know the PICos18 kernel does some complex operation with task and that it
does not permit to be interrupted during the process (for instance during the preemption of one new
task on the current task). Then to be as simple as possible the kernel is non-interruptible. But we've
seen the determinism of PICos18 is 50µs (what is called the latency time), so there is a kind of
blackout when an IT cannot be detected.

To avoid this problem we allow fast interrupts of the PIC18 which uses a hardware mechanism to
save the elemtary registers (like WREG, STATUS, ...). Unfortunately to use the fast mode interrupt of
the PIC18 you need to write a very simple C code...

If you need to write a more complex code that calls C functions for instance you have to use slow
interrupts... with this specific 50 µs blackout!

35 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

/**********************************************************************
* Function you want to call when an IT occurs.
**********************************************************************/
extern void AddOneTick(void);
/*extern void MyOwnISR(void); */
void InterruptVectorL(void);
void InterruptVectorH(void);

/**********************************************************************
* General interrupt vector. Do not modify.
**********************************************************************/
#pragma code IT_vector_low=0x18
void Interrupt_low_vec(void)
{
_asm goto InterruptVectorL _endasm
}
#pragma code

#pragma code IT_vector_high=0x08


void Interrupt_high_vec(void)
{
_asm goto InterruptVectorH _endasm
}
#pragma code

/**********************************************************************
* General ISR router. Complete the function core with the if or switch
* case you need to jump to the function dedicated to the occuring IT.
**********************************************************************/
#pragma code _INTERRUPT_VECTORL = 0x003000
#pragma interruptlow InterruptVectorL save=section(".tmpdata"), PROD
void InterruptVectorL(void)
{
EnterISR();

if (INTCONbits.TMR0IF == 1)
AddOneTick();
/*Here is the next interrupts you want to manage */
/*if (INTCONbits.RBIF == 1) */
/* MyOwnISR(); */

LeaveISR();
}
#pragma code

/* BE CARREFULL : ONLY BSR, WREG AND STATUS REGISTERS ARE SAVED */


/* DO NOT CALL ANY FUNCTION AND USE PLEASE VERY SIMPLE CODE LIKE */
/* VARIABLE OR FLAG SETTINGS. CHECK THE ASM CODE PRODUCED BY C18 */
/* IN THE LST FILE. */
#pragma code _INTERRUPT_VECTORH = 0x003300
#pragma interrupt InterruptVectorH
void InterruptVectorH(void)
{
if (INTCONbits.INT0IF == 1)
INTCONbits.INT0IF = 0;
}
#pragma code

At the first sight the "int.c" file seams to be very difficult to read but in fact it is very easy to
understand. The only 2 areas that need to be modified are the InterruptVectorL() and
InterruptVectorH() functions. In almost 99% of cases the slow interrupt mode will be suitable for your
applications then you will only need to modify the InterruptVectorL() function.

36 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> The "fast interrupt" mode


Here is the "fast interrupt" function :
/* BE CARREFULL : ONLY BSR, WREG AND STATUS REGISTERS ARE SAVED */
/* DO NOT CALL ANY FUNCTION AND USE PLEASE VERY SIMPLE CODE LIKE */
/* VARIABLE OR FLAG SETTINGS. CHECK THE ASM CODE PRODUCED BY C18 */
/* IN THE LST FILE. */
#pragma code _INTERRUPT_VECTORH = 0x003300
#pragma interrupt InterruptVectorH
void InterruptVectorH(void)
{
if (INTCONbits.INT0IF == 1)
INTCONbits.INT0IF = 0;
}
#pragma code

The external interrupts INT0 (RB0 pin), INT1 (RB1 pin) and INT2 (RB2 pin) are by default in fast
interrupt mode so when an interrupt occurs the current code processing is stopped and the
InterruptVectorH() is executed.

The INT0 interrupt is not


settable that means it always
calls the InterruptVectorH()
function.

At the opposite side the INT1


and INT2 can be set to call
the InterruptVectorL()
function.
To do it you need to modify
the INTCON3 register and
particularly the INT2IP and
INT1IP bits.t INT1IP.

If you wish to connect the 2 buttons on the INT1 and INT2 pins you will need to write the anti-rebound
code in the InterruptVectorH() function. But we've seen the fast interrupt code has to be very simple
and that it is not allowed to call any function... The only one thing we can do is to increment or
decrement a global variable...!

The reason is easy to understand: you cannot use a register of the PIC18 except the WREG,
STATUS and BSR registers. If you hesitate between fast and slow interrupts have a look at the
assembling listing generated by C18 to know if another register has been used. Because we don't
need a precision higher than 50 µs to manage the buttons we choose the "slow interrupt" mode.

37 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> The "slow interrupt" mode


In the most of the cases the "slow interrupt" mode is suitable. The only 3 interrupts by default in the
"fast interrupt" mode are INT1 and INT2. Because INT0 cannot be modified we'll use INT1 and INT2
by setting them in the "slow interrupt" mode:

To use INT1 and INT2 in "slow interrupt" mode modify the INTCON3 register as above in the init
phase of the main file.
Then modify the int.c file to catch the INT1 and INT2 interrupts:

/**********************************************************************
* Function you want to call when an IT occurs.
**********************************************************************/
extern void AddOneTick(void);
extern void MyOwnISR(void);
void InterruptVectorL(void);
void InterruptVectorH(void);

...

/**********************************************************************
* General ISR router. Complete the function core with the if or switch
* case you need to jump to the function dedicated to the occuring IT.
**********************************************************************/
#pragma code _INTERRUPT_VECTORL = 0x003000
#pragma interruptlow InterruptVectorL save=section(".tmpdata"), PROD
void InterruptVectorL(void)
{
EnterISR();

if (INTCONbits.TMR0IF == 1)
AddOneTick();

38 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
/*Here is the next interrupts you want to manage */
if (INTCON3bits.INT1IF || INTCON3bits.INT2IF)
MyOwnISR();

LeaveISR();
}
#pragma code

We need now to add the "MyOwnISR" function in any C file, in any task of the both idle tasks
connected to the button processing. For instance we add the function in the "tsk_task2.c" file:
void MyOwnISR(void)
{
if (INTCON3bits.INT1IF)
{
INTCON3bits.INT1IF = 0;
/* ... */
}
if (INTCON3bits.INT2IF)
{
INTCON3bits.INT2IF = 0;
/* ... */
}
}

Do not forget to declare the function at the beginning of the file:


#include "define.h"

void MyOwnISR(void);

/**********************************************************************
* Definition dedicated to the local functions.
**********************************************************************/
#define ALARM_TSK0 0

You can now rebuild the project (F10).

> Idle tasks management


At this moment the "MyOwnISR" function cannot send the information a button has been pressed.
Moreover the idle tasks continue to run in an infinite loop. Then we need to put to sleep the idle tasks
and to wake them up if a button is pressed. To do so we modify the both tasks to be a BASIC task:

TASK(TASK2)
{
unsigned int i;

for (i = 0; i < 10000; i++)


Nop();
if (PORTBbits.RB1 == 1)
hour++;

TerminateTask();
}

39 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
As you can notice the task number 2 don't have any more the "while(1)" loop and is finished with the
"TerminateTask()" call.

Here is BASIC task features:

• no "WaitEvent()" function call,


• no "while(1)" loop,
• a "TerminateTask()" function call at the end.
The goal is to set the task in SUSPENDED state by default then to activate it with the "ActivateTask()"
function call.

Change the "tascdesc.c" file to set task 2 and 3 at the SUSPENDED state by default:

/**********************************************************************
* ----------------------------- task 2 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task2 = {
TASK2_PRIO, /* prioinit from 0 to 15 */
stack2, /* stack address (16 bits) */
TASK2, /* start address (16 bits) */
SUSPENDED, /* state at init phase */
TASK2_ID, /* id_tsk from 1 to 15 */
sizeof(stack2) /* stack size (16 bits) */
};
/**********************************************************************
* ----------------------------- task 3 ------------------------------
**********************************************************************/
rom_desc_tsk rom_desc_task3 = {
TASK3_PRIO, /* prioinit from 0 to 15 */
stack3, /* stack address (16 bits) */
TASK3, /* start address (16 bits) */
SUSPENDED, /* state at init phase */
TASK3_ID, /* id_tsk from 1 to 15 */
sizeof(stack2) /* stack size (16 bits) */
};

Modify the task 3 to be a BASIC task:


TASK(TASK3)
{
unsigned int i;

for (i = 0; i < 10000; i++)


Nop();
if (PORTBbits.RB2 == 1)
min++;

TerminateTask();
}

40 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

Then modify the "MyOwnISR" function to activate the task dedicated to the button management:
void MyOwnISR(void)
{
TaskStateType State;

if (INTCON3bits.INT1IF)
{
INTCON3bits.INT1IF = 0;
GetTaskState(TASK2_ID, &State);
if (State == SUSPENDED)
ActivateTask(TASK2_ID);
}
if (INTCON3bits.INT2IF)
{
INTCON3bits.INT2IF = 0;
GetTaskState(TASK3_ID, &State);
if (State == SUSPENDED)
ActivateTask(TASK3_ID);
}
}

Rebuild (F10) and start the simulation (F9).

Put a breakpoint in the task 3 and another one in the "MyOwnISR" function. Start the simulation and
stop it anytime (F5). Modify INTCON3 to set the interrupt (put for instance 0x1A to set the INT2
interrupt) : you will see the pointer stops in "MyOwnISR" then in the task 3.

If you continue to run the simulation you will see the pointer does not pass through the task 3 any
more before the next interrupt : the task has been suspended.

41 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

8. Using drivers

You want to communicate through the serial port or the CAN interface ? Now you know how to write
interrupts and tasks and you know how to manage alarms and events it will be easy to use and to
write a real driver for PICos18.

> Driver features


A driver is often compared to a library but it's really something different. A library is a set of functions
written in a language (like the C language for instance) and used to simplify the development phase.
In the case of a RS232 transfer a library proposes for example a function to open or close the
channel or to receive and send data…
A driver is a layer dedicated to a specific peripheral management. Its goal is not to offer a set of
functions to use such a peripheral because it's the job of the driver to be in charge of the peripheral
usage...

A driver is in fact composed of an ISR (Interrupt Service Routine) and a task. We have already
seen the ISR in the previous chapter through the InterruptVectorL() and InterruptVectorH() functions.

The ISR is in charge of catching the interrupt (IT) and to inform the driver task the interrupt occurred.
So the mission of the task is to do what is necessary to manage these IT.

42 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> Software layer usage


PICos18 is delivered with the kernel and this tutorial. But in the DOWNLOAD page of the web site we
will find also the drivers and libraries available for free. This is to let you develop your application like
a puzzle, with a lot of free layers you can add to your project without wasting time to study how it
works.

We're going to study how to use a software layer. More precisely we're going to use the RS232 driver
of PICos18 in order to display our "software swatch" with the global variables "hour", "min", and "sec".

Download the RS232 driver from the DOWNLOAD of PICos18:

The package has a text file (TXT link) that indicates how to include and use the driver in your
application (how to set the baudrate for instance or how to register the task to the RS driver).

43 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

______________________________________________________________________
> <
> RS232 driver v1.06 <
> for <
> PICos18 release 2.00 <
> <
> PICos18 - Real-time kernel for PIC18 family <
> <
> <
> www.picos18.com www.pragmatec.net <
>______________________________________________________________________

...

Now you can insert tasks to your projet, write ISR, setup your application thanks to the "tascdesc.c"
file then follow the recommandations of the text file step by step to insert the driver in your
application.

You don't need to add the "Example" task references like the alarm of the Alarm_list structure
(chapter IV of the text file) or the EXAMPLE_ID definition in the define.h file. Do not reach the chapter
VII, because this one will be use in the next paragraph.

> Driver usage


In order to use the driver create a new task called "TASK4" to replace the "Example" task of the text
file. Do not forget to add the ALARM_TASK4 settings in the "tascdesc.c" file.

Here is what should be the TASK4 task :

#include "define.h"
#include "drv_rs.h"
#include <stdio.h>
#include <string.h>

#define ALARM_TSK4 1

int Printf (const rom char *fmt, ...);


extern unsigned char hour;
extern unsigned char min;
extern unsigned char sec;

/**********************************************************************
* Definition dedicated to the local functions.
**********************************************************************/
RS_message_t RS_msg;
unsigned char buffer[80];

/**********************************************************************
* ------------------------------ TASK4 -------------------------------
*
* Fifth task of the tutorial.
*
**********************************************************************/
TASK(TASK4)
{
SetRelAlarm(ALARM_TSK4, 1000, 1000);

44 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
Printf(" ______________________________________________________________________ \r\n");
Printf("> <\r\n");
Printf("> PICos18 Tutorial <\r\n");
Printf("> <\r\n");
Printf("> <\r\n");
Printf("> PICos18 - Real-time kernel for PIC18 family <\r\n");
Printf("> <\r\n");
Printf("> <\r\n");
Printf("> www.picos18.com www.pragmatec.net <\r\n");
Printf(">______________________________________________________________________<\r\n");
Printf(" \r\n");
Printf(" \r\n");

while(1)
{
WaitEvent(ALARM_EVENT);
ClearEvent(ALARM_EVENT);

Printf("%02d : %02d : %02d\r", (int)hour, (int)min, (int)sec);


}
}

/**********************************************************************
* Function in charge of structure registration and buffer transmission.
*
* @param string IN const string send to the USART port
* @return void
**********************************************************************/
int Printf (const rom char *fmt, ...)
{
va_list ap;
int n;
RS_enqMsg(&RS_msg, buffer, 50);
va_start (ap, fmt);
n = vfprintf (_H_USER, fmt, ap);
va_end (ap);
SetEvent(RS_DRV_ID, RS_NEW_MSG);
WaitEvent(RS_QUEUE_EMPTY);ClearEvent(RS_QUEUE_EMPTY);
return n;
}

The first part of the code is used to include the headers dedicated to the RS232 driver and the "printf"
functions. Then you need to declare the ALARM_TASK4 identifier and also to declare as "extern" the
external variables "hour", "min" and "sec" to tell the C18 compiler the definition is not in this C file.

In RAM we add 2 kinds of variables:

• RS_message_t RS_msg: this structure is mandatory to send anything with the RS driver

• unsigned char buffer[80]: it is the buffer to transmit

Then you discover the TASK4 task core with an alarm that occur every 1000ms, so every secondes.
The function "Printf" is called to send a const string, to convert data from one type to another,... Every
format is managed by C18 except the FLOAT variables...!

The "Printf" function needs a "\r\n" at the end of the string if you whish a carriage return with a line
feed: the "\r" is used to go back to the beginning of the line and the "\n" to load a new line.

To display the banner we need a "\r\n" and to display the time at the same location we just need "\r".

45 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
Finally you have to get the following message with HyperTerminal :

> HyperTeminal settings


Be careful with the COM settings: set 115200 bits per second and no hardware check (sorry for the
screenshots in French only ;-) :

46 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

9. Application example

The tutorial is terminated with this last chapter about PICos18 development. The sources of this
typical application are located in the Project/Tutorial directory of PICos18. This example is here to
show you how easy it is to develop a complex application with PICos18.

> Multiple interrupts


If you run the application now and push one of the both buttons you will see pretty soon there is a
problem : the PIC18 seams to be like frozen after a while, and it occurs when you press a button
quite fast !
Stop the application if you're using a Microchip ICD2 in debug mode or stop the simulation if you're
using the MPLAB simulator and have a look at the following registers:

You can notice the "kernelPanic" variable is not null. In our case its value is 0x53.

Actually this variable indicates if there is a stack overflow. When a stack overlaps another one the
kernel detects it automatically and stop the task at the origin of the problem. This allows to save your
application and also to debug with PICos18 in order to find out what appends.

kernelPanic value is 0x53.

The right nibble ("3") means the task with the ID 3 has a stack overflow.

The left nibble ("5") means the task with the ID 5 has a stack trashed by an overflow.

The kernel has then decided to stop the both tasks because the behaviour is no safer for both of
them. This safety mechanism lets the PIC18 runs even with a stack overflow and lets you fix the bug.

The task 2 in charge of the button processing runs anormaly and its software stack is
overload and has trashed the following one, the one of the task 4.

47 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
But why such an overflow ?

2 cases can explain this:

• the task code is huge and you've under-estimated your need in term of software stack =>
increase the size of the stack at the origin of the problem
• An infinite interrupt forces a task to save its context (the PIC18 registers and the hardware
stack) in loop that brings a stack overflow.
We're using push buttons and we have seen in the previous chapters these buttons have some
rebounds when they are pressed. Then many interrupts occur and overload the PIC18. At every
interrupt the current task needs to save its context but the IT are so close we are finally in an infinite
loop in the InterruptVectorL() up to the stack overflow....

The behaviour occurs quite often even if you don't use a real-time kernel. The only one difference
here is that PICos18 inspects the application in "real-time" to see if such an overflow occur and stop
some task if necessary. Without an OS the PIC18 will crash after a while... In fact it is not an
architecture default but a coding trouble we'll fix in the next chapter.

> Bug fixing


The problem occurs because we always enable the interrupts from the RB1 and RB2 ports while we
didn't start to treat the first interrupt. Detect every button interrupts is not useful: no need to know that
the button has 50 rebounds before stabilizing the signal. We just need to know it has been pressed.
Modify the tasks TASK2 and TASK3:

TASK(TASK2)
{
unsigned int i;

hour++;
if (hour == 24)
hour = 0;
INTCON3bits.INT1IF = 0;
INTCON3bits.INT1IE = 1;
TerminateTask();
}

...

TASK(TASK3)
{
unsigned int i;

min++;
if (min == 60)
min = 0;
INTCON3bits.INT2IF = 0;
INTCON3bits.INT2IE = 1;
TerminateTask();
}

48 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

And modify your interrupt ISR:


void MyOwnISR(void)
{
TaskStateType State;

if (INTCON3bits.INT1IF)
{
INTCON3bits.INT1IE = 0;
GetTaskState(TASK2_ID, &State);
if (State == SUSPENDED)
ActivateTask(TASK2_ID);
}
if (INTCON3bits.INT2IF)
{
INTCON3bits.INT2IE = 0;
GetTaskState(TASK3_ID, &State);
if (State == SUSPENDED)
ActivateTask(TASK3_ID);
}
}

...

void InterruptVectorL(void)
{
EnterISR();

if (INTCONbits.TMR0IF == 1)
AddOneTick();
/*Here is the next interrupts you want to manage */
if ((INTCON3bits.INT1IF & INTCON3bits.INT1IE)||
(INTCON3bits.INT2IF & INTCON3bits.INT2IE))
MyOwnISR();
if ((PIR1bits.RCIF)&(PIE1bits.RCIE))
RS_RX_INT();
if ((PIR1bits.TXIF)&(PIE1bits.TXIE))
RS_TX_INT();

LeaveISR();
}

You can see MyOwnISR() disable the interrupts (INTxIE = 0 means Interrupt Enable disabled) and
the task has to manage the interrupt enable flag once the interrupt processing is completed.
You can now program your PIC18 to test the application: you will be able to update the software
swatch by pushing the both buttons. But there is still a problem: if you press many times a button very
fast the new value is not taken into account immediately but every second when the display is
updated. To fix that we need the real-time capability of PICos18!

49 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

> Real-time updates


To update the display each time you press a button you have to inform the display each time there is
a new value.... but without disturb the display that runs every seconds it means without breaking our
software swatch behaviour.

To do so we need to post an event to the task TASK4:

TASK(TASK2)
{
unsigned int i;

hour++;
if (hour == 24)
hour = 0;
SetEvent(TASK4_ID, UPDATE_EVENT);
INTCON3bits.INT1IF = 0;
INTCON3bits.INT1IE = 1;
TerminateTask();
}

...

TASK(TASK3)
{
unsigned int i;

min++;
if (min == 60)
min = 0;
SetEvent(TASK4_ID, UPDATE_EVENT);
INTCON3bits.INT2IF = 0;
INTCON3bits.INT2IE = 1;
TerminateTask();
}

Then the task TASK4 needs to wait for this new event:

...

while(1)
{
WaitEvent(ALARM_EVENT | UPDATE_EVENT);
GetEvent(id_tsk_run, &Time_event);

if (Time_event & ALARM_EVENT)


ClearEvent(ALARM_EVENT);
if (Time_event & UPDATE_EVENT)
ClearEvent(UPDATE_EVENT);

Printf("%02d : %02d : %02d\r", (int)hour, (int)min, (int)sec);


}

...

Do not forget to add the variable "EventMaskType Time_event" as a global or a local variable.

50 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01
The UPDATE_EVENT definition is unknown in our application then update the define.h file:
...

/***********************************************************************
* ----------------------------- Events --------------------------------
**********************************************************************/
#define ALARM_EVENT 0x80
#define TASK1_EVENT 0x10
#define UPDATE_EVENT 0x02

#define RS_NEW_MSG 0x10


#define RS_RCV_MSG 0x20
#define RS_QUEUE_EMPTY 0x10
#define RS_QUEUE_FULL 0x20

...

> Final application


Now you can rebuild the application, load it into the PIC18F452 and test it, you will see the software
swatch to be displayed in HyperTerminal and you will be able to update it in real-time with the push
buttons.

Of course you can simplify the application. It has not been done to let the tutorial has simple as
possible. You can also to add your own code and to use the PICos18 drivers: for instance you can
add a RTC (Real Time Clock) on a I2C bus (then use the I2C master driver) ad update it from
HyperTerminal...

51 / 52
Bâtiment EARHART
ZAC Grenoble Air Parc Real-time kernel for PIC18
38590 St Etienne de St Geoirs -
France
www.pragmatec.net
PICos18 v 2.01

10. Book and Internet references

To learn more about the OSEK standard and the use of the PIC18 with PICos18, here is a list of
useful books and some Internet links.

Books

Written by Joseph LEMIEUX of CMPbooks edition.


This book presents the Windriver OsekWorks kernel through a card game.

Internet links

www.osek-vdx.org : to get the OSEK/VDX standard (PDF files).

www.picos18.com : to get the last release and news of PICos18.

www.pragmatec.net : if you are interested in PICos18 based products.

www.microchip.com : the official web site of MICROCHIP useful to get:


- PIC18 datasheets
- last release of MPLAB®
- last release of C18

www.fsf.org : the GPL licence.

52 / 52

Potrebbero piacerti anche