You are on page 1of 4

Small operating system for Freescale HCS08 microcontrollers

Jan Dolinay, Petr Dostlek, Vladimr Vaek


Faculty of Applied Informatics Tomas Bata University in Zlin Zlin, Czech Republic e-mail: dolinay@fai.utb.cz

AbstractThis contribution deals with small real-time operating system RTMON developed at our institute as a teaching aid for microcontroller programming lessons. This new system is based on previous versions of RTMON for HC11 microcontroller and for PC. It should make it possible for students to understand the basic concepts of creating applications with use of operating system and easily write their own applications with several concurrently running processes in C language. The operating system currently works on Freescale HCS08 GB60 and QE128 microcontrollers and also on Atmel AVR Mega8 microcontroller. Keywords-Microcontroller, system HC08, real-time, operating

I.

INTRODUCTION

In microcontroller (MCU) programming, real time operating system (RTOS) can be used to help solve the usual problems related with this task, for example, the requirement of executing multiple tasks concurrently, quick response to high priority events, managing hardware resources of the MCU, etc. In our lessons of microcontroller programming we include RTOS based programming as well. On 16-bit or 32-bit MCUs, RTOS are used quite often; on smaller 8-bit systems it is not usual, because these systems have limited memory and CPU power and it is more efficient to write the required program without RTOS. Nevertheless, if the RTOS is small enough to fit into such MCU, it can still bring the same advantages as on a bigger MCUs. In our lessons we use Freescale Semiconductor 8-bit MCU with HCS08 core. As we wanted to include a RTOS programming techniques into our lessons we needed a RTOS capable of running on this MCU. The other options would be to add to our portfolio another MCU, e.g. 32-bit, but then the students would have to learn 2 different MCUs in the same limited time, which would probably lead to confusion. Moving to 32 MCU completely, abandoning 8-bit would seems as better option, maybe, but this would have the disadvantage that such an MCU is typically very complex (many peripherals with advanced functionality resulting in many control registers). For programming such an MCU one typically uses software drivers (either stand-alone or included in a RTOS) because programming some peripheral at the level of setting up the register values is very long and tedious task. This would not fit the purpose of our course, which is to give the students understanding of the basic principles.

If we look at the available RTOS there are quite many of them. As mentioned above, most of them are focused on bigger 16-bit and 32-bit MCUs, but there are some which support also small 8 bit MCUs. FreeRTOS [2] can be mentioned, which is distributed under GPL license and currently officially ported to 23 architectures. Another example is MicroC/OS-II [3] which is also free for educational, non-commercial use. It is suitable for use in safety critical embedded systems such as aviation or medical systems and is ported to great number of architectures including Freescale HC08 and Atmel AVR. One disadvantage of using such a professional system is that it is often quite complex due to the wide options it offers; typical RTOS for 32 bit MCU contains drivers for USB, Ethernet etc. and even though it is configurable to work in simple arrangements, the user can still have too many things to worry about. Moreover, there was already an RTOS system developed at our institute for PC based systems and also for HC11, and the students are familiar with its interface. So even if it would not be impossible to choose from existing systems, it was decided to implement a light-weight version of the RTMON system for our lessons. Once the system was up and running for our HCS08 derivative (GB60) it became useful to port it to other derivatives also. As a result, RTMON currently supports two members of HCS08 MCU family: GB60 and QE128 [4], and also Atmel AVR MCUs ATmega8 and ATMega168. Adding new derivative is quite simple so the list will possibly grow in the future. In the following text we describe the properties of the RTMON for HC08 (and AVR) microcontrollers, the original system for PC and HC11 has wider options II. RTMON DESCRIPTION

The RTMON system is used as a precompiled library accompanied by a header file. This simplifies the organization of the project and the build process. User enables RTMON usage in his program by including the header file (rtmon.h) in his source and by adding the library to his project. Currently the library and sample projects are available for two development tools: Freescale CodeWarrior and Atmel AVR Studio with WinAVR suite. If needed, user can also rebuild the RTMON library. Typically this is useful to change the configuration such as maximum number of tasks, length of the OS time period (tick), etc. There is documentation which describes the

