The basics of embedded multitasking on a PIC, part 2 Cooperative
By Gamal Ali Labib
(12/12/07, 12:22:00 AM EST)
Working with Microchip's PIC18F452, the author demonstrates how you can pack
the programs of tasks that have exactly the same functionality but in different
domains into one reentrant program that can be invoked several times
concurrently to serve all those domains.
Part 1: The basics of embedded multitasking on a PIC--Introduction
Part 3: The basics of embedded multitasking on a PIC--Preemptive multitasking
Cooperative multitasking requires concurrently running tasks to willingly give up
system control throughout their execution to a scheduler program so that the latter can
switch the control to the task that meets the preset policy. When tasks have exactly the
same functionality but in different domains, it is presumably possible to pack all tasks'
programs into one reentrant program that can be invoked several times concurrently to
serve all those domains. This article describes a project that illustrates this kind of
multitasking with some useful pieces of code you can reuse in your own control
Working with PIC18F452
The Microchip's PIC18F452 is a high-performance enhanced flash microcontroller with
10-bit A/D, four I/O ports, on-chip 32KB program memory, 1,538-byte data memory,
256-byte EEPROM, 18 interrupt sources, four timers, and 75 instruction sets. I chose
this device for my project as it represents the high-end of the popular PIC18Fxx2 family
and realizes the fundamental architecture of Microchip's MCUs. Both factors indicate
that multitasking can look appealing for applications based on this device.
The projects' development environment
I used Microchip's MPASM assembler to write the code for my projects. MPASM
assembler is a command-line or Windows-based PC application that provides a platform
for developing assembly-language code for Microchip's PICmicro microcontroller
(MCU) families. I prefer working at the assembly-language level to have full control of
the MCU's internal operations and to keep my code optimization in my own hands
especially when I work on operating-systems modules such as the task scheduler and
interrupt handlers. However, some readers may prefer higher-level programming
languages, such as C, which is also supported by Microchip's MPLAB C18 C compiler.
I also used Microchip's MPLAB IDE (integrated development environment), which is a
software package that provides a single integrated "environment" to develop code for
embedded Microchip microcontrollers.
MPLAB IDE has five built-in components that consist of:
The Project Manager, which provides integration and communication between
the IDE and the language tools.
The Editor, which is a full-featured programmer's text editor. The
Assembler/Linker and Language Tools. The assembler works with the linker to
build a project from separate source files, libraries, and recompiled objects.
The Debugger, which allows breakpoints, single-stepping, watch windows, and
all the features of a modern debugger for the MPLAB IDE.
The Execution Engines, which run Simulators that use the PC to simulate the
instructions and some peripheral functions.
I relied on the Debugger and the Simulators heavily while working in my projects, and I
find them extremely important to get a working application well done.
You can also find additional optional components for MPLAB IDE that include
compiler language tools, MCU programmers, and in-circuit emulators to test code as it
runs in the applications hardware.
You can download MPLAB IDE for free from Microchip's web site
Modularity and reusability
I built the project modules with full utilization of macros and grouped all work memory
areas in a separate (.inc) files to have the freedom of upgrading the project as needed
and achieve variant functionality as required in different implementations. The reader
will experience the benefits of this design approach when we discuss preemptive
multitasking in the following article as I shall reuse almost all of those modules and
macros in that project.
The cooperative task project
The project features four identical tasks that display rotating preset messages once
whenever they gain control of the PIC, and then they pass the control back to the
scheduler, which looks for the next task in the sequence of the four tasks. The scheduler
loads that task's data and passes to it the PIC control. To achieve message rotation
effect, the task in control changes the next starting position within the preset message
prior to giving away PIC control to the scheduler. To prevent tasks from overwriting
each other's display, they are preset to use different lines on the screen. Figure 1
illustrates schematically what we should expect at some time during project run.
Figure 1: 14-byte display buffers filled with preset text at different starting points.
I use hardware simulation to complete the project. I replaced the screen with MPLAB
IDE debugger Watch window to show the contents of the display buffers allocated to
The project is composed of three basic modules: the task initialization, the task
scheduler, and the reentrant program. In what follows, I shall elaborate on those
Task initialization module
This module (PREINIT macro) initializes the work areas of the display tasks. What I
care about here is the starting position of the preset display text that will be sent to the
display buffer. The pointers responsible for the marking the display positions are
maintained in the following work areas:
Pgm-pos0 (of task #0),
Pgm-pos1 (of task #1),
Pgm-pos2 (of task #2),
Pgm-pos3 (of task #3).
I also need to set the Table-Pointer register TBLPTR to point to Task #0's preset display
text as it is kept in program memory. The other task's TBLPTR setup will be calculated
later on based on this initial setup.
Based on my assumption that the length of the display text of all four tasks is the same,
I let this module keep the length of Task #0's text in the global size variable 'Temp-
When we consider multitasking, we must take into consideration the possible conflicts
between tasks contending for the same embedded resources, such as the hardware
display module. In this project, display tasks return system control willingly after they
send a complete message to the relevant display buffer. Accordingly, contention in our
case of cooperative tasks is not an urgent matter to tackle in this project. However,
when we deal with task preemption in the next article, we will be confronted with that
Task scheduler module
The scheduler (COPSCHED macro) has a simple role in task switching due to the fact
that the task in control returns that control to the scheduler willingly (via an
unconditional jump using goto instruction) after it displays a complete line of text. The
scheduler increments the (cur-task) variable to point to the next due task. The
scheduler makes sure that task number never exceeds three as we have four display
tasks to manage. The scheduler then passes control to the reentrant program to resume
displaying a new line of text from the task's preset text.
The reentrant program
Each round of this program sends the preset text of one of the four display tasks, in
some order, producing text rotation effect. The program loads the preset display text
(TASDAT macro) and the new starting position for display within that text (TASPOS
macro). Prior to displaying text, the program may clear the display line (if you wish to)
to make the rotation effect more visible. Figure 2 illustrates the MPLAB IDE debugger
Watch window showing a snap-shot of the rotating text for the four tasks.
Figure 2: MPLAB IDE Watch window showing a snap-shot of the rotating text.
You can see here how display would look like at some point in time during the project
run. Each task data is identified by the task identifier (i.e., 0, 1, 2, and 3). Comparing the
displayed text in the four lines indicates the rotation effect you may expect. Note that
due to the limitation of Symbol viewing in the Watch window, I divided the display
buffers of each task into four sub-buffers of 4-bytes length each. Taking task #0 as an
example, I declared those buffers as:
Dsp_area0 RES 4
Dsp_area1 RES 4
Dsp_area2 RES 4
Dsp_area3 RES 4
Following the display of a single line of text and prior to returning control to the
scheduler, the program moves the text start pointer one step forward for the task it
serves, or resets the pointer if end-of-text is reached.
I included an optional delay routine (DELAY macro) to sustain the displayed text for a
preset duration to reasonably slow down fast PICs so that the user can comfortably
catch the text rotation.
The project is composed of a main program file 'ReentCop.asm' that groups all
modules together. Macros used to realize different operations of those modules are
coded in file 'ReentMac.inc' (see Table 1 for a list of those macros and their roles),
and the project work areas are declared in file 'ReentWork.inc'. The reentrant
program is coded in the main assembly file 'ReentCop.asm' since it represents the
embedded system core application.
Table 1: Project macros list.
Code listings for all three files are available by contacting me
firstname.lastname@example.org. Two additional files 'P18F452.inc' and '18f452.lkr'
are required for the assembler to generate the object code of the project, and they are
provided with MPLAB IDE package (see paragraph below for more details).
The user may by curious to know how the project uses the embedded system memory.
Figures 3 and 4 illustrate the program and data memory maps. I can't say it is optimally
organized and manipulated. However, I found that putting things as they are helped me
in a way to get the project done in a fairly short time. The reader can of course put his or
her touch to reduce wasted space. It is interesting to know that the executable code of
the project, apart from data and work areas, occupies around 230 bytes of program
memory, which is only 40% of that required for the four display tasks without reentrant
Figure 3: Program memory allocation.
Figure 4: Data memory allocation.
Putting things together
Now, it is time to build up the project using MPLAB IDE. You need to start the Project
Wizard under Project menu (see Figure 5). You will go through the following four
steps to create the project.
Figure 5: MPLAB IDE Project Wizard.
View the full-size image
Step 1: select the device PIC18F452.
Step 2: choose Microchip MPASM Toolsuite.
Step 3: name the project and locate the directory you wish to keep it in.
Step 4: add project files as show in Figure 6 from the left pane to the right using the
ADD button. Make sure to tick the boxes adjacent to added file to copy them into the
Figure 6: Including required files into the project.
View the full-size image
Now we move to building the project and running it. Point the cursor to the project
window (see Figure 7) and right-click to get a similar view of Figure 8, and select
Build All. Under the Debugger menu, select Watch, then use ADD Symbol button to
add the display buffers to the view as shown in Figure 2. Make sure to set the properties
of each buffer (right-click its Symbol Name) as 32-bit ordered as Low: High except for
buffers 3, 7, 11, 15, as they have only 16-bit length.
Figure 7: The project window.
Figure 8: Building the project.
View the full-size image
Now, choose Animate from the Debugger menu (see Figure 9), and you got the rotating
text on the move in the Watch window.
Figure 9: Running the project in animation mode.
View the full-size image
In this article, I presented a working project presenting the concept of multitasking with
reentrant program implementation for user tasks that concurrently display rotating
preset text. The tasks exemplify identical control tasks that can simultaneously serve
different application domains. Those tasks were designed in such a way that they
willingly give up control to the operating system, represented by a scheduler program,
so that it can activate different tasks. Such type of tasks is called cooperative in
In the next article, I shall present another project tackling a different kind of tasks, those
requiring interrupts to suspend their operation to the operating system. Such embedded
system is called preemptive, which is more sophisticated than cooperative systems.
Gamal Ali Labib is an IT consultant in Cairo, Egypt. He specializes in IT security and
IT turn-key projects management. He is also interested in parallel processing and VLSI.
Dr. Labib has a B.Sc. and M.Sc. in computer engineering and electronics from Ain
Shams University, Egypt, and a PhD in computer science from University of London,
U.K. You can reach Dr. Labib at email@example.com.
Please login or register here to post a comment