Open 653
Open 653
Project Report
Group d707e16
Aalborg University
Department of Computer Science
Embedded Software Systems
Copyright © Aalborg University 2016
Department of Computer Science
Aalborg University
http://www.cs.aau.dk
Title: Abstract:
An OS Implementation based on the
ARINC 653 Standard ARINC 653 addresses the increasing
number of microcontroller units in avi-
Theme: ation systems. By unifying applica-
Operating Systems tions under a single API, and using
time and space partitioning, it is pos-
Project Period: sible to use a single computing de-
Fall Semester 2016 vice to support multiple safety criti-
cal applications. This project describes
Project Group: the implementation of the ARINC 653
d707e16 standard, as an Operating System, on
an embedded platform, Mini-M4 for
Participants: STM32.
Anders Normann Poulsen
Charles Robert McCall
Gabriel Vasluianu
Jakob Østergaard Jensen
José M. R. S. d’Assis Cordeiro
Supervisor:
Ulrik Mathias Nyman
Copies: 1
Date of Completion:
21st December 2016
The content of this report is freely available, but publication (with reference) may only be pursued with the
authors consent.
Preface
This report is written by the d707e16 group following the Embedded Systems Soft-
ware master programme at Aalborg University. Its subject is the 7th semester
project - An OS Implementation based on the ARINC 653 Standard. This resulted
in developing a system that fulfils the study regulations.
The group would like to thank Ulrik Nyman for great guidance.
The group is also grateful to AAURacing, at Aalborg University, for letting us use
their build configuration and basic drivers for the hardware used in this project.
v
Reading Guide
In this report, references are written using the Harvard method [last name(author
or company),year(if available)]. Sources are listed alphabetically in the bibliogra-
phy. Figures, Tables, Equations, and Listings (code snippets) are numbered after
the chapter they are in, for example, the first figure in chapter two is called 2.1,
the next 2.2 etc. All illustrations and figures are made by the group members un-
less otherwise stated. All data sheets and code can be found on the zip archive
electronically uploaded with the report.
A prerequisite for reading this report is basic knowledge in the computer science
field.
Glossary
1 Introduction 1
2 Analysis 3
2.1 Real-time systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Integrated Modular Avionics . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 ARINC 653 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3.2 Decision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 Other existing standards and ARINC implementations . . . . . . . . 6
2.4.1 DO-178B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4.2 Alternative ARINC 653 platforms . . . . . . . . . . . . . . . . 6
2.4.3 Decision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5.1 The rise of embedded devices . . . . . . . . . . . . . . . . . . 7
2.5.2 The lower bound on systems . . . . . . . . . . . . . . . . . . . 8
2.5.3 Some of the options out there . . . . . . . . . . . . . . . . . . . 9
2.5.4 Settling on a platform . . . . . . . . . . . . . . . . . . . . . . . 10
2.5.5 Decision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.5.6 Communication with the board . . . . . . . . . . . . . . . . . 10
2.5.7 Helper libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5.8 The legacy from the AAU Racing project . . . . . . . . . . . . 11
2.6 Programming language choice . . . . . . . . . . . . . . . . . . . . . . 11
2.6.1 Decision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Problem statement 13
4 System Design 15
4.1 System Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.1 Essential components . . . . . . . . . . . . . . . . . . . . . . . 16
ix
x Contents
4.2 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.3 Memory Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.4 HAL and CMSIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.5 Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.6 OS kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.6.1 Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.6.2 Interpartition communication . . . . . . . . . . . . . . . . . . . 24
4.6.3 Memory Management . . . . . . . . . . . . . . . . . . . . . . . 26
4.6.4 The MPU on a STM32F415 . . . . . . . . . . . . . . . . . . . . 27
4.6.5 Memory strategy . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.6.6 System calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.6.7 Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7 Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7.1 Schema design . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7.2 Full ARINC 653 schema . . . . . . . . . . . . . . . . . . . . . . 31
4.7.3 Schema translation . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.8 APEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.9 Partitions and processes . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5 System Implementation 35
5.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.1.1 JTAG Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2 Source Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.3 Toolchain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.1 CMAKE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.2 GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3.3 OpenOCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3.4 GDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.4 Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.4.1 System clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.4.2 UART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.3 LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.4 Delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.5 MPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.6 Timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.7 Watchdog timer . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.4.8 RTC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.5 XML configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.6 XML Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.6.1 xml_data.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.6.2 xml_data.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Contents xi
5.7 C Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.8 OS kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.8.1 OS Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.8.2 Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.8.3 Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
5.8.4 System/APEX Calls . . . . . . . . . . . . . . . . . . . . . . . . 65
5.8.5 Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
5.9 Partitions and processes . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.9.1 Partitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.9.2 Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.9.3 idle_sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.9.4 stdio_sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.9.5 yellow_toggler and red_toggler . . . . . . . . . . . . . . . . . . 71
5.9.6 The evil partition . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.10 Features of the system . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
6 Testing 75
6.1 Memory Mapping Algorithm . . . . . . . . . . . . . . . . . . . . . . . 75
6.2 XML validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.3 Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.4 ARINC 653 specification - Part 3 . . . . . . . . . . . . . . . . . . . . . 80
6.5 Interpartition Communication . . . . . . . . . . . . . . . . . . . . . . 80
7 Conclusion 83
7.1 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
7.2 Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Bibliography 87
B Hardware setup 97
One might argue that these regulations are loosely formulated and too limited
in scope. For example, if one compares the existing standards for the avionics and
automotive fields, there are large discrepancies. The standards in use in the auto-
motive industry are applying certain rules from the avionics regulations, but only
to a certain extent[13]. These two fields seem to be converging in terms of safety
requirements as the automotive industry develops. This gives rise to the idea of
applying these avionics safety critical systems to other fields. There is potential
for reducing weight of products with a single computing device[50], facilitating
more safety procedures or increasing portability of applications across generations
of products.
1
2 Chapter 1. Introduction
• The standard itself, that specifies an IMA (Integrated Modular Avionics) ap-
proach to run applications
• The physical platform that would contain the system and serve as a research
launchpad
The Analysis chapter provides more details about the software specification that
need to be fulfilled, as well as the different available hardware options.
CHAPTER 2
Analysis
This chapter includes information about the standard, the hardware going to be
used as well as the programming The ARINC 653 requirements are analysed, while
looking at existing projects and other relevant standards in the field of avionics.
Based on this, decisions can be made regarding the following stages of Open653 's
development, and narrowing the project's scope.
3
4 Chapter 2. Analysis
The main benefits of using the IMA concept are: aircraft weight reduction[50]
and lower maintenance costs[53]. There are certain guidelines how such a system
should be designed and implemented, as well as standards that specify how space
and time should be partitioned.
2.3.1 Overview
ARINC 653 is said to bring a new quality in real-time systems development[53]. This is
achieved through its API (APEX), the interface between the OS and the software
applications. Applications are residing in partitions, which have their own memory
and scheduled processing time slots. These partitions can not interfere with each
other and can not take resources from each other. If an error in a partition occurs,
it will only crash itself; the remaining partitions will not be affected.
The following is a brief description of what the standard specifies.
Modules refer to the aviation concept of IMA, where a module can be seen as
a piece of hardware, controlling other subsystems. A module can contain one or
more processors. However, this does not fit well with the concept of partitions,
which have to run on a single processor[21]. A processor used for ARINC 653
applications should have sufficient processing power and access to the required
inputs and outputs, as well as memory and time resources. Besides this, the pro-
cessor should be able to isolate a partition from the others, if it fails[22].
Partitions are program units designed to obey space and time limitations set by
the developer. The way partitions are being run by the processor, is in a static,
cyclic manner meaning that they do not have any priorities. One partition should
only have writing rights to its own memory space[23]. The resources used by the
partitions are specified at build time[24]. The standard differentiates between par-
titions that run applications and system partitions. The latter are optional, and can
be used to contain services not provided in the APEX[53].
Processes are the parts of the program running on partitions. One partition may
contain one or more processes. These may operate concurrently, and may oper-
ate in a periodic or aperiodic manner. A process's characteristics are: data and
stack areas, program counter, stack pointer, priority and deadline. This makes
2.3. ARINC 653 5
them resemble threads in the POSIX[68] process model. Certain attributes are stat-
ically defined, and cannot be changed during operation[25]. Process management
is done with the use of APEX calls. Processes can be in different states: dormant,
waiting, running, ready. Their scheduling is done in such a way that the process
in the ready state with the highest priority, is always executing when the partition
is active. This entails processes being preempted at any time, by the process with
a higher current priority[26].
Memory spaces are defined during the system configuration. These can not be
changed later on.
Health Monitor Has the purpose of monitoring, reporting and isolating hardware
or software faults and failures. Its responsibilities are divided into the following
levels: process, partition and module. The health monitor has error response mech-
anisms to take action in case typical error occurs at any of these levels [30].
partitions the access and resources needed, in the system configuration phase, in
order to satisfy the applications' requirements[31].
2.3.2 Decision
The idea is to bring such an operating system based on ARINC 653 in to the wider
embedded world. The focus will now change to understanding if, and how other
projects have approached this idea.
2.4.1 DO-178B
DO-178B[66] is a set of guidelines to be used for software assurance in safety-
critical avionics systems. Use of the standard can determine the reliability of the
software in an airborne environment. There is a safety assessment process and hazard
analysis to determine the result of failures in the system. Applications are graded
with a software level of A to E, where A is the best level to be achieved and E is
the worst. A level A compliance means the system has been verified and validated
against catastrophic failures, whereas an E compliance has been verified against
trivial failures. Its successor, DO-178C[67] was released in January 2012.
2.4.3 Decision
The research on the existing ARINC 653 platforms concluded with at least four
options. The commercial OSs are excluded from the start since they are not in
the project's scope. The only remaining variant, the ARLX has to be excluded as
well, since it is a hypervisor, and does not fit the scope of the Masters programme.
There has been gained in-depth knowledge about certification and other standards,
but for the rest of this document, only the ARINC 653 specification and design
consideration will be used. The fact that the group does not work on top of an
existing implementation increases the degree of freedom for choosing a hardware
platform to fit the scope of the project and of the education programme.
2.5 Hardware
Having the ARINC 653 specification basic prerequisites in mind, the different op-
tions for hardware are investigated in this section.
For embedded devices this change has meant more capable systems and an in-
creasingly narrowing gap between embedded and workstation computing[11][8].
Capable low power devices and cheap manufacturing of this new generation of
RISC based computing systems, has made it possible to build computers to solve
problems on all scales using the same, or similar, platforms. This has brought a
surge of development for the middle layer of computing, a little more capable than
traditional embedded devices and a little less capable than the typical workstation.
• Have sufficient main memory to support the stacks for all running applica-
tions and the operating system
The first two requirements depend almost entirely on the tasks being solved. The
more applications being run and the more resource demanding they are, the more
CPU time and memory they are going to utilize. The requirement to provide an
MMU or MPU to safely segregate blocks of memory between applications and the
operating system, puts a lower bound on the type of hardware required.
More capable systems may provide an MPU for basic memory protection. The
smallest embedded systems typically do not provide any memory protection. Only
being required to run single purpose applications where all drivers and interfaces
2.5. Hardware 9
are compiled and executed as a single binary, hence they can expect no foreign el-
ement disrupting their execution. More powerful systems may come with a MMU,
providing a memory sandbox of each application.
Creator Ci40 is a platform meant for IoT development. It comes with easily avail-
able ports and connections for embedded development and networking over pro-
tocols like Ethernet and Bluetooth. It is built around the cXT200 chip which is
based on a JZ4780 550MHz dual-core MIPS CPU[64]. It comes with an MMU, is
capable of running Linux and is generally more powerful than many low power
embedded platforms.
MINI-M4 for Tiva is similar to the MINI-M4 for STM32 above, based on the same
ARM Cortex-M4 architecture, but using the TM4C123GH6PM chip from Texas In-
struments instead. It has a pin layout similar to the MINI-M4 for STM32, a USB
connection for power and programming and comes with an MPU, but only runs
at 80 MHz[48].
The two MINI-M4 devices represent a lower, but capable end of the performance
spectrum, while the Raspberry Pi and the Creator Ci40 are more capable. All four
devices have the necessary features to run a simple low power OS, but building
the OS gives rise practical concerns to the complexity and ease of setup.
Focusing on core OS features, only a few basic peripherals like timers, MPU/MMU,
UART and basic IO are necessary for the project. The ARINC 653 does not pro-
vide a solution to scaling the operating system or containers across multiple cores,
hence more capable hardware is likely to see a low utilisation. Since the project is
focused on the implementation of an OS and less so the partitions running on it.
The MINI-M4 modules are more attractive choices from the utilisation standpoint.
A comprehensive datasheet is available for both of them, making it easier to pro-
gram them from scratch. Some experience with the STM32 is present within the
project group on how to setup a Linux based tool-chain. The manufacturer of
the STM32 provides sample code implementations as well as hardware abstraction
layer libraries, which would give a head start on the project.
2.5.5 Decision
This leads to the decision of using Mini-M4 for STM32 as the hardware for Open653.
Ada was created during the 70's by the Defense Department of the USA. It was
created to reduce the number of languages used between departments. It is a high
level language with real-time capabilities.
For the passing of the schema, a higher level language can be used since it is
running on the computer used in development, hence there is little concern for op-
12 Chapter 2. Analysis
timisation and memory usage. The schema will be translated into a usable format
to the embedded system. Once translated it will be compiled and uploaded to the
embedded system.
Python is an easy high level language to use. There is very little boiler plate code
involved, it is not typeset, nor does it need to compile before it is executed. It
has many libraries to interact with structured data types such as XML and JSON,
which makes it a well suited option for developing the schema parser.
2.6.1 Decision
Python is chosen as the language to parse the schema because of its simplicity and
because it is cross-platform. C is chosen for embedded development because of its
simplicity and the level of experience within the group, with the language.
The choice of these languages have the added benefit that the resulting code can
be compiled from all three major PC operating systems.
CHAPTER 3
Problem statement
The goal of this project is to develop an ARINC 653 operating system called
Open653, in order to facilitate time and space partitioning of applications in differ-
ent industries, based on the concepts defined in the Introduction.
Based on the knowledge acquired in the Analysis and limited by the time sched-
uled for the project, this problem can be expanded into the following sub-questions:
• How can this system be developed without the use of pre-existing implemen-
tations?
13
CHAPTER 4
System Design
In this chapter the project is further analysed. Diagrams are given and other no-
tions are described, setting up the premise for implementing Open653 based on
the ARINC 653 standard.
APEX defines the methods by which the partitions talk to other mod-
ules and interact with other partitions or the OS, running on the
same core module or connected to other ARINC systems.
15
16 Chapter 4. System Design
Drivers define the way the hardware runs. They serve the OS with meth-
ods to create an environment in which partitions can run and
scheduled without influencing one another.
HAL and CMSIS are libraries that provide hardware abstraction layers for setting
up the hardware.
Partitions
APEX
OS Schema
Drivers
Hardware
• Hardware platform
4.2. Hardware 17
• Partition communication
The design of these components is described in the rest of the chapter. Memory
separation is not an essential feature for facilitating the execution of applications,
but is essential to separate them for security and reliability reasons, thus memory
protection is also described.
The features “Health Monitor” and “Intrapartition Communication” have been
excluded from the project to limit the scope to a manageable amount.
4.2 Hardware
As mentioned in the Settling on a platform section, the hardware used for the de-
velopment of this system is the Mini-M4 board. It is build around the STM32F415RG
microcontroller[61], based on an ARM Cortex-M4 core. This is a 32-bit RISC ar-
chitecture CPU using the ARMv7M instruction set[6]. Additional information was
found in the ARM technical reference[4]
The chip provides two interfaces for debugging:
There was no thought process involved in choosing one of the two. The JTAG
interface is enabled by default, and worked right from the early phases of the
project. In some situations, SW would have been preferred to JTAG, due to physical
space constraints. JTAG uses 5 wires, while SW only uses 2. Also, the IDE of choice
can have some limitations on the debugging platform.
JTAG is actually an association1 that develops standards about how physical cir-
cuit boards should be tested. However, for the rest of the document, JTAG will be
referred to as the main communication interface for the Mini-M4 board. This will
mainly be used for flashing the program on the chip and debugging it. In order for
1 Joint Test Action Group[41]
18 Chapter 4. System Design
Another way of communicating with the chip is the serial communication. For this
purpose the UART will be used. This is a common peripheral for embedded de-
vices, but it needs to be set up before it can be used. This involves initialising the
UART, configuring the data format and the transmission speed and sending the
actual data. In order to see this data on a computer, one could use a serial-to-USB
adapter [42]. This creates a virtual COM (Communication port), that is accessed
using a serial console such as PuTTY2 .
The final setup of the Mini-M4 board comprises of the 5 wires from the JTAG, the
2 wires from the UART, the mini-USB cable that provides power and a breadboard
to accommodate electrical connections.
There are 192 KB of RAM, divided into 128 KB of SRAM and 64 KB of CCM data
RAM. The SRAM is volatile memory, where the static tag means that it does not
need to be refreshed in order to keep its state. This is divided furthermore into a
section of 112 KB, and another of 16 KB, which can be useful if one needs to boot
from RAM[49]. They are adjacent in address space and can be treated as one block.
The memory has a feature called bit-banding, in order to let the system perform
atomic operations on bits[3].
The other 64 KB of CCM data RAM are always ready for access by the CPU, but
cannot be accessed by the peripherals through direct memory access. Beside the
192 KB of SRAM, there are 4 KB of SRAM used for backup purposes. These won’t
be used, since they are not within the scope of the project.
Figure 4.2 presents a simplified model of the memory map implemented in the
STM32F415RG microcontroller[62]. The blocks on the left column are legacy of the
ARM Architecture. This provides 4 GB of addressable memory. Some of these
regions are correlated to the microcontroller's actual memory, as it can be seen in
the column on the right. Each block in this column contains their start and end
addresses, on their side.
2 Free and open-source terminal emulator, serial console and network file transfer application
4.4. HAL and CMSIS 19
0xFFFF FFFF
ARM CORTEX-
M4 internal CORTEX-M4 0xE00F FFFF
peripherals internal
0xE000 0000 peripherals 0xE000 000
0xDFFF FFFF
0x6000 0000
0x5FFF FFFF
Peripherals
0x5FFF FFFF
Peripherals
0x4000 0000 0x4000 0000
0x3FFF FFFF
SRAM
0x2001 FFFF
SRAM 128 KB
0x2000 0000 0x2000 0000
0x1FFF FFFF
0x1000 FFFF
CCM RAM 64KB
Code 0x1000 0000
0x080F FFFF
Flash
0x0000 0000 0x0800 0000
As seen in figure 4.3, CMSIS defines the data structures and address mapping
20 Chapter 4. System Design
for some of the ARM peripherals. Besides this, it can be used to configure the
microcontroller oscillators, as well as providing support for the instrumentation
trace during debug sessions [45]. HAL is build on top of CMSIS, which defines
exceptions specific to the chip. HAL uses these definitions to configure interrupts
(e.g. SysTick timer).
Application
code
HAL library
CMSIS core
Nested vectored
Debug and
CPU SysTick interrupt Peripherals
Trace
controller
4.5 Drivers
The drivers controlling the hardware would have to be implemented at an early
stage of the project, in order to have access to the low level subsystems. The
following list contains the drivers that would provide the OS a basic interface to
access the hardware.
System Clock is used as the CPU frequency, and is scaled down to provide a
clock source for peripherals.
The system clock relies on an oscillator. There is a multitude of
choices, ranging from internal or external oscillators, to high or
low speed crystals. In some cases, certain peripherals can use
their own, independent clock sources that also have to be config-
ured
UART used by the system to communicate with the outside world. This
can either receive or transmit data to another UART devices
4.6. OS kernel 21
LEDs mainly used for debugging. They are connected to two of the
GPIO pins
MPU provides the system a way to manage its memory. This is required
by the ARINC 653 standard. Operating systems built on more
advanced processors generally use an MMU
Timing has the purpose of keeping track of relative time. As the standard
specifies, it should be counting nanoseconds
4.6 OS kernel
The OS kernel has the purpose to link the APEX interface with the hardware. This
is a monolithic kernel. The following sections contain the kernel's features and
functionalities.
4.6.1 Scheduler
Schedulers are used to allow a system to run multiple processes concurrently on a
single CPU core. A scheduler decides which process to execute by an available pro-
cessor, according to predefined rules. Based on these rules, two or more processes
may run concurrently, sharing CPU time. The ARINC 653 specification defines two
levels of scheduling, a partitions level scheduler and a process level scheduler. The
algorithms for both are strictly defined.
22 Chapter 4. System Design
The partition level scheduler uses manual scheduling. Time is split into fixed
length intervals, major frames. Each partition is given one or more windows (i.e.
time slices) in the major frame. Each window has a start time relative to the time
of the major frame and a duration. Windows are set up by the system integrator in
the XML file[32]. When a partition has run for the duration specified, the sched-
uler switches to the partition containing the next window. The switch will happen
regardless of what the partition is doing at that time; a partition can not overrun
its allotted time and thereby cause other partitions to overrun their deadlines.
The process level scheduler is a pre-emptive priority scheduler. All processes will
always have a priority. Processes can only be scheduled when the partition they be-
long to is scheduled by the partition level scheduler. The process scheduler selects
the process with the highest priority that is also in the ready state. If two or more
processes have the same priority, the one that became ready first is scheduled[33].
The ARMv7M architecture has two special interrupts that are especially useful for
scheduling: SysTick interrupt and PendSV interrupt. The SysTick interrupt is trig-
gered at a regular interval, and can be used for time based scheduling. The PendSV
interrupt is triggered by software and can be used to trigger scheduling from other
interrupt service routines, e.g. when a process blocks to wait for something.
LR, PC and PSR on the stack. These are only some of the registers. When the ISR
exits, and control is handed back to the NVIC, the NVIC will restore these registers
again.
If the operating system wishes to switch context, it must save the remaining regis-
ters, R4-R11 and stack pointer, to memory; pick a new context to restore; reload the
registers R4-R11 and the stack pointer of the new context from memory, and hand
back control to the NVIC. The NVIC will then reload the remaining registers from
the stack of the new context. Table 4.1 shows the registers and who saves them.
Table 4.1: A table of the CPU registers of a Cortex M4. Notice that register R13 (stack pointer) is
banked; there are separate registers for user space and kernel space. Aliases are written in parenthe-
sis in the Registers column, and calling convention is written in parenthesis in the Purpose column.
Additionally, the Cortex M4 utilises a banked3 stack pointer. The logical SP register
consists of two physical registers: the Master Stack Pointer (MSP) and the Process
Stack Pointer (PSP). The MSP is intended for kernel space execution while the
PSP is intended for user space execution, although this not enforce by hardware.
Selecting which stack pointer to use can not be done by software within an ISR.
Instead, this must be done by the NVIC. This makes it impossible to restore a
context entirely from software. Software can instruct the NVIC which stack pointer
should be used by the new context. Software can do this by putting a specific value
into the PC register. This value is the EXC_RETURN value. Table 4.2 shows the
different EXC_RETURN values and their meaning. An ISR is always concluded by
putting an EXC_RETURN value in to the PC register. Before entering an ISR, the
NVIC puts the EXC_RETURN value that denotes the state of the CPU before the
interrupt was triggered, in to the LR register. When an ISR is not used to perform
3 A banked register is a logical register implemented across multiple physical registers. The state
of the hardware determines which physical register the logical register refers to[5]
24 Chapter 4. System Design
Value Description
0xFFFF FFF1 Return to Handler mode, using the Master Stack Pointer,
but without the floating point unit.
0xFFFF FFF9 Return to Thread mode, using the Master Stack Pointer,
but without the floating point unit.
0xFFFF FFFD Return to Thread mode, using the Process Stack Pointer,
but without the floating point unit.
0xFFFF FFE1 Return to Handler mode, using the Master Stack Pointer,
with the floating point unit.
0xFFFF FFE9 Return to Thread mode, using the Master Stack Pointer,
with the floating point unit.
0xFFFF FFED Return to Thread mode, using the Process Stack Pointer,
with the floating point unit.
Table 4.2: A table of the possible EXC_RETURN values. An interrupt service routine is exited by
loading one of these values into the Program Counter register.
At the application level messages are atomic and as such channels are required
to ensure the correctness of every message received[34]. Multiple different modes
exist for the messages and different checks and methods should be applied to com-
ply with the ARINC 653 standard. Only a subset of these features is designed and
implemented, to give a basic feature set which allows partitions to communicate
on a single microcontroller.
A simplified design of queuing ports and sampling ports is made for Open653.
Since ports and their attributes are declared and defined statically, very little has
4.6. OS kernel 25
A port belongs to a partition and contains a reference to its channel. Some nec-
essary attributes for queuing ports and sampling ports are listed in the sections
4.6.2.1 and 4.6.2.2 respectively.
The OS has to facilitate some methods to push and pop complete messages to and
from a circular buffer, which would be auto-generated from the configuration file.
Open653 also has to provide functions to handle the following APEX calls defined
in the standard[35]:
• CREATE_QUEUING_PORT
• SEND_QUEUING_MESSAGE
• RECEIVE_QUEUING_MESSAGE
• GET_QUEUING_PORT_ID
• GET_QUEUING_PORT_STATUS
26 Chapter 4. System Design
The OS has to facilitate some methods to transmit and validate sampling mes-
sages. A simple buffer has to be provided for this by the auto-generated structures.
Open653 also has to provide functions to handle the following APEX calls defined
in the standard[35]:
• CREATE_SAMPLING_PORT
• WRITE_SAMPLING_MESSAGE
• READ_SAMPLING_MESSAGE
• GET_SAMPLING_PORT_ID
• GET_SAMPLING_PORT_STATUS
*E\WHV
5HJLRQ
5HJLRQ
5HJLRQ
5HJLRQ
5HJLRQ
5HJLRQ
06Y9
Figure 4.4: Example of nested and overlapping regions from [55].
The MPU is unified, meaning that there are not separate regions for the data and the
instructions.
The MPU can be used also to define other memory attributes such as the cacheability,
Every region has a fixed priority and is numbered from 0-7, where region 7 has
which can be exported to the system level cache unit or the memory controllers. The
the highest priority.
memory attributeRegions
settings cancan be nested
support 2 levels ofand overlapping.
cache: inner cache and The
outer behavior
cache. when
nesting and overlapping
The cache is dictated
control is done bycache
globally by the the control
priority of the
register, region
but the MPU can asspecify
depicted in
figure 4.4.the cache policy and whether the region is cacheable or not. The MPU allows to set the
cache attributes for level 1 (L1) cache by region (only for the STM32F7 Series which
implements a L1-Cache).
4.6.5 Memory strategy
As the memory available is not abundant, there is the need of avoiding wasting
memory. For that, the memory needed by the partitions is optimised by a sorting
algorithm in order to fit the most partitions possible in a limited region of memory
and by expanding the partition size, fulfilling the empty gaps. It is important
to keep the size, initial pointer and the region of each partition for enabling and
disabling the right area of memory when a different partition is active.
System calls are critical to accomplish ARINC 653's strict space and time separa-
tion. Therefore, ARINC 653 explicitly specify that partition code must be executed
in unprivileged mode only[36]. If partition code is not run in an unprivileged
mode, it will have the ability to disrupt the system (e.g. changing the scheduling
table and memory protection).
4.7 Schema
An ARINC 653 schema specifies the structure of the configuration and the required
elements for the core module. The schema is a recipe used to create a configuration
file.
Partition_Memory Memory_Requirements
PartitionIdentifier RegionName
PartitionName Type
PhysicalAddress
SizeBytes
Access
Sampling_Port
Partition RefreshRateSeconds PortType
PartitionIdentifier
PartitionName PortName
Queuing_Port MaxMessageSize
Criticality
SystemPartition MaxNbMessages
EntryPoint
Source StandardPartition
Channel PartitionIdentifier
Connection_Table PartitionName
ChannelIdentifier Destination PortName
ChannelName
PhysicalAddress
Procedure
The figure presents the schema and the relationship between the elements. An
ARINC 653 Module has four elements. One or more Partition Memory elements,
a Module Schedule, one or more Partitions and a Connection Table.
Window_Schedule defines when a partition needs to run and for how long it will
run. PartitionPeriodStart is not used, and it purpose is not understood.
Partition has one or more queuing ports and one or more sampling ports; it has five
attributes which specify information about the partition. EntryPoint is the name
of the partition initialisation function, SystemPartition specifies what type the par-
tition is. Criticality is not currently used, it is meant to define the importance of a
partition.
The ports have four attributes which define information about the port such as
size and source or destination. Sampling_Ports are not well supported currently
in the project but will function. This is due to not having or needing any sampling
ports in the current implementation.
The figure shows the intended schema for a fully compliant ARINC 653 implemen-
tation as found in the ARINC 653 standard. The greyed out areas, are the aspects
of the Open653 schema not yet implemented in this project.
4.8 APEX
The APEX defines an API for applications running on Open653. Its functions are
grouped into seven major categories[37]. Table 4.3 contains the headers declaring
these calls (column on the right), classified according to the standard.
These header files only declare the calls, which will be implemented later in the
kernel. apex_types.h declares their arguments: global and constant variables, as
well as the types used by the calls. All the content is found in the standard, in the
form of an ANSI C compliant code. The input (IN) arguments are types defined
here. The output (OUT) arguments are dependent on the RETURN_CODE value. This
can be one of the values shown in listing 4.1.
67 typedef
68 enum {
69 NO_ERROR = 0, /* r e q u e s t v a l i d and o p e r a t i o n p e r f o r m e d */
70 NO_ACTION = 1, /* s t a t u s o f s y s t e m u n a f f e c t e d by r e q u e s t */
71 NOT_AVAILABLE = 2, /* r e s o u r c e r e q u i r e d by r e q u e s t u n a v a i l a b l e */
72 INVALID_PARAM = 3, /* i n v a l i d parameter s p e c i f i e d in r e q u e s t */
73 INVALID_CONFIG = 4, /* parameter i n c o m p a t i b l e with c o n f i g u r a t i o n */
74 INVALID_MODE = 5, /* r e q u e s t i n c o m p a t i b l e w i t h c u r r e n t mode */
75 TIMED_OUT = 6 /* t i m e −o u t t i e d up w i t h r e q u e s t h a s e x p i r e d */
76 } RETURN_CODE_TYPE ;
While information about the overall partition is defined statically, its processes
are defined and created at runtime and for this reason every partition needs some
memory allocated to store this information. A starting process is created by default
using the partitions' entry-point, which is then allowed to spawn any additional
processes.
Processes, just like partitions are collections of information. Processes hold infor-
mation about their own state and how they are to be scheduled.
CHAPTER 5
System
Implementation
This chapter deals with how the system's functionalities are implemented. Dia-
grams are included when necessary, as well as code snippets for the interesting
parts of the program.
5.1 Hardware
The Mini-M4 board is a development board, which means that beside the micro-
controller, it also contains two crystal oscillators, two LEDs, a reset button and the
peripherals for regulating the power it gets from the micro-USB connector. Some of
the GPIO connections can be accessed using external pins. These pins are soldered
to the board, and this is setup on a breadboard for practicality, as seen in 5.1.
The JTAG connector is wired to the five corresponding pins of the board. The serial
35
36 Chapter 5. System Implementation
communication is established with two other wires, going to the UART pins of the
board. The final setup can be seen in the next figures.
(a) The JTAG lines (b) Both the JTAG and serial interfaces
After this, the board is ready to be used in the development process. The only
drawback of this setup, is that it requires three USB ports: one for powering the
board, another one for the JTAG interface, and a last for the serial communication.
For detailed photos of the process, consult Appendix B.
2 4 6 8 10 12 14 16 18 20
VCC GND
The tags on the upper part of figure 5.3, are JTAG specific:
RESET used for resetting the target device. This is connected to the MCLR (Master
Clear or Reset) pin of the board
The tags on the lower part of the figure represent the pins of the microcontroller,
where P stands for port, A or B for the port identity (PORTA or PORTB) and the
number being the individual GPIO needed.
A driver1 is needed to be installed on Windows machines, in order to recognize
and program using ST-LINK/v2.
/
build
...
src
drivers
...
kernel
...
partitions
...
utils
third_party
ARINC
APEX
...
CMSIS
...
linker_scripts
STM32F4xx_HAL_Driver
...
...
Figure 5.4: A rough depiction of the source file structure
5.3 Toolchain
To write, compile and load code to the embedded platform, a regular computer
is used with the editor of choice. A C compiler and a programmer unit is used
to transmit the code by the JTAG interface (5.1.1). The toolchain is adopted from
AAURacing[1] which uses a similar chip and develop on Linux/OSX. For this
project the toolchain is generalized to also work on Windows 10. In the rest of the
section the toolchain and source code structure are explained.
5.3.1 CMAKE
CMake is used to setup the makefiles for the project. It is of little benefit comparing
to writing the makefiles from scratch, but has been adopted in Open653, since it
came with the toolchain.
Like Make, CMake is run from a file containing a set of instructions on a project.
The instructions are separated in a nested structure of files to limit complexity. A
project can have multiple CMake files, they all have to be named CMakeLists.txt
and hence are placed in separate folders. The main CMake file is placed in the
root-folder of the project and contains the main compiler information. Specific
information about compile targets and their files are placed in sub files in folders
as depicted in figure 5.5.
/
src
CMakeLists.txt
third_party
CMakeLists.txt
CMakeLists.txt
Figure 5.5: Placement of CMakeLists.txt files in source directory.
As denoted by the first line of the CMakeLists.txt file in ‘/’, no less than version
2.8.8 of CMake is required. The rest of the file contains:
Make is a UNIX tool[18] often used to make many calls to GCC in the C language
projects. Objects are compiled in separate calls to GCC and Make provides features
to set up a dependency tree of calls when many objects are linked together in a
target.
40 Chapter 5. System Implementation
5.3.2 GCC
The GNU Compiler Collection or GCC is used for compiling and linking the C
files into a target called ‘OS’. In order to compile for the ARM architecture a cross
compiled version of GCC is necessary, in this case the arm-none-eabi-gcc compiler
which is available in all newer Ubuntu versions[65].
MCU flags
These options can be found at gcc.gnu.org [14].
-mcpu=cortex-m4 This specifies the name of the target ARM processor.
-mtune=cortex-m4 This option specifies the name of the target ARM processor
for which GCC should tune the performance of the code.
-mthumb Generate code that executes in Thumb state.
-mlittle-endian Generate code for a processor running in little-endian
mode.
-mfpu=fpv4-sp-d16 This specifies what floating-point hardware is available on
the target.
-mfloat-abi=hard Specifies which floating-point ABI to use. ‘hard’ allows
generation of FPU-specific floating-point instructions.
-mthumb-interwork Generate code that supports calling between the ARM and
Thumb instruction sets.
Linker flags
These options can be found at gcc.gnu.org [17].
-Wl, -T.../file.ld Use the linker-script STM32F415RG_FLASH.ld in the
folder /third_party/linker_scipts (section 5.3.2.2).
-nostartfiles Do not use the standard system startup files when link-
ing. Used to force GCC to use a custom implementation of
Newlibc implemented functions.
-Map=./result.map Print a link map to the file result.map showing where ob-
ject files and symbols are mapped into memory.
Debugging flags
These options can be found at gcc.gnu.org [16].
-g Produce debugging information.
-ggdb Produce debugging information for use by GDB.
C flags
These options can be found at gcc.gnu.org [15].
-std=c99 Determine the language standard to be ISO C99.
-fms-extensions Accept some non-standard constructs, useful in some static
structures (section 5.8.3).
Table 5.1: Showing the important GCC flags used to compile the OS.
There are two important flags, which have not been mentioned in table 5.1. the
-DHSE_VALUE=16000000 and -DSTM32F415xx are not compiler options but defini-
tions passed to GCC to use at compile time.
42 Chapter 5. System Implementation
Listing 5.1 shows how the memory layout is defined in the linker script. While
FLASH, RAM and CCMRAM define mappings of memory in hardware (see section 4.3),
OS, DUMMY1, DUMMY2 and STDIO_SYS define the location and sizes of the system mem-
ory. In listing 5.1, ORIGIN denotes the starting address of a section of memory and
LENGTH denotes the size of the section.
40 / * S p e c i f y t h e memory a r e a s */
41 MEMORY
42 {
43 FLASH ( r x ) : ORIGIN = 0 x08000000 , LENGTH = 1024K
44 OS ( r x ) : ORIGIN = 0 x08000000 , LENGTH = 64K
45 DUMMY1 ( r x ) : ORIGIN = 0 x08010000 , LENGTH = 8K
46 DUMMY2 ( r x ) : ORIGIN = 0 x08012000 , LENGTH = 8K
47 STDIO_SYS ( r x ) : ORIGIN = 0 x08014000 , LENGTH = 8K
48 RAM ( xrw ) : ORIGIN = 0 x20000000 , LENGTH = 128K
49 CCMRAM ( rw ) : ORIGIN = 0 x10000000 , LENGTH = 64K
50 }
By default all symbols and associated memory goes into the OS. Only when a parti-
tion is specifically defined to a location in the linker-script, can it be separated from
the OS. Listing 5.2 shows how to allocate a specific partition. The linker-script uses
5.3. Toolchain 43
the fact that every partition is compiled as a library, and the library name is added
in the listed format under its corresponding label (in this example: STDIO_SYS).
This scheme assures the code is separated from the kernel in flash. It does not,
however, separate the statically allocated variables and structures in RAM.
85 . s t d i o _ s y s :
86 {
87 . = ALIGN ( 4 ) ;
88 libstdio_sys . a :*
89 . = ALIGN ( 4 ) ;
90 } >STDIO_SYS
Similar to listing 5.2, the compiled libraries of the compiled partitions are confined
to a space in flash, as defined by their labels in 5.1.
5.3.3 OpenOCD
Open On-Chip Debugger or OpenOCD[51] is used together with the ST-LINK/v2
to program the chip and create a channel for GDB to debug the system at run-time.
The CMakeLists.txt file in ‘/’ defines a function running the following commands
using OpenOCD:
After execution of this command, OpenOCD will remain open and connected to
the chip and will accept incoming connections on port 3333 for GDB debugging as
a GDB server (see more in 5.3.4).
5.3.4 GDB
The GNU Project debugger[12], GDB (arm-none-eabi-gdb), is an open source soft-
ware debugger built to compliment the GNU Project compilers, GCC (see 5.3.2). It
allows programmers to debug their applications. GDB can:
• if the hardware supports it, show the value of each CPU register
• execute code line by line, letting the programmer see how each line affects
the state of the program, and in case of crashing code, which line of code
crashes the program
This feature set, makes GDB especially useful for tracking down complex bugs
and bugs in otherwise inaccessible systems, (e.g. systems with no screen to di-
rectly print to). GDB also allows programmers to investigate buggy code while it is
running, as opposed to after-the-fact debugging of logging, printing, etc. Many ad-
vanced text editors and integrated development environments feature direct seam-
less GDB integration. Outside of such programs, GDB can be run in a terminal.
To debug the code running on the chip, an active OpenOCD connection to the chip
is required. When OpenOCD is connected, it will act as a GDB server. GDB can be
connected to OpenOCD with the command target remote localhost:3333.
5.4 Drivers
Setting up the drivers took place in the early phases of the project. Their function-
ality rely a lot on the HAL library. The library's documentation is a good starting
point, and the things it lacks can be found in the microcontroller's datasheet.
External
Internal
Independent
LSI
watchdog
32 kHz
timer
RTC
Real Time
clock
Clock
select
LSE
32,768 kHz
HSI
CPU
16 MHz
High speed
APB2 domain /2
peripherals
PLL
The lower part of figure 5.6 shows that the frequency of the HSE is multiplied by a
PLL (Phase-locked loop) system, before it gets to the clock selection block. This is
the frequency supplied to the CPU and memory through the AHB bus, and scaled
down for the peripheral buses. These buses are divided into low and high speed
domains as:
AHB Advanced High-speed bus. This runs at 168 MHz, and connects
mainly the CPU, memory and the GPIOs
APB1 domain low-speed domain, running at 42 MHz. This includes among other
peripherals the UART
The PLL registers3 have to be set up in such a way that the frequency it generates
is compatible with the prescaling settings of the peripheral buses.
3 Specifically the division/multiplication factor registers
46 Chapter 5. System Implementation
5.4.2 UART
The UART allows the transmission and reception of information between the MINI-
M4 and a terminal. Information is transceived one character at a time. An UART
has a fractional baud rate generator system and the speed is limited by the GPIO
frequency. UART4 is used with pin 10 and 11.
5.4.3 LEDs
The LEDs are used mainly for debugging. There are three LEDs on the Mini-M4
board, two of them being programmable. Since they are connected to two pins of
a pins, these need to be initialised first. Afterwards, using the functions defined in
the HAL library, these pins can be turned high, low or toggled, thus changing the
state of the LEDs.
5.4.4 Delay
The delay function is also used for debugging, giving the developers the chance of
seeing when things are happening. This is because most of the program instructions
are executed so fast, that the they appear to be instant. Delay is defined in the HAL
library, and relies on the SysTick.
SysTick is a timer4 that can be used to generate the main system event clock. That
is exactly how the HAL library has it implemented it. Its default time base is one
millisecond. This means that every millisecond, SysTick generates an interrupt (to
look after sensor values, scheduling or basic timing tasks). To see a more detailed
explanation of the SysTick timer consult 5.8.2.1.
5.4.5 MPU
The MPU functionality of the MCU was tested but not implemented, beyond the
extend of getting the driver working.
5.4.6 Timing
This driver is used to accurately measure the execution time of different functions.
It uses the DWT (Data Watchpoint and Trace support) internal peripheral registers
defined in the ARM-M4 Architecture manual[6]. Since the HAL library does not
define them, they are accessed by their addresses. These addresses are found in
the range shown in the upper part of figure 4.2, while the registers used by this
driver are shown in listing 5.3.
4 Fed with the system clock optionally divided by 8
5.4. Drivers 47
DWT_CYCCNT is a 32 bit counter, that when enabled counts the number of core
cycles. DWT_CONTROL5 is the control register for the Data Watchpoint and Trace
support. By setting its least significant bit, the cycle counter mentioned above is
enabled. The last register, SCB_DEMCR (Debug Exception and Monitor Control
Register), and is used to manage exception behavior during debugging.
The returned value is a 64 bit signed integer, as the ARINC 653 standard specifies
[38]. The count is incremented in the range of nanoseconds, but the sampling
frequency limits the step to 5.45 nanoseconds. In order to fully comply with the
standard (one nanosecond steps), A counter would be necessary with a 1 GHz
clock source.
oscillators fail. Its basic functionality is represented in figure 5.7. After the program
starts running, a function is called that initialises and starts the watchdog timer.
Here, a period of time is defined, in which the program has to refresh (reload) the
watchdog timer. If this fails to happen, either by mistake, the developer forgetting
to call the refresh function, or by a software/hardware fault, the watchdog timer
restarts the program (depicted with the red arrow).
5 Referred to as DWT_CTRL in the ARM documentation
6 LSI running at 32 kHz, seen in the upper part of 5.6
48 Chapter 5. System Implementation
Program Starts Watchdog is initialised and started Watchdog restarts the program
The second watchdog timer, is called a window watchdog. In contrast to the in-
dependent watchdog, one can provide a time interval in which the timer has to
be reset. Resetting the timer outside this interval (as well as not resetting it in
the mentioned time window) would restart the program. It uses the system clock,
which means that if this fails, the watchdog won't be able to reset the system. This
watchdog has not been implemented, but its functionality is relevant to Open653,
in regards to what the standard specifies. The processor should be able to isolate a
partition that fails [22]. This could be done by using the window watchdog timer
to define the time intervals for partitions to run. The feature called Early Wakeup
Interrupt can be used to do some safety operations, just before the reset is done
by the watchdog[58]. In short, if the window watchdog is not reset in the window
interval it receives (correspondent to each partition), then the EWI will isolate the
partition and the MCU will be reset to continue its operation with the remaining
partitions.
5.4.8 RTC
The real-time clock is implemented as a way to give the system the possibility to
keep track of time. It was realised at a later point that ARINC 653 specifies that
time keeping should be done in nanoseconds, a range that the RTC is not capable
of. This is the reason for continuing researching other ways of timing the system,
as seen in section 5.4.6.
The RTC could be used for timestamps on error logs and such, as the standard
specifies[39]. The use of the LSE oscillator, as well as the design of the RTC7 ,
makes this a reliable secondary clock source.
7 Which includes all time components, as well as subseconds and year correction
5.5. XML configuration file 49
5.6.1 xml_data.h
xml_data.h contains the static declarations for the structs written to the xml_data.c,
and the symbols for the xml_data.c functions and variables.
The declarations for the structs are included into xml_data.h from a file called
types.h. The symbols for the functions and variables are written to the file whilst
parsing the XML.
5.6.2 xml_data.c
xml_data.c is mostly dynamic and generated from the elements in the XML. The
static elements of its generation are handled by two functions and the self.idle_partition
set in the init. The static functions are called write_file_c_header and write_file_c_footer.
These functions write the static code needed at the beginning and the end of the
xml_data.c file to function, e.g. the includes and the #endif. The idle partition is
not included in the XML. It is hard-coded into the partition loop as it is always
required to exist. For more information about the idle partition refer to section
5.9.3.
5.7 C Structures
The data structure undergoes change during the translation from the XML de-
scribed in section 4.5 to C structs to support ease of use. The structure of the data
and relationships of the elements are presented in the figure 5.8.
part_mem_t mem_req_t
partitionidentifier type
partitionname sizebytes
nummemory access
memory_arr address
majorFrameSeconds
partition_schedule
window_schedule
partitionidentifier
partitionname windowidentifier
periodseconds windowstartmilliseconds
perioddurationseconds windowdurationmilliseconds
numWindows partitionperiodstart
window_arr
partition_t port_t
partitionidentifier portname
partitionname is_queueing_port
criticality q_buf {
systempartition WAITING_PROCESSES
entrypoint PORT_DIRECTION
nb_ports MESSAGEBUFFER()
ports }
channel_t
id port_t
channelname
nb_ports
ports
The global structure of ARINC_653_Module (figure 4.5) has been removed, its
sub elements now exist without a dependency. Module_schedule as also been
removed, leaving its attribute majorFrameSeconds as an independent variable def-
inition. partition_memory (part_mem_t) and partition_schedule have maintained
their one-to-many structures with their sub elements. Partitions' sub elements,
sampling and queuing ports, are combined into a single structure called ports.
The XML element Connection_Table is removed, and StandardPartition is trans-
formed into a port reference list which shares an association with the ports.
The following structures have been extended to contain an array of its substruc-
tures:
• and channel_t contains an array ports which references to the ports available
to the channel
Each of these structures has an associated variable to indicate the number of ele-
ments in the array.
5.8 OS kernel
This section gives an overview of the features of Open653 and how they are imple-
mented. At the end a feature list is provided to give summary of the features and
services implemented in Open653.
5.8.1 OS Initialisation
Open653 is initialised from the main() function in /src/kernel/main.c. Its job is to set
up the following:
The setup of the UART is fixed to use port C pin 10 and 11 with a baud-rate of
115200 baud. Setting it up is a matter of passing these arguments to the HAL li-
brary and is not covered further in the report.
The last action taken by the main function is enabling the SysTick interrupt for
starting the scheduler and entering unprivileged mode.
In the following sections the main clock setup (section 5.8.1.1), the partition and
process setup (section 5.8.1.2), and partition schedule setup (section 5.8.1.3) are
explained in further detail.
The rest of the partitions listed in the auto-generated C file are initialised by setting
the number of active processes to one, setting up their specified entrypoint with
a memory address within their memory space and setting the rest of the empty
process entries to DORMANT.
Note that in this implementation every process is given 1 KB of RAM to use for
stack. This can cause a fault if partitions initialise more processes than their defined
memory spaces hold.
5.8. OS kernel 53
Provided the same XML schema, the schedule is always the same; each time the
system boots, a schedule identical to the one last used is built. In future builds of
Open653, the schedule should ideally be built by the XML schema parser, to avoid
rebuilding the same schedule during each boot of the system.
The algorithm to build the schedule is as follows:
54 Chapter 5. System Implementation
Provided that the data in the XML schema is valid, this algorithm will create a
schedule of chronologically ordered windows, including windows pointing to the
idle partition.
Figure 5.9 shows what the finished schedule may look like, given a certain schedule
in the XML schema.
XML Kernel
been build
WindowsStart 0.000 partitionname idle partitionname yellow_toggler partitionname red_toggler partitionname stio_sys partitionname evil
WindowDuration 0.020
5.8. OS kernel
Window_Schedule
WindowsStart 0.100
WindowDuration 0.020 window_t window_t
partition partition
startTime 0 startTime 100
duration 20 duration 20
Window_Schedule
window_t window_t
WindowsStart 0.030
WindowDuration 0.010 partition partition
startTime 20 startTime 120
duration 10 duration 10
Window_Schedule
WindowsStart 0.130 window_t window_t
WindowDuration 0.010
partition partition
startTime 30 startTime 130
duration 10 duration 10
Window_Schedule
window_t window_t
WindowsStart 0.140
WindowDuration 0.030 partition partition
startTime 70 startTime 170
duration 30 duration 10
window_t
Window_Schedule
Figure 5.9: Windows as represented in the XML schema, and in the kernel after the schedule has
55
partition
WindowsStart 0.180 startTime 180
WindowDuration 0.020 duration 20
56 Chapter 5. System Implementation
5.8.2 Scheduling
The ARINC 653 specification defines two levels of schedulers and the rules by
which these schedulers decide which processes may execute at any given time.
There are two different kinds of rescheduling, temporal rescheduling and event
driven rescheduling. Partitions are exclusively rescheduled because of time, whereas
processes may be rescheduled because of both time and events. As for temporal
scheduling, the ARINC 653 specification does not explicitly specify a minimum or
maximum time resolution for scheduling, though it does imply a resolution of 1
nanosecond should be available[38].
For Open653 the SysTick is used for triggering temporal scheduling. This led to a
time resolution of 1 millisecond. Scheduling is never disabled; every millisecond
the scheduler will be invoked and check which process of which partition should
run next.
5.8.2.1 SysTick
The SysTick timer is a 24-bit decreasing timer that wraps when reaching zero. Un-
like other timers on the MINI-M4, this timer is specified as part of the ARMv7M
specification. Other timers are implementation specific; the vendor decides which
timers to add to a chip. Therefore, between two different boards, there may be
a different number of timers, and timers may have a different resolutions. This
makes it more difficult to port code from one board to another. The SysTick timer
however, is guaranteed to be 24-bit on any board that implements it. In the Cortex-
M group of ARM microcontrollers, the SysTick timer is required for M3, M4 and
M7; any code written for these can assume portability.
The clock source for the SysTick timer is the CPU clock, optionally divided by eight.
The reset value of the SysTick timer is programmable. This makes it possible for
software to program how often this timer wraps. Unless otherwise specified, this
timer operates in polling mode; software has to poll for wraps, but it is possible to
program the SysTick timer to trigger an interrupt upon wrapping.
By default, the HAL library sets up the SysTick timer to wrap every 1 millisecond
and to trigger an interrupt upon wrapping.
5.8. OS kernel 57
After the context has been saved, control is handed over to the scheduler, which
then decides which process should run next.
Once all the operations the ISR has completed, the context of the process selected
by the scheduler must be restored. From this point, the code is once again writ-
ten in assembly to avoid overwriting a register after it has been restored. First,
the registers saved by software on the stack must be restored, then based on the
EXC_RETURN value that the process interrupted with, it can be determined to
which stack pointer register the new stack pointer must be pushed to. Lastly, ex-
ecution must return to the process by pushing the EXC_RETURN value to the PC
register. The EXC_RETURN value pushed to the PC register must be the same
8A naked function has no compiler generated prologue and epilogue. This means that the com-
piler does not save any registers on the stack before using them, and it does not restore them before
ending a function.
58 Chapter 5. System Implementation
37 _ _ a t t r i b u t e _ _ ( ( a l w a y s _ i n l i n e ) )
38 s t a t i c i n l i n e u i n t 3 2 _ t c o n t e x t _ s a v e ( )
39 {
40 / / C r e a t e a new v a r i a b l e t o s t o r e t h e c o n t e x t −s a v e d − s t a c k p o i n t e r o f
the previous process .
41 / / We e x p l i c i t l y c h o o s e t h e r e g i s t e r t o a v o i d GCC p i c k i n g a r e g i s t e r
t h a t hasn ' t been saved y e t .
42 r e g i s t e r u i n t 3 2 _ t s t a c k p o i n t e r __asm ( " r 0 " ) ;
43 / / Context switch l o g i c .
44 / / We o n l y s a v e R4−R11 on t h e s t a c k , b e c a u s e t h e NVIC a l r e a d y s a v e d
the other r e g i s t e r s before calling this function .
45 __asm v o l a t i l e (
46 "AND R1 , LR , #0x0D \n\ t " / / L o g i c a l AND w i t h 0xD
47 "CMP R1 , #0x0D \n\ t " / / Use CMP t o s e t EQ/NE f l a g
48 "BEQ use_psp \n\ t " / / Branch t o u s e _ p s p i f EQ i s
set
49 "BNE use_msp \n\n " / / Branch t o use_msp i f NE i s
set
50 " use_psp : \n\ t "
51 "MRS %0, PSP \n\ t " / / Move P r o c e s s S t a c k P o i n t e r
t o R1 ( t h e s t a c k p o i n t e r v a r i a b l e )
52 "STMFD %0! , { R4−R11 } \n\ t " / / S t o r e r e g i s t e r s R4 t o R11
on t h e s t a c k . ( The FD i n STMFB means f u l l y d e s c e n d i n g [ s t a c k ] )
53 "MSR PSP , %0 \n\ t " / / Update t h e a c t u a l PSP
s t a c k p o i n t e r r e g i s t e r w i t h t h e new v a l u e a f t e r STMFD .
54 "B exit \n\n " / / S k i p o v e r t h e use_msp
routine
55 " use_msp : \n\ t "
56 "MRS %0, MSP \n\ t " / / Move M a s t e r S t a c k P o i n t e r
t o R1 ( t h e s t a c k p o i n t e r v a r i a b l e )
57 "STMFD %0! , { R4−R11 } \n\ t " / / S t o r e r e g i s t e r s R4 t o R11
on t h e s t a c k .
58 "MSR MSP, %0 \n\n " / / Update t h e a c t u a l MSP
s t a c k p o i n t e r r e g i s t e r w i t h t h e new v a l u e a f t e r STMFD .
59 " exit : \n\ t "
60 : " =r " ( s t a c k p o i n t e r )
61 : :
62 );
63 return stackpointer ;
64 }
as that read from the LR register when the process was interrupted. Figure 5.10
shows the flow when switching contexts. Listing 5.6 shows the source code that
restores the context of a process and branches to the EXC_RETURN.
Determine user-/kernelspace
Push R4-R11 to
New stack pointer user-/kernel stack
Save SP and EXC
for Process 1
Determine next process
Next process
Load SP and EXC for Process 2
Determine user-/kernelspace
Pop R4-R11 from
user-/kernel stack
Figure 5.10: This figure shows the steps involved in switching context from one process to another
60 Chapter 5. System Implementation
66 _ _ a t t r i b u t e _ _ ( ( a l w a y s _ i n l i n e ) )
67 s t a t i c i n l i n e void c o n t e x t _ r e s t o r e A n d S w i t c h ( u i n t 3 2 _ t s t a c k p o i n t e r , u i n t 8 _ t
exc_return_value )
68 {
69 / / R e s t o r e t h e s o f t w a r e c o n t e x t o f t h e new p r o c e s s .
70 / / Variable data i s loaded into s t a t i c r e g i s t e r s in the beginnning
71 / / t o make s u r e t h e GCC d o e s n ' t d e c i d e t o u s e t h e r e g i s t e r s R4−R11
after
72 / / t h e y ' v e b e e n r e s t o r e d ; t h a t would b e c a t a s t r o p h i c !
73 __asm v o l a t i l e (
74 "MOV R0 , %[ s t a c k ] \n\ t " / / Move t h e s t a c k
p o i n t e r t o R0
75 "MOV R2 , %[exc ] \n\ t " / / Move t h e p r o c e s s
s p e c i f i c EXC_RETURN v a l u e t o R2
76 "LDR R1 , =0xFFFFFF00 \n\ t " / / Load R1 w i t h t h e
c o n s t a n t p a r t o f EXC_RETURN v a l u e s
77 "LDMFD R0 ! , { R4−R11 } \n\ t " / / Restore the stacked
r e g i s t e r s R4−R11
78 " TST R2 , #0 x4 \n\ t " / / Test b i t 2 of
EXC_RETURN
79 " ITE EQ \n\ t " / / Which s t a c k p o i n t e r
was u s e d ?
80 "MSREQ MSP, R0 \n\n " / / Update MSP i f EQ i s
set
81 "MSRNE PSP , R0 \n\ t " / / Update PSP i f NE i s
set
82 "ADD R1 , R1 , R2 \n\ t " / / Add t h e p r o c e s s
s p e c i f i c p a r t o f t h e EXC_RETURN v a l u e t o t h e c o n s t a n t
83 "BX R1 \n\ t " / / Branch t o t h e
EXC_RETURN v a l u e t o a c t i v e t h e NVIC ' s c o n t e x t r e s t o r e
84 : : [ s t a c k ] " r " ( s t a c k p o i n t e r ) , [ exc ] " r " ( e x c _ r e t u r n _ v a l u e ) :
85 );
86 }
5.8.2.3 Windows
Windows are the abstract concept used by system integrators to schedule parti-
tions in ARINC 653. A window consists of a start time, relative to the major frame,
and a duration. These windows are specified by the system integrator in the XML
schema (see section 4.7).
Time is allocated to partitions according to the windows specified in the XML
schema, but windows do not have to be contiguous; there may be unused time
between the end of one window and the start of the next. In that case, this time is
considered to be an implicit idle period.
5.8. OS kernel 61
To see an example of how windows from the XML are reordered in the kernel, and
how implicit idle periods are filled in, see figure 5.9.
The partition scheduler is supposed to keep track of the position within a major
frame, and based on the position, figure out which window that corresponds to,
and then schedule the partition of that window.
The scheduler keeps track of the position within a major frame with the HAL tick.
This tick is incremented every millisecond. This is the same tick used by the delay
function (section 5.4.4). The position within each major frame is derived by the
tick count modulo the length of a major frame in milliseconds. If the result of this
operation is zero, it is assumed that a new major frame has begun. Otherwise,
if the position within the major frame is on or after, the active window closes.
The scheduler then switches to the next window, and schedules the next partition.
Although the time at which a window closes can be derived from the start time
plus the duration, the end time of the active window is cached in memory to avoid
repeated calculation of the end time.
The process scheduler first iterates through all the processes of a partition and se-
lects the first available process in the READY state. However, the processes are
not stored in a ready queue, but are instead stored only in the order they were
created. Therefore, finding the first ready processes does not guarantee that it is
also the processes with the highest priority. The scheduler therefore continues to
iterate through the available processes to try to find a better fitting process. For
each iteration, if a process is found, it is selected as the base for further iterations.
At the end of the loop, the process in the READY state with the highest priority
will be selected.
If there are no processes in the READY state, none will be selected, and kernel will
fault, so each partition must have at least one process in the READY state.
62 Chapter 5. System Implementation
5.8.3 Ports
Interpartition communication (section 4.6.2) is implemented with an initialisation
function and a function for every APEX call to the given port type.
As described in 4.6.2, a generic port struct as referenced in listing 5.7 is used to
define a port with all its attributes. All methods operate on the data in these
structs, which also contains all messages received.
13 struct q u e u i n g _ p o r t {
14 QUEUING_PORT_STATUS_TYPE ;
15 circBuf_t circ_buf ;
16 uint8_t *buffer ;
17 } ;
18
19 struct s a m p l i n g _ p o r t {
20 SAMPLING_PORT_STATUS_TYPE ;
21 uint8_t *buffer ;
22 } ;
23
24 typedef struct {
25 bool is_queuing_port ;
26 union {
27 struct q u e u i n g _ p o r t q_buf ;
28 struct s a m p l i n g _ p o r t s_buf ;
29 };
30 bool activated ;
31 void * channel_link ;
32 NAME_TYPE portname ;
33 } p o r t _ t ;
Listing 5.7 shows how every port_t has the four following common variables:
• The first being a boolean indicating whether the port is a a queuing port or
sampling port
• A void pointer channel_link is used to reference the channel which the port
belongs to. This pointer is said at when all the ports are initialized.
As for the port attributes specific to the port type, they are declared as a union of
the two different port attribute types struct queuing_port and struct sampling
_port. Both types contain a byte array to hold buffered messages. The buffer of
the sampling port is a simple buffer with the size of maximum message size, while
the buffer of the queuing port is used as a circular buffer, hence the use of an object
with the type circBuf_t to hold additional data, used when pushing and popping
messages.
Besides arrays to contain the buffers each type of port also has a port status
struct of type QUEUING_PORT_STATUS_TYPE and SAMPLING_PORT_STATUS_TYPE. These
types are declared in apex_queuing.h and apex_sampling.h from the folder src/
third_party/ARINC/APEX. They contain the specific status attributes for the port
type. The structs are embedded (listing 5.7) in as anonymous structs meaning that
one can access its members directly instead of as a conventional substruct. While
this is not strictly a native C feature it is enabled in GCC with the -fms-extensions
flag and is only used to make the code easier to read and edit.
While the ports.h file is used to declare all information about the ports, the func-
tions to work on sampling ports and queuing ports are located in src/kernel/sam-
pling_port.c and src/kernel/queuing_ports.c respectively.
For the rest of section 5.8.3, queuing ports will be used to explain how interparti-
tion communication is implemented in these files.
The same scheme of having a similar named kernel function for every system calls
is used for everything which has to do with the ports.
Since the attributes and starting values for the ports is auto-generated at compile-
time, the setup can be kept simple:
64 Chapter 5. System Implementation
51 ( void ) QUEUING_DISCIPLINE ;
52
53 partition_t * this_partition = getActivePartition ();
54 p o r t _ t * p o r t s = t h i s _ p a r t i t i o n −>p o r t s ;
55
56 for (APEX_INTEGER n = 0 ; n < t h i s _ p a r t i t i o n −>nb_ports ; ++n ) {
57 i f ( ! s t r c m p ( p o r t s [ n ] . portname , QUEUING_PORT_NAME) &&
58 p o r t s [ n ] . q_buf . MAX_MESSAGE_SIZE == MAX_MESSAGE_SIZE &&
59 p o r t s [ n ] . q_buf .MAX_NB_MESSAGE == MAX_NB_MESSAGE &&
60 p o r t s [ n ] . q_buf . PORT_DIRECTION == PORT_DIRECTION)
61 {
62 ports [ n ] . activated = true ;
63 *QUEUING_PORT_ID = n ;
64 *RETURN_CODE = NO_ERROR;
65 return ;
66 }
67 }
68
69 *RETURN_CODE = INVALID_PARAM ;
Since open653 only features a simplified implementation of the ARINC 653 stan-
dard, only a minimal functioning featureset is present for the ports.
The input variable QUEUING_DISCIPLINE for example is in this case not used, hence
it has been casted to type void as seen in listing 5.8 at line 51.
The remaining input variables are checked for their validity after the current port
in question has been located. If these are found to be consistent with the auto-
generated attributes, the port is activated by setting the activated attribute to true
(line 62). An ID is also set as a return value and an error is cleared before returning.
If no port is found to match the input attributes passed to the function the APEX
defined INVALID_PARAM error code is passed instead (line 69).
The code for the sampling port, follows the same pattern and much of the code is
in fact the same. Messages are passed in a different manner and circular buffers
5.8. OS kernel 65
are not used. Instead a simple buffer is overwritten with new messages or being
read from, which makes it simpler to implement than queuing ports, having to use
less code for managing the buffer.
1. Userspace Partition code calls one of the system call wrapper functions.
2. Userspace The wrapper function moves the number denoting the system
call function into register R0.
3. Userspace The wrapper function moves any input arguments into the
registers R1-R3 and R12. If the function has more than four
input arguments, those must be stacked.
4. Userspace The wrapper function issues an SVC instruction.
5. Hardware The NVIC stacks the registers R0-R3, R12, PC and LR and
branches to the SVC_Handler function.
6. Kernelspace The SVC_Handler function investigates the stacked value of
register R0 to determine which function the partition level
code wished to execute.
7. Kernelspace The SVC_Handler function calls the appropriate function with
the input arguments from the stacked registers.
8. Kernelspace The SVC_Handler puts the results of the function in the
stacked registers. The return code is moved to R0, and ad-
ditional output is put in the registers R1-R3 and R12. If nec-
essary, more output is put in the stack.
9. Kernelspace The SVC_Handler returns.
10. Hardware The NVIC restores the registers R0-R3, R12, PC and LR from
the stack and returns execution to the system call wrapper
function.
11. Userspace The wrapper function returns the output from the system call
as stored in the registers to the calling partition code.
Only the registers R0-R3 and R12 are available for argument passing, as these are
the only general purpose registers that are stacked by the NVIC. The NVIC does
9 It is necessary to use assembly code to issue an SVC instruction
66 Chapter 5. System Implementation
Identifier Name
0xC0FFEE0A CREATE_PROCESS
0xC0FFEE0B GET_TIME
0xC0FFEE0C CREATE_QUEUING_PORT
0xC0FFEE0D RECEIVE_QUEUING_PORT
0xC0FFEE0E SEND_QUEUING_PORT
0xC0FFEE0F GET_QUEUING_PORT_ID
0xC0FFEE10 GET_QUEUING_PORT_STATUS
0xC0FFEE11 PROCESS_STOP_SELF
Table 5.2: A table of the implemented system calls and their identifier.
not clear the registers before entering the SVC_Handler function, and thus all the
general purpose registers may contain the same values as when the SVC instruction
was executed, but their consistency is not guaranteed, as other interrupt service
routines could have run before the SVC_Handler function started execution.
To avoid rescheduling occurring during a system call, the SysTick interrupt is
turned off during the execution of the SVC_Handler function.
Each system call is identified by the number the caller has moved into the R0 reg-
ister before issuing the SVC instruction. The SVC instruction does supply a way
to embed this number directly as a part of the instruction as an immediate value,
instead of using a separate register, but dedicating a register to this was chosen
for two reason: One, it is poorly documented how software can read the value
embedded in the instruction, and two, to keep it consistent with how system calls
are handled on other architectures such as x86.
Table 5.2 shows all the implemented system calls and their identifier.
58 typedef struct {
59 uint8_t id ;
60 NAME_TYPE partitionname ;
61 CRITICALITY c r i t i c a l i t y ; /* Not u s e d */
62 bool s y s t e m p a r t i o n ; /* Not u s e d */
63 void ( * e n t r y p o i n t ) ( void ) ;
64 APEX_INTEGER nb_ports ;
65 port_t * ports ;
66 uint32_t nb_processes ;
67 uint32_t index_running_process ;
68 process_t processes [
MAX_PROCESSES_PER_PARTITIONS ] ;
69 } p a r t i t i o n _ t ;
For the drivers, if they are not initialised properly, the HAL library would notify
the error handler that it encountered an error, and again, turn on the LEDs and
halt the system.
5.9.1 Partitions
Partitions are wrapped in the struct partition_t (see listing 5.9). The data in this
data structure is filled in by both the XML schema parser, through the xml_data.c
file, and by the kernel itself. The XML schema parser defines all but process infor-
mation; as processes are dynamic, they are not defined in the XML schema.
As there is no compile-time knowledge of the number of processes each partition
may create, the processes array has a static size of 3. This makes the memory
consumption of a partition in the kernel more consistent, but moreover, it makes
the dynamically created processes statically allocated.
Partition memory spaces are allocated in the XML schema, and they are parsed by
the XML schema parser and made available to the kernel in xml_data.c. Listing
5.10 shows the memory data structures of the generated XML data.
68 Chapter 5. System Implementation
71 typedef struct {
72 mem_type_t type ;
73 uint32_t size ;
74 mem_access_t access ;
75 uint32_t address ;
76 } mem_req_t ;
77
78 typedef struct {
79 uint8_t id ;
80 NAME_TYPE partitionname ;
81 uint32_t arr_size ;
82 mem_req_t * memory_arr ;
83
84 /* T h i s value could be calculated every time we make a new
process ,
86 uint32_t mem_offset ;
87 } part_mem_t ;
If time had allowed it, the space separation of partitions would have been ensured
by the MPU (see 4.6.4). Time separation of partition is handled by the partition
scheduler (see 4.6.1 and 5.8.2.4).
Partitions run in unpriviledged mode; to access control registers, and to call APEX
functions, they need to do a system call (see 4.6.6 and 5.8.4).
Partitions do not directly execute any code, but rely on default processes. As
partitions have no directly executable code, there is nothing to go to, if no processes
are ready to execute. Therefore, it is important that each partition has at least one
process in the READY-state during its windows.
5.9.2 Processes
Processes are wrapped in the struct process_t (see listing 5.11). The process_t
data structure covers over the ARINC 653 defined attributes, such as priority, state,
stack size, etc. through an anonymous struct (PROCESS_STATUS_TYPE) defined
in the appendix of the ARINC 653 specification[40]. Additionally, the data struc-
ture contains three Open653 specific attributes: the memory address of the stack-
pointer (set and read only during context switching), the EXC_RETURN value
generated by the NVIC when the process was last pre-empted (see table 4.2), and
a timestamp denoting when the process last transitioned from the DORMANT or
WAITING state to the READY state. This timestamp is set to and compared with
5.9. Partitions and processes 69
51 typedef struct {
52 uint32_t stackpointer ;
53 uint8_t exc_return_value ;
54 uint32_t tickStamp ;
55 PROCESS_STATUS_TYPE ; / * unamed struct with −f m s− e x t e n s i o n s * /
56 } p r o c e s s _ t ;
Now, processes are allocated from the pool of available processes in the partition_t
data structure. Unallocated processes are identified by their state. If a processes is
in the DORMANT state, it is considered unallocated. Process 0, the main process
of a partition, is allocated during the OS initialisation, and it is the main function
(in ARINC 653 terms, the entrypoint), of a partition. From userspace, processes
can create other processes through the APEX call CREATE_PROCESS (see the ARINC
653 specification for details about this call).
There is currently no way for a processes to enter the WAITING state; if a process
needs to wait, it must be implemented as a busy wait. Processes can, however,
transition themselves back into the DORMANT state through the the APEX call
STOP_SELF (see the ARINC 653 specification for details about this call).
5.9.3 idle_sys
The idle partition, technically named idle_sys, is an implicitly generated partition.
This partition is used to fill out potentially empty time between different windows
(see 4.6.1). This partition should not be specified in the XML schema, but will
be automatically defined by the XML parser. This partition will always be the
partition with index 0. The reason this partition is kept visible in the generated
xml_data.c file, is to make it more transparent to the system integrator what is
running during idle periods.
The purpose of this partition is to have something to switch to, when nothing else
is scheduled, while using the minimum amount of resources possible. To keep the
partition as lightweight as possible, the partition only does a NOP-loop. See listing
5.12 to see the source code of the idle partition.
70 Chapter 5. System Implementation
1 idle_main :
2 NOP
3 NOP
4 NOP
5 B idle_main
Listing 5.12: The entire code of the idle partition (excluding the assembly flags)
The partition code is written in assembly to make sure it uses the least possible
resources. While executing, the code uses no memory, although it needs at least 32
bytes to store the hardware stacked registers during a context switch. The reason
the code consists of three NOP instructions before a branch, is to fill the pipeline10
with NOP operations before each branch. It is assumed, although no attempt has
been made to prove it, that this will allow the CPU to run slightly more efficient.
5.9.4 stdio_sys
The stdio_sys partition is named after the ‘standard IO’ (stdio.h) from the standard
C library, with the _sys being present to indicate that it is a system partition. User
partitions should only interface with the rest of the system through APEX calls, so
not to enter kernel space and directly communicate with the UART. This partition
makes this interface possible by offering a port, to send strings or raw data over
the UART.
34 void w o r k e r ( void )
35 {
36 QUEUING_PORT_ID_TYPE QUEUING_PORT_ID ;
37 RETURN_CODE_TYPE RETURN_CODE;
38 CREATE_QUEUING_PORT( " s y s _ s t i o " , 3 2 , 3 2 , DESTINATION , FIFO ,
39 &QUEUING_PORT_ID, &RETURN_CODE ) ;
40
41 char s t r [ 1 0 2 4 ] ;
42 while ( 1 ) {
43 RETURN_CODE_TYPE RETURN_CODE;
44 MESSAGE_SIZE_TYPE l e n ;
45 RECEIVE_QUEUING_MESSAGE(QUEUING_PORT_ID, 0 , ( u i n t 8 _ t * ) s t r ,
46 &l e n , &RETURN_CODE ) ;
47 i f (RETURN_CODE == NO_ERROR) {
48 BSP_UARTx_transmit ( ( u i n t 8 _ t * ) s t r , l e n ) ;
49 }
50
51 HAL_Delay ( 1 0 ) ;
52 }
53 }
Lines 36-39 in the listing show how the port sys_stdio is initialized and lines 43-49
show how messages are read from the port, and how on success the messages are
transmitted on the UART with the BSP_UARTx_transmit() function.
Just like the stdio_sys partition in section 5.9.4, the only job of the function's
entrypoint is to initialise a new process worker, which is shown in listing 5.14.
72 Chapter 5. System Implementation
34 void w o r k e r ( void )
35 {
36 QUEUING_PORT_ID_TYPE QUEUING_PORT_ID ;
37 RETURN_CODE_TYPE RETURN_CODE;
38 CREATE_QUEUING_PORT( " y e l l o w _ p r i n t " , 3 2 , 3 2 , SOURCE, FIFO ,
39 &QUEUING_PORT_ID, &RETURN_CODE ) ;
40
41
42 while ( 1 ) {
43 char * s t r = " Y e l l o w t o g g l e r \n\ r " ;
44 size_t len = s t r l e n ( st r );
45 RETURN_CODE_TYPE RETURN_CODE;
46 SEND_QUEUING_MESSAGE(QUEUING_PORT_ID, ( u i n t 8 _ t * ) s t r ,
47 l e n , 0 , &RETURN_CODE ) ;
48
49 for ( s i z e _ t i = 0 ; i < 1 0 ; i ++) {
50 onboard_led_toggle ( yellow_led ) ;
51 delay_ms ( 1 0 0 ) ;
52 }
53 }
54 }
Lines 36-39 in listing 5.14 show how the port yellow_print is initialised and lines
43-47 show how messages are sent to the stdio_sys partition. For every message
the yellow led is toggled 10 times with 100 milliseconds inbetween (lines 49-52).
In a complete ARINC 653 compliant operating system, direct calls to the driver to
toggle LEDs should not be possible, but might be implemented with the use of
sampling ports. This has not been addressed at this stage of development, because
of time restrictions. The same goes for the delay_ms() function (line 48), used to
delay a process with a time interval. This functionality is ideally accessed through
an APEX call, with added integration with the process scheduler. The same is the
case for the stdio_sys partition in section 5.9.4.
Service Completeness
Schema parser Parses an XML file to C structs to provide
the information required by Open653
Partition management A RT partition scheduler
Process management A simple pre-emptive process scheduler
Memory management MPU driver
Time management Timer with a basetime of 5 nanoseconds
and RTC for error logging
Interpartition communication Queuing and sampling ports
Intrapartition communication Not implemented
Health monitor Basic error notification
Debugging Serial interface and JTAG
CHAPTER 6
Testing
6.1 Memory Mapping Algorithm
The sizes of memory regions are powers of two. This means that the more memory
a partition uses, the more memory it can potentially waste. To combat this waste,
partitions can share memory regions, and be separated into subregions. This will
allow the same level of safety, but more control. To help optimise the memory
layout of partitions a utility program is implemented that can sort the memory
regions of partitions. Each region can contain 8 subregions. All subregions within
a region are of equal size.
The following is an example of how this utility program can help optimise a mem-
ory layout:
Assume five partitions with the sizes 20, 65, 120, 80 and 40 bytes, as seen in figure
6.1.
75
76 Chapter 6. Testing
Some of these partitions will waste a lot of memory space if they are allocated their
own memory region. Two of the partitions in particular, the ones with the sizes
65 and 80 bytes, because they only barely cross the 64-byte barrier, needs to be
allocated 128 bytes each.
Without optimising the memory layout of the partitions, the memory needed for all
of these would be 480 bytes, which leaves 155 bytes unused. Figure 6.2 illustrates
how each partition would fit in a memory region, and how much of that memory
would be wasted.
6.1. Memory Mapping Algorithm 77
Figure 6.2: An example of a partition memory layout when no partition share a single MPU memory
region
The algorithm for optimising the memory layout is simple. First, allocate a memory
region to the biggest partition. If this partition leaves any unused subregions, an
attempt is made to find the biggest partition fitting into those. This is continued
until all partitions are allocated space. Once optimised, the five example partitions
will only use 384 bytes of memory. Figure 6.3 shows the optimised memory layout.
Partitions are additionally padded, in case they do not fill an entire the subregion.
78 Chapter 6. Testing
Figure 6.4: An example of how partition memory is padded to fill entire subregions
In order to test the memory partition mapping, the sorting algorithm is applied
and the final memory distribution printed to a terminal. The test variables are:
memory size, and partition size. When testing the partition size may change. The
output in figure 6.5 shows the space given to each partition and the location in the
memory map.
The results show the new region sizes containing the larger partitions and sub-
regions containing the smaller partitions. The results correspond to the mapping
algorithm.
6.2. XML validation 79
6.3 Scheduler
The scheduler has been tested to work provided the XML file specifies reasonable
windows. The scheduler has not been tested with edge cases.
The kernel does not record any runtime metrics. Empirical evidence shows that
the scheduler is working according to the windows specified in the XML schema
and according to the designed algorithms. Window durations is scaled up to make
it possible with the human eye to determine that the scheduler indeed follows the
windows.
80 Chapter 6. Testing
Figure 6.6: Terminal showing the strings originating from two different partitions.
6.5. Interpartition Communication 81
As can be seen from the figure, the yellow_toggler is sending twice as many mes-
sages as red_toggler. This is due to the scheduling of the two partitions. The
file main_schema.xml shows that both partitions are scheduled to execute twice
within the major time-frame of 20 seconds, but that yellow_toggler is given twice
the time of red_toggler at every interval and hence gets to print more often.
Even though the sampling port module is implemented in the codebase, it is yet to
be fully integrated into Open653 and therefore is not tested.
CHAPTER 7
Conclusion
Open653 is implemented and capable of parsing and compiling the XML, to setup
and run partitions, providing a working product that can be observed physically
in the real world. The scope defined and implemented demonstrates the execution
of space and time partitioned applications.
Despite this success, many of the features are not complete or contain compliance
mistakes. Small inconsistencies exist due to lack of foresight as the project evolved
and members collaborated in the same domains of the system.
Ultimately the goal has been achieved and the foundation for future development
has been set. The questions presented in the Problem statement can be addressed
as follows:
How can this system be developed without the use of pre-existing implementations?
Open653 is developed as a ground up implementation on top of the MINI-M4. The
HAL library has been used to supplement the development of most drivers and
hardware specific functions.
83
84 Chapter 7. Conclusion
• Understanding the need for using special GCC attributes when constructing
special functions for context switching
7.1 Discussion
A the project progressed certain problems stand out from the rest, as highlighted
in the conclusion. The group recommends following this advice, when conducting
a similar project:
• When direct manipulation of the control flow is required, GCC must be in-
structed not to auto-generate instructions
• It is very important to address the schema early on, as it will shape the
whole project. Furthermore special care should be taken to fully understand
the ARINC 653 standard
7.2 Reflection
The implementation of Open653 as a whole, provided sufficient challenges for each
of the groups members to develop themselves and follow the education's require-
ments.
The software development process flowed naturally. The nature of the project
allowed the team to cover different areas at the same time, whilst progressing
without a strict plan. The project was pursued by applying the principles of agile
software development. Being the first time the group has implemented an OS from
scratch, a different approach would be taken given a similar problem in the future.
Bibliography
[1] AAURacing. url: http://aauracing.dk/.
[2] SYSGO AG. PikeOS Hypervisor. url: https:/ /www.sysgo.com /products/
pikeos-hypervisor/why-pikeos/#tab_c87.
[3] ARM. Application Note 179 - Bit-banding. url: http://infocenter.arm.com/
help/index.jsp?topic=/com.arm.doc.dai0179b/CHDJHIDF.htm.
[4] ARM. ARM® Cortex®-M4 Processor - Technical Reference Manual. url: http:
//infocenter.arm.com/help/topic/com.arm.doc.100166_0001_00_en/
arm_cortexm4_processor_trm_100166_0001_00_en.pdf.
[5] ARM. ARM Generic Interrupt Controller. url: http://www.cl.cam.ac.uk/
research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.
pdf.
[6] ARM. ARMv7-M Architecture Reference Manual. url: http : / / infocenter .
arm.com/help/index.jsp?topic=/com.arm.doc.ddi0403e.b/index.html.
[7] ARM. CMSIS core documentation. url: http://arm- software.github.io/
CMSIS_5/Core/html/index.html.
[8] Mason Cheung. Microsoft empowers new development opportunities in mixed re-
ality, gaming and cellular PCs. Dec. 2016. url: https://news.microsoft.com/
2016/12/07/microsoft- empowers- new- development- opportunities- in-
mixed-reality-gaming-and-cellular-pcs/#sm.00000u22mjr5svewzvjspco7iwi64.
[9] CMake. url: https://cmake.org/.
[10] Philippa Conmy. What is Integrated Modular Avionics (IMA)? url: https://
www-users.cs.york.ac.uk/~philippa/IMA.html.
[11] Raspberry Pi Foundation. Raspberry Pi 3 Model B. Feb. 2016. url: https :
//www.raspberrypi.org/products/raspberry-pi-3-model-b.
[12] GDB, GNU Project debugger. url: http://www.gnu.org/software/gdb/.
87
88 Bibliography
[13] Matthias Gerlach, Robert Hilbrich, and Stephan Weißleder. “Can Cars Fly?
From Avionics to Automotive: Comparability of Domain Specific Safety Stan-
dards”. In: 2011. url: http://publica.fraunhofer.de/eprints/urn_nbn_
de_0011-n-2485950.pdf.
[14] GNU. GCC ARM Options. url: https://gcc.gnu.org/onlinedocs/gcc/ARM-
Options.html.
[15] GNU. GCC C Dialects. url: https : / / gcc . gnu . org / onlinedocs / gcc / C -
Dialect-Options.html.
[16] GNU. GCC Debugging Options. url: https://gcc.gnu.org/onlinedocs/gcc/
Debugging-Options.html.
[17] GNU. GCC Linking Options. url: https://gcc.gnu.org/onlinedocs/gcc/
Link-Options.html.
[18] GNU. GNU Make. url: https://www.gnu.org/software/make/.
[19] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: (Mar.
2006).
[20] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 2.
[21] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 11.
[22] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 12.
[23] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 13.
[24] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 14.
[25] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 19.
[26] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 20.
[27] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 25.
[28] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 27.
[29] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 36.
[30] AERONAUTICAL RADIO INC. “ARINC Specification 653P1-2”. In: Mar.
2006, p. 40.
Bibliography 89
Creator Ci40
93
94 Appendix A. Proposed Embedded Devices
Chip manufacturer: ST
Chip: STM32F415RG
Processor: 168 MHz, 32-bit Cortex-M4
Arch.: ARM
Memory 192+4 KB SRAM
Storage 1 MB Flash
Price: 206,45 DKK
Link to shop: dk.rs-online.com
Link to site: mikroe.com
link to datasheet: st.com/.../en.DM00031020.pdf
Chip manufacturer: TI
Chip: TM4C123GH6PM
Processor: 80 MHz, 32-bit Cortex-M4
Arch.: ARM
Memory 32 KB SRAM, 2 KB EEPROM
Storage 256 KB Flash
Price: 212,87 DKK
Link to shop: dk.rs-online.com
Link to site: ti.com
link to datasheet: ti.com/.../tm4c123gh6pm.pdf
95
Raspberry Pi 3
97
98 Appendix B. Hardware setup
Figure B.2 shows the pinout of the JTAG connector. Out of the 20 pins, only
five will be used by the interface, and two for getting a voltage reference into the
module.
Figure B.3 shows the corresponding pins for the JTAG interface, on the Mini-M4
board. Some of the wires are hidden under the board.
Figure B.3: The five lines of the JTAG interface and their corresponding pins on the board
99
Figure B.4 shows the way the serial communication was connected. The only thing
to remember here is that the Tx of a device goes to the Rx of the other device it
needs to communicate to.
• arm-none-eabi-gcc
• make
• cmake
• openocd
The steps to compiling the OS with partitions and flashing it to the chip are as
follows:
3. Make a new folder to contain the build files (eg. mkdir build)
4. From within the build fonder run the command ‘cmake ..’. This reads the
CMakeLists.txt files and builds make files
5. Run ‘make’ to build the project or use ‘make help’ to get a list of available
targets
101
APPENDIX D
Forum Responses
Conversation taken from the "Embedded Related" forum in the thread 1 created by
the group, to see how an open source implementation of the ARINC 653 standard
is seen among professionals.
"Hi everyone,
Me and my group are developing the ARINC653 protocol this semester in Open-
Source.
The idea is to have independent partitions than can run OS, applications or other
things, in well defined and restricted amounts of memory, completely independent
of each others in the same platform. If one crashes it won't affect the other par-
titions. This was first created 10 years ago for airplanes, we are trying to adapt
this to other industries. We developed the OS and the memory and time partitions
already, now we are looking for different points of view about the subject, what
is worth it or not to explore about the different possibilities in the future using this."
gillhern321:
"Jose, could you explain the major difference between ARINC653 and a fault tol-
erant OS distributed across multiple blades on a blade server configuration? The
fault tolerant, fault redundant servers actually have two OS's running at the same
time with multi-processing being done across 10-20 blades. So when one OS fails
the failover defaults to the secondary processor and within 32ms the processing
1 https://www.embeddedrelated.com/thread/1326/
103
104 Appendix D. Forum Responses
continues same stack same interrupts. We were doing this 23 years ago at Bell
Labs with the 5ESS and AMPS/PCS switching platforms, they are still in use today
across all of north america they are still the core of our communications infrastruc-
ture.
Your question is, is it worth it. When you look at the processing power today ver-
sus then, and I think this is something more then worth it to all of us doing coding
or developing hardware. And the potential impact to distributed processing in our
home is a powerful thing to have available. OPENSOURCE OHHHH YAAAAAA.
LOL"
Reply:
"Hey! Not sure if is that. We only have one main OS, that runs different partitions,
which can contain independent processes, multi threads or single threads that have
fixed amount of memory and processor available. If one crashes doesn't affect the
others, it can shut it down or restart (up to the programmer), but all the rest keeps
running normally. When the context switching happens the whole environment is
"saved" and return to the same stage when the processor is given to that partition
again."
Tim Wescott:
Having said that, I could see such a thing being an asset in any sort of system
where I wanted to partition a design by criticality levels, but keep it all on the
same processor. I've always done that by putting the critical stuff on separate pro-
cessors, possibly on the end of a long wire from the box with the bells and whistles
– but that was in a system that naturally called for that partition anyway. If you
were just bound and determined to put everything on to one processor, and you
had a mix of jobs between things that would cost 1M Dollars if the software failed
and things that you wanted to let sales engineers play with, then I could see value
in that."
Tim Wescott:
"Doesn't this demand a processor with an MMU, and either put restrictions on
who gets to write ISRs, or put demands on the processor for letting ISRs be inter-
105
Reply:
"We are using a MPU with 8 well defined areas for each partition.
Yes, everytime the processor changes the context, the interrupts will change to the
partition in case. It has to due with the priorities.
The whole context switch completely when we go to a new partition or back to the
kernel."
Tim Wescott:
"So, if I have an interrupt that's attached to some piece of hardware that only
matters to my most critical task, then the most dumb-ass task might service the
interrupt?
That doesn't seem right.
I would think that you'd either want a separate interrupt-handling context (operat-
ing at the highest level of safety), or that you'd want to disable any interrupts that
aren't "owned" by the current context. I see problems with both of these – what
does the ARINC standard say you should do?"
Tim Wescott:
"Another thought:
Anyone who wants to use this is going to be interested in safety. They may well
want the software quality to be traceable back to some standard, like DO-178, or
whatever that IEC standard is for medical software. Developing software to meet
these standards is far more work than just whipping out any old thing – the es-
timate that I was given, a long long time ago (with head-nodding from everyone
who had been there) is that each time you go up a level of criticality under DO-
178, the software development gets 7 times more costly. Level E is "software quality
doesn't matter"; level A is "smoking hole in the ground, with bodies and TV re-
porters". Designing software and certifying it for level A costs about 2500 times as
much as doing so for level E.
106 Appendix D. Forum Responses
So, in your market research, you may want to ask if anyone is going to buy it if it's
just the typical "thrown together" quality of most desktop and phone apps."