978-1-61284-361-2/11/$26.00 c 2011 IEEE

70

procedure and also projects for the two supported IDEs, which can be simply opened and rebuild. RTMON is preemptive multitasking OS which is simplified to a great extend to allow easy use for students. It is written in C language with the exception of small platform-specific code written in assembler. The scheduler assigns time slices to processes based on their priority. The priority is integer in the range 1 to 254. Priority 0 is the highest and is reserved for the RTMON initialization process and priority 255 is the lowest and is reserved for the idle process (called dummy in RTMON). RTMON allows execution of two different types of processes (taks): normal processes which execute only once (such process typically contain infinite loop) and periodical process which is started automatically by RTMON with given period. These periodical processes are useful for many applications, typically for example in discrete controllers which need to periodically sample the input signal and update the outputs. For the sake of simplicity of both the implementation and usage, several restrictions are applied. First, the RAM memory for processes and their stacks is statically allocated for the maximal number of processes as defined in configuration file. In the user program, it is not possible to use this memory even if there are fewer processes defined. In case more RAM is needed for the user program, the maximum number of tasks and/or stack-pool size can be changed in configuration file and the RTMON library must be rebuild. The priority of each task must be unique, so that in each moment one task (the one with highest priority) can be selected and executed on the CPU. The scheduler does not support cyclical switching of several processes with the same priority on the CPU in round-robin fashion; it simply chooses the task with highest priority from the list of tasks which are ready to run. Processes can be created on the fly, but it is not possible to free and reuse memory of a process. No more than the maximal number of processes can be created, even if some processes were previously deleted. These restrictions however do not present any big problem for most applications and allow for small kernel code size and ease of use. There are only two objects (data structures) in the RTMON system: process (task) and queue. The queues are buffers for transferring data between processes. It would more properly be called mailboxes in our implementation as each queue can contain only 1 message. Several queues can be created, each containing a message (data buffer) of certain size. The size can be specified when creating the queue and is limited by the total size of RAM reserved for all buffers of all the queues (queue pool size). Processes can read and write data to the queue and wait for the queue to become empty or to become full. This allows for use of the queue also as a synchronization object (semaphore). III. RTMON SERVICES

function in the RTMON library which user program can call. These functions are described in more details below. create process start process stop process delay process continue process execution abort (delete) process For queues there are the following functions: create queue (specify size) write to queue with/without waiting read from queue with/without waiting There are also two functions for controlling the RTMON itself: initialize RTMON end RTMON operation First service called by the user program should be rtm_init, which has the following prototype: char rtm_init(IDPROC** init_id); This function will initialize RTMON data structures and create 2 built-in processes: init and dummy. The dummy is the idle process which runs when no other process is ready to run. It has priority 255, which is the lowest. The init process in RTMON is a special process with highest priority (0) and it is the process which controls creation and end of all other processes. By calling rtm_init the user program obtains ID of this init process. In fact, the C function which calls rtm_init (typically it is the main() function) becomes the body of the init process. So from the call to rtm_init on from the RTMONs point of view the code of function main is now the code of the init process and it is executed until it delays itself by call to rtm_delay_p. The init process will create other processes and then start them, but no other process will actually execute until init process puts itself into sleep because the init process has the highest priority. The returned value is either RTMON_OK of one of the error codes defined in RTMON.h. This is the convention for all RTMON functions that they returns this code. Function rtm_end is used to end RTMON operation. char rtm_end(IDPROC* init_id); It stops the init and dummy processes and stops the periodical timer interrupt which provides ticks for the OS. This service can be called at the end of user program (end of main function). However, since typical embedded application runs infinitely and never ends, it is often not needed to call this service at all. Services for working with processes start with the function which creates a new process rtm_create_p, which has the following prototype: char rtm_create_p(const char* pname, unsigned char prio, void(*pfunc)( ), int stack_size, IDPROC** proc_id );

The following basic operations can be performed with a process in RTMON. Each operation corresponds to a

2011 12th International Carpathian Control Conference (ICCC)

71

