uC/OS-II - Port for the LINUX Operating System

Copyright (C) Werner Zimmermann (wernerzimmermann.name)


Overview

uC/OS-II (uCOS II) is a small, yet powerful real-time operating system developed by Jean J. Labrosse and described in his book "MicroC/OS-II - The Real-Time-Kernel", Second Edition, published by CMP Books. The operating system is highly CPU independent and has been ported to numerous microprocessor platforms (see www.micrium.com). The source code as provided together with the book and via the web site may be freely used for non-commercial applications and educational purposes. Licenses for commercial use are available too.

This document describes the LINUX port of uC/OS-II, which allows to run uC/OS-II applications under LINUX. As the port relies on LINUX' process and thread management features, the uC/OS-II LINUX port does ***NOT*** turn LINUX into a real-time operating system! It was developed for didactic purposes to teach students at the Esslingen University of Applied Sciences, Esslingen, Germany, the basics of real-time operating systems with an insight to OS internal implementation. This approach was chosen, because students do have much easier access to PCs at home or at university computing centers rather than to proprietary embedded systems. Powerful PC-based development tools like GCC are available free of charge as compared to costly embedded system cross-compilers and debuggers. Thus real-time system mechanisms can be studied with uC/OS-II under LINUX providing a soft real-time-environment on PCs at home or in the university computer center. If the basic functionality of the application is working correctly, the application can be easily ported to an embedded system later in the lab.


Release Notes

Only the port specific files of uC/OS-II (and some examples) are provided here. It is assumed, that you do have the uC/OS-II platform-independent source code as available together with the book or via www.ucos-ii.com. However, you can modify the example programs and recompile them without having installed the uC/OS-II source code, as long you do not touch the uC/OS-II configuration in os_cfg.h.

The port originally was developped with the uC/OS-II sources V2.52, which are distributed together with the second edition of Jean J. Labrosse's book. The current release was tested with uC/OS-II V2.84. You will need GNU GCC C-compiler to compile the LINUX samples provided here. The port has been developed using GCC 4.2.1. The LINUX port is based on the WIN32 port of the same author, so in many points a solution, which allowed to make the WIN32 and LINUX port match as closely as possible instead of a more elegant LINUX solution was chosen.

There have been reports, that the LINUX port does not run on SMP and/or Dual Core machines. This is not really astonishing, because the code does not contain any provisions to do so ... :-)) Unfortunately, due to a big shortage in available time, this probably will not change for a while. Help with this issue would be welcome ...

V1.5 is the first published version of the LINUX port, as I chose to have the same version number for WIN32 and Linux.

In V1.6 the resolution of the time measurement PC_Elapsed... in the Cygwin GCC and LINUX version was improved. Now these ports also use the Pentium time stamp counter.

In V2.0 signal handling was modified to adapt it to Linux kernel version 2.6.x. Older versions did not run with that kernel, because the Linux thread implementation saw some changes, which were not backward compatible. In V2.0 instead of getpid() now gettid() and instead of kill() now tkill() is used. Real code changes were kept small by using #define in os_cpu.h.

V2.1 some include paths were modified to work with uC/OS-II 2.70.

V3.0 was modified to be compatible with uC/OS-II 2.8x and some internal functions were modified to make the code easier to maintain.

V3.1 saw slight modifications to be compatible with uC/OS-II 2.84 and GCC 4.2.1. It was tested under OpenSuSE 10.3 with kernel 2.6.22 (modified by SuSE). In the past from time to time I got reports, that the port may have problems with different kernel and/or compiler or glibc versions. This is not really astonishing, because the Linux guys are changing the Linux scheduler and thread handling more frequently than ever even in the so called "stable" kernel versions. Strange but true, since Linux is a real competition to Windows, its stability has more and more become like that of Windows ...

V3.2 was slightly modified to keep example sources between Linux and Win32 in sync.


Installation, Running and Recompiling the Samples

You should unpack the files of the LINUX port into the uC/OS-II installation directory (normally "/software/uCOS-II/"), keeping the directory structure of the LINUX port intact. If you installed uC/OS-II in "/software/uCOS-II" with uC/OS-II source files in "/software/uCOS-II/source", you will find the LINUX port for GCC in "/software/uCOS-II/Ports/80x86/Linux/GCC/" with the source code of the port files in subdirectory "./src", some examples under "./examples/" and some template files as starting point for your own applications in "./templates/".

To run one of the samples, CD to the appropriate sample's subdirectory, e.g. ".\examples\example1" and run the file "./test". All sample programs can be stopped by hitting the "ESC" key. The samples "example1", ..., "example4" are described in Jean J.Labrosse's book in chapter 1.

To recompile one of the samples, go to the appropriate sample's subdirectory and type "make". If you did not install uC/OS-II or the LINUX port as recommended, you may need to edit the sample's "makefile", where paths are set in the makefile variables UCOS_SRC, UCOS_PORT_SRC, UCOS_PORT_LIB and UCOS_PORT_EX. You can modify an example programs and recompile it without having installed the uC/OS source code, as long you do not touch the uC/OS-II configuration in os_cfg.h.

If you get some 'file not found' errors, check your path and file names, especially watch out for upper/lower case letter bugs and for '\' - '/' bugs . This especially happens, when copying files from Windows to LINUX, because LINUX is case-sensitive, whereas Windows is not and uses a different path delimiter.

As a starting point for your own applications you may use the template files in subdirectory "./templates". To get familiar with uC/OS-II read Jean J. Labrosse's book. To learn about the limitations of the LINUX port, you should read the section about LINUX port internals and limitations in this document.

