ENEA OSE Epsilon ARM Kernel User's Guide
ENEA OSE Epsilon ARM Kernel User's Guide
ARM Kernel
ARM Kernel
Users Guide
Copyright
Copyright 2005 by Enea Embedded Technology. All rights reserved. No part of this publication may be reproduced, transmitted, stored in a retrieval system, or translated into any language or computer language, in any form or by any means, electronic, mechanical, optical, chemical or otherwise, without the prior written permission of Enea Embedded Technology. If, however, your only means of access is electronic, permission to print one paper hardcopy is hereby granted. The software described in this document is furnished under a licence agreement or a non-disclosure agreement. The software may be used or copied only in accordance with terms of agreement.
Disclaimer
Enea Embedded Technology makes no representations or warranties with respect to the contents hereof and specifically disclaims any implied warranties of merchantability or fitness for any particular purpose. Further, Enea Embedded Technology reserves the right to revise this publication and to make changes from time to time in the contents hereof without obligation to Enea Embedded Technology to notify any person of such revision or changes.
ARM Kernel
Trademarks
OSE is a registered trademark of Enea Embedded Technology
EArmKrnUG4.6
OSE Epsilon/ ARM Kernel
Contents
1 Introduction 2 Introduction to OSE
2.1 Definition of an RTOS 10 2.2 Purpose of an RTOS 10 2.3 Real-Time Operating System Tasks 10 2.3.1 Resource Management 11 2.3.2 Time Management 11 2.3.3 Interprocess Communication 11 2.3.4 Speed Considerations 12 2.4 OSE Design Benefits 12 2.5 Concurrent Processes 12 2.5.1 Process States 13 2.5.2 Priority Based Process Scheduling 14 2.5.3 Round-Robin Process Scheduling 14 2.6 Process Categories in OSE 16 2.7 Process Types in OSE 16 2.7.1 Prioritized Processes 17 2.7.2 Background Processes 17 2.7.3 Interrupt Processes 17 2.7.4 Interrupt Performance 18 2.7.5 Timer Interrupt Processes 19 2.8 OSE Operating System Tools 19 2.8.1 Messages 20 2.8.1.1 Message Passing Through Mailboxes 20 2.8.1.2 Direct Message Passing in OSE 21 2.8.2 Fast Semaphores 22 2.8.3 Semaphores 23
7 9
ARM Kernel
3 Getting Started
3.1 Example System Description 26 3.2 Step by Step Tutorial 28 3.2.1 Equipment 29 3.2.2 Preparation 30 3.2.3 OSE Configuration 30 3.2.4 Getting the System Files 33 3.2.5 Getting Specific Drivers 33 3.2.6 Getting the Example Source Files 34 3.2.7 Building the System with ARM ADS 35 3.2.8 Building the System with IAR EWB 36 3.2.9 Building the System with GNU GCC 37 3.2.10 Running the System without OSE Illuminator 40 3.2.11 Running the System with OSE Illuminator 40 3.2.12 Debugging 42 3.2.12.1 Epsilon Debug Server 42 3.2.12.2 Debugging with OSE Illuminator 42
25
Contents 3
43
ARM Kernel
5 Building a System
5.1 5.2 5.3 5.4 5.5 System Files 79 Configuration 79 Configuration Utility 79 Illuminator System Level Debugger 79 Assembly-Time Errors 80
77
6 System Design
6.1 System Creation Cycle 83 6.2 Processes 84 6.2.1 Prioritized Processes 85 6.2.2 Background Processes 86 6.2.3 Interrupt Processes 87 6.2.4 Timer Interrupt Processes 88 6.2.5 Selecting Process Type 89 6.2.6 Process Include Files 90 6.2.7 Process Declarations in C 91 6.2.7.1 Prioritized and Background Processes 91 6.2.7.2 Interrupt and Timer-Interrupt Processes 91 6.2.8 Process Declarations in Assembler 92 4 Contents
81
ARM Kernel
6.2.8.1 Prioritized and Background Processes 92 6.2.8.2 Interrupt and Timer-Interrupt Processes 92 6.2.9 Process Design Rules 93 6.3 Starting and Stopping Processes 93 6.4 Signals 94 6.4.1 Using Signals In Processes 95 6.4.2 Buffer Transfer 96 6.5 Fast Semaphores 97 6.6 Semaphores 97 6.7 Memory Utilisation 98 6.7.1 Global Variables 98 6.7.2 Memory Requirements 99 6.7.2.1 Memory Used By the Buffer Pool 99 6.7.2.2 Memory Required By Stacks 99 6.7.2.3 Memory requirements 100 6.8 Speed Considerations 102 6.8.1 Task Switch Performance 102 6.8.2 Timer-Interrupt Process Frequency 102 6.8.3 Signal Transmission Performance 103 6.8.4 Interrupt Handling Performance 103 6.8.5 Time Consumption of Other Functions 103 6.9 System Start 104 6.10 Writing the Interrupt Handler 104 6.10.1 Sample Interrupt Handler 104 6.10.2 Nested OSE Interrupts 104 6.10.3 Interrupt Enable/Disable Functions 105 6.11 Writing a Link Handler 106 6.11.1 Multiple Physical Links 107 6.11.2 Buffer Structure 107 6.11.3 Reformatting Buffers 107 6.12 Writing an Error Handler 108 6.12.1 Error Information 108 6.12.2 Continuing After an Error 110
7 Illuminator Debugger
7.1 Serial Line Connection 112 7.1.1 System Configuration 113 7.1.2 Testing the Target Debug Connection 114 7.1.3 Epsilon Debug Server 115 7.2 Symbolic Signal Information 116
111
8 Timeout Server
8.1 Request Timeout 118 8.2 Cancel Timeout 119 8.3 Retrigger Timeout 119
117
9 Glossary
121
Contents 5
ARM Kernel
6 Contents
1 Introduction
OSE for ARM is a fast, compact, real-time operating system for the ARM (Thumb) line of microprocessors from ARM Ltd. The purpose of this manual is to give the reader a good understanding of real-time system design in general, and the different mechanisms in OSE in particular. This manual is intended for users not familiar with real-time programming as well as experienced users and is intended for application developers. This manual describes how to use the ARM Kernel in the following sections:
Introduction to OSE on page 9 gives an introduction into OSE and describes its main features. Getting Started on page 25 is a step by step tutorial on how to generate a system. Configuring OSE Epsilon for ARM on page 43 describes how to configure a system. Building a System on page 77 explains how to build and to generate OSE for ARM system. System Design on page 81 explains how to design an OSE for ARM system. Illuminator Debugger on page 111 gives an introduction in the OSE Illuminator system level debugger. Timeout Server on page 117 contains information about the OSE for ARM Time Out Server. Glossary on page 121 defines common terminology used with OSE
ARM Kernel
Introduction 7
ARM Kernel
8 Introduction
2 Introduction to OSE
OSE is a fast, compact, real-time operating system (RTOS) for microprocessors and microcontrollers for embedded systems. A system under OSE consists of a number of independent subprograms called processes. A process may be written to some extent as if it had the entire CPU for its own exclusive use. By assigning a priority to each process, OSE ensures that the right process is always executing. An event which requires another process with a higher priority to execute, forces an immediate switch of process. This scheme ensures fast response to important events. Processes co-operate by exchanging signals. A process may send a signal to the mailbox of another process to inform the receiver of an event or to respond to an event. Signal transmissions often cause execution to switch to another process (a task switch). A signal is a dynamically allocated message buffer containing a signal number and an optional data structure.
ARM Kernel
Signal numbers are used to select which signals to receive, while leaving others in the mailbox of the receiving process. It is possible to ignore events which are unimportant at the moment simply by selecting which signals to receive. Other processes use the CPU while a process is waiting for a signal to arrive. Unused message buffers are stored in the central buffer pool until allocated by a process. Only one process at a time may access a signal (or message buffer), thereby eliminating conflicts. If a process needs to suspend execution for a specific interval of time, it calls OSE which monitors time and activates other processes during the wait. For more information on the OSE real-time operating system, see:
Definition of an RTOS on page 10 Purpose of an RTOS on page 10 Real-Time Operating System Tasks on page 10 OSE Design Benefits on page 12 Concurrent Processes on page 12 Process Categories in OSE on page 16 Process Types in OSE on page 16 OSE Operating System Tools on page 19 Fast Semaphores on page 22 Semaphores on page 23
Introduction to OSE 9
ARM Kernel
One major advantage of using a real-time operating system is that the manpower required to write a program system is substantially reduced. There are several reasons for this. One is that a large and potentially difficult part of the program has already been written and debugged before a project is even started. Another reason is that many small independent programs are considerably easier to write, debug and modify than one large complex program. Once a program system is written, it can be easier to debug when a real-time operating system is used if the debugging tools are designed to detect real-time problems in the interaction between many programs. The control structure of program systems without OS tends to vary considerably depending on both the application and the particular designer. Using an OS, the tools and techniques are the same in every project, making it much easier for programmers to be efficient in various projects.
Resource Management on page 11 Time Management on page 11 Interprocess Communication on page 11 Speed Considerations on page 12
10 Definition of an RTOS
ARM Kernel
To keep inter process connections as few as possible. To make inter process connections clearly visible. To use standardized inter process connections. To allow debugging to focus on the interaction between processes. To improve process response time.
Resource Management 11
ARM Kernel
12 Speed Considerations
If you are running a system without a real-time operating system, the processor will often find itself unable to respond quickly to an event if the wrong part of the program is running and continues to do so for some time. Herein lies an important distinction between an OSE real-time operating systems and other operating systems. The OSE real-time operating system has what is referred to as a "pre-emptive" dispatcher. This means that the dispatcher has the power to stop the current process after the next assembler instruction and immediately move execution to a completely different part of the program system. All OSE operating systems have pre-emptive dispatchers and can be pre-empted even inside system calls.
RUNNING The process is the one currently in control of the CPU. In a single processor system, only one process can be in this state at a time.
ARM Kernel
READY The process needs the CPU and will be running as soon as it is permitted to do so. However, another process of higher or equal priority is RUNNING and the READY process must wait until all READY processes of higher priority are WAITING.
WAITING The process is waiting for something, for example a message, and has no need of the CPU.
Process States 13
ARM Kernel
In priority based scheduling, processes are switched whenever a process on a higher priority level becomes READY. On the other hand, a process could run indefinitely if no process of higher priority became ready. That means that a process running indefinitely would lock out other processes. Another scheduling scheme is the round-robin principle. In this case, processes on the same priority level share CPU time, and they share it equally in the simplest case. When a process has used up its time-slice, it is interrupted by the operating system, even if the process is still RUNNING and may be put last in the queue. The size of time-slices need not be equal. The round-robin scheduling principle is used in many larger systems such as the UNIX operating systems. In such systems, the size of the time-slice is often changed at run-time according to various principles. Since round-robin is the only scheduling principle in many larger systems, response times are slow, for no process change occurs until the current time-slice is used up. Many unimportant processes may also be allocated CPU time before an important process. Many real-time operating systems allow the user to select either a priority based or a round-robin scheduling scheme. Some of them allow both principles to be used at the same time in one system. A system using both principles simultaneously might be utilized in the following way: 1. Time critical processes are scheduled on a priority basis and thus allowed to finish their job without interruption. 2. Operators are round-robin scheduled on one priority level. Operators have time- slices of equal length, except the superuser who has a longer time-slice. Operators thus share
the available CPU time equally. The superuser is allowed a larger share of CPU resources. None of the operators can lock the others out from the system. 3. Tests and other housekeeping processes share time on a lower priority level. They are allowed CPU time only when nothing time critical is under way and no operator has work to do. Processes intended for a priority based scheduling scheme must be written in a different way than those intended for round-robin scheduling. There must be no infinite loops in the internal control structure in a process written for priority based scheduling. If there is an infinite loop in one process, processes on lower priorities will never be allowed to use the CPU. If the loop contains a call to the operating system that causes the process to become WAITING, lower priority processes can come in, and there is no problem. Processes written for round-robin scheduling can contain whatever loops the programmer desires; in this respect they are always handled safely by the operating system. In an OSE system, processes scheduled according to the round-robin principle are called background processes.
ARM Kernel
CPU
Figure 2.2 Round-robin process scheduling For each priority equal or below the background priority level, a process (FIFO) queue is maintained. Processes enter the READY list at the end of the queue and processes are selected for execution from the head of the queue. OSE gives each process a user selected time-slice for running before pre-empting it to allow the next process in the READY queue to run.
Prioritized Processes on page 17 Background Processes on page 17 Interrupt Processes on page 17 Interrupt Performance on page 18 Timer Interrupt Processes on page 19
ARM Kernel
ARM Kernel
These are identical to prioritized processes except that they do not have priority. A background process will only be allowed to run when no prioritized process is ready. The time left over when no prioritized process is running is divided between ready background processes. Running background process is switched by the operating system at user defined intervals. A background process is allowed to execute until it becomes not ready or a prioritized process becomes ready or until the background process has executed for the duration of the user defined interval. Background processes may be written either in assembly or C.
Prioritized Processes 17
Processes have priorities assigned by the operating system. Interrupt processes have the priority assigned to its interrupt by hardware. In some CPUs they may, however, change priority by writing to some status register.
External Interrupt Hardware
Hardware Delay Encoding Incoming Interrupt Stacking of CPUs state data Finish current Instruction
Software
Interrupt process including system calls
ARM Kernel
USER PROCESS
OSE
Figure 2.3 Interrupt processes There can exist only one interrupt process for each of the available hardware interrupt vectors. An interrupt process is called as a subroutine whenever its interrupt occurs, provided that no other interrupt is running.
18 Interrupt Performance
processes. This design is used by operating systems that do not disable interrupts. Another way to effectively achieve zero interrupt latency is to disable interrupts for a shorter time than the longest CPU instruction. This method has the advantage of permitting most system calls to be used by an interrupt process. Many real-time operating systems allow the user to set aside some hardware interrupt priority levels and request that these levels should not be disabled by a real-time operating system. Interrupt handlers working on such levels may never call any real-time operating system function. If they do so nonetheless, the system will crash sooner or later. Since such interrupts cannot use system calls, they are, among other things, unable to activate a process that runs under non-interrupt. If other processes are to act on data from such an interrupt, they must poll some suitable variables.
ARM Kernel
2.8.1 Messages
When a process wants to receive a message it calls the operating system, requesting a message. If none is available, the operating system puts the process to sleep until one arrives. When a process wants to send a message, it calls the operating system, submitting the message. If the receiving process is of higher priority, or if a higher priority process is sleeping at the mailbox in question, the calling process is put to sleep, and the higher priority process is allowed to use the CPU. Mailboxes are described further in this chapter. A message is often actually a buffer, an area of memory, where processes may read and write data. A buffer may be used by many different processes, but only one process at a time may access a buffer. If processes should access buffers without control, the resulting errors would be difficult to find. Messages not only carry data; they may also initiate actions by the various processes.
2.8.1.1 Message Passing Through Mailboxes
ARM Kernel
OSE is not using message passing trough mailboxes. Under some other operating systems, messages are sent to mailboxes to which any process can send and from which any process can receive. In this case there must be some set of rules determining which processes are to send to a certain mailbox and which processes are to receive from the mailbox. Processes must send their messages to the mailbox where the addressee is waiting when it requires these messages. Which mailbox to send to is determined by set of rules that evolves as the system is designed and tested. If some messages are unwanted at certain times, more mailboxes can be created and processes can wait at these. If it is not desirable to create more mailboxes, the user may design his process as a state machine and receive all messages at one mailbox. When a new message is added to the work of the process, the number of states can double. Most of the state machine is often affected when new functions are added to it. Processes must be carefully designed, since a process that needs prompt response from another must know at which mailbox the target process is waiting or else it must send messages to all possible mailboxes. In the latter case, the unused messages must be removed once the process has received one copy of the message. Mailboxes are not used in the OSE operating system.
20 Messages
The figure below shows mailbox message passing in one direction only. In reality, the situation becomes more complex when messages are passed in both directions.
Sending Processes
Receiving Processes
ARM Kernel
OSE operating systems send messages directly to processes. In OSE the name signal is also often used. Messages and Signals are exactly the same in an OSE system. In this scheme it is not necessary to know which mailboxes to create, kill and send to and receive from. With this design it is not possible to avoid unwanted messages by creating more mailboxes. Possibly, more processes could be introduced to solve the problem.
Messages 21
Another solution is to let a process select the messages it is interested in receiving at any particular moment. If this tool is available, the "prompt response" problem of the previous paragraph is also solved, for a process is always waiting at the same mailbox.
Sending Processes Receiving Processes
ARM Kernel
Figure 2.5 Direct message passing In OSE signals (or messages) are sent between processes. Each message is a buffer, an area of memory, where processes may read and write data. A buffer may be used by many different processes, but only one process at a time may access a buffer. Signals not only carry data, they also initiate actions by the various processes. All processes can exchange signals, even those residing in other computers. (Through the use of a link handler.) When a process gains access to a signal buffer by allocating it or receiving it, the process becomes the owner of the buffer. Only the owner may perform operations on the buffer. Once a signal has been sent to another process it can no longer be accessed by the sending process. A process may select the signals it is interested in receiving at any particular moment. The process will then wait for signals to arrive. Meanwhile, other processes are allowed to execute.
22 Fast Semaphores
Fast semaphores work like this: A fast semaphore is a signed integer owned by a process. It is operated by system calls WAIT (WAIT_FSEM) and SIGNAL (SIGNAL_FSEM). Only the owner may wait at a fast semaphore. Other processes may signal it.
2.8.3 Semaphores
Semaphores are somewhat similar to fast semaphores, but they differ in one very important aspect: A semaphore is not related to any specific process. Any background or prioritized process may wait at a semaphore, not just the owner. Any type of process may signal a semaphore. The main purpose of semaphores is to protect critical code sections from concurrent execution (so called mutual exclusion) without disabling interrupts. This is often done to protect global shared resources. If the compiler supports static initialisation of C structures this can be used to declare a semaphore at compile time. OSE is a message-passing real-time operating system. It is therefore strongly recommended to not use global variables and semaphores in an OSE system. Only message passing design ensures a clear and secure system and makes it possible to use some powerful features in the OSE Illuminator system level debugger.
ARM Kernel
Semaphores are mainly used to ensure that only one process at a time is using a global shared resource. As soon as the process currently occupying the resource releases it, it will automatically be given to the next in its waiting queue. Use the wait_sem system call to get in line to use the resource as soon as possible and the signal_sem system call to releases it as soon as the resource is no longer needed. A semaphore is a counter to which 1 can be added and from which 1 can be subtracted. Adding 1 is called "signalling the semaphore" and subtracting 1 is called "waiting for the semaphore". If the counter is 0 and a process tries to subtract 1, the subtracting (waiting) process is put to sleep. If a process is asleep at the semaphore and another process signals the semaphore, the sleeping process becomes READY and will be allowed to run if it is of higher priority than the signalling process. The counter of a semaphore may be a single bit, in which case the semaphore is referred to as a binary semaphore. The other type is often called a counting semaphore.
Semaphores 23
Semaphore example: Assume a system with two printers. When the system is started, the semaphore is initialised to 2. Each process needing a printer first waits at the semaphore. When the process has finished with the printer, it signals the semaphore. When the first two processes wait for the semaphore, the counter is simply decreased. When the third process waits for the semaphore, it is put to sleep because the semaphore is 0. When one of the first two processes is finished, the semaphore is signalled and the third process is awakened. In this way, the semaphore sees to it that only one process at a time uses each printer. One way to solve the same problem with messages: A process owns the printer (the printer process for example). Processes that need a printer send a message to the printer process, and when the process receives a reply message, the printer is available. As long as there is no reply message, the requesting process is sleeping.
ARM Kernel
24 Semaphores
3 Getting Started
This is a step-by-step tutorial that shows how to generate a simple application with the OSE for ARM real-time operating system, see Example System Description on page 26. You will be guided through the configuration and the generation of an example system in Step by Step Tutorial on page 28.
ARM Kernel
Users Guide / 4.6
Getting Started 25
runner
ARM Kernel
Figure 3.1 Example system There is a keyboard where commands can be typed, a test process which reads some current sensor, a display process where messages can be displayed, a motor process controlling the rather big motor and a control process controlling the system. There is also a runner process, which gives simulated input to the keyboard and the test process.
This process gives test stimuli (signals KEY_HIT and TEST_VAL) to the keyhand and test processes. This process calls also the function feedback() at a regular rate. Feedback is included in the module led.c and controls the LEDs on the evaluation board (if there are LEDs available on the board).
ARM Kernel
keyhand.c
In reality an interrupt process managing the keyboard. In this simulated system this process receives the signal KEY_HIT from runner. The characters are just echoed to control, and keyhand then waits for a receipt (signal KEY_R).
test.c
In reality a timer-interrupt process, measuring the current from a sensor and sending the value to control. In this simulated system test receives TEST_VAL signals from runner, and transfers the content inside the signal CURRENT to control.
motor.c
This process receives the MOTORON signal and starts and stops the motor accordingly.
display.c
This is the spider in the net, controlling the system. Receives KEY_HIT and CURRENT signals, sends MOTORON to motor, CHARACTER and OVERCURR to display, and KEY_R to keyhand.
bg.c
Two background processes, which do not have a specific functionality. It is just to show how to setup a background process.
led.c
Includes the function feedback() which controls a row of leds on the evaluation board.
Equipment on page 29 Preparation on page 30 OSE Configuration on page 30 Getting the System Files on page 33 Getting Specific Drivers on page 33 Getting the Example Source Files on page 34 Building the System with ARM ADS on page 35 Building the System with IAR EWB on page 36 Building the System with GNU GCC on page 37 Running the System without OSE Illuminator on page 40 Running the System with OSE Illuminator on page 40 Debugging on page 42
ARM Kernel
3.2.1 Equipment
To run this Getting Started System, you need the following equipment:
PC running Windows 98, 2000 or NT. A target evaluation board preferably one where an OSE for ARM board support package is delivered. This tutorial is designed for the ARM Evaluator-7T evaluation board. You could use any board with a processor where the OSE for ARM kernel runs but you might have to modify the system startup files and some drivers. Your preferred debugger connected to your selected ARM evaluation board. One of the following development environments:
ARM Developer Suite IAR Embedded Workbench GNU GCC
OSE Epsilon for ARM RTOS. If you would like to run also the OSE Illuminator system level debugger, you will need the additional equipment:
A serial line connected of one of your PCs COM ports to the serial port of
ARM Kernel
OSE Illuminator Users Guide for information about installation and usage.
Equipment 29
3.2.2 Preparation
This Getting Started example is not a ready to run plug-and-play project where you push a button and your system is generated and after down loading you see something running in the target. This is maybe quite nice for a demonstration but not very useful to learn how to configure and generate an OSE for ARM system. In this Tutorial we will guide you through the whole configuration and generation process. You will learn what files you need and which configuration entries you have to define. First, you will need to create a work directory in a suitable place.
ARM Kernel
5. For the ARM Evaluator-7T evaluation board define the following CPU:
CPU ARM7T DMI
30 Preparation
8.If you will not use the OSE Illuminator system level debugger enter the following debugger options:
OPTION DEBUGGER,NO
If you are using the OSE Illuminator system level debugger over a serial line enter the following debugger option definitions:
OPTION DEBUGGER,ONCHIP,1024,20
This will generate the OSE for ARM debug kernel. Please consult Option Debugger on page 52 for more information concerning the debugger options. It is simpler to first generate a system without OSE Illuminator support. 9. You do not need to modify the memory allocation default settings for this simple getting started example:
POOL BUFFERSIZES 1024 4,8,16,32,64,128,256,512
This will define a message pool of a size of 1024 bytes and individual message sizes of 4, 8, 16, 32, 64, 128, 256 and 512 bytes.
ARM Kernel
10.We will use the default interrupt and temporary stack sizes:
ISTACK_SIZE TEMP_STACK_SIZE 256,512 256
11.We define one start handler. This handler is included in the file timer_setup.* of the board support package delivery.
START_HANDLER TimerSetup
For all process we declare a stack of 256 bytes. All processes have the same priority of 17 except process runner which has a priority of 18 and motor with 14. 13.To show how OSE background processes are defined, we have included the background processes bg1 and bg2:
BG_PROC BG_PROC bg1,256,10 bg2,256,10
The two background processes have a stack of 256 bytes and a times slice of 10 ticks.
OSE Configuration 31
14.The file osarm.con is now complete and should look more or less like this (without comments):
COMPILER ARM TARGET_NAME motcon CPU ARM7T DMI MEMORY_MODEL LITTLE DEBUG YES BUFFER_CHECK YES STACK_CHECK YES OPTION DEBUGGER,ONCHIP,1024,20 POOL 1024 BUFFERSIZES 4,8,16,32,64,128,256,512 ISTACK_SIZE 256,512 TEMP_STACK_SIZE 256 START_HANDLER TimerSetup PRI_PROC motor,256,14 PRI_PROC control,256,17 PRI_PROC test,256,17 PRI_PROC display,256,17 PRI_PROC keyhand,256,17 PRI_PROC runner,256,18 BG_PROC bg1,256,10 BG_PROC bg2,256,10 END
ARM Kernel
The file can vary depending on used compiler, evaluation board and debug option. 15.Open a shell window and change the directory to your example working directory. Run the configuration utility confarm.exe by declaring osarm.con as input file:
<install_dir>\arm\krnxxx\bin\confarmosarm.con
For every change in the osarm.con configuration file the confarm.exe utility must be executed again. If your IDE allows to define external utilities or you are using a makefile you could add this step in the IDE or in the makefile. 16.The kernel will be generated in your working directory. The file name of the kernel is osarm.*. The extension differs from compiler to compiler (ARM: osarm.s, GNU: osarm.S, IAR: osarm.s79).
32 OSE Configuration
ARM Kernel
ARM Kernel
3. There is a system header file delivered for the example. This file will be included by some processes. Copy the file system2.h into your working directory. You will find this file in the example directory of the kernel delivery: <installdir>\arm\krnxxx\<yourCompiler>\exp\motcon\ 4. If there are LEDs on your board available there is a function called feedback() to manage these LEDs. This function is defined in the file led.c and led.h. Copy led.c and led.h to your working directory. You will find these files in the board support package directory for your selected board, e.g.: <installdir>\arm\bspxxx\<yourBoard>\src\ <installdir>\arm\bspxxx\<yourBoard>\include\
ARM Kernel
Select pane Build extras and uncheck Use modification date caching. Select pane ARM Assembler -> ATPCS. Check ARM/Thumb interworking. Select pane ARM Linker. Choose Linktype: Scattered and enter a Scatterdefinition File. Now click save. 5. Adding files to the project: Menu Project -> Add Files => File selector dialogue. a) Select all .c files b) Select all .s files 6. Building the project Menu Project -> Make 7.Go to Running the System without OSE Illuminator on page 40 or Running the System with OSE Illuminator on page 40.
ARM Kernel
ARM Kernel
C_OBJ = $(C_SRC:.c=.o)
ARM Kernel
12.Instead of running the OSE for ARM configuration utility confarm.exe manually (see OSE Configuration on page 30), you could include this step in the makefile:
osarm.S : osarm.con confarm osarm.con
15.The file Makefile is now complete and should look more or less like this:
CC=arm-thumb-elf-gcc AS=arm-thumb-elf-as LD=arm-thumb-elf-ld CPP=$(CC) -E -xc # OS stuff RM=rm -f ASFLAGS = -mthumb-interwork -EL CFLAGS = -Wall -O2 -fomit-frame-pointer CFLAGS = -mthumb -mthumb -interwork -mlittle-endian LDFLAGS = -s -marmelf -e OSE_RESET -T gnu.lnk INC = -I/OSE/epsilon/ARM/krn361/GNU/include INC += -I/usr/arm-thumb-elf/include LIBS = -lc
all: motcon.elf C_SRC C_SRC C_SRC C_SRC C_SRC C_SRC C_SRC C_SRC = += += += += += += += bg.c control.c display.c keyhand.c motor.c runner.c test.c timer.c
ARM Kernel
C_OBJ = $(C_SRC:.c=.o) AS_SRC = osarm.S AS_SRC += crt0.S AS_SRC += inthdlr.S AS_SRC += timer_setup.S AS_OBJ = $(AS_SRC:.S=.o) OBJ= $(C_OBJ) $(AS_OBJ) .SUFFIXES: .c .o .S .S.o: $(CC) $(CFLAGS) $(INC) -c $< -o $@ .c.o: $(CC) $(CFLAGS) $(INC) -c $< -o $@ osarm.S : osarm.con confarm osarm.con motcon.elf: $(OBJ) osarm.o gnu.lnk $(LD) $(LDFLAGS) -Map motcon.map $(OBJ) $(LIBS) osarm.o -o motcon.elf clean: $(RM) osarm.S $(RM) *.o $(RM) *.elf $(RM) *.*~
The file can vary depending on used compiler, evaluation board and debug option. 16.Run the make utility to generate the executable. 17.Go to Running the System without OSE Illuminator on page 40 or Running the System with OSE Illuminator on page 40.
ARM Kernel
The main system level debugger functionality resides in the target system for the serial line version. On the host, you have the graphical user interface (written in Java) and a communication module called Epsilon Debug Server (edbgserver). For the serial line Illuminator, you need a free serial interface in your target system and on your host. It is an easy to use and simple configurable architecture which is very well suited for single chip systems. If you have selected the debug option (OPTION DEBUGGER) in the ARM kernel configuration file, the Debug Kernel will be generated. The Debug Kernel includes beside the standard OSE for ARM kernel also debug code and memory to use with the OSE Illuminator system level debugger. To connect the Debug Kernel to the host system, you need a serial driver eldm_uart.s), the serial interfaces and the serial cable.
Host Illuminator
TCP/IP
edbgserver
ARM Kernel
18.Connect your Source Level Debugger to the JTAG debug port of your evaluation board. Switch-on the debugger. 19.Connect the serial cable from a free serial port on your host PC to the serial interface connector of the target board. 20.Switch-on the target board. 21.Start the debugger and download the generated file motcon.* into your target system. 22.Run the target system from your source level debugger.
3.2.12 Debugging
We are supposing that you have generated the system for Serial Line Illuminator, downloaded the executable into your target system and started the target program.
3.2.12.1Epsilon Debug Server
You have to start the communication program on the host system called edbgserver manually.
If you have installed OSE for ARM at the default location on your PC, you can find the edbgserver.exe file at the location: c:\ose\epsilon\arm\krnxxx\bin Open a MS-DOS shell window and change the working directory of this window to the directory where edbgserver.exe is located. Run edbgserver.exe. You will now see the following window:
ARM Kernel
Please consult the Illuminator Users Guide for a detailed description of OSE Illuminator.
42 Debugging
ARM Kernel
Users Guide / 4.6
C Compiler on page 45 Target Name on page 46 CPU Type on page 47 Memory Model on page 48 Debug Option on page 49 Buffer Check Option on page 50 Stack Check Option on page 51 Option Debugger on page 52 Option Conditional Halt on page 53 Option Dispatcher in RAM on page 54 Pool Size on page 55 Buffer Sizes on page 56 Interrupt Stack on page 57 Temporary Stack on page 58 Error Handler on page 59 Start Handlers on page 60 Swap Handler on page 61 Send Handler on page 62 Receive Handler on page 63 Power On Handler on page 64 Power Off Handler on page 65 Idle Handler on page 68 Fast interrupts as IRQ:s on page 69 Interrupt Processes on page 70 Timer Interrupt Processes on page 71 Prioritized Processes on page 72 Link Handler Processes on page 73 Background Processes on page 74 Enable Wake Up on page 75
Users Guide / 4.6
ARM Kernel
4.1
C Compiler
Defines the used C compiler product. Supported compilers are: ARM (ARM Ltd.) ADS/RVCT, IAR (IAR Systems AB) and GNU GCC. The option SINGLECHIP enables the generation of a Single-Chip version. This is very useful for projects which need limited memory consumption. There is only one restriction for the Single-Chip version: All OSE data segments must reside in the first 64 Kbyte memory range. This declaration must be the first entry in osarm.con. This declaration must always be present.
Description:
Syntax: Parameter:
COMPILER<type>[,SINGLECHIP]
type
ARM Kernel
C Compiler 45
4.2
Target Name
This entry allows you the give your target a specific name. The target name will be displayed in the OSE Illuminator system level debugger and can be used in OSE Linkhandlers to access targets in a distributed environment.
Description:
Syntax:
TARGET_NAME
<name>
Parameter: Example
name
TARGET_NAME
motcon
ARM Kernel
46 Target Name
4.3
CPU Type
The possible CPU types are ARM7TDMI (includes all ARMv4T derivatives), ARMv5T (includes also ARMv5TE) and XSCALE. This declaration must always be present.
CPU <type>
Description:
Syntax:
Parameter:
type
Example
CPU
ARM Kernel
Users Guide / 4.6
CPU Type 47
4.4
Memory Model
Defines the endian type. Select LITTLE for little endian and BIG for big endian. This declaration must always be present. This item must correspond with compile and debug options.
Description:
Syntax:
MEMORY_MODEL
<model_type>
Parameter: Example
model_type
LITTLE BIG
MEMORY_MODEL
LITTLE
ARM Kernel
48 Memory Model
4.5
Debug Option
The debug option enables some of the error checks and also makes it possible to use the Illuminator debugger. If debug is not enabled, there is a substantial reduction of the code size of the operating system. There is also an increase in execution speed. This declaration must always be present.
DEBUG <state>
Description:
Syntax:
Parameter: Example
state
YES NO
DEBUG
YES
ARM Kernel
Users Guide / 4.6
Debug Option 49
4.6
Description:
ARM Kernel
Syntax:
BUFFER_CHECK
<state>
Parameter: Example
state
YES NO
BUFFER_CHECK
YES
4.7
Description:
Syntax:
STACK_CHECK <state>
Parameter: Example
state
YES NO
STACK_CHECK
YES
ARM Kernel
Users Guide / 4.6
4.8
Option Debugger
This option is used to enable the possibility to connect the OSE Illuminator System Level Debugger.
OPTION DEBUGGER,<type>
Description:
Syntax:
Parameter
type
NO No system level debugger will be used. ONCHIP, <max. trace>,<max. evact> This option is used to enable the possibility to connect the OSE Illuminator System Level Debugger over a serial line interface to the target system. Please consult the OSE Illuminator manual for more information. <max. trace> Maximum number of entries in the trace ring buffer of the target OSE debugger. <max. evact> Maximum number of entries in the evact table of the target OSE debugger.
ARM Kernel
Example
OPTION DEBUGGER,NO
52 Option Debugger
4.9
Description:
Syntax:
OPTION COND_HALT_W_TIMINT,<switch>
Parameter: Example
switch
YES NO
OPTION COND_HALT_W_TIMINT,YES
ARM Kernel
Users Guide / 4.6
Parameter: Example
switch
YES NO
OPTION DISPATCHER_IN_RAM,YES
ARM Kernel
54 Option Dispatcher in RAM
Parameter:
size
The buffer pool size in bytes. 48..4294967292 The limits are determined by system design. (Refer to Memory Requirements in Building a System.)
Example
POOL 2000
ARM Kernel
Users Guide / 4.6
Pool Size 55
ARM Kernel
Parameter:
Buffer size 1. Buffer size 2. Buffer size 3. Buffer size 4. Buffer size 5. Buffer size 6. Buffer size 7. Buffer size 8. NOTE that sizes must be stated in order of increasing size.
Range: Example
BUFFERSIZES 32,64,128,256,1024,2048,4096,8192
56 Buffer Sizes
Parameter:
stacksize second
The extra stack space in bytes. The limits are determined by system design. The second stack is used by nested interrupts only. With nested interrupts, the first stack is used to save the registers, and the second is used for local variables of the interrupt functions. Size estimation: (max nesting level - 1) * 60 for the first stack (max nesting level ) * (max stack usage) for the second stack.
ARM Kernel
Example
ISTACK_SIZE 2048
Interrupt Stack 57
Parameter: Example
stacksize
TEMP_STACK_SIZE
160
ARM Kernel
58 Temporary Stack
Parameters: Example
name
ERROR_HANDLER
ERROR_DISPLAY
ARM Kernel
Users Guide / 4.6
Error Handler 59
This declaration is optional and need be present only if test handlers are needed.
Syntax: START_HANDLER <name>
ARM Kernel
Parameters: Example
name S
START_HANDLER START_HANDLER
RAM_TEST my_init_of_global_data
60 Start Handlers
ARM Kernel
This declaration is optional and need be present only if a swap handler is needed.
Syntax: SWAP_HANDLER <name>
Parameters: Example
name
SWAP_HANDLER swaplog
Swap Handler 61
ARM Kernel
This declaration is optional and need be present only if a send handler is needed.
Syntax: SEND_HANDLER <name>
Parameters: Example
name
SEND_HANDLER siglog
62 Send Handler
ARM Kernel
This declaration is optional and need be present only if a receive handler is needed.
Syntax: RECEIVE_HANDLER <name>
Parameters: Example
name
RECEIVE_HANDLER siglog
Receive Handler 63
ARM Kernel
has been powered down. This is particularly useful if the system was powered down as a consequence of the COND_HALT system call. See power off handler for information about how to use ADD_TICKS safely. A power on handler should be written in assemlber because the C system is not yet setup. A power on handler written in assembler should return a int value in R0. This declaration is optional and need be present only if the POWER_FAIL system call is utilised.
Syntax: POWER_ON_HANDLER <name>
Parameters: Example
name
POWER_ON_HANDLER
my_power_on
64 Power On Handler
ARM Kernel
The power off handler is called with interrupts disabled. The parameter is idle_ticks: zero => power fail not equal zero => cond_halt ticks
A power off handler written in C may be declared as: (This example deals with COND_HALT by halting the processor)
void my_power_off(OSTICK idle_ticks) { If (idle_ticks != 0) { <Prepare timer to wake up after idle_ticks> <Halt processor> <Re-initialies timer and call ADD_TICKS> } else { <Save current state of all I/O ports.> <Set warm start flag.> <Create ram checksum and save it.> <Turn off power and enforce hardware reset.> } }
The above pseudo code contains a few tricky parts that need further explanation. They concern handling of the timer and the halt mechanism: It is assumed that the halt mechanism wakes up by an interrupt. It should never fall asleep if an interrupt is pending when the halt operation is performed. It is also assumed that the processor continues executing on the instruction after halt when the interrupt arrives. The interrupt should be serviced as soon as a interrupts are enabled (when the handler is exited). It is imperative that the halt mechanism does not lack any of these properties. Otherwise the algorithm described here will be prone to dead-locks. One tricky aspect o handling timer chips is that they may wrap around and cause an interrupt during the execution of the handling code. The software must deal with this in some way. The idle_ticks parameter defines how many ticks may be skipped without disturbing the OSE Epsilon for ARM time-out, delay and timer system. The timer hardware should be adjusted to generate an interrupt that many system ticks later than planed. E.g. if idle_ticks is 3 and the timer hardware has 27% of a tick time remaining until the next interrupt, it should be reinitialized to generate an interrupt after 3,27 tick times. It is also possible that the timer issues an interrupt during the execution of this code, e.g. resulting in a pending interrupt and 99% of a tick time until the next tick. This must be detected and countered. In this case by initialising the timer to 2.99 tick time and clearing the pending interrupt. The processor can wake up from halt by any interrupt. I.e. it could be woken up either by a timer interrupt or another interrupt, whichever occurs first. The software should be able to handle both cases, perhaps by checking if a timer interrupt is pending. (Remember that interrupts are disabled during the execution of the handler.) The timer should be re-synchronised to generate interrupts at tick intervals. This should be done without disturbing any pending interrupts. The system call add_ticks should be called with the number of ticks that have been skipped during the halt time. This value should never be more than the idel_ticks parameter. Note that the time will usually be one more than the idle_ticks parameter if the time expired. In this case the last tick should be handled by a call to OSE_TIMER_ENTRY, for more information see appendix. This will happen naturally when the system handles the pending interrupt, provided that the interrupt is not cleared by the reinitialisation of the timer.
ARM Kernel
66 Power Off Handler
If the system sleeps by powering down instead of by using a halt mechanism, the code for reinitializing the timer and updating the system timer must reside in the power on andler. This declaration is optional and need be present only if either the POWER_FAIL or the COND_HALT system call is utilised.
Syntax: POWER_OFF_HANDLER <name>
Parameters: Example
name
POWER_OFF_HANDLER
my_power_off
ARM Kernel
Users Guide / 4.6
Note that the Idle Handler must never end. It is an error for an Idle Handler to execute a return statement. This declaration is optional and need be present only if an idle handler is needed.
Syntax: IDLE_HANDLER <name>
Parameters: Example
name
IDLE_HANDLER
my_idle
ARM Kernel
68 Idle Handler
Syntax:
Parameters: Example
switch
YES NO
FIQ_AS_IRQ YES
ARM Kernel
Users Guide / 4.6
calling the entry code from your interrupt handler, add OSE_ to the named declared below. The interrupt process should not be called directly from the interrupt handler.
The interrupt process is called from ARM-mode. Therefore interworking
ARM Kernel
These declarations are optional and need be present only if interrupt processes are needed.
Syntax: INT_PROC <process_name>
Parameter: Example S
70 Interrupt Processes
Parameters:
process_name The name of a process. call_interval The interval between calls to the process.Range: 1..4294967295. init Initial delay. This an optional parameter. A timer interrupt process starts normally at time 0 at system start. You can give an initial delay before the interrupt will be started. Range: 1..4294967295.
ARM Kernel
Example
TI_PROC TI_PROC tnuctipun,155 poll,100,10
Parameters:
process_name The name of a process. stack_size The requested size in bytes for the stack of the process. Range: 160..4294967295. priority The requested priority for the process. 0 = highest priority, 31 = lowest priority. Optional CPU mode SYS (default) USR
ARM Kernel
mode
Example
PRI_PROC PRI_PROC PRI_PROC my_process,128,1 outsider,128,19 SLAVER,128,15
72 Prioritized Processes
Parameters:
process_name The name of the link handler process. stack_size The requested size in bytes for the stack of the process. Range: 160..4294967295. priority The requested priority for the process. 0 = highest priority, 31 = lowest priority. Optional CPU mode SYS (default) USR
ARM Kernel
mode
Example
LINKHANDLER my_link,128,10
Parameters:
process_name The name of a process. stack_size The requested size in bytes for the stack of the process. Range: 160..4294967295. timeslice The number of system ticks the process will be allowed to run before being swapped out. Range: 160..4294967295. mode Optional CPU mode SYS (default) USR
ARM Kernel
Example
S
BG_PROC BG_PROC background_tests,128,12 THRINT,1024,1
74 Background Processes
Syntax:ENABLE_WAKE_UP <state>
Parameter: Example
state
YES NO
2
YES
ENABLE_WAKE_UP
ARM Kernel
Users Guide / 4.6
Enable Wake Up 75
ARM Kernel
76 Enable Wake Up
5 Building a System
To build a system, do the following: 1. Determine the specifications of the system, such as functions, speed requirements, environment etc. 2. Design the system, i.e. determine hardware configuration, memory usage, interrupt structure, processes and process interface. 3. Select the files you need from the OSE Epsilon for ARM installation and copy them to your working directory. 4. Modify the system files for the used board. This should include at least the system initialization functions, the interrupt handler and a tick timer setup file. You can find examples of such files in the Board Support Package delivery. 5. Configure the system, that is, enter configuration data into the configuration file osarm.con.
ARM Kernel
Run confarm.exe to create the assembler file osarm.*. Ensure you have the correct version of osarm.con. File extensions differ from compiler to compiler (e.g. ARM: *.s, GNU *.S, IAR: *.s79). 6. Generate the ARM kernel by assembling the file osarm.*. 7. Write your signal specifications. A reasonable approach is to have a small set of related signals in each include file. If you are using the OSE Soft Kernel, you should keep your signal specifications consistent with Softkernel demands. 8. Write your processes and compile/assemble them. 9. If you have selected the debug option (OPTION DEBUGGER) in the osarm.con configuration file the Debug Kernel will be generated and you also need a communication module to connect the Debug Kernel to the host. For an asynchronous serial line connection, you can find a driver in the OSE Epsilon for ARM Board Support Package. 10.We recommend that you also write an error handler if you have a display device in your target system. An error handler may display errors quickly and conveniently during debugging 11.Link the generated kernel, the bsp system files, your processes, your handlers and the compiler library together to form the target binary file.
Building a System 77
Configuration osarm.con
confarm
ARM Kernel
Assemble
Compile
clib
Link
See also:
System Files on page 79 Configuration on page 79 Configuration Utility on page 79 Illuminator System Level Debugger on page 79 Assembly-Time Errors on page 80
78 Building a System
crt0.* inthdir.* timer_setup.* File extensions will differ from compiler to compiler (e.g. ARM: *.s, GNU *.S, IAR: *.s79).
Examples of these system files can be found in the OSE Epsilon for ARM board support package delivery. If your board is not supported, you can use these system files as templates.
5.2 Configuration
The OSE operating system can be configured to have completely different characteristics depending on the trade-offs you want to make between speed, memory consumption and code size. The configuration is accomplished by entering the desired values into the osarm.con configuration file. As shipped, osarm.con contains a configuration suitable for a typical system. Browse through it and change the settings as required for your application. If you are unsure about a setting use the current setting. However, you must always define the names of the processes in your particular system.
ARM Kernel
For every change in the osarm.con configuration file, the confarm.exe utility must be executed again.
System Files 79
ARM Kernel
80 Assembly-Time Errors
6 System Design
OSE Epsilon for ARM is a fast, compact, real-time operating system for the ARM line of microprocessors from ARM Ltd. OSE Epsilon for ARM is designed exclusively to fit the peculiarities of the ARM processor family. Every conceivable effort has been made making OSE Epsilon for ARM as fast as possible. The entire system is written in heavily optimized assembler. The data structures are designed to fit the processor memory structure and the specific system calls. Tasks which traditionally have been left to the user to accomplish as best he can has been taken over by the operating system. Most of the design effort has been spent in selecting and tuning a set of system calls which provides maximum system performance. Speed is not always paramount. At times it is necessary to preserve code memory. This can be done in two ways when using OSE Epsilon for ARM. In a small system the size of the operating system itself may be a problem. Should such be the case you may use OSE in a minimum code configuration. If the system is large, the size of the operating system will be a minor problem since it is inherently small.
ARM Kernel
A system under OSE Epsilon for ARM consists of a number of independent subprograms called processes. A process may be written to some extent as if it had the entire CPU for its own exclusive use. By assigning a priority to each process, OSE Epsilon for ARM ensures that the right process is always executing. An event which requires another process with a higher priority to execute, forces an immediate switch of process. This scheme ensures fast response to important events. Processes co-operate by exchanging signals. A process may send a signal to the mailbox of another process to inform the receiver of an event or to respond to an event. Signal transmissions often cause execution to switch to another process (a task switch). A signal is a dynamically allocated message buffer containing a signal number and an optional data structure. Signal numbers are used to select which signals to receive, while leaving others in the mailbox of the receiving process. It is possible to ignore events which are unimportant at the moment simply by selecting which signals to receive. Other processes use the CPU while a process is waiting for a signal to arrive. Unused message buffers are stored in the central buffer pool until allocated by a process. Only one process at a time may access a signal (or message buffer), thereby eliminating conflicts. If a process needs to suspend execution for a specific interval of time, it calls OSE which monitors time and activates other processes during the wait.
System Design 81
System Creation Cycle on page 83 Processes on page 84 Starting and Stopping Processes on page 93 Signals on page 94 Fast Semaphores on page 97 Semaphores on page 97 Memory Utilisation on page 98 Speed Considerations on page 102 System Start on page 104 Writing the Interrupt Handler on page 104 Writing a Link Handler on page 106 Writing an Error Handler on page 108
ARM Kernel
82 System Design
ARM Kernel
Users Guide / 4.6
6.2 Processes
A process is an independent program running under OSE. In every instant of time, the most important process ready to run is running. As soon as a more important process wants to run the current process is removed from the CPU and the new process is entered and allowed to run. This is called a task switch. If you are running a system without OSE, the processor will often find itself unable to respond quickly to an event since the wrong part of the program is running and continues to do so for some time. There are several types of processes to allow you to run each part of your program at the right moment. The process types differ mainly in the way in which they are activated and in the way they use memory. The total number of processes of all types may not exceed 254. Each process is associated with a unique process identity, which is used in system calls to select the process. This identity is allocated by the operating system during system start, and it is placed in a global variable where it can be accessed by other processes. This variable is named as the process with an appended underscore character. E.g. a process named "keyboard" has an id which is placed in a variable named "keyboard_".
ARM Kernel
In the ..\example directory of the OSE Epsilon for ARM Installation you will find process example files. Processes are further described in:
Prioritized Processes on page 85 Background Processes on page 86 Interrupt Processes on page 87 Timer Interrupt Processes on page 88 Selecting Process Type on page 89 Process Include Files on page 90 Process Declarations in C on page 91 Process Declarations in Assembler on page 92 Process Design Rules on page 93
84 Processes
ARM Kernel
Note that a prioritized process must never end. When its task is done it should loop back to the beginning and wait for another request for its services. If it is certain that it will not again be needed, it may call STOP to stop itself. It is an error for a process to execute a return statement. Prioritized processes may be written either in assembly or C.
Prioritized Processes 85
ARM Kernel
86 Background Processes
ARM Kernel
The interrupt process must be declared. The interrupt handler must be modified to recognise the interrupt source, and call the interrupt process entry code. The interrupt process entry code is created by OSE Epsilon for ARM. When calling the entry code from your interrupt handler, add OSE to the name declared in the osarm.con. The interrupt process should not be called directly from the interrupt handler. The interrupt process is called from ARM-mode. Therefore interworking should be enabled for thumb-mode routines. The interrupt generating hardware must be initialised.
Interrupt Processes 87
ARM Kernel
88 Timer Interrupt Processes
ARM Kernel
Users Guide / 4.6
Prioritized and Background Processes written in C and running in USR mode must include ose_usr.h
Interrupt and Timer Interrupt Processes written in C must include the file ose_i.h Prioritized and Background Processes written in Assembler must include the file
osarm.anc.
OSE Interrupt and Timer Interrupt Processes written in Assembler must include the file osarmi.anc.
ARM Kernel
90 Process Include Files
C Syntax:
OS_PROCESS (<process_name>) { /* Code for process <process_name> */ }
ARM Kernel
You have to declare a second parameter for Interrupt and Timer-Interrupt Processes which holds the information from what source the interrupt occurred. The source can be: 1. The real hardware interrupt. 2. A signal sent to the process. 3. The fast semaphore was signalled. C Syntax:
OS_INT_PROCESS (<process_name>,<int_src>) { . . . }
int_src
Source of interrupt (variable, type int): 0 Invoked by hardware interrupt 1 Invoked by signal sent to this process 2 Invoked by a SIGNAL_FSEM to this process. This irrespective of the actual FSEM value. GET_FSEM gives no real value.
Process Declarations in C 91
Prioritized and Background Processes written in assembler must contain the declaration:
PROCESSMY_PROCESS.
Assembler Syntax:
PROCESS <process_name> ; ; Process entrypoint. This is ; ; where the process is called ; ; from the operating system. . . .
ARM Kernel
For Interrupt and Timer-Interrupt Processes the register R0 holds the information from what source the interrupt occurred. The source can be: 1. The real hardware interrupt. 2. A signal sent to the process. 3. The fast semaphore was signalled.
Assembler syntax: OS_INT_PROCESS <process_name> ; ; Process entrypoint. This is where the process ; ; is called from the operating system. ; ; ; ; Test register R0 for source ; ; of interrupt. . . END
Parameter:process_nameThe name of the process R0 Source of interrupt (register R0): 0 1 2 Invoked by hardware interrupt Invoked by signal sent to this process Invoked by a SIGNAL_FSEM to this process.
Avoid doing several things at a time in a process. Concurrent work should be in different processes. Do not send lots of signals from a process without waiting for a reply once in a while. Remember that the receiving process may not run at all until the sender becomes not ready. Avoid taking advantage of knowledge on process priorities when designing a system. Priorities should be used only to promote fast response to the environment. A well designed system uses only a few priority levels. If a procedure is called from more than one process, the procedure must be re- entrant or interrupts must be disabled while the procedure is executing. Do not use global variables. If you must, then disable interrupts while accessing them. Do not share ports between processes. Shared ports must be treated as global variables. Never modify buffers after they have been sent to other processes. Avoid using large auto arrays in C processes. If these are instead declared static, stack requirements are much easier to determine. Make sure the correct version of osarm(i).anc is included in an assembler process.
ARM Kernel
When testing your system, always have a breakpoint set on the label Q_ERR in osarm.s. If this breakpoint is reached, an error has occurred. (For details on errors, refer to RunTime Error Messages.) If you forget this breakpoint, the system will be unable to inform you of errors.
6.4 Signals
Signals are messages sent between processes. Each message is a buffer, an area of memory, where processes may read and write data. A buffer may be used by many different processes, but only one process at a time may access a buffer. Signals not only carry data, they also initiate actions by the various processes. All processes can exchange signals, even those residing in other computers. (Through the use of a link handler.) Before a signal can be sent a buffer must be allocated and the data, if any, must be entered into the buffer. The signal number, which must always be present, is entered by the operating system when the buffer is allocated, but may be altered by the user if convenient. The signal number is always the first word of a buffer. When a process gains access to a signal buffer by allocating it or receiving it, the process becomes the owner of the buffer. Only the owner may perform operations on the buffer. Once a signal has been sent to another process it can no longer be accessed by the sending process. A process may select the signals it is interested in receiving at any particular moment. The process will then wait for signals to arrive. Meanwhile, other processes are allowed to execute.
ARM Kernel
94 Signals
ARM Kernel
Parameters: sig_nameThe name of the signal struct_memberSome data of the signal SIG_NAMEA number 0..32767 which identifies the signal. value_1A variable name or number.
Example
#define MY_SIGNAL (17) struct my_signal { SIGSELECT sig_no; char character; }; union SIGNAL { SIGSELECT sig_no; struct my_signal my_signal; }; union SIGNAL *sig_ptr; sig_ptr = alloc( sizeof(struct my_signal), MY_SIGNAL ); To access the signal buffer:
ARM Kernel
sig_ptr->my_signal.character = 0xd;
96 Buffer Transfer
ARM Kernel
There is one fast semaphore associated with each prioritized or background process. This semaphore must be explicitly initialised by the process before it is referenced the first time by any process (using the system call SET_FSEM). The current value of a fast semaphore may be examined (GET_FSEM) so that semaphore overrun can be avoided.
6.6 Semaphores
Semaphores are somewhat similar to fast semaphores, but they differ in one very important aspect: A semaphore is not related to any specific process. Any background or prioritized process may wait at a semaphore, not just the owner. Any type of process may signal a semaphore. The main purpose of semaphores is to protect critical code sections from concurrent execution (so called mutual exclusion) without disabling interrupts. This is often done to protect global shared resources. If the compiler supports static initialisation of C structures this can be used to declare a semaphore at compile time. Semaphores are mainly used to ensure that only one process at a time is using a global shared resource. As soon as the process currently occupying the resource releases it, it will automatically be given to the next in its waiting queue. Use the wait_sem system call to get in line to use the resource as soon as possible and the signal_sem system call to releases it as soon as the resource is no longer needed. OSE also implements a simpler form of semaphores for exclusive use by the OSE kernel and associated products. For example, the FLUSH system call uses an internal semaphore to protect internal data structures.
Fast Semaphores 97
ARM Kernel
One way of avoiding global variables is to design the hardware such that processes need not to share it. This is possible if the ports are organized in such a way that the bits needed by one process reside in one port. If global variables are used, interrupts must be disabled/enabled at each access, with the concomitant response time increases.
98 Memory Utilisation
The buffer pool is a major user of data memory. There are eight fixed, user selected, sizes of signal buffers. Estimate maximum number of buffers of each size used by your system. Each buffer also uses a 12 byte administration block (8 bytes in single-chip version). If the debug option is used, each buffer needs an additional eight bytes. Use the following formula to calculate buffer pool size
POOL = no_of_buffers_size1*size1+no_of_buffers_size2*size2 +no_of_buffers_size3*size3+no_of_buffers_size4*size4 +no_of_buffers_size5*size5+no_of_buffers_size6*size6 +no_of_buffers_size7*size7+no_of_buffers_size8*size8
ARM Kernel
In a normal system with only a few permanently allocated buffers, something like 2 kilobytes is a reasonable pool size. In a large system, 4-6 kilobytes may be more appropriate.
6.7.2.2 Memory Required By Stacks
Each prioritized and background process must have its own stack. The stack will contain return addresses, local variables and any data that the process may push. The stack must be large enough to contain all data needed at any one time. When an interrupt occurs the interrupt process must have a stack to use during the interrupt. OSE Epsilon for ARM maintains one stack shared by timer-interrupt and interrupt processes. Stack requirements of these processes do not affect the size of the stacks reserved for prioritized and background processes. A process written in C typically requires 160-256 bytes of stack. However, this depends largely on the application. A few C library functions need a lot of stack, maybe 1-2 kilobyte. If a process requires large dynamic arrays or strings it may also need more stack. A reasonable approach is to start with 256 bytes and adjust stacksizes after a while when actual demands can be seen.
Memory Requirements 99
Table 1: RAM requirement for OSE Epsilon for ARM mode: kernel per process, PCB per process, minimum stack Signal header 160 12 160 8 376 68 normal 220 52 single chip
Add stacks, pool size and the amount of memory used by the operating system to find out total data memory needs.
ARM Kernel
Note: There is a 72 byte register save area as well (80 byte for XSCALE).
Table 2: ROM requirements for OSE Epsilon for ARM RTOS Kernel (minimum, no debug) Kernel (full, no debug) Kernel (minimum, debug) Kernel (full, debug) Kernel (minimum, debug + eldm) Kernel (full, debug + eldm) 2.0 kbytes 4.0 kbytes 2.5 kbytes 4.5 kbytes 7.5 kbytes 9.0 kbytes memory required
The amount of code memory required is mainly determined by the size of the application programs. Only if the system is very small the size of the operating system is important
ARM Kernel
In the minimum configuration, only the system calls alloc, send, receive, free_buf and delay are used. eldm is the debug monitor which is needed if the OSE Illuminator system level debugger will be used.
ARM Kernel
ARM Kernel
Interrupts are usually used to provide fast response. The time from hardware signals an interrupt until execution of the first line of code dealing with the interrupt is often referred to as interrupt latency. Two components determine interrupt latency: 1. The time required to initialize the interrupt. The state before the interrupt must be saved and execution must be transferred to the interrupt handling routine. 2. Interrupts are disabled from time to time. This is done by the CPU itself, by OSE and by user programs. OSE disables interrupts for a maximum duration of us. The time under (1) above must be added to the time interrupts may be disabled.
ARM Kernel
In OSE Epsilon for ARM, you have to supply a user-written Interrupt Handler to be able to use OSE Interrupt Processes.
ARM Kernel
Users Guide / 4.6
ARM Kernel
ARM Kernel
The buffers received from RECEIVE directed to an external process have a different format than ordinary buffers. The format of ordinary buffers is described in the section on the system call ALLOC, the special format was detailed in the section above. NOTE that the special format is applicable only to signals directed to external processes. Signals sent from a process directly to the link handler are of standard format. Special format buffers must be reformatted before they can be returned to the system. This is done by the system call RESTORE. (For details, see System Calls.)
ARM Kernel
EXAMPLE
extern unsigned int ERR_MSG[5]; display( ERR_MSG[1] ; /* /* /* /* Display running process, assuming you have written a procedure display to show the digits. */ */ */ */
ERR_MSG[0] Error number. (For details, see Run-Time Error Messages.) ERR_MSG[1] The process which was running when the error occurred. Processes are numbered from 1 which is assigned to the first process declared in osarm.con and increased by one for each subsequent process. ERR_MSG[2] The address of the process control block (PCB) of the running process. ERR_MSG[3] Current stackpointer. ERR_MSG[4] Zero when called from user.
If the operating system itself detected the error, ERR_MSG[2] will be non zero. If this occurs ERR_MSG[0] - ERR_MSG[4] have the following functions:
ERR_MSG[0] Error number. (For details, see Run-Time Error Messages.) ERR_MSG[1] The process which was running when the error occurred. Processes are numbered from 1 which is assigned to the first process declared in osarm.con and increased by one for each subsequent process. ERR_MSG[2] The address of the process control block (PCB) of the running process. ERR_MSG[3] Current stackpointer. ERR_MSG[4] Non zero when called from user.
ARM Kernel
Users Guide / 4.6
ARM Kernel
110 Continuing After an Error
7 Illuminator Debugger
Illuminator is a System Level Debugger for the OSE Real-Time Operating System from Enea Embedded Technology. Illuminator can be used for OSE (aka OSE Delta), OSEck (aka OSE for DSP) and OSE Epsilon systems. OSE Illuminator is delivered on a separate OSE Delta CD (labelled OSE X.X, where X.X represents the version). In a typical real-time system, the crucial parts are the interfaces between the different system components and the real-time behaviour and status of system functions and resources. In an OSE system, the components are processes and the interface is always made up of OSE signals. With a traditional source code debugger, it would be a tough job to supervise or debug these interfaces because a source level debugger concentrates on code lines. Our OSE Illuminator system level debugger is designed to make it easy to work with the signal interfaces. Illuminator is a standalone debugger which will be used together with a serial line or other interfaces for target connection. It can therefore be used together with any other debugging tool such as Emulators and ROM-Monitor-HLL-Debuggers from any supplier. The OSE Illuminator System Level Debugger can be connected in different ways to an OSE Epsilon target system. Illuminator consists of a user interface and a communication module called Epsilon Debug Server (edbgserver.exe) on the host, and the ARM Debug Kernel on the target. Please consult the Illuminator Users Guide for a detailed description of OSE Illuminator. You can find this manual in the OSE Delta delivery.
ARM Kernel
Users Guide / 4.6
Host Illuminator
TCP/IP
edbgserver
ARM Kernel
Figure 7.1 Serial line connection between host and ARM target Illuminator is connected to the Epsilon Debug Server (edbgserver) over a host TCP/IP connection. The debug server translates the Illuminator signals into a special debug protocol which is send over the serial line to the target system. The ARM Debug Kernel contains the target system level debug functions. It is connected over a serial driver (serial.c) to the serial line connection to the host system. By means of different hooks into the OSE kernel the debug module gets all necessary system information from the kernel. As all debug functions are located in the target the Debug Kernel functions need some target resources. The hooks into the kernel results in some timing overhead when debug is enabled. The debug functions also uses code and data memory from the target system. All event trace is performed in the target. The ARM Debug Kernel will automatically be generated if the debug option (DEBUG YES) is selected in the OSE Epsilon for ARM configuration file osarm.con. You also need a communication module to connect the ARM Debug Kernel to the host. For an asynchronous serial line connection the driver serial is included.
ARM Kernel
The entries for DEBUG, BUFFER_CHECK and STACK_CHECK must not be left empty and you can switch on these run-time functions also without using OSE Epsilon Illuminator. A Buffercheck or Stackcheck error will then jump into an errorhandler if you have defined one. The OPTION DEBUGGER must not be left empty. The OPTION DEBUGGER, ONCHIP will enable some hooks in the OSE Epsilon for ARM kernel and generate the OSE Epsilon for ARM Debug Kernel. After the system configuration file osarm.con is satisfactory run the configurations utility confarm.exe. Confarm.exe reads the configuration file osarm.con and produces the configured kernel. Assemble this file and link it together with your system. You will find the confarm.exe in the ..\conf\ directory of your OSE Epsilon for ARM installation.
ARM Kernel
If the target system is not responding you need to debug the target modules and to check the communication settings.
ARM Kernel
edbgserver communicates by default over COM1 with a baudrate of 115200 baud. If you need another baudrate or another serial interface, type edbgserver in the command window with the following parameters:
edbgserver <com=x> <bd=y> <silent> <debug>
where:
<com=x> is the comport x = 1, 2, 3 or 4. Default value is 1. <bd=y> is the baudrate yy = 9600, 19200, 38400, 57600 or 115200. Default value is 115200. <silent> The silent option will remove the system alive prompt (swimming fish) from the edbgserver window. This allows user debug messages from the target to be displayed in the edbgserver window.
<debug> If the debug option is selected, you can see the eldm low level debug commands. All eldm debug messages from the target are displayed, e.g.:
edbgserver edbgserver com=2 bd=38400 com=2 silent debug
ARM Kernel
116 Symbolic Signal Information
8 Timeout Server
The Time-Out Server allows processes to handle time intervals either to schedule events or to detect time-out conditions. Include the following entry in osarm.con:
TI_PROC tosv,<timeslice>
The time resolution is <timeslice> * system clock ticks. The Time-Out Server is delivered in source code. The file name is tosv.c and can be found in SRC directory of the OSE installation. The functions are described in:
Request Timeout on page 118 Cancel Timeout on page 119 Retrigger Timeout on page 119
ARM Kernel
Users Guide / 4.6
request_tmo( 10000,0x1234);
ARM Kernel
User process can cancel their own previously given time-out request by calling cancel_tmo. Do not use the same signal ID at the same time when using cancel_tmo.
ARM Kernel
ARM Kernel
120 Retrigger Timeout
9 Glossary
Many of the terms used in this manual are specific to operating systems and real-time systems. These can have a different meaning in different contexts. Below, you will find definitions of terms as they are used in this manual.
The OSE-files as they were delivered to your company. A section of memory. It is reserved using the ALLOC system call. It is often used to store signals. The section of memory containing all reserved buffers. At times there is memory left in the pool where more buffers may be reserved. The instructions which make up a program. The memory where code constants are stored. It is often ROM or PROM but can also be RAM in an emulator or target system. System call designed specifically for communications software. In OSE, FLUSH, RESTORE, ADDRESSEE and SEND_W_S are communication functions. Events which occur at the same time. For example, in a terminal, the operator may type at the keyboard and the host computer may send characters concurrently. The operating system may contain different parts of code and behave differently depending on the configuration. The configuration is determined by data entered by the designer into the ostri.con configuration file. Locating end removing errors from a system. The tools used to develop a system. For example: editors to write source code, assemblers/compilers to generate machine readable instructions, emulators to find errors. To decide which process is to run at a particular moment. The ready process which has the highest priority is always selected. See also: swap, task switch.
code
ARM Kernel
configuration
dispatcher
Glossary 121
emulator
A tool to locate errors. With an emulator you may look inside the CPU to see where in the code it is executing, the value of variables etc. An emulator can also stop execution at interesting points in the program. An emulator is necessary to be able to use the full power of the OSE system level debugger. Something happens in the system. For example, the operator may have pressed a button. Events are often connected to interrupts or polled. To issue instructions to the CPU. The instructions are then carried out by the CPU. The program system has experienced a deadlock. It will cease to function and the system will appear to be dead to an observer. The boundary between processes. Together, all contacts between two processes is their interface. In OSE, the process interface consists of the signals exchanged between the processes. An event which, through hardware, causes the CPU to transfer control from the currently running program to another program called interrupt process. For example, as soon as a bit changes the CPU starts executing a subroutine which handles that event. No time is spent checking whether the bit has changed or not. See also: poll.
event
ARM Kernel
interrupt
The time from the occurrence of an event until the first instruction of the corresponding interrupt process is executed. The hardware which causes an interrupt. For example, a timer or a pin on the CPU. See buffer pool. See signal. When a process has no further work to do it becomes not ready. It will then be swapped out by the operating system. See also: ready (p. 123).
operating system
The part of a program system which decides which processes to run, and when. It also distributes the resources of a system, such as memory and time. OSE is an operating system. A process is a program which runs independently of other programs. In principle, a process may act as if it was alone in the CPU.
process
122 Glossary
pointer
A word (2 bytes) of memory containing an address to another part of memory. A pointer may, for example, point to a buffer, i. e. contain the address to a buffer. To check for an event at regular or irregular intervals. For example checking the value of a bit every millisecond. If the bit has changed, a subroutine is executed to handle that event. After the bit has changed, there may be some time before it is checked and the subroutine is started. The CPU always spends a fraction of its time checking the bit, and perhaps other bits. See also: interrupt (p. 122).
poll
pool ready
See buffer pool (p. 121). As soon as a process has something to do it becomes ready. If it has higher priority than the process currently running the currently running process is swapped out. A process may be ready for a long time without being permitted to execute. See also: not ready (p. 122).
ARM Kernel
real-time
An administrative program, for example a word processor, may keep its user waiting for long intervals of time. It will still not be considered useless. A program controlling the brakes of a car will not be very useful if it needs a minute to calculate what to do when the brake pedal is pressed. Programs which have to react to external events within a limited time are called real-time programs. An operating system designed to handle such programs is a real-time operating system. Code is re-entrant if more than one process at a time may execute it. This requires that the code does not use fixed variable locations i. e. it must use registers or the stack. The OSE system calls are reentrant. Code which is not re-entrant can not be called from more than one process unless interrupts are disabled. For example, consider the following C-procedure:
my_proc() { extern int my_variable; my_variable += 1;
re-entrant
Glossary 123
Assume that my_variable has the value 17. If process A calls my_proc, the procedure reads my_variable and finds 17. Then process A is swapped out for some reason and process B is swapped in. After a while process B calls my_proc and my_proc increments my_variable which then becomes 18. A moment later process B is swapped out and process A is swapped in again. It has already read my_variable which was then 17 and now increments it to be 18. Result: my_variable is still 18 although it has been incremented twice since it was 17! run signal swap See execute (p. 122). A buffer which is sent from one process to another. To save the environment of one process and then restore the environment of another process. Together, all hardware and software of your product form the system which you design. The processes may call the operating system when they want to use its services, for example sending or receiving a signal. Such calls are referred to as system calls. System calls are the only way for processes to obtain service from the operating system. The program system executes out of control. The behaviour of the system can not be predicted in case of a system crash. A system crash is the result of errors in user processes or it may result from electrical upsets. Almost every system crash is detected by the error locating devices of the operating system. Is the act of entering configuration data into the configuration file and assembling the operating system. At regular intervals, the operating system checks to see if delays or timeouts have run out or if a timer-interrupt process should be activated. These intervals are called system ticks. The hardware where your programs will ultimately run. Work to be performed by some part of some program. To swap out a process, perform a dispatch and swap in a new process. See also: dispatch (p. 121), swap (p. 124).
124 Glossary Users Guide / 4.6
ARM Kernel
system crash
Someone using the operating system. The system calls programmers use when they communicate with the operating system.
ARM Kernel
Users Guide / 4.6
Glossary 125
ARM Kernel
126 Glossary
Index
A
ARM Assembly-Time Errors 45 80 74, 86 115 50 56 107 96 113 77
43 43 110 11 47
D
DEBUG 113 Debug Kernel 40, 77, 79, 111, 113 49 Debug Option 121 Definition of Terms Dispatcher 12 54 DISPATCHER_IN_RAM
B
Background Process baudrate Buffer Check Option Buffer Sizes Buffer Structure Buffer Transfer BUFFER_CHECK Building a System
E
edbgserver Enable Wake Up Epsilon Debug Server ERR_MSG Error Handler Error Information Execution time 40, 42, 112, 115 75 40, 42, 111, 112, 115 108 59 108 102
C
C Compiler Cancel Timeout comport COND_HALT_W_TIMINT Configuration configuration background processes buffer buffer sizes C compiler check conditional halt CPU types debug option enable wake_up error handler Idle Handler interrupt processes interrupt stack Link Handler processes option debugger OSE dispatcher power off handler power on handler prioritized processes receive handler send handler start handler swap handler target name temporary stack 45 119 115 53 79 74 50 56 45 51 53 47 49 75 59 68 70 57 73 52 54 65 64 72 63 62 60 61 46 58
ARM Kernel
F
Fast Semaphore FLUSH 22, 97 97
G
GET_FSEM Getting Started GHS Global Variables 97 25 45 98
H
Hardware 11
I
IAR 45 40, 42, 79, 111 Illuminator Interprocess Communication 11 103 Interrupt Handling Performance 103 Interrupt latency Interrupt Performance 18 17, 70, 87 Interrupt Process 18 Interrupt response time Interrupt Stack 57
L
led.c led.h LEDs Link Handler Processes 34 34 34 73 20
M
Mailbox
Index 127
max. evact 52 52 max. trace Memory Model 48 100 Memory Required By OSE for ARM 99 Memory Required By Stacks Memory Requirements 99 Memory Used By the Buffer Pool 99 98 Memory Utilisation Message 20, 22, 94 107 Multiple Physical Links
N
Nested interrupts 57
O
ONCHIP Option Conditional Halt OPTION DEBUGGER Option Debugger Option Dispatcher in RAM osarm.con osarm.s OSE 4.2 52, 113 53 113 52 54 30, 43, 79 77 111
ARM Kernel
P
Pool Size 55 64 Power On Handler Pre-emptive 13 17, 72 Prioritized Process 14 Priority Based Process Scheduling Process 9, 11, 81, 83 13 Process States
Serial Line Connection serial line Illuminator system SET_FSEM Signal Signal transmission sequence SIGNAL_FSEM SINGLECHIP Speed Speed Considerations Stack Check Option STACK_CHECK Start Handler Starting and Stopping Processes Static Process Swap Handler Symbolic Signal Information System Configuration System Creation Cycle System Design System Initialization System Start system2.h
112 41 97 9, 81, 94 103 23, 97 45 12, 81 102 51 113 60 93 16 61 116 113 83 81 79 104 34 46 58 114 114 11 117 19, 71 14 95 23, 97 13 106 108 104
T
Target Name Temporary Stack Terminal Testing the Target Debug Connection Time Management Timeout Server Timer Interrupt Process
R
RAM requirement READY Receive Handler Reformatting Buffers Request Timeout Resource Resource Management RESTORE Retrigger Timeout ROM requirements Round-Robin Process Scheduling RUNNING 100 13 63 107 118 11 11 96 119 101 14 13 23 97 62 112
U
UNIX Using Signals In Processes
W
WAIT_FSEM WAITING Writing a Link Handler Writing an Error Handler Writing the Interrupt Handler
S
Semaphore Semaphores Send Handler serial
Index 128