You are on page 1of 18

Project Report

Porting µC/OS-II to a PIC Microcontroller

David Fischer

February 7, 2007
Project Report David Fischer

Contents
1. Project Idea................................................................................................3
1.1 Approaches ...............................................................................................................3
1.2 Hardware Requirements...........................................................................................3
1.3 Software Requirements ............................................................................................3
2. Approach 1: Running µC/OS-II in Virtual Breadboard ............................4
2.1 Choosing the Target System ...................................................................................4
2.2 Getting the µC/OS-II Code ........................................................................................4
2.3 Compiling µC/OS-II with MPLAB for the PIC18F452 ..............................................4
2.3.1 Compiling Problems .............................................................................................5
2.4 Virtual Breadboard Simulator ..................................................................................7
2.4.1 Virtual Breadboard Problems ...............................................................................7
3. Approach 2: Running µC/OS-II Using Real Hardware.............................8
3.1 Hardware Design.......................................................................................................8
3.2 Running the Basic µC/OS-II Port .............................................................................8
4. Using µC/OS-II for Multitasking..............................................................10
4.1 Digital Input Switches.............................................................................................10
4.2 Source Code............................................................................................................11
4.2.1 Tasks..................................................................................................................11
4.2.2 Final Code Size ..................................................................................................11
5. Conclusion and Outlook.........................................................................12
References...................................................................................................13
Appendix: Source Code of test.c ...............................................................14

2/7/07 Page 2/18


Project Report David Fischer

1. Project Idea
Microchip’s 8-bit low-cost PIC microcontrollers feature a powerful architecture, flexible
memory technologies, and comprehensive easy-to-use development tools [1]. The author
has used PIC microcontrollers many times and is still fascinated by the simplicity of their
architecture and instruction set.
Porting µC/OS-II to a PIC microcontroller is the first goal of this project. The µC/OS-II
website [2] indicates that there is a possibility to port µC/OS-II to the PIC18F
microcontroller family.
For convenience reasons, a software simulator (Virtual Breadboard) for emulating some
popular PIC microcontrollers without using any hardware will be used. Also, there is a free
student version of the C-compiler that is tailored for the PIC18F family.
After porting µC/OS-II, the ultimate goal of this project is to create, run, and manage
several independent tasks with different priorities in µC/OS-II on a PIC. The tasks will be
simple counters and their progress will be observed on a display.

1.1 Approaches
There are two possible approaches for completing this project:
• Set up the hardware exclusively with virtual components in Virtual Breadboard.
• Set up the hardware on a real breadboard with real components.

If possible the first approach will be used. If there are any problems with the first approach,
the second approach is an equally good but more time-consuming backup solution.

1.2 Hardware Requirements


Following the first approach, no actual hardware is needed. The PIC microcontroller and all
peripheral components can be simulated using Virtual Breadboard.
However, for the PIC18F family and especially Virtual Breadboard, the code for µC/OS-II is
quite sophisticated. Therefore, there is the possibility that the simulator will not be able to
process µC/OS-II correctly. If this should happen, the hardware will be built on a real
breadboard using real components according to the second approach. The details will be
discussed in a later chapter.

1.3 Software Requirements


The following software packages will be used:
• Embedded OS: µC/OS-II
• C-compiler: MPLAB C18 v3.02 Student Edition [1]
• Assembler: MPLAB IDE v7.40 [1]
• PIC simulator: Virtual Breadboard [3]

2/7/07 Page 3/18


Project Report David Fischer

2. Approach 1: Running µC/OS-II in Virtual Breadboard


Following the first approach, the goal is to get the basic µC/OS-II port running in Virtual
Breadboard. The steps for reaching this goal are described in the following chapters.

2.1 Choosing the Target System


The first decision that had to be made was the selection of the actual microcontroller within
the PIC18F family. The PIC18F452 [4] is one of the most widely used microcontrollers in
this particular family and support for most of the problems that might occur can be found on
the Internet. It is also implemented in the Virtual Breadboard simulator. Therefore, µC/OS-II
will be ported to the PIC18F452 microcontroller.

2.2 Getting the µC/OS-II Code