There are several support functions for displaying characters or strings and measuring execution times and installing (simulated) "interrupt" service routines on the PC platform, see PC.c and PC.h in the "./src" subdirectory. Where possible, these functions were modeled according to the functions provided in Jean J. Labrosse's 80x86 real mode port.



LINUX Port Internals and Limitations

As LINUX does not allow application programs to bypass its own scheduler or provide their own timers and interrupt handlers, uC/OS-II scheduling and task managment functions must be remapped to LINUX functions.

The LINUX port is based on the WIN32 port of the same author, so in many points a solution, which allowed to make the WIN32 and LINUX port match as closely as possible instead of a more elegant LINUX solution was chosen. The WIN32 port uses WIN32 threads, which are suspended and resumed via WIN32 API functions and scheduling is triggered by WIN32 events. The LINUX port uses the same mechanisms with the system call clone() to create threads and LINUX signals instead of WIN32 events.

uC/OS-II tasks are mapped to LINUX threads. The mapping is done, when a task is created in OSTaskCreateHook(). Additionally two special LINUX threads OSScheduleThread() for thread scheduling handling and OSInterruptThread() for interrupt handling are created in OSInitHookBegin(). The scheduling and the interrupt thread are created with the a higher LINUX process priority. The threads associated with uC/OS-II tasks are created with a lower priority and set to suspended state (via signal SIGSTOP).

When the uC/OS-II scheduler preempts a task and wants to switch context to a new uC/OS-II task, the uC/OS-II context switch function OSCtxSw() or OSIntCtxSw() triggers the scheduler thread via a signal hScheduleEvent (=SIGCONT). Because the scheduling thread OSScheduleThread() has a higher LINUX priority than all the WIN32 threads associated with uC/OS-II tasks, LINUX will start the scheduling thread immediately. This thread will suspend the LINUX thread associated with the preempted uC/OS-II task and resume the LINUX thread associated with the new uC/OS-II task. Then the scheduler thread will wait for the next scheduler event (via system call pause()). So always exactly one LINUX thread associated with a uC/OS-II task will be ready to run, all other uC/OS-II task associated threads will be in LINUX suspended state. Thus this LINUX thread will be invoked by the LINUX operating system's internal scheduler, once the OSScheduleThread() waits for the next scheduling event, and will remain running until the uC/OS-II scheduler is invoked the next time and retriggers the OSScheduleThread().

To generate the uC/OS-II time tick, a LINUX timer is used. Theoretically this timer provides a 10ms resolution (LINUX internal time tick). Therefore your application should set OS_TICKS_PER_SECOND to not more than 100 ticks per second (i.e. to a tick period of 10ms min.). The timer will be started automatically via OSStartHighRdy() and OSTimeTickInit(), once your application starts uC/OS-II multitasking by calling OSStart().

LINUX periodically invokes a the signal handler OSTimeTickCallback() for the timer signal SIGALARM, which triggers the signal hInterruptEvent. Due to this signal, LINUX immediately invokes the interrupt thread OSInterruptThread(), because this thread has a higher process priority than all uC/OS-II task related threads. As expected by uC/OS-II, the interrupt thread calls OSTimeTick(), which may reschedule another uC/OS-II task. Then the interrupt thread waits for the next interrupt event.

uC/OS-II's critical sections normally disable interrupts. LINUX application programs, however, cannot disable interrupts. This issue is resolved by LINUX suspending the interrupt thread instead, once a uC/OS-II critical section is entered by OS_ENTER_CRITICAL().

uC/OS-II provides several hook functions to allow applications to modify the uCOS internal behaviour. Some of these hook functions are used to interact with the LINUX operating system in the LINUX port. Thus the following hooks MUST NOT be used by your application:

            OSInitHookBegin(), OSTCBInitHook()
            
If your application must execute own code when uC/OS-II calls these hooks, you should add this code in file os_cpu_c.c. The appropriate points are marked in the code by
            //ADD YOUR OWN HOOK CODE HERE IF NECESSARY
            
All other hook functions can be redefined by your application directly if you set OS_HOOKS_EN = 0, as described in the uC/OS-II documentation.

OS_TaskChangePrio() should not be used, i.e. OS_TASK_CHANGE_PRIO_EN should be set to 0 in OS_CFG.h.

uC/OS-II tasks are mapped to LINUX threads. These threads use their own LINUX stacks rather than the 'normal' uC/OS-II task stacks. Stack size and stack management during context switches are automatically handled by LINUX. Nevertheless for compatibility reasons, when a uC/OS-II task is created, a uC/OS-II stack must be provided. Only a few bytes of this stack will be initialized, but this stack will not really be used by the running tasks. If you plan to test your application under LINUX and then port it to an embedded system, you ***CANNOT*** use the LINUX simulation to find out the necessary stack size. Your uC/OS-II LINUX application should not rely on the uC/OS-II stack checking and clearing functions and should not use any stack related programming tricks.



Disclaimer and Copyright Information

All files are provided in the hope, that they might be useful, but without any warranty or support. You may use them on your own risk in non-commercial applications. Even if this software is provided free of charge, it is no freeware. It is copyrighted by Werner Zimmermann, but may be freely used for non-commercial applications. If you do modify the source code and/or implement additional features, you are expected to provide the author with a copy of your source code and a description of the changes.

uC/OS-II, Windows , LINUX and other product names mentioned here may be trademarks or registered trademarks of their respective owners.



(C) wernerzimmermann.name