The basics of embedded multitasking on a PIC, part 2 - Embedded.com

The basics of embedded multitasking on a PIC, part 2

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 projects.

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 www.microchip.com.

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 each task.

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 modules.

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-size' .

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 issue.

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     4Dsp_area1     RES     4Dsp_area2     RES     4Dsp_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.

Implementation aspects
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 . 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 programming.

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 project directory.

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

Next steps
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 computer jargon.

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 .

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.