The standard µC/OS-II code was obtained from the CD that comes with the book by Jean
J. Labrosse [5]. There is a link on [2] pointing to [6]. This website contains a personal
project executed by Nathan Brown, in which he wrote a PIC18F family port code for
µC/OS-II. However, his code is from 2002 and is not quite compatible with the new version
of the MPLAB C18 compiler (v3.02). Nevertheless, his code is available free of charge and
will be used as a basis for further development steps.

2.3 Compiling µC/OS-II with MPLAB for the PIC18F452


Table 2-1 shows an overview of all the files needed for compiling. The links among the files
is shown in Figure 2-1. After understanding the purpose of each file and the different links
among them, a project structure in MPLAB has been created (see Figure 2-2). Most of the
C- and H-files are part of the µC/OS-II kernel and some of them have not been changed at
all.
The test.c file contains a simple test function to verify the correct execution of µC/OS-II. It
activates a 4-bit counter that counts from 0 to 9 in an endless loop. The counter outputs are
directed to PORTD of the PIC and the counting can be observed on a 7-segment display.
The details of the other files can be seen in Table 2-1.
Some compiler settings tips are posted on Nathan Brown’s website [6]. Additionally, he
claims that the libraries that come with MPLAB C18 have to be recompiled with the multi-
bank stack model enabled. As far as the author knows, the libraries of the current MPLAB
C18 version already have this feature enabled. Therefore, nothing has to be done in this
matter.

2/7/07 Page 4/18


Project Report David Fischer

Name Function Changes for PIC18F


OSMapTbl and OSUnMapTbl are placed in program memory because
OS_CORE.C CPU independent
of limited RAM space
OS_FLAG.C CPU independent no changes
OS_MBOX.C CPU independent no changes
OS_MEM.C CPU independent no changes
OS_MUTEX.C CPU independent no changes
OS_Q.C CPU independent no changes
OS_SEM.C CPU independent no changes
OS_TASK.C CPU independent no changes
OS_TIME.C CPU independent no changes
Adjust path to included C-files, delete include of OS_CORE.C since it
UCOS_II.C CPU independent
is in the source file list, delete OS_GLOBALS definition
OSMapTbl and OSUnMapTbl are placed in program memory because
UCOS_II.H CPU independent
of limited RAM space

OS_CFG.H Application specific Set global definitions


INCLUDES.H Application specific Set processor specifics, include header files

OS_CPU.H CPU specific CPU specific definitions


OS_CPU_C.C CPU specific CPU specific functions
VECTORS.C CPU specific Interrupt service routine hook

test.c Test code -

Define one large RAM grp instead of six smaller grps, change stack
uc-18f452.lkr Linker Script
size to 0x30
Table 2-1: µC/OS-II File Structure

2.3.1 Compiling Problems


Compiling the combination of original and ported code files generated a number of errors
which had to be resolved first.
• Some labels for floating point operations were out of date
• The path for included code files was incorrect
• Include, library, and linker paths were incorrect

After resolving the problems, the project has successfully been compiled.

2/7/07 Page 5/18


Project Report David Fischer

Figure 2-1: Links among Code Files

Figure 2-2: Compiler Project Structure

2/7/07 Page 6/18


Project Report David Fischer

2.4 Virtual Breadboard Simulator


Virtual Breadboard [3] can be used to simulate hardware setups without using any actual
hardware. At this point, it is used to visualize the correct function of µC/OS-II.
After the hex-code generated by the MPLAB C18 compiler is loaded into the virtual
PIC18F452, the simulation can be started.
Figure 2-3 shows the setup for testing the first running task (the counter described in
chapter 2.3) in µC/OS-II. PORTD of the PIC18F452 feeds a 7-segment driver (the chip
labeled 4511), which is connected to the 7-segment display.

2.4.1 Virtual Breadboard Problems


Unfortunately, the new version 1.6 of Virtual Breadboard, which supports microcontrollers
from the PIC18F family for the first time, has still some bugs:
• Start-up problems with the compiled code
• Wait function (for loop) is not working
• Microcontroller flags may be faulty