This service creates a new process in RTMON and returns the caller (via the proc_id parameter) the identificator of this process which is then used for all further operations with this process (e.g. to start or stop it). The arguments of this function must provide enough information to configure the process. pname this is descriptive name of the process. It is currently not supported by RTMON to save memory, so it is ignored and need not be set. prio the priority of the process. This is integer between 1 and 254, the values 0 and 255 are reserved for RTMON. The higher is the number the lower is the priority. pfunc pointer to the function which represents the process. This is the code of the process. stack_size size of the stack for this process. Each process has its own stack which must be big enough to hold all CPU registers (saved on interrupt), all local variables (defined within the function which represents the process) and all return addresses for function calls made from the process including system calls. RTMON keeps an array in RAM (stack pool) from which it allocates stacks as specified in call to rtm_create_p. The maximal size of stack of all processes cannot exceed the size of this stack pool. The pool size is defined in header file and can be changed, but the RTMON library must be then rebuilt. Required size of stack depends on architecture and also on the number of variables and function calls in the process, typical minimum value is about 32 bytes if the process uses virtually no stack and about 64 for normal processes. If some stack-consuming function is used, the stack size must be extended accordingly. For example, on HC08 GB60 we found out that when using sprintf function within the process, the stack should be at least 100 bytes big, or even more. char rtm_start_p(IDPROC* proc_id, int time_to_start, int time_period); Starts a process. After using rtm_create_p the process exists in RTMON but is not scheduled, not executed on the CPU. For the process to actually start executing, it must be started by rtm_start_p service. proc_id - is the ID of the process to start. It is obtained by previous call to rtm_create_p. time_to_start is the delay for the start, so that the process is not started immediately but only after specified number of ticks. Typically this argument has value 0 which means the process is started immediately. time_period this argument allows specifying the period with which the process is automatically restarted. If it is 0 the process is started only once (typical for processes which then run in infinite loop). If it is nonzero then is the period in ticks with which the process is started repeatedly. It is important to ensure that the process ends in shorter time than is the period of start in this case. This is

useful for high priority processes which need to periodically perform some short action, e.g. measure input and save the result. char rtm_delay_p(IDPROC* proc_id, int time_to_delay); This service allows pausing execution of given process for specified period of time (given in ticks). Value of 0 means infinite delay, which puts the process into sleep until it is waken up by other process. char rtm_continue_p(IDPROC * proc_id); This service continues execution of a process previously delayed by rtm_delay_p call. char rtm_ch_period_p(IDPROC * proc_id, int time_period); This service changes the period of a process. The argument time_period specifies the new period of start of the process. Typical use of this function is to cancel the periodical start of a process by calling this function with time_period equal to 0. This is necessary when periodical process is to be stopped because without changing the period to 0 (canceling periodical start) the process would automatically start in the next period. char rtm_stop_p(IDPROC * proc_id ); Stops execution of a process. Most common use is to call this function at the end of the process in periodical processes. Such process must end by this call to return control to RTMON. Another use is to stop all processes when RTMON is ended if such situation is needed. char rtm_abort_p(IDPROC * proc_id ); Removes process from the list of existing processes in RTMON. This function has currently no use because RTMON does not allow reclaiming memory occupied by a process when the process is aborted, so even if process is aborted, it does not allow creating a new process instead if the maximum number of processes is reached. Besides the services for working with processes, RTMON also contains services for working with queues. Queues are optional component which can be excluded from the system if not needed, to save memory. In such case these services are not available. There are three basic operations supported on a queue: create, write and read. Deleting a queue is not supported. It is assumed that the developer defines all required queues ahead and does not need to dynamically create and delete queues in the run time. Before use, queue must be created using rtm_create_q service which has the following prototype: char rtm_create_q(const char* pname, char l_msg, char n_buff, IDQUEUE** pid_queue); pname is the name of the queue, it is not used similarly as in process name in rtm_create_p. l_msg is the size of the buffer (message) which this queue can hold. The size is limited by size of queue

72

2011 12th International Carpathian Control Conference (ICCC)

