DOC

Chapter8PORTING

By Warren Brown,2014-04-16 09:18
9 views 0
Chapter8PORTING

     Chapter 8

Porting µC/OS-II

    This chapter describes in general terms what needs to be done in order to adapt µC/OS-II to different processors. Adapting a real-time kernel to a microprocessor or a microcontroller is called a port. Most of µC/OS-II is written in

    C for portability, however, it is still necessary to write some processor specific code in C and assembly language. Specifically, µC/OS-II manipulates processor registers which can only be done through assembly language. Porting µC/OS-II to different processors is relatively easy because µC/OS-II was designed to be portable. If you already have a port for the processor you are intending to use then you don’t need to read this chapter, unless of course you want to know how µC/OS-II’s processor specific code works.

A processor can run µC/OS-II if it satisfies the following general requirements:

    1. You must have a C compiler for the processor and the C compiler must be able to produce reentrant

    code.

    2. You must be able to disable and enable interrupts from C.

    3. The processor must support interrupts and you need to provide an interrupt that occurs at regular

    intervals (typically between 10 to 100 Hz).

    4. The processor must support a hardware stack, and the processor must be able to store a fair amount of

    data on the stack (possibly many Kbytes).

    5. The processor must have instructions to load and store the stack pointer and other CPU registers either

    on the stack or in memory.

    Processors like the Motorola 6805 series do not satisfy requirements #4 and #5 so µC/OS-II cannot run on such processors.

    Application Software

    /OS-II/OS-II Configuration

    (Processor Independent Code)(Application Specific)

    uCOS_II.COS_CORE.C

    uCOS_II.HOS_MBOX.COS_CFG.HOS_MEM.CINCLUDES.HOS_Q.C

    OS_SEM.C

    OS_TASK.C

    OS_TIME.C

    /OS-II Port

    (Processor Specific Code)

    OS_CPU.H

    OS_CPU_A.ASM

    OS_CPU_C.C

    Software

    Hardware

    CPUTimer

    Figure 8-1, µC/OS-II Hardware/Software Architecture

Figure 8-1 shows µC/OS-II’s architecture and its relationship with the hardware. When you use µC/OS-II in an

    application, you are responsible for providing the Application Software and the µC/OS-II Configuration sections. This books (and diskette) contains all the source code for the Processor Independent Code section as well as the Processor Specific Code for the Intel 80x86, Real Mode, Large Model. If you intend to use µC/OS-II on a different

    processor, you will need to either obtain a copy of a port for the processor you intend to use or, write one yourself if the

    desired processor port is not available. Check the official µC/OS-II WEB site at www.uCOS-II.com for a list of available ports.

Porting µC/OS-II is actually quite straightforward once you understand the subtleties of the target processor and the

    C compiler you will be using. If your processor and compiler satisfy µC/OS-II’s requirements, and you have all the necessary tools at your disposal, porting µC/OS-II consists of:

    1. Setting the value of 1 #define constants (OS_CPU.H)

    2. Declaring 10 data types (OS_CPU.H)

    3. Declaring 3 #define macros (OS_CPU.H)

    4. Writing 6 simple functions in C (OS_CPU_C.C)

    5. Writing 4 assembly language functions (OS_CPU_A.ASM)

    Depending on the processor, a port can consist of writing or changing between 50 and 300 lines of code! Porting µC/OS-II could take you anywhere between a few hours to about a week.

    Once you have a port of µC/OS-II for your processor, you will need to verify its operation. Testing a multitasking real-time kernel such as µC/OS-II is not as complicated as you may think. You should test your port without application code. In other words, test the operations of the kernel by itself. There are two reasons to do this. First, you don’t want to complicate things anymore than they need to be. Second, if something doesn’t work, you know that the problem lies in the port as opposed to your application. Start with a couple of simple tasks and only the ticker interrupt service routine. Once you get multitasking going, it’s quite simple to add your application tasks.

8.00 Development Tools

    As previously stated, you need a C compiler for the processor you intend to use in order to port µC/OS-II. Because µC/OS-II is a preemptive kernel, you should only use a C compiler that generates reentrant code. Your C compiler must also be able to support assembly language programming. Most C compiler designed for embedded systems will, in fact, also include an assembler, a linker, and a locator. The linker is used to combine object files (compiled and assembled files) from different modules while the locator will allow you to place the code and data anywhere in the memory map of the target processor. Your C compiler must also provide a mechanism to disable and enable interrupts from C. Some compilers will allow you to insert in-line assembly language statements in your C source code. This makes it quite easy to insert the proper processor instructions to enable and disable interrupts. Other compilers will actually contain language extensions to enable and disable interrupts directly from C.