The first problem has been resolved by the Virtual Breadboard developer, the second and
the third could not be resolved so far. Another more serious problem is that the µC/OS-II
function OSStart(), which starts the counting task in the multitask environment, is not
working. This might have something to do with the other Virtual Breadboard bugs, but it
may also be another problem. If the counting task is called in a foreground/background
environment, it works fine.
At this point, the author decided to use a real breadboard to set up the hardware instead of
Virtual Breadboard.

Figure 2-3: Test Setup in Virtual Breadboard

2/7/07 Page 7/18


Project Report David Fischer

3. Approach 2: Running µC/OS-II Using Real Hardware


Fortunately, changing to the second approach does not mean that the project has to start
over. The code which was compiled in chapter 2.3 can be used for the virtual and the real
hardware. Therefore, it can be taken from there and the next step is to set up the real
hardware.

3.1 Hardware Design


Figure 3-1 shows the schematic of the hardware built for testing the compiled code from
chapter 2.3. It is basically the same test setup as in Virtual Breadboard (Figure 2-3). The
same components (PIC18F452, 7-segment driver, 7-segment display) can easily be
identified in the schematic. The external crystal Q1 for the PIC18F452 ensures a stable
clock signal. Additionally, seven resistors between the driver and the display are needed to
limit the current flow through the seven LED’s of the 7-segment display.
For the implementation of multitasking in chapter 4, the final hardware setup, which
supports three counter tasks, is shown in Figure 3-2. In the final design, there are three 7-
segment displays, three 7-segment drivers, and nine digital inputs used as switches. The
switches are described in more detail in a later chapter.

VCC
U1
2 11
3 RA0/AN0 VDD 32
4 RA1/AN1 VDD
5 RA2/AN2/VREF- 15
6 RA3/AN3/VREF+ RC0/T1OSO/T1CKI 16
7 RA4/T0CKI RC1/T1OSI/CCP2 17
14 RA5/AN4/SS/LVDIN RC2/CCP1 18
RA6/OSC2/CLKO RC3/SCK/SCL 23
33 RC4/SDI/SDA 24
34 RB0/INT0 RC5/SDO 25
35 RB1/INT1 RC6/TX/CK 26
36 RB2/INT2 RC7/RX/DT U2 R 150 V1
37 RB3/CCP2 19 7 13 7 3
38 RB4 RD0/PSP0 20 1 A a 12 6 a C 8
VCC 39 RB5/PGM RD1/PSP1 21 2 B b 11 4 b C
40 RB6/PGC RD2/PSP2 22 6 C c 10 2 c
Q1 12M RB7/PGD RD3/PSP3 27 D d 9 1 d
13 RD4/PSP4 28 VCC 4 e 15 9 e
OSC1/CLKI RD5/PSP5 29 5 BI f 14 10 f
1 RD6/PSP6 30 3 LE g 5 g
C1 C2 MCLR/VPP RD7/PSP7 LT dp
22p 22p 12 8 16 8 LSHD-5503
31 VSS RE0/RD/AN5 9 VDD GND
VSS RE1/WR/AN6 10 CD4511B
RE2/CS/AN7
PIC18F452

Figure 3-1: Hardware Schematic for Initial Test Setup

3.2 Running the Basic µC/OS-II Port


After some initial problems with the configuration of the PIC18F452 and some minor
hardware changes, the initial test code from chapter 2.3 worked just fine!

2/7/07 Page 8/18


Page 9/18
David Fischer

U1 R1 150 V1
7 13 7 3

Figure 3-2: Hardware Schematic for Final Setup