pool defined in RTMON for all queues. Typically this operand is given as sizeof of the type passed by this queue. For example, if processes will exchange an integer value through this queue, then the l_msg argument would be given as sizeof(int). n_buff the number of messages (buffers) this queue can hold. This argument must be 1, this version of RTMON does not support more than one message. pid_queue - this receives the id of the newly created queue. User program then uses this ID for all further operations with the queue. For writing and reading messages to queues there are two versions of functions one with suffix _w which stands for wait. Such function waits for the queue to become full/empty if it is not in the proper state. These wait functions can be used to synchronize process execution. The queue functions have the following prototypes: char rtm_write_q(IDQUEUE* pid_queue, void* pdata); char rtm_write_q_w(IDQUEUE* pid_queue, void* pdata); char rtm_read_q(IDQUEUE* pid_queue, void* pdata); char rtm_read_q_w(IDQUEUE* pid_queue, void* pdata); pid_queue is the ID of the queues obtained by previous call to rtm_create_q and pdata is pointer to memory buffer which received or contains the data to be read from or written to the queue. RTMON always reads/writes the number of bytes defined by queue size into this buffer; the user must ensure that this buffer has the proper size (is a pointer to proper data type). IV. CONFIGURING RTMON

There are projects prepared for these IDEs, so rebuilding the RTMON library is just a matter of opening the project, changing defines in the header file as required and rebuilding the project. VI. CONCLUSION

There are several macros defined RTMON configuration file which allow customizing the system to users needs. It is important to note however, that after changing any of these defines the RTMON library must be rebuild, otherwise the changes have no effect. Examples of configuration constants are: RTMON_SMALL allows using 8-bit instead of 16-bit variables in process data structure. USE_QUEUES allows removing the queues from the RTMON library, so that if queues are not needed, the respective functions can be removed and thus memory space is saved. V. REBUILDING RTMON

Simple real-time operating system for Freescale HCS08 microcontrollers has been created. This system is intended as a teaching aid for lessons of microcontroller programming. The interface is based on already existing version of the system for PC and HC11 microcontroller, but the internals have been written completely for the scratch to allow it to work with limited data and code memory of small 8-bit microcontrollers. RTMON is pre-emptive multitasking system which allows defining processes up to certain number (typically 10) and running these processes either in infinite loops or periodically with given period. Available functions are very simple due to the limited memory of the target microcontrollers and intended use of the system, but still the system provides the advantage of easy implementation of embedded system as a set of independent, concurrently running tasks. The main limitation of current implementation can be seen in the inefficient use of RAM memory for process stacks and queues which are allocated at build-time of the RTMON library and must be therefore defined in close relation with intended application, number of processes and their contents. This implementation is advantageous for school exercises because it allows easier implementation in user application, but for practical use in the industry it is not comfortable as it requires rebuilding the library for each application. However, this rebuild is not a difficult task, so even in this implementation the system is usable. Currently, RTMON is ported to Freescale HCS08 GB60 and QE128 derivatives and to Atmel AVR Mega8 MCU. The source code is structured for easy modification and porting to other platforms. In the future it would be desirable to port RTMON to more MCUs, but also to extend the functionality by some I/O drivers, such us driver for general purpose inputs and outputs, serial communication etc. ACKNOWLEDGMENT This work was supported by the Ministry of Education, Youth and Sports of the Czech Republic under the Research Plan No. MSM 7088352102 and by the European Regional Development Fund under the project CEBIA-Tech No. CZ.1.05/2.1.00/03.0089. REFERENCES
[1] [2] [3] [4] T. D. Morton, Embedded Microcontrollers, Prentice Hall, Upper Saddle River, 2001. The FreeRTOS Project. Available from: <http://www.freertos.org> Micrium RTOS and Tools. Available from: <http://micrium.com/page/products/rtos/os-ii> Freescale 8-bit microcontrollers. Available from: <http://www.freescale.com/webapp/sps/site/homepage.jsp?code=8BI TMCU>

As mentioned, RTMON can be customized by either the configuration defines described earlier or by modifying the code itself. In either case the system library must be rebuild. Rebuilding the system is not different from building any other program in the development IDE. In case of HCS08 microcontrollers, this IDE is CodeWarrior, in case of AVR MCUs, this is AVR Studio with WinAVR tools installed.

2011 12th International Carpathian Control Conference (ICCC)

73

You might also like