8.01 Directories and Files

    The installation program provided on the distribution diskette will install µC/OS-II and the port for the Intel 80x86 (Real Mode, Large Model) on your hard disk. I devised a consistent directory structure to allow you to easily find the files for the desired target processor. If you add a port for another processor, you should consider following the same conventions.

    All the ports should be placed under the \SOFTWARE\uCOS-II directory on your hard drive. The source code for each microprocessor or microcontroller port MUST be found in either two or three files: OS_CPU.H,

    OS_CPU_C.C and optionally, OS_CPU_A.ASM. The assembly language file is optional because some

    compilers will allow you to have in-line assembly language and thus, you can place the needed assembly language code directly in OS_CPU_C.C. The directory in which the port is located determines which processor you are using. Below are examples of the directories where you would store different ports. Note that each have the same file names even though they are totally different targets.

    Intel/AMD 80186: \SOFTWARE\uCOS-II\Ix86S:

     OS_CPU.H

     OS_CPU_A.ASM

     OS_CPU_C.C

     \SOFTWARE\uCOS-II\Ix86L:

     OS_CPU.H

     OS_CPU_A.ASM

     OS_CPU_C.C

    Motorola 68HC11: \SOFTWARE\uCOS-II\68HC11:

     OS_CPU.H

    OS_CPU_A.ASM

     OS_CPU_C.C

8.02 INCLUDES.H

    As I mentioned in chapter 1, INCLUDES.H is a MASTER include file and is found at the top of all .C files as follows:

     #include “includes.h”

INCLUDES.H allows every .C file in your project to be written without concerns about which header file will

    actually be needed. The only drawback to having a master include file is that INCLUDES.H may include header

    files that are not pertinent to the actual .C file being compiled. This means that each file will require extra time to

    compile. This inconvenience is offset by code portability. You can edit INCLUDES.H to add your own header

    files but, your header files should be added at the end of the list.

8.03 OS_CPU.H

    OS_CPU.H contains processor and implementation specific #defines constants, macros, and typedefs.

    The general layout of OS_CPU.H is shown in listing 8.1:

     #ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif /* ********************************************************************************************************* * DATA TYPES * (Compiler Specific) ********************************************************************************************************* */ typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /* Unsigned 8 bit quantity */ (1) typedef signed char INT8S; /* Signed 8 bit quantity */ typedef unsigned int INT16U; /* Unsigned 16 bit quantity */ typedef signed int INT16S; /* Signed 16 bit quantity */ typedef unsigned long INT32U; /* Unsigned 32 bit quantity */ typedef signed long INT32S; /* Signed 32 bit quantity */ typedef float FP32; /* Single precision floating point */ (2) typedef double FP64; /* Double precision floating point */ typedef unsigned int OS_STK; /* Each stack entry is 16-bit wide */ /* ********************************************************************************************************* * Processor Specifics ********************************************************************************************************* */ #define OS_ENTER_CRITICAL() ??? /* Disable interrupts */ (3) #define OS_EXIT_CRITICAL() ??? /* Enable interrupts */ #define OS_STK_GROWTH 1 /* Define stack growth: 1 = Down, 0 = Up */ (4) #define OS_TASK_SW() ??? (5)

    Listing 8.1, Contents of OS_CPU.H

8.03.01 OS_CPU.H, Compiler Specific Data Types

    Because different microprocessors have different word length, the port of µC/OS-II includes a series of type definitions that ensures portability. Specifically, µC/OS-II’s code never makes use of C’s short, int and, long

    data types because they are inherently non-portable. Instead, I defined integer data types that are both portable and intuitive L8.1(1). Also, for convenience, I have included floating-point data types L8.1(2) even though µC/OS-II doesn’t make use of floating-point.

    The INT16U data type, for example, always represents a 16-bit unsigned integer. µC/OS-II and your application code can now assume that the range of values for variables declared with this type is from 0 to 65535. A µC/OS-II port to a 32-bit processor could mean that an INT16U is actually declared as an unsigned short instead of an

    unsigned int. Where µC/OS-II is concerned, however, it still deals with an INT16U.

You must tell µC/OS-II the data type of a task’s stack. This is done by declaring the proper C data type for OS_STK.

    If stack elements on your processor are 32-bit and your compiler documentation specify that an int is 32-bit then,

    you would declare OS_STK as being of type unsigned int. All task stacks MUST be declared using

    OS_STK as its data type.

&