1 A a 12 6 a C 8
2 B b 11 4 b C
6 C c 10 2 c
D d 9 1 d
VCC 4 e 15 9 e
5 BI f 14 10 f
3 LE g 5 g
LT dp
16 8 LSHD-5503
VDD GND
CD4511B
VCC
U2
2 11 U3 R8 150 V2
Counter 1/Priority-Bit 0 RA0/AN0 VDD
3 32 7 13 7 3
Counter 1/Priority-Bit 1 RA1/AN1 VDD A a a C
4 1 12 6 8
Counter 2/Priority-Bit 0 RA2/AN2/VREF- B b b C
5 15 2 11 4
Counter 2/Priority-Bit 1 RA3/AN3/VREF+ RC0/T1OSO/T1CKI C c c
6 16 6 10 2
Counter 3/Priority-Bit 0 RA4/T0CKI RC1/T1OSI/CCP2 D d d
7 17 9 1
Counter 3/Priority-Bit 1 RA5/AN4/SS/LVDIN RC2/CCP1 e e
14 18 VCC 4 15 9
Counter 1/Switch RA6/OSC2/CLKO RC3/SCK/SCL BI f f
23 5 14 10
Counter 2/Switch RC4/SDI/SDA LE g g
33 24 3 5
Counter 3/Switch RB0/INT0 RC5/SDO LT dp
34 25
35 RB1/INT1 RC6/TX/CK 26 16 8 LSHD-5503
36 RB2/INT2 RC7/RX/DT VDD GND
37 RB3/CCP2 19 CD4511B
38 RB4 RD0/PSP0 20
VCC 39 RB5/PGM RD1/PSP1 21 U4 R16 150 V3
40 RB6/PGC RD2/PSP2 22 7 13 7 3
Q1 12M RB7/PGD RD3/PSP3 27 1 A a 12 6 a C 8
13 RD4/PSP4 28 2 B b 11 4 b C
OSC1/CLKI RD5/PSP5 29 6 C c 10 2 c
Project Report

1 RD6/PSP6 30 D d 9 1 d
C1 C2 MCLR/VPP RD7/PSP7 VCC 4 e 15 9 e
22p 22p 12 8 5 BI f 14 10 f
31 VSS RE0/RD/AN5 9 3 LE g 5 g
VSS RE1/WR/AN6 10 LT dp
RE2/CS/AN7 16 8 LSHD-5503
PIC18F452 VDD GND

2/7/07
CD4511B
Project Report David Fischer

4. Using µC/OS-II for Multitasking


The final project step consists of writing the code to create, run, and manage three
independent tasks with different priorities in µC/OS-II. The following features will be
included:
• Turn each task on and off individually.
• Change each task’s priority on-the-fly.

4.1 Digital Input Switches


At this point the nine digital input switches are introduced. Each switch can be switched to
logic 0 (connected to Ground) or logic 1 (connected to 5 Volts). Table 4-1 shows their
specific functions.

Digital Input Switch Function Logic 0 (GND) Logic 1 (VCC)


RA0 Define priority bit 0 of task 1 1
Task 1 priority = RA0 * 1 + RA1 * 2
RA1 Define priority bit 1 of task 1
RA2 Define priority bit 0 of task 2 1
Task 2 priority = RA2 * 1 + RA3 * 2
RA3 Define priority bit 1 of task 2
RA4 Define priority bit 0 of task 3 1
Task 3 priority = RA4 * 1 + RA5 * 2
RA5 Define priority bit 1 of task 3
RE0 Turn task 1 on or off Turn task 1 off Turn task 1 on
RE1 Turn task 2 on or off Turn task 2 off Turn task 2 on
RE2 Turn task 3 on or off Turn task 3 off Turn task 3 on

Table 4-1: Switch Functions

Assigned priorities should be either 1, 2, or 3. Priority 0 is reserved for the task manager.
Also, the priority assigned to each task has to be unique at all times. This is a requirement
of µC/OS-II. Therefore, if priorities can’t be changed at the exact same time (which is
hardly possible with this design), all tasks should be turned off when priorities are changed.
However, there is no need to stop µC/OS-II for this matter.

1
The two digital input switches for each task’s priority make up the two bits of a binary number. Bit 0
0 1
represents the LSB (2 = 1), whereas bit 1 represents the MSB (2 = 2) of the binary number. Setting these
two bits to a combination of either logic 0 or logic 1 assigns the priorities 0, 1, 2, or 3.

2/7/07 Page 10/18


Project Report David Fischer

4.2 Source Code


The source code of test.c can be found in the appendix. Fist, the PIC is configured and the
global variables are defined. After that, the main function does the following things:
• Initialize PIC’s digital I/O ports
• Initialize PIC’s timer0 which is used for the tick interrupt service routine
• Determine the task’s priorities by reading from the digital input switches (see table 4-1)
• Initialize µC/OS-II
• Create four tasks (details are described in the next chapter)
• Start µC/OS-II

