Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Pragmatec
Products and services dedicated to real time embedded systems
PICos18
Real time kernel for PIC18
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
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
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
6. A MULTI-TASK APPLICATION..................................................................................................................................31
9. APPLICATION EXAMPLE............................................................................................................................................47
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.
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.
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.
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.
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 ».
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.
ü 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.
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 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.
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.
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.
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.
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
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.
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
> 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).
In our application there is only one task defined in the "tsk_led.c" file :
TASK(TASK0)
{
while(1);
}
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:
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.
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).
/**********************************************************************
* --------------------- 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.
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);
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).
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.
/**********************************************************************
* ----------------------------- 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
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 :
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
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;
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.
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;
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 */
},
};
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.
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.
/**********************************************************************
* ---------------------- 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:
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...").
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:
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 :
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.
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.
First of all we start to create a first task that inspects the RB0 port where is located the BNT0 push
button.
/**********************************************************************
* ---------------------- 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) */
};
/**********************************************************************
* ------------------------------ 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...").
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.
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
/**********************************************************************
* 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
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 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.
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
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;
/* ... */
}
}
void MyOwnISR(void);
/**********************************************************************
* Definition dedicated to the local functions.
**********************************************************************/
#define ALARM_TSK0 0
TASK(TASK2)
{
unsigned int i;
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.
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) */
};
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);
}
}
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.
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
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".
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.
#include "define.h"
#include "drv_rs.h"
#include <stdio.h>
#include <string.h>
#define ALARM_TSK4 1
/**********************************************************************
* 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);
/**********************************************************************
* 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.
• RS_message_t RS_msg: this structure is mandatory to send anything with the RS driver
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 :
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.
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.
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 ?
• 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.
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
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
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);
...
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
...
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
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
Internet links
52 / 52