4.2.1 Tasks
Four tasks are created. The first task with the highest priority is the task manager. It
assigns the priorities for the other three tasks on-the-fly by reading from the digital input
switches. This process works as follows:
• Determine the task’s priorities by reading from the digital input switches
• If priorities have changed assign dummy priorities to all three tasks (this is to ensure
that no tasks have the same priority at any given time)
• Assign the new priorities to the three tasks
• Delay for some time to yield the CPU to the other tasks
• Start over

The other three tasks are all the same. They count from 0 to 9 in an endless loop if they
are switched on. If they are switched off they delay until they are switched on again. This is
to yield the CPU to the other tasks. Tasks with higher priorities always preempt tasks with
lower priorities. As long as higher priority tasks are running, lower priority tasks cannot run.
Therefore, a higher priority task has to be turned off if a lower priority task wants to run.

4.2.2 Final Code Size


The final hex-file size of the kernel and the test.c code is about 16 KB which includes some
overhead (byte count, memory address, record type, check sum). The actual code size is
only 11.2 KB!

2/7/07 Page 11/18


Project Report David Fischer

5. Conclusion and Outlook


The project goals could be achieved. The µC/OS-II port for the PIC18F family has been
successfully compiled and tested.
Unfortunately, it was not possible to run µC/OS-II in the Virtual Breadboard simulator. Even
though the developer of Virtual Breadboard has been very helpful and has quickly resolved
some issues, the author could not get it working. Therefore, the author decided to use real
hardware on a real breadboard.
Once the µC/OS-II port’s basic functionality was tested, a test code which creates, runs,
and manages three counter tasks has been implemented. The correct function can be
presented using the hardware on the breadboard.
Apart from the Virtual Breadboard problem, there were some other minor problems that
had to be solved. Some changes and adjustments in the µC/OS-II port code had to be
made in order to get it working with the latest version of the MPLAB C18 compiler. Also,
the author had to get familiar with the hardware design surrounding the PIC18F452.
In conclusion, the project has been an excellent and challenging experience. µC/OS-II is
an outstanding example of an embedded OS and the author has learned a lot along the
way.
Future steps in the project will include the fabrication of a PCB for the hardware instead of
the breadboard. Additionally, the functionality of the software could be extended for using
additional services of µC/OS-II.

2/7/07 Page 12/18


Project Report David Fischer

References
[1] Microchip Technology, Inc., Website.
http://www.microchip.com

[2] Micriµm, Inc., Website.


http://www.ucos-ii.com

[3] Virtual Breadboard, Website.


http://www.virtualbreadboard.com

[4] Microchip Technology, Inc., PIC18FXX2 Data Sheet, PDF Document.


http://ww1.microchip.com/downloads/en/DeviceDoc/39564c.pdf

[5] Labrosse, Jean J., MicroC OS II: The Real Time Kernel, Newnes, June 2002.
http://www.amazon.com/exec/obidos/tg/detail/-/1578201039

[6] Sputnick Online, Website.


http://www.sputnickonline.com/projects/programs/micro/uCOS_for_PIC18

2/7/07 Page 13/18


Project Report David Fischer

Appendix: Source Code of test.c

/*****************************************************************************
* Filename : test.c *
* Purpose : Implement 3 test tasks and a task manager for uC/OS-II *
* Project : NPU / CE589B *
* MCU : PIC18F452 *
* Language : C *
* Compiler : MPLAB IDE v7.40 / MPLAB C18 v3.02 *
* *
* Programmed by : David Fischer *
* *
* Version/Date : 1.0 / 07-1-16 *
* Changes : *
*****************************************************************************/

//----------------------------------------------------------------------------
// Config
//----------------------------------------------------------------------------

#include "includes.h"
#include "timers.h"
#include "delays.h"

// PIC configuration
#pragma config OSC = HS
#pragma config BOR = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF

// Number of tasks
#define TASK_NUMBER 3

//----------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------

// Stack for tasks


OS_STK taskmanagerStk[100L];
OS_STK countertask1Stk[150L];
OS_STK countertask2Stk[200L];
OS_STK countertask3Stk[250L];

INT8U prio_old[TASK_NUMBER+1];
INT8U prio_new[TASK_NUMBER+1];

2/7/07 Page 14/18


Project Report David Fischer

//----------------------------------------------------------------------------
// Initialize I/O ports
//----------------------------------------------------------------------------

void port_init(void)
{
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;
ADCON1 = 0x07; // disable analog inputs
INTCONbits.RBIE = 0; // disable RB interrupt
TRISB = 0x00; // outputs
TRISC = 0x00; // outputs
TRISD = 0x00; // outputs
}

//----------------------------------------------------------------------------
// Initialize timer
//----------------------------------------------------------------------------

void timer_init(void)
{
OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_4);
WriteTimer0(-10000);
}

//----------------------------------------------------------------------------
// Determine task priorities from PORTA
//----------------------------------------------------------------------------

void get_prio(void)
{
prio_old[1] = prio_new[1];
prio_new[1] = PORTA & 0x03;
prio_old[2] = prio_new[2];
prio_new[2] = PORTA >> 2 & 0x03;
prio_old[3] = prio_new[3];
prio_new[3] = PORTA >> 4 & 0x03;
}

2/7/07 Page 15/18


Project Report David Fischer

//----------------------------------------------------------------------------
// 1. Task: Task manager
//----------------------------------------------------------------------------

void taskmanager(void *pdata)


{
pdata = pdata;

while (1)
{
get_prio();

if (prio_old[1] != prio_new[1] || prio_old[2] != prio_new[2] ||


prio_old[3] != prio_new[3])
{
OSTaskChangePrio(prio_old[1],10);
OSTaskChangePrio(prio_old[2],11);
OSTaskChangePrio(prio_old[3],12);
OSTaskChangePrio(10,prio_new[1]);
OSTaskChangePrio(11,prio_new[2]);
OSTaskChangePrio(12,prio_new[3]);
}

OSTimeDly(100);

// while (PORTEbits.RE0 == 0); --> not used at this time


}
}

//----------------------------------------------------------------------------
// 2. Task: Counter 1
//----------------------------------------------------------------------------

void countertask1(void *pdata)


{
pdata = pdata;

while (1)
{
while (PORTEbits.RE0 == 0) // Task on/off switch
{
OSTimeDly(100);
}

Delay10KTCYx(100);

while (PORTB < 0x09)


{
PORTB ++;
Delay10KTCYx(100);
}

PORTB = 0x00;
}
}

2/7/07 Page 16/18


Project Report David Fischer

//----------------------------------------------------------------------------
// 3. Task: Counter 2
//----------------------------------------------------------------------------

void countertask2(void *pdata)


{
pdata = pdata;

while (1)
{
while (PORTEbits.RE1 == 0) // Task on/off switch
{
OSTimeDly(100);
}

Delay10KTCYx(100);

while (PORTC < 0x09)


{
PORTC ++;
Delay10KTCYx(100);
}

PORTC = 0x00;
}
}

//----------------------------------------------------------------------------
// 4. Task: Counter 3
//----------------------------------------------------------------------------

void countertask3(void *pdata)


{
pdata = pdata;

while (1)
{
while (PORTEbits.RE2 == 0) // Task on/off switch
{
OSTimeDly(100);
}

Delay10KTCYx(100);

while (PORTD < 0x09)


{
PORTD ++;
Delay10KTCYx(100);
}

PORTD = 0x00;
}
}

2/7/07 Page 17/18


Project Report David Fischer

//----------------------------------------------------------------------------
// Main function
//----------------------------------------------------------------------------

void main(void)
{
port_init();

timer_init();

get_prio();

OSInit();

OSTaskCreate(taskmanager, (void *)0, (OS_STK *)&taskmanagerStk[0], 0);

OSTaskCreate(countertask1, (void *)0, (OS_STK *)&countertask1Stk[0],


prio_new[1]);

OSTaskCreate(countertask2, (void *)0, (OS_STK *)&countertask2Stk[0],


prio_new[2]);

OSTaskCreate(countertask3, (void *)0, (OS_STK *)&countertask3Stk[0],


prio_new[3]);

OSStart();
}

2/7/07 Page 18/18

You might also like