DEPARTMENT OF INFORMATICS

TECHNISCHE UNIVERSITÄT MÜNCHEN

Master’s Thesis in Informatics

Dependable and Modular Command and Data Handling Platform for Small Spacecraft using MicroPython on RODOS

Tejas Kale DEPARTMENT OF INFORMATICS

TECHNISCHE UNIVERSITÄT MÜNCHEN

Master’s Thesis in Informatics

Dependable and Modular Command and Data Handling Platform for Small Spacecraft using MicroPython on RODOS

Zuverlässige und Modulare Steuer- und Datenverarbeitungsplattform für kleine Raumfahrzeuge mittels MicroPython und RODOS

Author: Tejas Kale Supervisor: Prof. Dr. rer. nat. Martin Schulz Advisors: M.Sc. Dai Yang M.Sc. Sebastian Rückerl M.Sc. Vladimir Podolskiy Submission Date: 15th September 2019 I confirm that this master’s thesis in informatics is my own work and I have documented all sources and material used.

Munich, 15th September 2019 Tejas Kale Abstract

In this thesis, MicroPython is integrated into RODOS with the goal of using it as a scripting language for next generation of small satellites being developed at the Chair of Astronautics. MicroPython runs as a RODOS application, sharing its stack with the application’s stack and uses a statically allocated heap area for its internal memory allocations. The process of running MicroPython scripts, and extending the base MicroPython libraries with user modules is explored in this thesis. Further, a development board using a STM32F4 microcontroller, 2 CAN transceivers and several sensors is designed, manufactured and programmed. The development board enables testing of MicroPython, RODOS, CAN bus communications and the integrated sensors. Additionally, one can also connect external sensors using the exposed interfaces to the microcontroller. Using this board, several performance analyses are carried out to characterize the impact of using an interpreted language like MicroPython as compared to a native machine language like . The various available code emitters of the MicroPython compiler are also tested and their performance characterized.

iii Contents

Abstract iii

1. Introduction 1 1.1. Motivation ...... 1 1.2. Goal ...... 2 1.3. Outline ...... 2

2. Background 3 2.1. RODOS ...... 3 2.2. Micropython ...... 3 2.2.1. MicroPython Internals ...... 4 2.2.2. Micropython Compiler ...... 4 2.2.3. Garbage collection ...... 5

3. Related work 6 3.1. RODOS ...... 6 3.1.1. TubiX Nanosatellite Platform ...... 6 3.1.2. MAIUS-I ...... 6 3.1.3. Other RODOS Use Cases ...... 7 3.2. Use of Scripting Languages in Spacecrafts ...... 7 3.2.1. MOVE-II Cubesat ...... 7 3.2.2. PyCubed Platform ...... 7 3.2.3. LEON 3 MicroPython port ...... 7 3.2.4. James Webb Space Telescope ...... 8

4. Micropython Port on RODOS 9 4.1. MicroPython Build Process ...... 9 4.2. Micropython Core Configuration ...... 10 4.3. RODOS API Wrappers ...... 11 4.4. User C Module ...... 11

5. RODOS Development Board 12 5.1. Microcontroller ...... 12 5.2. CAN Transceivers ...... 12 5.3. Power Supply ...... 14 5.4. Peripherals ...... 14 5.4.1. Sensors ...... 14

iv Contents

5.5. Physical design ...... 15

6. Evaluation 17 6.1. Experimental Setup ...... 17 6.1.1. Micropython Configuration ...... 17 6.2. Experiments ...... 18 6.2.1. Overheads due to Parsing and Compilation ...... 18 6.2.2. Matrix Multiplication : CPU Bound Application ...... 19 6.2.3. Large Array Sorting : Memory Bound Application ...... 21 6.2.4. Micropython Script execution overhead ...... 22 6.2.5. Garbage Collection ...... 23 6.3. Discussion ...... 24

7. Conclusion and Future Work 25

A. Development board schematics 26

B. Micropython Configuration 33

C. Rodos Configuration 36

D. Example MicroPython C Module 38

List of Figures 40

Listings 41

Bibliography 42

v 1. Introduction

1.1. Motivation

Command and Data Handling (CDH) subsystem, sometimes referred to as the On Board Computer (OBC), is the heart of small satellites and spacecraft. This subsystem is the main onboard flight computer and handles data from all other subsystems. The CDH provides a functional interface to the satellite for ground based controllers via the communications subsystem. It receives commands from ground, executes them and relays the results back. As the CDH is typically connected to all the other subsystems on the satellite, it can control them. The Electronic Power System (EPS) houses the power system of the satellite, including the batteries, solar cells, circuitry to charge the batteries and power conversion circuitry to provide the other subsystems with their desired voltage levels. The CDH can thus control the power states of all the other subsystems of the satellite using the EPS. Spacecrafts are commanded using tele-commands from ground. These tele-commands can be statically defined and frozen into the CDH software, or can be defined as a commanding language that allows for dynamically defining complex tasks. The commanding language can be a custom defined language like Plan Execution Interchange Language (PLEXIL) [1] [2] or System Test and Operations Language (STOL). However the development of a custom language presents a significant challenge and risk. As compared to other mainstream scripting languages, such a custom language is difficult to test and validate fully. As an alternative, more mainstream scripting languages such as Bash(for based systems), Javascript, Python etc. can be used. The primary advantage to using these languages is that they are already widely used in other applications, thus have been extensively tested and validated. Additionally these languages are easy to understand as they use a human readable syntax. Users of the satellite who may not be familiar with programming, can thus easily understand the scripts, reducing development effort and errors. On a hardware level, CDH systems are implemented using small microprocessors capable of hosting complete Linux environment or also on small low power microcontrollers that can only support a basic real time operating system. The size limitations imposed by satellite structure standards (For e.g cubesats [3]) limit the available power for the satellite. Reducing power consumption of the CDH is thus a primary design goal. While Linux based CDH systems are extremely powerful and flexible, they also are quite power hungry. This power consumption can be reduced drastically by using low power microcontrollers like the STM32L4. Building on experience gathered from the MOVE-II project, where the Linux based CDH system was one of the contributing factors for the insufficient power budget [4], the MOVE-BEYOND project plans to use multiple low power STM32L4 microcontrollers as a modular flight computer with each node running RODOS as its Operating System (OS). MicroPython would be the ideal choice for a scripting language on this system.

1 1. Introduction

1.2. Goal

The main goal of this thesis is to port MicroPython to work as an application on Realtime Onboard Dependable Operating System (RODOS). This will allow the use of MicroPython as a for future Munich Orbital Verification Experiment (MOVE) projects. MicroPython, being and interpreted language, is expected to be worse in performance as compared to a native C implementation. Knowing how much of a performance impact MicroPython has is important as this allows the programmer to know when to use native C code as opposed to MicroPython. Thus MicroPython performance is characterized and compared to a native C implementation. To enable testing and development on realistic hardware, a development board is designed and manufactured. The board is designed in a way so that it can serve as a starting point for future designs.

1.3. Outline

The thesis is structured as follows: Chapter 2 gives the reader a background on RODOS and MicroPython. Chapter 3 summarizes the use of RODOS, scripting languages in other satellite missions. It also looks at the MOVE-II satellite and how scripting was critical in controlling it after launch. Chapter 4 explains how the MicroPython port works on RODOS. Chapter 5 details the hardware design of the development board. Chapter 6 uses the development board to evaluate the performance impacts of using MicroPython. Chapter 7 concludes the thesis by summarizing the results and looks at some possible future enhancements to the MicroPython port and development board.

2 2. Background

2.1. RODOS

RODOS is a real-time operating system designed for embedded systems where high dependability is desired [5]. It uses a priority based real-time scheduler which is fully preemptive; using round- robin for threads with the same priority. The microkernel provides support for synchronization, resource management and interrupt handling. The Application Programming Interface (API) is implemented in C++ using a object oriented framework. RODOS provides a middleware layer that enables transparent communication between both remote and local applications. All communication is asynchronous using the publisher - subscriber protocol. Publishers publish messages tagged with a specific unique topic id. Subscribers receive only those messages which they subscribe to. By default all published messages are only routed to the local subscribers. However, using a Gateway, they may be exposed externally; enabling communication across nodes. Logical tasks can be encapsulated into applications. Each application could be composed of multiple threads, event handlers, subscribers and publishers. The idea being to integrate all services related to a specific task into a single unit. The RODOS API and middleware are implemented independent of any hardware dependent libraries. All hardware dependent functionality is provided by the Hardware Abstraction Layer (HAL). Thus RODOS can be easily ported multiple embedded platforms, using the HAL specific to that platform. Such a separation of hardware and software domains, allows RODOS applications to be very portable. The applications themselves can be run unmodified on multiple target hardware platforms provided a RODOS port exists for it.

2.2. Micropython

MicroPython is an implementation of the Python 3 programming language that is optimized to run on microcontrollers and resource constrained environments. It is implemented in C with a focus on minimizing memory usage and code size, allowing it to run in as little as 8 Kb of RAM with a binary size of only about 70 Kb [6]. MicroPython includes a compiler and a full Python like runtime. Using this, at runtime, it can compile and execute code, or also load and execute pre-compiled code. It supports most of the Python 3 features including arbitrary precision integers, closures, list comprehension, floating point operations and also exception handling. Care is taken to follow the Python 3 syntax as closely as possible, however there are some differences stemming from the need to conserve every bit of memory. A subset of the Python standard library is also included. Moreover, users can extend MicroPython with either MicroPython libraries or C modules. A few libraries from Python Package Index (PyPI) have already been ported to Micropython. Dependencies on external code are kept to as low as possible. This

3 2. Background enables MicroPython to be ported to almost any platform. Popular ports include the STM32 port which is used on the popular Pyboards, a ESP32 and ESP8266 port, a PIC16 port and even a Javascript port.

2.2.1. MicroPython Internals

Generates REPL Input User Script Eval String Runtime

Executed by MicroPython Bytecode Lexer VM

Tokens

Native Code Calls Calls

Parser Produces Viper Code Parse Tree

External Compiler Bindings

Figure 2.1.: MicroPython internals showing how the compiler, runtime and virtual machine interact with each other.

Figure 2.1 shows the key components of how the MicroPython environment works. The MicroPython runtime, on the top right, is responsible for providing all the necessary components required for executing MicroPython code. It implements the MicroPython built in types like float, tuples, dicts etc. External C bindings with a MicroPython interface allow it to interact with hardware. The MicroPython Virtual Machine (VM) is responsible for maintaining the global state of the MicroPython environment. Bytecode execution is done by the VM. Some operations like basic arithmetic, binary operations etc. are directly executed by the VM. For other more complex operations like for eg. list sorting, the VM calls helper functions provided by the runtime environment. Hardware access or access to external API’s is also provided via wrapper functions that are defined as part of the runtime environment. The runtime call stack is also maintained by the VM. Memory allocations are done by the VM on the heap and when required , a garbage collector is run to try and free up some memory. Pre-compiled code, which can be stored either as native machine code or optimized viper code, can also be loaded and executed directly by the runtime.

2.2.2. Micropython Compiler

On the left side of Figure 2.1 are the parts related to the MicroPython compiler. The lexer is the first stage of the compilation process. It can receive strings as inputs from various sources, like the Read Eval Print Loop (REPL), eval strings generated by the MicroPython runtime environment or user scripts. It breaks down the input into a stream of tokens and passes it to the parser. The parser then generates a

4 2. Background parse tree out of the token stream which is then passed on to the compiler to generate bytecode or native machine code.

1 @micropython.bytecode 1 00: b0 LOAD_FAST_0

2 def x(a,b): 2 01: b0 LOAD_FAST_1

3 return a + b 3 02: db BINARY_OP_ADD

4 4 03: 5b RETURN_VALUE Listing 2.1: A MicroPython function. Listing 2.2: The generated bytecode The MicroPython compiler features 3 different code generators(called code emitters).Each of the three code emitters offer varying performance levels which are measured in chapter 6.

• Bytecode Emitter produces bytecode that can be interpreted by the MicroPython virtual machine. The VM decodes each bytecode and calls the appropriate C runtime function. Listing 2.1 shows an example of a MicroPython function and Listing 2.2 shows the corresponding generated bytecode. This is the default mode, but can be forced with the @micropython.bytecode annotation.

• Native Code Emitter generates native machine code by inlining the function corresponding to each bytecode. This removes the function call overhead when executing each bytecode, significantly speeding up the execution. Currently x86, x64, armv6, armv7m and xtensa architectures are supported by the native code emitter. This emitter can be invoked with the @micropython.native annotation.

• Viper Code Emitter builds on top of the Native code emitter by using the fact that many bytecode operations(for eg. the addition shown in Listing 2.1) can be realized with a single machine instruction. Thus rather than calling the appropriate C runtime function, it emits native machine code. However, not all of the MicroPython bytecodes are currently supported. This can be invoked with the @micropython.viper annotation.

• Inline Assembler allows for embedding assembly code in MicroPython scripts.This code is translated directly to machine instructions at runtime and executed. Currently only a subset [7] of the ARM Thumb-2 instruction set is supported. The inline assembler can be invoked with the @micropython.asm annotation.

MicroPython also provides a cross compiler which can be used to compile MicroPython scripts to both bytecode and native/viper code offline. This can be used to precompile user scripts to save storage space and save compile time onboard the microcontroller.

2.2.3. Garbage collection

The MicroPython heap space is managed by the garbage collector. The available memory is divided into a set of blocks, with each block having a 2 bit allocation status attached to it. The garbage collector is a simple mark and sweep garbage collector which maintains an allocation table to keep track of allocated memory. By default the garbage triggers automatically when a memory allocation is requested but no free memory can be found. This may not be desirable as it makes the runtime of the program unpredictable. However to avoid this problem, the GC can be triggered manually.

5 3. Related work

RODOS due to its real-time capabilities and task communication via a publisher subscriber model is used in various time critical control tasks including quadcopter control, rocket telemetry and telecommand system and satellite CDH software. Scripting languages, being easy to learn and understand have been widely used for task automation in traditional software tasks. However they can also be used as high level programming languages for complex control tasks on embedded devices. Bash, JavaScript and Python have been used for applications ranging from small Internet of Things (IOT) devices to control of large spacecraft. This chapter provides and overview on the use of RODOS, MicroPython and JavaScript in various applications.

3.1. RODOS

3.1.1. TubiX Nanosatellite Platform

The TU Berlin inovative neXt generation satellite bus (TUBiX) is nanosatellite platform series developed at TU berlin for use in satellites with masses ranging from 10 kg(TUBiX10) to 20 kg(TUBiX20). The platform focuses on modularity and reusability as its core design concepts in both the hardware and software domains. In the hardware domain, a base set of common components including the microcontroller and Controller Area Network (CAN) transceiver’s are used. Each subsystem is realized as a node, with each node having its own hardware and software. A CAN bus is used as the system bus providing inter-subsystem communication. The use of the same microcontroller on each nodes , allows each of them to run RODOS. All subsystem functionality is split in to applications which exchange data via topics managed and abstracted by the middleware. Inter-subsystem communication is achieved by publishing the topic data on the CAN bus. As the inter-subsystem communication is facilitated via the RODOS middleware, Hardware in the Loop (HiL) testing is carried out by emulating middleware on a Linux host PC. This allows for easy communication between the simulation software and target subsystems [8][5]. The Technosat mission is one such mission that uses the TUBiX20 platform [9].

3.1.2. MAIUS-I

MAIUS-I is a 2 stage sounding rocket developed as a demonstration mission for creation of Bose-Einstein condensates in space The onboard telemetry and telecommand system for the rocket is based on RODOS. The different software modules are implemented as independent RODOS applications(called services) that communicate with each other using RODOS middleware topics. The BoardConfig service gathers housekeeping data. The ConfigManager is used read the stored configuration databases. The FlightParameter service is used for gathering sensor data from Global Positioning System (GPS) and other sensors. The MassStorage service provides an interface to the onboard mass storage device. The

6 3. Related work

Timing service allows for synchronization with a GPS clock. The Telemetry and Telecommand (TMTC) service acts as a gateway between the middleware topics and ground support equipment [10].

3.1.3. Other RODOS Use Cases

RODOS as a realtime OS has also been used in various other applications. It was used as the onboard OS for the Autonomous Vision Approach Navigation and Target Identification (AVANTI) experiment. The experiment was launched on the Berlin Infrared Optical System (BIROS) satellite. The software consists of a set of RODOS applications which are run every 30 s [11] [12]. It is also being used as a real-time OS on mini Unmanned Aerial Vehicle (UAV)s and quadcopters [13] [14].

3.2. Use of Scripting Languages in Spacecrafts

3.2.1. MOVE-II Cubesat

Munich Orbital Verification Experiment II (MOVE-II) is a 1-Unit cubesat developed at the Chair of Astronautics. The CDH system for the satellite is powered by a SAMA5D2 processor. A custom Linux kernel is used as the base operating system. The system consists of a multiple background services called daemons. Each subsystem has one daemon and all communication to the subsystem is handled by it. Most subsystems only have a data connection to the CDH. Inter-subsystem communication is handled by using a software bus(called D-bus), which the individual daemons can send and receive messages on. In-orbit commanding and control is achieved through uploading Bash scripts from the ground station over Ultra High Frequency (UHF) link. After launch, MOVE-II was found to be spinning extremely fast with rotational rates over 500 ° s−1 [4]. The resulting unstable communication line severely limited the uplink bandwidth and a two way communication link was never reliably established. Only very small commands were found to be reliably uplinked and no data download other than the exit status of the script was received back on the ground. However, eventual control of the satellite was achieved by shortening the Bash scripts by relying on Bash parameter expansions and creating short symlinks to frequently used scripts. This allowed the eventual recovery of the satellite by activating the Attitude Determination and Control System (ADCS) system over a period of 7 months.

3.2.2. PyCubed Platform

The PyCubed platform is an Cubesat platform that combines an EPS, CDH, an ADCS and a communica- tions system into a single PC/104 compatible module. The hardware is radiation tested and has been flight proven on the KickSat2 mission. The software architecture is based on CircuitPython which is a fork of the MicroPython project that adds many additional libraries. All of the flight software is written using the Python syntax and is executed by the MicroPython interpreter [15].

3.2.3. LEON 3 MicroPython port

LEON 3 is a 32-bit microprocessor core based on the SPARC-V8 instruction set. It was developed at European Space Research and Technology Centre (ESTEC) which is a part of European Space Agency

7 3. Related work

(ESA). The processor core is designed in VHDL and is highly configurable to the specific needs of the applications. Fault tolerance and protection against single event latchups is a core design principle fot this microprocessor architecture, making it particularly suitable for use in the harsh space environment [16]. The MicroPython interpreter has been ported to the LEON 3 microprocessor architecture for use as the primary On Board Control Procedure (OBCP) controller. The MicroPython interpreter is highly configurable and controllable, allowing complete control over it by the underlying operating system. Efforts have also been made to formally test and qualify the MicroPython interpreter according to European Cooperation for Space Standardization (ECSS) standards(ECSS-E-ST-70-01C [17]) [18].

3.2.4. James Webb Space Telescope

The James Webb Space Telescope (JWST) is a large space based telescope with a 6.5 meter primary mirror. It images in the infrared range to look at the origins of the universe [19]. The telescope uses and event driven system architecture that uses a Javascript execution environment. All operations related tasks are programmed as scripts written in using Javascript with some custom extensions to allow it to talk to the telescope hardware. The ScriptEase Javascript engine is embedded into the payload computers real time operating system(VxWorks). The engine runs as an self contained application with sufficient isolation to ensure that if the engine itself crashes, other parts of the system are unaffected [20].

8 4. Micropython Port on RODOS

RODOS

MicroPython

MicroPython MicroPython RODOS Heap Runtime Aplications

MicroPython MicroPython C Application Frozen User Scripts Modules/Libraries Modules

Figure 4.1.: The MicroPython application running inside RODOS.

Figure 4.1 shows the anatomy of a MicroPython instance running as a RODOS application. RODOS applications are a convenient way of encapsulating the MicroPython instance, allowing for a clear isolation of the MicroPython stack and heap space from the other applications running in the system. The MicroPython call stack is shared with the application’s stack. This is a direct consequence of the fact that most bytecode operands are realized as C functions.

4.1. MicroPython Build Process

MicroPython itself is compiled as a static library(libmicropython.a) using a Makefile. The Makefile and mpconfigport.h (Appendix B) defines all the necessary configuration required to build MicroPy- thon. Only the target architecture related flags are set by the RODOS build process, enabling MicroPython to be compiled for the correct target platform that RODOS is being compiled for. During the build process, the MicroPython core, comprising of the the VM, compiler and runtime are combined. Weak references to the some of the RODOS API calls needed by MicroPython are left undefined at this state. These are filled up later when the static libraries is linked against the RODOS API. MicroPython can be extended by defining C modules with MicroPython bindings to make them available for use in the MicroPython environment. Such modules are compiled and stored along with the other Micropython core components. The external C modules with MicroPython bindings are also added to the build for the MicroPython VM.

9 4. Micropython Port on RODOS

Port External MicroPython External Python Frozen Python Configuration Modules, Core Libraries Modules (mpconfigport.h) User C modules

RODOS API MicroPython MicroPython VM Wrappers Cross Compiler

MicroPython MicroPython Static LIbrary Build (libmicropython.a)

RODOS User RODOS RODOS Core Applications Configuration

RODOS Executable Build

Figure 4.2.: The Micropython build process.

The MicroPython cross compiler is used to precompile the external libraries and user scripts. These precompiled libraries(called frozen modules) are then combined with the MicroPython VM core and archived into a static library. The frozen modules can then be used in MicroPython code by importing them. The RODOS build process defines the target architecture in its configuration files(dosis.build). This enables MicroPython to be automatically built for the target that RODOS is being built for. Figure 4.2 gives an overview of the MicroPython build process.

4.2. Micropython Core Configuration

The file mpconfigport.h defines all of the options that control the MicroPython build process. The following options are enabled for the port: • MICROPY_ENABLE_COMPILER : Enables the compiler and adds it to the binary.

• MICROPY_EMIT_INLINE_THUMB : Allows the compiler to use the Native and Viper code emitters to generate inline ARM Thumb-2 instructions.

• MICROPY_REPL_EVENT_DRIVEN : Configures the REPL to use a event driven architecture, triggered by a character received on the UART.

• MICROPY_ENABLE_GC : Enables the garbage collector. The garbage collection threshold is set to 0 to disable automatic garbage collection.

• MICROPY_MODULE_FROZEN_MPY : Causes frozen modules to be loaded at runtime.

10 4. Micropython Port on RODOS

A more complete configuration file can be found in Appendix B.

4.3. RODOS API Wrappers

A MicroPython port requires the following functions to be defined in the context of the parent OS:

• Print Functions are used by MicroPython to output data and render the REPL environment. MicroPython uses the RODOS PRINTF functions for this purpose.

• Along with the RODOS print functions, the UART API is also used to provide character input to the REPL application.

• For time measurement, MicroPython uses the getNano(), mp_hal_ticks_ms(), mp_hal_ticks_us() and mp_hal_ticks_cpu() functions. These are mapped to the RODOS NOW() function with appropriate conversions for CPU ticks, milliseconds and nanoseconds.

• The mp_hal_delay_ms() and mp_hal_delay_us() functions use the RODOS Thread::suspendCallerUntil(time) function to suspend the MicroPython thread.

• mp_import_stat() and mp_lexer_new_from_file() provide access to the filesystem API via RODOS.

• Uncaught MicroPython exceptions cause the control flow to call the nlr_jump_fail() function which currently prints an error message and enters into a infinite while loop.

4.4. User C Module

User defined C modules can be used to extend the MicroPython language by providing functionality to access hardware and operating system API’s. They are implemented as C functions with some boilerplate code to add them the the global MicroPython runtime environment. Appendix D shows an example module which defines a function to add 2 integers.

11 5. RODOS Development Board

The RODOS development board was designed to enable rapid testing of RODOS and MicroPython on realistic hardware. By defining a standard design for some of the more commonly used components, it also endeavors to be used as a starting point for future hardware designs. Figure 5.1 shows the various logical components of the development board. This chapter explains the design choices for the various components used on the development board Printed Circuit Board (PCB) and also the overall physical design of the board. Complete schematics for the development board can be found in Appendix A. The first page shows the overall hardware architecture.

5.1. Microcontroller

The STM32F407(specifically STM32F407ZGT6) [21] microcontroller is used as the central processor for the development board. It features an ARM®32-bit Cortex®-M4 CPU with a Floating point unit. It has 1 Mbytes of flash storage and 192 Kbytes of SRAM. It supports 15 communication configurable interfaces including 3 x I2C, 4 x USART, 3 x SPI, 2 x CAN and a SDIO interface. Also available are up to 136 GPIO ports. The STM32F4 microcontroller family was chosen primarily because both RODOS and MicroPython have already been ported to the STM32F4 microcontrollers. The microcontroller is programmed using a JTAG interface. The required programming connections are made using the debug header located above the microcontroller. Using this interface. the development board can be programmed using a standard STM32F4 Discovery board. The debug header also includes a UART connector which can used to print debug messages and send data back to the microcontroller. The SDIO interface is connected to a microSD card holder allowing for high capacity data storage to be attached to the development board. Figure 5.1 shows the microcontroller along with all the peripherals around it. Also labelled are the interfaces used by each peripheral to interface with the microcontroller. Page 2 of Appendix A shows the complete schematic of the microcontroller.

5.2. CAN Transceivers

Each of the CAN controllers on the microcontroller(CAN T1 and CAN T2) are connected to a TCAN332D [22] transceiver from Texas Instruments. The TCAN332D also operates at 3.3 V and can be powered from the same 3.3 V power supply as the microcontroller. It supports a 1 Mbps CAN interface and has a wide operating temperature range from −45 ◦C to 125 ◦C which is useful for space applications. The 120 Ω CAN termination resistors are connected to ground over a 100 pF capacitor. When plugging multiple boards together, only one of the boards needs to have the termination resistors. Figure 5.3 shows the connections of CAN T1 on the development board.

12 5. RODOS Development Board

V_BAT

3V3_EXT POWER POWER

DEBUG / PROGRAMMING

LED 1..7 SD Card ANSION HEADER T Holder , SPI, I2C Analog, PWM EXP T

AG , SDIO JT UAR DBG_UAR I2C T V_BA BNO055 BME680 Stm32F407VGTX IMU ENV 3V3 3V3 Microcontroller Converter

CAN TCR CAN TCR I2C INA226 1 2

CAN 1 , CAN 2 CAN 2 CAN 2 CAN 1, CAN 1,

Figure 5.1.: Logical architecture of the development board showing the microcontroller and the various sensors(Not to Scale).

Figure 5.2.: Connections for CAN T1 on the development board.

13 5. RODOS Development Board

5.3. Power Supply

The development can be supplied with 2 different power sources: unregulated battery voltage(VBAT ) or externally regulated 3.3 V (3V3EXT ) supply. In case of being supplied with the battery voltage, the voltage needs to be stepped down to 3.3 V for the microcontroller and other peripherals. For this purpose, the LMZM23601 [23] from Texas Instruments is used. It supports an input voltage range of 4 - 36 V, thus supporting most common battery voltages. On its output, it is capable of delivering an output current of upto 1 A. The LMZM23600 was particularly chosen because of its extremely small size. Input and output decoupling capacitors are the only other required external components. A jumper header allows for selection between the onboard 3.3 V supply or the externally regulated 3.3 V supply. Immediately after the power selection header, a 0.1 Ω shunt resistor is placed. This is used by the INA226(described in section 5.4) current sensor to measure power the consumption of the development board. Both VBAT and 3V3EXT are fused using resettable polyfuses that prevent short circuits, can also be reset by removing the fault. A LED placed at the output of the LMZM23601 serves as a power status indicator. Page 3 of Appendix A shows the power supply related components.

Figure 5.3.: The onboard LMZM23601 DC-DC converter.

5.4. Peripherals

The following peripherals are included on the development board.

5.4.1. Sensors INA226 Current Sensor

The INA226 [24] current sensor measures the current consumption of the microcontroller and the peripherals by measuring the voltage drop over a small shunt resistor(0.1 Ω). It is connected the the microcontroller over the I2C bus.

BNO055 IMU

The Bosch BNO055 [25] Inertial Measurement Unit (IMU) integrates a 3-axis accelerometer, a 3-axis gyroscope and a 3-axis magnetometer into one device. Additionally, it also features on-board configurable

14 5. RODOS Development Board sensor fusion which uses the data from all 3 sensors and provides an absolute orientation in the form of a quaternion. It also uses the I2C interface of the microcontroller.

BME 680 Enviornment Sensor

The BME680 [26] is a low power gas resistance, pressure, humidity and temperature sensor. It has a extremely low power consumption(few mA for gas resistance measurements and few µA for other measurements. It is also connected to the microcontroller using the I2C bus.

Extension Headers

In order to provide easy access to the microcontroller’s peripherals, the pins from the microcontroller are exposed externally via an expansion header. The header has the following digital and analog signals present: Serial Peripheral Interconnect (SPI), Universal Asynchronous Reciever/Transmitter (UART), I2C, 4 Analog Inputs, 6 Timer I/O’s which can be used as Pulse Width Modulation (PWM) outputs, 6 General Purpose Input/Output (GPIO) pins from port F of the microcontroller and 3.3 V power and ground connections. All the extension header and other connectors are shown in detail on page 6 of Appendix A.

5.5. Physical design

Figure 5.4.: 3 Development boards connected together. They are powered from a laboratory power supply connected at the top left.

Physical design of the development board was guided by the following requirements:

• The development board should have a 10 x 10 cm form factor. As this is the most common size for electronics boards in cubesats [3].

• Multiple boards should be able to be connected to each other, enabling testing of the common CAN bus shared amongst them.

• When stacked, the boards should share a power over the connector.

15 5. RODOS Development Board

• When stacked, the boards should be freely accessible to allow easy access to all the connectors.

• The microcontroller, CAN controllers and the power supply components should accommodate as low a area as possible on the PCB, leaving most of the area free for other future components on the board.

Horizontal board to board connectors are placed on the four corners of the PCB. This enables multiple development boards to be connected together as shown in Figure 5.4. Connectors on the top side of the board are used to interconnect the battery voltage(VBAT ) and the external 3V3(3V3EXT ) supply across boards. The bottom connectors carry the 2 CAN bus signals. This placement of the connectors allows multiple boards to be plugged in to each other while lying on a flat surface. Debug headers of each board can be easily reached form the top. The shared power and CAN bus signals can also be probed by connecting to the respective connectors on the first or the last board. The whole setup needs only one external power connection, and power is distributed to all the boards over the top connectors. Figure 5.1 shows the rough placement of all the components and the data/power signals between them on the PCB. Figure 5.4 shows a photograph of 3 development boards connected to each other. The bottom left of the board houses the power supply components. A jumper header is provided to switch between the onboard DC-DC converter(i.e using VBAT ) and the external 3V3(3V3EXT ) supply. In the middle is the large microcontroller surrounded by its decoupling capacitors and Realtime Clock (RTC) oscillator crystal. Its programming header is located above it. On the left are the 2 CAN transceivers. These components form the basis of future hardware designs. Additional sensors(described in detail in section 5.4) are located above the CAN transceivers, along with a SD card holder module. The LED’s and expansion header is located on the top right of the PCB.

16 6. Evaluation

MicroPython being an interpreted language, inherently has a performance disadvantage to a pure C/C++ implementation. Knowledge of what overheads exist and what steps can be taken to mitigate them is crucial in determining when MicroPython is the appropriate language of choice. This chapter provides a quantitative analysis of MicroPython performance by measuring the overheads in executing MicroPython code. It also performs a comparative analysis between MicroPython code and a pure C implementation of the same algorithm. Additionally, the power consumption of the development board is also measured using the included INA226 sensor.

6.1. Experimental Setup

The RODOS development board described in chapter 5 is the base hardware for all the performance evaluations. A lab power supply provides 10 V over the VBAT input. The microcontroller is clocked to run at a base clock speed of 168 MHz. A STM32F4 Discovery board is used to program the development board. The Discovery board also serves as a USB to UART converter, which is used to log debug messages to a computer. All measured timings are recorded using this method. Individual stages of MicroPython execution are measured by timing each stage of the execution(Parsing, compilation and execution) using the NOW() function in RODOS. The NOW() function uses a hardware timer that ticks with a resolution of 166.66 ns and returns the current time in nanoseconds. As printing data to the debug UART output is a slow operation, care is taken to ensure that the measurements do not include any print statements. All data is printed after the measurement is complete. RODOS is built with the following compile time options; hardware floating point support is enabled with the -mfloat-abi=hard and -mfpu=fpv4-sp-d16 options, the GCC optimization level is set to -O3 and all debugging flags are disabled. A more complete build configuration can be found in Appendix B. Only a single RODOS application is loaded which has a single thread that executes the desired test.

6.1.1. Micropython Configuration

The MicroPython VM is built with the following configuration parameters (Configured in mpconfigport.h):

• The Thumb and Inline Thumb code emitters are enabled.

• The garbage collector is enabled but its automatic garbage collection threshold is set to 0; effectively disabling automatic garbage collection. The garbage collector is manually called after each test run. This excludes the garbage collector runtime from the measurements.

• MicroPython compiler support is enabled.

17 6. Evaluation

• Frozen bytecode and Frozen string modules are enabled.

• Hardware floating point support is enabled.

• Arbitrary precision integer support is enabled and uses the MICROPY_LONGINT_IMPL_MPZ implementation.

MicroPython is run as a RODOS application. A separate 32 Kb of heap space is allocated to MicroPython at compile time. All scripts which are measured for their runtime are stored as frozen modules on the microcontroller flash. A full listing of the MicroPython build configuration can be found in Appendix B.

6.2. Experiments

C++ implementations, being compiled directly to machine code are inherently much faster than a interpreted MicroPython scripts. The MicroPython compiler generates bytecode. Each bytecode operand is implemented as a C function call, thus adding a function call overhead to each line of code in Micropython. MicroPython does feature a native code emitter that produces native machine code, however this still does not provide performance comparable to a C++ implementation as it only avoids the function call overhead. The viper optimized native code, as described in chapter 2, is only useful in certain situations like register access and bit operations. Additionally, in order to use the viper optimization, one must step away from standard Python syntax and use special data type hints. This section described the various performance evaluations done and how they help in characterizing MicroPython performance.

6.2.1. Overheads due to Parsing and Compilation

As described in chapter 2, before a MicroPython program is executed, it needs to be parsed and then compiled to machine code. In order to characterize the performance of the MicroPython parser and compiler, a MicroPython script of increasing length was parsed and compiled. The script simply defines a MicroPython function which is a repeated series of additions of 2 variables. Listing 6.1 shows the function being parsed and compiled. Starting with a single addition statement, at each iteration, the same line is appended to the end of the function and the resulting longer script is parsed from scratch. As we are only in characterizing the parsing and compilation time, the function is never called. Thus the execution time remains minimal and can be ignored for this test.

1 def f():

2 a = 1

3 b = 2

4 c = a + b

5 c = a + b

6 ... Listing 6.1: The MicroPython function used to test the parsing and compilation performance. The c = a + b line is repeated multiple times to generate a long script.

18 6. Evaluation

Figure 6.1 shows the time required for each of the three steps(parsing, compilation and execution) as a function of the script length. A very linear relationship is observed. In Figure 6.2 we can clearly see that the percentage of time required for each of the 3 steps remains constant with increasing script size.

6.2.2. Matrix Multiplication : CPU Bound Application

In order to measure the execution speed of a Central Processing Unit (CPU) bound workload, a 3 x 3 matrix multiplication is implemented using MicroPython arrays. The multiplication is carried out using nested loops and the 3 required matrices are pre-allocated. Listing 6.2 and Listing 6.3 lists the respective MicroPython and C functions that are timed.

1 def matrix_mul():

2 a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3 b = [[3, 2, 1], [6, 5, 4], [9, 8, 7]]

4 c = [[0 for row in range(3)] for col in range(3)]

5 x = 0.0;

6 for reps in range(1000):

7 for i in range(3):

8 for j in range(3):

9 c[i][j] = 0

10 for k in range(3):

11 c[i][j] = c[i][j] + a[i][k]* b[k][j]

12 matrix_mul() Listing 6.2: MicroPython 3x3 matrix multiplication.

1 uint64_t matrix_mul() {

2 uint64_t t = NOW();

3 uint32_t a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

4 uint32_t b[3][3] = {{3, 2, 1}, {6, 5, 4}, {9, 8, 7}};

5 uint32_t c[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};

6 for (uint16_t n = 0; n < 1000; n++) {

7 for (uint8_t i = 0; i < 3; i++) {

8 for (uint8_t j = 0; j < 3; j++) {

9 c[i][j] = 0;

10 for (uint8_t k = 0; k < 3; k++) {

11 c[i][j] += a[i][k] * b[k][j];

12 }

13 }}}

14 return NOW() - t;

15 } Listing 6.3: C++ 3x3 matrix multiplication

Each is run independently of each other and the time taken to execute the script or function is measured as an average of 1000 runs. Figure 6.3 compares the runtime of the MicroPython with the

19 6. Evaluation

Execution Compilation Parsing

150

100

50 Time required(Milliseconds)

0 53 173 293 413 533 653 737

Code Length

Figure 6.1.: Total time required for parsing, compiling and executing Micropython code.

Execution Compilation Parsing 100%

75%

50%

25% Percentage of time Spent

0% 53 173 293 413 533 653 737

Code Length

Figure 6.2.: The time spent(in %) in the various stages of Micropython code execution as a function of code size.

20 6. Evaluation

C++ implementation. For the MicroPython implementation, all 3 types of code emitters are separately measured. Additionally a MicroPython C - module which implements the matrix multiplication in C code is also measured. Bytecode is the worst measuring at about 0.383 ms per matrix multiplication. Moving to the native code emitter, we see a 40% performance improvement(0.231 ms) as compared to bytecode. The native and viper code emitters have a very similar runtime as the viper optimizations have no effect on standard MicroPython objects. They are rather meant to be used for pointer and register manipulation operations. The RODOS and MicroPython C module implementations are significantly faster. They require only 0.0120 ms and 0.0125 ms per matrix multiplication; a gain of 96%!

0.4

0.3

0.2

0.1 Time(milliseconds)

0 Bytecode Native Viper C Module RODOS Optimized

Figure 6.3.: Comparison of runtime of a 3x3 matrix multiplication implemented in MicroPython and RODOS

6.2.3. Large Array Sorting : Memory Bound Application

Memory bound operations like accessing large static arrays stored in flash memory are also compared. For this, a 500 element array containing random integers generated using the Python random library. A simple bubble sort algorithm is implemented in MicroPython, C++ and as a MicroPython module. Additionally the inbuilt list sort function is also included in the timings. It should be noted that the inbuilt sort function uses the quicksort algorithm rather than bubble sort. Listing 6.4 shows the bubble sort script in MicroPython and Listing 6.5 shows the sorting implemented in C++.

1 #’large’ is an array with 500 integers.

21 6. Evaluation

2 large = [708, 383, 644, ....]

3 @micropython.native

4 def bubble_sort():

5 for i in range(500):

6 for j in range(i, 500):

7 if(large[i] > large[j]):

8 large[i], large[j] = large[j], large[i]

9 bubble_sort() Listing 6.4: Bubble sort implemented in MicroPython and compiled using the native code emitter.

1 static uint32_t large[500] = {708, 383, 644, ...};

2 uint64_t bubble_sort() {

3 uint64_t t = NOW();

4 for (uint16_t i = 0; i < 500; i++) {

5 for (uint16_t j = 0; j < 500; j++) {

6 if (large[i] > large[j]) {

7 uint32_t temp = large[i];

8 large[i] = large[j];

9 large[j] = temp;

10 }

11 }

12 }

13 return NOW() - t;

14 } Listing 6.5: C++ bubble sort implementation.

Figure 6.4 shows the runtime of the array sort script using different implementations. We see a 15% increase in performance when using the native code emitter as compared to bytecode. Bytecode needs 3.69 s, Native needs 3.18 s and the Viper emitter needs also 3.18 s for sorting the array. Again, the Native and Viper emitters are closely matched. The C++ bubble sort implementation is more than 98% faster and needs only 50 ms. For memory bound operations, the native code emitter has a much lesser impact on the runtime as compared to CPU bound operations.

6.2.4. Micropython Script execution overhead

MicroPython scripts in this project are primarily aimed at being used in time critical scenarios, where the script is executed as a reaction to some external event like an interrupt. Execution of a script includes several overheads like script load, parse and compilation. When executing a pre-compiled frozen script, the parsing overhead is absent. Additionally, if any import statements are present, the module in question is loaded, parsed and compiled if required, before proceeding with script execution. In realistic scenarios, scripts would likely contain multiple import statements and multiple functions, class definitions etc; However we can establish a baseline by measuring the time required for importing a single MicroPython

22 6. Evaluation

Figure 6.4.: Comparison of runtime of sorting a 500 element array.

module. Using the test module which defines a single function(Appendix D), it is found that on an average, importing the test module requires 1.82 ms.

6.2.5. Garbage Collection

In all of the above tests, automatic garbage is disabled to prevent it from influencing the measurements. This also makes sense in time critical applications where a automatic garbage collection can cause the runtime to be unpredictable. To schedule manual garbage collection , its useful to know how much time the garbage collector requires on average. The garbage collector runtime was measured by triggering a manual garbage collection after each of the above mentioned tests. The average runtime of the garbage collector was 0.341 ms. For a worst case analysis, the script shown in Listing 6.6 was run. The script creates new MicroPython dictionary objects and appends it to an array, exhausting almost all of the 32 Kb heap space. After the script ends, the array goes out of scope and subsequently all the dict objects and the array itself are garbage collected. The average worst case runtime for the garbage collector is 1.943 ms.

1 a = []

2 for i in range(1,500):

3 a.append({10:20.0}) Listing 6.6: Script for measuring worst case runtime for the garbage collector.

23 6. Evaluation

6.3. Discussion

MicroPython, at first glance, seems to be orders of magnitude worse in performance. However its primary use is as a scripting language to control and automate tasks rather than to perform computationally heavy tasks. MicroPython is perfectly adequate for reading a sensor value and saving it once every second. However if the task is computationally expensive, like grabbing an image from a camera and compressing it before saving, a pure MicroPython implementation would be a severe performance bottleneck. MicroPython makes several optimization options available to the user. When constrained to only MicroPython code, the Native code emitter, depending on the situation, offers up to 40% improvement in performance. When dealing with bit operations, register manipulations and other low level operations, the Viper code emitter performs a little better than the Native code emitter. Performance critical and computationally expensive code can be outsourced to MicroPython C modules. Their performance is on par with a plain C/C++ implementation. The script compilation and execution overheads can be also be reduced in certain cases. The MicroPython cross compiler allows for offline precompilation of MicroPython code to either bytecode or native machine code. At runtime, for frequently used scripts, a caching strategy can be used. The compilation would only be required on the first run and subsequent runs will be faster.

24 7. Conclusion and Future Work

The MicroPython port for RODOS was programmed with the objective of using MicroPython as a scripting language for future MOVE projects. The hardware development board proved very useful in the development and testing of not only MicroPython but also other RODOS applications. The board has been setup as a testing and development environment with remote access. The CAN transceivers integrated onto the development board have enabled testing of the CAN bus and its latencies. During the development several areas of future work were identified. While the MicroPython port works, it still is running in a sandboxed environment as it has no access to hardware. As we want to rely on the hardware abstractions provided by RODOS, a possible solution to this problem would be to implement MicroPython wrappers for the RODOS API. This will enable MicroPython applications to fully utilize the capabilities of the hardware while still interacting with the other parts of the system in a safe manner. A starting point to this would be the RODOS Topic API. Porting this would immediately enable MicroPython applications to communicate with other applications by publishing or receiving messages. The STM32F4 microcontroller used currently on the development board consumes a lot of power. The power consumption of the board can be lowered by changing the microcontroller to a STM32L4. Both the microcontrollers are pin compatible with only a few changes to some of the power pins. Thus, from a hardware point of view, migrating to a SMT32L4 microcontroller is easy. However RODOS does not have a working STM32L4 port yet. The current development board does not feature an external clock oscillator for providing the system clock. While the internal oscillator works fine for testing, it is not very stable over long periods of time or varying temperature. Adding an external oscillator crystal will improve the stability of the clock.

25 A. Development board schematics

26 1 2 3 4

PowerSupply Regulator.SchDoc

A A

PowerRailsSupply 3V3 ] 0 . . 5 2 1 [ C F 2 I P

Microcontroller Sensor Peripherals Dosis_mcu.SchDoc Peripherals.SchDoc

3V3 ] ] 3V3 0 0 . . . . 5 5 1 1 [ [ B A

B P CAN2_BUS B P CAN1_BUS

SDCARD SDCARD JTAG I2C1 I2C1 DEBUG_UART CAN2 CAN2 ] ] ] 0 ] 0 0

. CAN1 CAN1 . . 2 . 0 . . . 5 . T 5 5 1 7 2 1 1 R 1 [ [ [ [ I C A F C D E BOOT0 P PF[15..0] 2 I P P P P Reset U S

Connectors C C connectors.SchDoc Reset ] ] ] ]

BOOT0 2 1 2 I 0 0 0 0 . . . . T C . . . . P CAN1_BUS 2 R 5 7 5 5 S I [ 1 1 1 A

[ [ [ CAN2_BUS C U F E P D P

DEBUG_UART P P JTAG

3V3 PowerRailsSupply

D D LRT Title DOSIS TOPLEVEL Tejas Kale Size: A4 Number:1. Revision:1 Date: 24/05/2019 Time: 14:07:18 Sheet1 of 6 File: Z:\Master Thesis\Dosis_Board\Dosis_toplevel.SchDoc 1 2 3 4 1 2 3 4 5 6 7 8

VCC_MCU 3V3 DEBUG_UART PA0 3V3 DEBUG_TX PA1 PO3V3PO3V303V3PO3V30GND3V3 PODEBUG0UARTPODEBUG0UART0DEBUG0RXPODEBUG0UART0DEBUG0TXDEBUG_UART DEBUG_RX GND COMCU1ACOMCU1BMCU1A PA0 PA0 34 141 NLPE0PE0 PIMCU1034 PA0 PE0 PIMCU10141 A GND PA1 PA1 35 142 NLPE1PE1 CAN1 A PIMCU1035 PA1 PE1 PIMCU10142 NLUART20TXPA2 NLPA2PA2 36 1 NLPE2PE2 PA11 PIMCU1036 PA2 PE2 PIMCU101 CAN1_RX NLUART20RXPA3 NLPA3PA3 37 2 NLPE3PE3 PA12 PIMCU1037 PA3 PE3 PIMCU102 POCAN1POCAN10CAN10RXPOCAN10CAN10TXCAN1 CAN1_TX NLSPI10NSSPA4 NLPA4PA4 40 3 NLPE4PE4 PIMCU1040 PA4 PE4 PIMCU103 NLSPI10SCKPA5 NLPA5PA5 41 4 NLPE5PE5 PIMCU1041 PA5 PE5 PIMCU104 NLSPI10MISOPA6 NLPA6PA6 42 5 NLPE6PE6 CAN2 PIMCU1042 PA6 PE6 PIMCU105 VCC_MCU NLSPI10MOSIPA7 NLPA7PA7 43 58 NLPE7PE7 PB12 MCU1B PIMCU1043 PA7 PE7 PIMCU1058 CAN2_RX 131 31 NLPA8PA8 100 59 NLPE8PE8 PB13 PIMCU10131 VDD VSSA PIMCU1031 PIMCU10100 PA8 PE8 PIMCU1059 POCAN2POCAN20CAN20RXPOCAN20CAN20TXCAN2 CAN2_TX 144 16 NLPA9PA9 101 60 NLPE9PE9 NLTIM10CH1PE9 PIMCU10144 VDD VSS PIMCU1016 PIMCU10101 PA9 PE9 PIMCU1060 121 38 NLPA10PA10 102 63 NLPE10PE10 PIMCU10121 VDD VSS PIMCU1038 PIMCU10102 PA10 PE10 PIMCU1063 108 51 PA11 PA11 103 64 NLPE11PE11 NLTIM10CH2PE11 PIMCU10108 VDD VSS PIMCU1051 PIMCU10103 PA11 PE11 PIMCU1064 84 61 PA12 PA12 104 65 NLPE12PE12 I2C1 PIMCU1084 VDD VSS PIMCU1061 PIMCU10104 PA12 PE12 PIMCU1065 95 83 PA13 PA13 105 66 NLPE13PE13 NLTIM10CH3PE13 PB6 PIMCU1095 VDD VSS PIMCU1083 PIMCU10105 PA13 PE13 PIMCU1066 I2C1_SCL 62 94 PA14 PA14 109 67 NLPE14PE14 NLTIM10CH4PE14 PB7 PIMCU1062 VDD VSS PIMCU1094 PIMCU10109 PA14 PE14 PIMCU1067 POI2C1POI2C10I2C10SCLPOI2C10I2C10SDAI2C1 I2C1_SDA 72 107 PA15 PA15 110 68 NLPE15PE15 PIMCU1072 VDD VSS PIMCU10107 PIMCU10110 PA15 PE15 PIMCU1068 PIC502 PIC602 52 120 PIMCU1052 VDD VSS PIMCU10120 C5COC5 COC6C6 39 130 NLPB0PB0 46 10 NLPF0PF0 PIMCU1039 VDD VSS PIMCU10130 PIMCU1046 PB0 PF0 PIMCU1010 I2C2 PIC501 100nF PIC601 100nF 30 NLPB1PB1 47 11 NLPF1PF1 PIMCU1030 VDD PIMCU1047 PB1 PF1 PIMCU1011 PB10 PIC702 PIC802 17 NLPB2PB2 48 12 NLPF2PF2 I2C2_SCL PIMCU1017 VDD PIMCU1048 PB2 PF2 PIMCU1012 POI2C2POI2C20I2C10SDAPOI2C20I2C20SCL PB11 C7COC7 COC8C8 GND PB3 PB3 133 13 NLPF3PF3 I2C2 I2C1_SDA PIMCU10133 PB3 PF3 PIMCU1013 PIC701 Cap Semi PIC801 Cap Semi 33 PB4 PB4 134 14 NLPF4PF4 PIMCU1033 VDDA PIMCU10134 PB4 PF4 PIMCU1014 1µF 1µF 32 NLPB5PB5 135 15 NLPF5PF5 PIMCU1032 VREF+ PIMCU10135 PB5 PF5 PIMCU1015 UART2 71 PB6 PB6 136 18 NLPF6PF6 VCAP_1 PIMCU1071 PIMCU10136 PB6 PF6 PIMCU1018 PA2 6 106 PB7 PB7 137 19 NLPF7PF7 UART2_TX PIMCU106 VBAT VCAP_2 PIMCU10106 PIMCU10137 PB7 PF7 PIMCU1019 POUART2POUART20UART20RXPOUART20UART20TX PA3 NLPB8PB8 139 20 NLPF8PF8 UART2 UART2_RX PIMCU10139 PB8 PF8 PIMCU1020 STM32F407ZGT6 PIC902 PIC1002 NLPB9PB9 140 21 NLPF9PF9 PIMCU10140 PB9 PF9 PIMCU1021 COC9C9 COC10C10 PB10 PB10 69 22 NLPF10PF10 PIMCU1069 PB10 PF10 PIMCU1022 SPI1 PIC901 4.7uF PIC1001 4.7uF PB11 PB11 70 49 NLPF11PF11 PA7 PIMCU1070 PB11 PF11 PIMCU1049 SPI1_MOSI B PB12 PB12 73 50 NLPF12PF12 PA6 B PIMCU1073 PB12 PF12 PIMCU1050 SPI1_MISO PB13 PB13 74 53 NLPF13PF13 PA5 PIMCU1074 PB13 PF13 PIMCU1053 POSPI1POSPI10SPI10MISOPOSPI10SPI10MOSIPOSPI10SPI10NSSPOSPI10SPI10SCK SPI1_SCK GND NLPB14PB14 75 54 NLPF14PF14 SPI1 PA4 PIMCU1075 PB14 PF14 PIMCU1054 SPI1_NSS NLPB15PB15 76 55 NLPF15PF15 PIMCU1076 PB15 PF15 PIMCU1055 PC0 PC0 26 56 NLPG0PG0 PIMCU1026 PC0 PG0 PIMCU1056 PC1 PC1 27 57 NLPG1PG1 PIMCU1027 PC1 PG1 PIMCU1057 PC2 PC2 28 87 NLPG2PG2 PIMCU1028 PC2 PG2 PIMCU1087 PC3 PC3 29 88 NLPG3PG3 PIMCU1029 PC3 PG3 PIMCU1088 VCC_MCU NLPC4PC4 44 89 NLPG4PG4 JTAG PIMCU1044 PC4 PG4 PIMCU1089 NLPC5PC5 45 90 NLPG5PG5 PA13 PIMCU1045 PC5 PG5 PIMCU1090 JTAG_SWDIO PIC1102 PIC1202 PIC1302 PIC1402 PIC1502 PIC1602 PIC1702 PIC1802 PIC1902 PIC2002 PIC3602 PIC3702 PIC3802 NLPC6PC6 96 91 NLPG6PG6 PA14 PIMCU1096 PC6 PG6 PIMCU1091 JTAG_SWCLK COC11C11 COC12C12 COC13C13 COC14C14 COC15C15 COC16C16 COC17C17 COC18C18 COC19C19 COC20C20 COC36C36 COC37C37 COC38C38 NLPC7PC7 97 92 NLPG7PG7 PA15 PIMCU1097 PC7 PG7 PIMCU1092 POJTAGPOJTAG0JTAG0NRSTPOJTAG0JTAG0SWCLKPOJTAG0JTAG0SWDIOPOJTAG0JTAG0TDIPOJTAG0JTAG0TDOJTAG JTAG_TDI PIC1101 100nF PIC1201 100nF PIC1301 100nF PIC1401 100nF PIC1501 100nF PIC1601 100nF PIC1701 100nF PIC1801 100nF PIC1901 100nF PIC2001 100nF PIC3601 100nF PIC3701 100nF PIC3801 100nF NLSDIO0D0SDIO_D0 98 93 NLPG8PG8 PB3 PIMCU1098 PC8 PG8 PIMCU1093 JTAG_TDO NLSDIO0D1SDIO_D1 99 124 NLPG9PG9 PB4 PIMCU1099 PC9 PG9 PIMCU10124 JTAG_NRST NLSDIO0D2SDIO_D2 111 125 NLPG10PG10 PIMCU10111 PC10 PG10 PIMCU10125 GND NLSDIO0D3SDIO_D3 112 126 NLPG11PG11 PIMCU10112 PC11 PG11 PIMCU10126 NLSDIO0CLKSDIO_CLK 113 127 NLPG12PG12 SDCARD PIMCU10113 PC12 PG12 PIMCU10127 COC21 7 128 NLPG13PG13 SDIO_D0 C21 PIMCU107 PC13 PG13 PIMCU10128 SDIO_D0 NLRCC0OSC320INRCC_OSC32_IN RCC_OSC32_IN 8 129 NLPG14PG14 SDIO_D1 PIC2101 PIC2102 PIMCU108 PC14 PG14 PIMCU10129 SDIO_D1 RCC_OSC32_OUT PIMCU1099 PIMCU10132132 NLPG15PG15 SDIO_D2 2 SDIO_D2 Cap PIY102 PC15 PG15 SDIO_D3 POSDCARDPOSDCARD0SDIO0CLKPOSDCARD0SDIO0CMDPOSDCARD0SDIO0D0POSDCARD0SDIO0D1POSDCARD0SDIO0D2POSDCARD0SDIO0D3SDCARD SDIO_D3 12.5pF COY1Y1 NLPD0PD0 114 23 SDIO_CLK PIMCU10114 PIMCU1023 SDIO_CLK XTAL NLPD1 PD0 PH0 PD2 COC22C22 PD1 PIMCU10115115 PIMCU102424 1 PD1 PH1 SDIO_CMD PIY101 NLRCC0OSC320OUTRCC_OSC32_OUT NLSDIO0CMDPD2 NLPD2PD2 116 PIC2201 PIC2202 PIMCU10116 PD2 GND NLPD3PD3 117 PIMCU10117 PD3 Cap NLPD4PD4 118 PIMCU10118 PD4 12.5pF NLPD5PD5 119 C PIMCU10119 PD5 NLPA0150000PA[15..0] C NLPD6PD6 122 POPA0150000POPA0POPA1POPA2POPA3POPA4POPA5POPA6POPA7POPA8POPA9POPA10POPA11POPA12POPA13POPA14POPA15PA[15..0] PIMCU10122 PD6 NLPD7PD7 123 PIMCU10123 PD7 NLPB0150000PB[15..0] NLPD8PD8 77 POPB0150000POPB0POPB1POPB2POPB3POPB4POPB5POPB6POPB7POPB8POPB9POPB10POPB11POPB12POPB13POPB14POPB15PB[15..0] PIMCU1077 PD8 NLPD9PD9 78 PIMCU1078 PD9 NLPC070000PC[7..0] NLPD10PD10 79 POPC070000POPC0POPC1POPC2POPC3POPC4POPC5POPC6POPC7PC[7..0] PIMCU1079 PD10 NLPD11PD11 80 PIMCU1080 PD11 NLPD0150000PD[15..0] NLTIM20CH1PD12 NLPD12PD12 81 POPD0150000POPD0POPD1POPD2POPD3POPD4POPD5POPD6POPD7POPD8POPD9POPD10POPD11POPD12POPD13POPD14POPD15PD[15..0] PIMCU1081 PD12 NLTIM20CH2PD13 NLPD13PD13 82 138 NLBOOT0BOOT0 VCC_MCU PIMCU1082 PD13 BOOT0 PIMCU10138 NLPE0150000PE[15..0] NLPD14PD14 85 143 POPE0150000POPE0POPE1POPE2POPE3POPE4POPE5POPE6POPE7POPE8POPE9POPE10POPE11POPE12POPE13POPE14POPE15PE[15..0] PIMCU1085 PD14 PDR_ON PIMCU10143 NLPD15PD15 86 25 NRST PIMCU1086 PIMCU1025 NLPF0150000PF[15..0] PD15 NRST POPF0150000POPF0POPF1POPF2POPF3POPF4POPF5POPF6POPF7POPF8POPF9POPF10POPF11POPF12POPF13POPF14POPF15PF[15..0] STM32F407ZGT6 I2C Pullups VCC_MCU BOOT0 VCC_MCU POBOOT0BOOT0 COR1 VCC_MCU PIR302 COR17R17 R1 COR3R3 PB10 PIR102 PIR101PB6 PIR1702 PIR1701 PIR202 10KOhm COR2 4.7K 4.7K R2 PIR301 10KOhm COR4 COR18R18 R4 PB7 PIR201 NLNRSTNRST PIR1802 PIR1801PB1 1 PIR402 PIR401 POResetReset GND Res2 Res2 4.7K 4.7K

D D

LRT Title DOSIS MCU * * Size: Number: Revision: A3 2. * * Date: 24/05/2019 Time: 14:07:18 Sheet2 of 6 * File: Z:\Master Thesis\Dosis_Board\Dosis_mcu.SchDoc 1 2 3 4 5 6 7 8 1 2 3 4

A A COU1U1 GND LMZ23600 GND

PIU10GNDGND PIC3302 PIC3402 GND PID902 COD9D9 COC33C33 COC34C34 PIDZ101 MOD LED1 PIU10MOD MODSYNC Cap PIC33014.7 µFPIC3401 Cap CODZ1DZ1 GNDT GNDT PIU10GNDT GND PowerRails_Supply 4.7µF VIN PIR2002PID901 COFUSE2 PIU10VIN VIN FUSE2 PIDZ102 FB R20COR20 VBAT PIFUSE202 PIFUSE201 FB PIU10FB EN 1K POPowerRailsSupplyPOPowerRailsSupply03V30EXTPOPowerRailsSupply0GNDPOPowerRailsSupply0VBATPowerRailsSupply 3V3_EXT COFUSE1 PIU10EN EN FUSE1 NL3V30EXT0F3V3_EXT_F VOUT PIR2001 3V3_REGNL3V30REG GND PIFUSE102 PIFUSE101 COP0GOODP_GOOD VOUT PIU10VOUT PGOOD PIP0GOOD01PIU10PGOOD PGOOD PIC3502 COC35C35 PIDZ202 Test Point CODZ2DZ2 GND Regulator LMZM23600 Cap PIC3501 47µF PIDZ201

GND GND B B I2C2 Current Measurement INA226_V+ 3V3 PB10 COU2U2 I2C2_SCL NLINA2260V03V3 9 5 NLI2C20SCLPB10 PB11 PIU209 VIN- SCL PIU205 CO3V30SEL POI2C2POI2C20I2C10SDAPOI2C20I2C20SCLI2C2 I2C1_SDA NLINA2260V0INA226_V+ 10 4 NLI2C20SDAPB11 3V3_SEL PIU2010 VIN+ SDA PIU204 2 3V3_EXT_FPI3V30SEL01 PI3V30SEL02 COR14 3V3 A0 PIU202 1 2 R14 8 1 3V3_REGPI3V30SEL03 PI3V30SEL04 PIR14011 PIR14022 3V3 PO3V3PO3V303V3PO3V30GND PIU208 VBUS A1 PIU201 3 4 3V3 3V3 ERJ-8BWFR100V GND 3 NLPF9PF9 Header 2X2 ALERT PIU203 PIR1502 NL3V3 COR15 GND 3V3 PIU2066 PIU2077 R15 PIC3902 VS+ GND 10M COC39C39 PIR1501 NLPF0150000PF[15..0] INA226AIDGST POPF0150000POPF0POPF1POPF2POPF3POPF4POPF5POPF6POPF7POPF8POPF9POPF10POPF11POPF12POPF13POPF14POPF15PF[15..0] PIC3901 100nF

GND GND

C C

D D LRT Title 3V3 Regulator & Power Measurement * * Size: Number: Revision: A4 3. * * Date: 24/05/2019 Time: 14:07:19 Sheet3 of 6 * File: Z:\Master Thesis\Dosis_Board\Regulator.SchDoc 1 2 3 4 1 2 3 4

COR5R5 NLBME03V3 PIR502 PIR501BME_3V3 3V3 COR60 BNO055 R6 NLBNO03V3BNO_3V3 bno055.SchDoc 3V3 PIR602 PIR601 BNO_3V3 PO3V3PO3V303V3PO3V30GND3V3 COR70 3V3 R7 NLCAN203V3CAN2_3V3 GND NLBNO0NRSTBNO_NRST GND PIR702 PIR701 GND 3V3 nRes PB7 CAN1_H COR80 SDA CAN1_H R8 NLCAN103V3CAN1_3V3 3V3 PB6 CAN1_L A PIR802 PIR801 SCL CAN1_L POCAN10BUSPOCAN10BUS0CAN10HPOCAN10BUS0CAN10LCAN1_BUS A GND 0 NLPF7PF7 COR9R9 NLDATA03V3 INT PIR902 PIR901DA TA_3V3 CAN1_BUS 0 CAN2_H CAN2_H COBME1BME1 CAN2_L CAN2_L POCAN20BUSPOCAN20BUS0CAN20HPOCAN20BUS0CAN20LCAN2_BUS BME_3V3 8 1 GND PIBME108 VDD GND PIBME101 CAN1 GNDNLGND 7 2 BME_3V3 CAN2_BUS PIBME107 GND CSB PIBME102 PA11 6 3 NLI2C10SDAPB7 CAN1_RX PIBME106 VDDIO SDA PIBME103 PA12 5 4 NLI2C10SCLPB6 POCAN1POCAN10CAN10RXPOCAN10CAN10TXCAN1 CAN1_TX PIC2302 PIC2402 PIBME105 SDO SCL PIBME104 COC23C23 BME680 CAN2 PIC2301 100nF PIC2401 C24COC24 PB12 100nF CAN2_RX PB13 POCAN2POCAN20CAN20RXPOCAN20CAN20TXCAN2 CAN2_TX COCANT1CANT1 GND NLCAN10TXPA12 1 8 PICANT101 TxD S/STB PICANT108 I2C1 GND 2 7 NLCAN10HCAN1_H PICANT102 GND CANH PICANT107 NLCAN10L PB6 CAN1_3V3PICANT1033 PICANT1066 CAN1_L PIR1002 B I2C1_SCL NLCAN10RX VCC CANL COR10R10 B POI2C1POI2C10I2C10SCLPOI2C10I2C10SDA PB7 PIC2502 PIC2602 PA11 PICANT1044 PICANT1055 PIR1102 I2C1 I2C1_SDA COC25C25 RxD SHDN/F COR11R11 0 PIC2501 Cap Semi PIC2601 COC26C26 CANTransceiver_TCAN332D 0 PIR1001 1µF 100nF PIR1101 SDCARD SDIO_D0 PIC2702 SDIO_D0 SDIO_D1 COC27C27 SDIO_D1 SDIO_D2 PIC2701 Cap SDIO_D2 SDIO_D3 GND 100pF POSDCARDPOSDCARD0SDIO0CLKPOSDCARD0SDIO0CMDPOSDCARD0SDIO0D0POSDCARD0SDIO0D1POSDCARD0SDIO0D2POSDCARD0SDIO0D3SDCARD SDIO_D3 SDIO_CLK COD7D7 SDIO_CLK PD2 COCANT2CANT2 GND SDIO_CMD NLPF0PF0 COR21R21 NLCAN20TXPB13 1 8 PIR2102 PIR2101PID701 PID702 PICANT201 TxD S/STB PICANT208 GND 2 7 NLCAN20HCAN2_H 1K PICANT202 GND CANH PICANT207 CAN2_3V3 3 6 CAN2_LNLCAN20L PIR1202 LED1 PICANT203 VCC CANL PICANT206 COD6D6 PIC2802 PIC2902 NLCAN20RXPB12 4 5 PIR1302 COR12R12 COC28 PICANT204 RxD SHDN/F PICANT205 COR13 POPF0150000POPF0POPF1POPF2POPF3POPF4POPF5POPF6POPF7POPF8POPF9POPF10POPF11POPF12POPF13POPF14POPF15 NLPF0150000PF[15..0] C28 R13 0 PF[15..0] NLPF1 COR22R22 Cap Semi COC29 0 PF1 PIR2202 PIR2201PID601 PID602 PIC2801 PIC2901 C29 CANTransceiver_TCAN332D PIR1201 1K 1µF 100nF PIR1301 LED1 C COD5D5 PIC3002 C COC30 GND COSD1 C30 NLPF2 COR23R23 SD1 Cap PF2 PIR2302 PIR2301PID501 PID502 SMD SD card reader PIC3001 DATA_3V3 4 100pF 1K PISD104 VDD LED1 PIC3102 PIC3202 COD4D4 COC31C31 NLSDIO0CMDPD2 3 GND PISD103 CMD PIC3101 Cap Semi PIC3201 C32COC32 NLSDIO0CLKSDIO_CLK 5 PISD105 CLK NLPF3PF3 COR24R24 1µF 100nF PF8 9 PIR2402 PIR2401PID401 PID402 PISD109 CD_SW GND S5 1K GND PISD10S5 NLSDIO0D0SDIO_D0 7 S3 LED1 PISD107 DAT0 GND PISD10S3 COD3D3 NLSDIO0D1SDIO_D1 8 S2 PISD108 DAT1 GND PISD10S2 NLSDIO0D2SDIO_D2 1 S1 PISD101 DAT2 GND PISD10S1 NLPF4PF4 COR25R25 GND NLSDIO0D3SDIO_D3 2 6 PIR2502 PIR2501PID301 PID302 PISD102 CD/DAT3 VSS PISD106 1K LED1 Card Detect Pullup DM3CS-SF COD2D2 GND DATA_3V3 COR16R16 NLPF8PF8 NLPF5 COR26R26 PIR1602 PIR1601 PF5 PIR2602 PIR2601PID201 PID202 10K D 1K D LED1 COD1D1 * Title * * NLPF6PF6 COR27R27 * PIR2702 PIR2701PID101 PID102 Size: A4 Number:4. Revision:* 1K * LED1 Date: 24/05/2019 Time: 14:07:19 Sheet4 of 6 * File: Z:\Master Thesis\Dosis_Board\Peripherals.SchDoc 1 2 3 4 1 2 3 4

3V3 GND A PO3V3PO3V303V3PO3V30GND3V3 A 3V3 GND

COC1C1 PIC101 PIC102 Cap 6.8nF COC2C2 PIC201 PIC202 POSDA Cap SDA 120nF PIRP302 1 0 CORP3RP3 8 7 6 5 4 3 2 2 2 PIBNO1011 PIBNO10282 PIBNO10272 PIBNO10262 PIBNO10252 PIBNO10242 PIBNO10232 PIBNO10222 PIBNO1021 PIBNO1020 Res2 COBNO1BNO1 B B PIRP301 10K PIC302 BNO055 1 0 1 2 2 4 3 2 O O 2 3 3 2 2 2 COC3 I I C3 N M I T N N N N N D D I I I I I O P

PIC301 Cap U D N P P P P C X O 100nF V G 2 X 19 PIBNO102 GND COM1 PIBNO1019 POSCLSCL 3 18 PIBNO103 VDD COM2 PIBNO1018 4 17 PIBNO104 nBOOT_LOAD_PIN COM3 PIBNO1017 5 16 PIBNO105 PS1 PIN16 PIBNO1016 T D E 5 N 2 3 I S 1 7 8 1 1 P _ E 0 T N N N N N A L S I I I I I R N P P P C B n P P I P PIRO102 6 7 8 9 0 1 2 3 4 5 1 CORO1RO1 PIBNO106 PIBNO107 PIBNO108 PIBNO109 PIBNO10101 PIBNO1011 PIBNO10121 PIBNO10131 PIBNO10141 PIBNO10151 Res2 PIRO101 10K POnResnRes POINTINT PIC402 C COC4C4 C PIC401 Cap 100nF

GND

D D * Title * * * Size: Number: Revision: A4 5. * * Date: 24/05/2019 Time: 14:07:19 Sheet5 of 6 * File: Z:\Master Thesis\Dosis_Board\bno055.SchDoc 1 2 3 4 1 2 3 4

NLPD0150000PD[15..0] POPD0150000POPD0POPD1POPD2POPD3POPD4POPD5POPD6POPD7POPD8POPD9POPD10POPD11POPD12POPD13POPD14POPD15PD[15..0] NLPE0150000PE[15..0] POPE0150000POPE0POPE1POPE2POPE3POPE4POPE5POPE6POPE7POPE8POPE9POPE10POPE11POPE12POPE13POPE14POPE15PE[15..0] NLPC070000PC[7..0] A POPC070000POPC0POPC1POPC2POPC3POPC4POPC5POPC6POPC7PC[7..0] A

NLPF0150000PF[15..0] POPF0150000POPF0POPF1POPF2POPF3POPF4POPF5POPF6POPF7POPF8POPF9POPF10POPF11POPF12POPF13POPF14POPF15PF[15..0]

COPOWER0LPOWER_L CODEBUGDEBUG POWER_RCOPOWER0R PowerRails_Supply NL3V33V3 NLJTAG0NRSTPB4 NLResetNRST COP10P10 PIPOWER0L01 1 2 PIPOWER0L02 PIDEBUG01 1 2 PIDEBUG02 POResetReset PIPOWER0R010 10 9 PIPOWER0R09 VBAT NLVBATVBAT VBAT NLJTAG0TDIPA15 NLJTAG0SWCLKPA14 VBAT VBAT VBAT PIPOWER0L03 3 4 PIPOWER0L04 PIDEBUG03 3 4 PIDEBUG04 PIP1001 1 PIPOWER0R08 8 7 PIPOWER0R07 3V3_EXT NLJTAG0TDOPB3 NLJTAG0SWDIOPA13 NLBOOT0BOOT0 POPowerRailsSupplyPOPowerRailsSupply03V30EXTPOPowerRailsSupply0GNDPOPowerRailsSupply0VBATPowerRailsSupply 3V3_EXT PIPOWER0L05 5 6 PIPOWER0L06 PIDEBUG05 5 6 PIDEBUG06 POBOOT0BOOT0 PIP1002 2 PIPOWER0R06 6 5 PIPOWER0R05 NL3V30EXT3V3_EXT 3V3_EXT NLGNDGND GND 3V3_EXT 3V3_EXT GND PIPOWER0L07 7 8 PIPOWER0L08 PIDEBUG07 7 8 PIDEBUG08 PIPOWER0R04 4 3 PIPOWER0R03 NLDebug0RXPA1 NLDebug0TXPA0 Header 2 PIPOWER0L09 9 10 PIPOWER0L010 PIDEBUG09 9 10 PIDEBUG010 PIPOWER0R02 2 1 PIPOWER0R01 3V3 GND Header 5X2 Header 5X2 Header 5X2 3V3 GND GND GND GND 3V3 COCAN0LCAN_L CAN_RCOCAN0R PO3V3PO3V303V3PO3V30GND3V3 COJ1J1 GND PICAN0L01 1 2 PICAN0L02 PICAN0R010 10 9 PICAN0R09 NLCAN10LCAN1_L NLCAN10HCAN1_H NLPD13PD13 NLPE14PE14 CAN1_H CAN1_L PICAN0L03 3 4 PICAN0L04 PIJ101 1 32 PIJ1032 PICAN0R08 8 7 PICAN0R07 NLPD12PD12 NLPE13PE13 PICAN0L05 5 6 PICAN0L06 PIJ102 2 31 PIJ1031 PICAN0R06 6 5 PICAN0R05 GND NLCAN20LCAN2_L NLCAN20HCAN2_H NLPE11PE11 CAN2_H CAN2_L B PICAN0L07 7 8 PICAN0L08 PIJ103 3 30 PIJ1030 PICAN0R04 4 3 PICAN0R03 B NLPE9PE9 PICAN0L09 9 10 PICAN0L010 PIJ104 4 29 PIJ1029 PICAN0R02 2 1 PICAN0R01 CAN1_BUS NLPC3PC3 PIJ105 5 28 PIJ1028 CAN1_H Header 5X2 NLPC2PC2 Header 5X2 CAN1_H PIJ106 6 27 PIJ1027 CAN1_L GND 3V3 NLPC1PC1 GND GND POCAN10BUSPOCAN10BUS0CAN10HPOCAN10BUS0CAN10LCAN1_BUS CAN1_L PIJ107 7 26 PIJ1026 GND 3V3 NLPC0PC0 PIJ108 8 25 PIJ1025 GND 3V3 NLI2C20SCLPB10 PIJ109 9 24 PIJ1024 CAN2_BUS NLPF0PF0 NLI2C20SDAPB11 PIJ1010 10 23 PIJ1023 CAN2_H NLPF1PF1 NLUART20RXPA3 CAN2_H PIJ1011 11 22 PIJ1022 CAN2_L NLPF2PF2 NLUART20TXPA2 POCAN20BUSPOCAN20BUS0CAN20HPOCAN20BUS0CAN20LCAN2_BUS CAN2_L PIJ1012 12 21 PIJ1021 NLPF3PF3 NLSPI10MOSIPA7 PIJ1013 13 20 PIJ1020 NLPF4PF4 NLSPI10MISOPA6 PIJ1014 14 19 PIJ1019 NLPF5PF5 NLSPI10SCKPA5 PIJ1015 15 18 PIJ1018 NLPF6PF6 NLSPI10NSSPA4 PIJ1016 16 17 PIJ1017 DEBUG_UART PA0 DEBUG_TX PA1 PODEBUG0UARTPODEBUG0UART0DEBUG0RXPODEBUG0UART0DEBUG0TXDEBUG_UART DEBUG_RX

JTAG C C PA13 JTAG_SWDIO PA14 JTAG_SWCLK PA15 POJTAGPOJTAG0JTAG0NRSTPOJTAG0JTAG0SWCLKPOJTAG0JTAG0SWDIOPOJTAG0JTAG0TDIPOJTAG0JTAG0TDOJTAG JTAG_TDI PB3 JTAG_TDO PB4 JTAG_NRST

I2C2 PB10 I2C2_SCL PB11 POI2C2POI2C20I2C10SDAPOI2C20I2C20SCLI2C2 I2C1_SDA

UART2 PA2 UART2_TX PA3 POUART2POUART20UART20RXPOUART20UART20TXUART2 UART2_RX

SPI1 PA7 SPI1_MOSI D PA6 D SPI1_MISO PA5 POSPI1POSPI10SPI10MISOPOSPI10SPI10MOSIPOSPI10SPI10NSSPOSPI10SPI10SCK SPI1_SCK * SPI1 PA4 Title * SPI1_NSS * * Size: Number: Revision: A4 6. * * Date: 24/05/2019 Time: 14:07:20 Sheet6 of 6 * File: Z:\Master Thesis\Dosis_Board\connectors.SchDoc 1 2 3 4 B. Micropython Configuration

Listing B.1 is the main file controlling the Micropython build.

1 // Options to control how MicroPython is built

2 // Checkout micropython/py/mpconfig.h fora brief

3 // description of each option.

4

5 #define MICROPY_HW_BOARD_NAME"DOSIS"

6 #define MICROPY_HW_MCU_NAME"STM32F407"

7

8

9 #define MICROPY_ALLOC_PATH_MAX (128)

10 #define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)

11 #define MICROPY_EMIT_THUMB (1)

12 #define MICROPY_EMIT_INLINE_THUMB (1)

13 #define MICROPY_COMP_MODULE_CONST (0)

14 #define MICROPY_COMP_CONST (0)

15 #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)

16 #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)

17 #define MICROPY_MEM_STATS (0)

18 #define MICROPY_DEBUG_PRINTERS (0)

19 #define MICROPY_ENABLE_GC (1)

20 #define MICROPY_GC_ALLOC_THRESHOLD (0)

21 #define MICROPY_ENABLE_COMPILER (1)

22 #define MICROPY_REPL_EVENT_DRIVEN (1)

23 #define MICROPY_HELPER_REPL (1)

24 #define MICROPY_HELPER_LEXER_UNIX (1)

25 #define MICROPY_ENABLE_SOURCE_LINE (0)

26 #define MICROPY_ENABLE_DOC_STRING (0)

27 #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)

28 #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)

29 #define MICROPY_PY_ASYNC_AWAIT (0)

30 #define MICROPY_PY_BUILTINS_BYTEARRAY (1)

31 #define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1)

32 #define MICROPY_PY_BUILTINS_MEMORYVIEW (1)

33 #define MICROPY_PY_BUILTINS_ENUMERATE (1)

34 #define MICROPY_PY_BUILTINS_FILTER (1)

33 B. Micropython Configuration

35 #define MICROPY_PY_BUILTINS_SET (1)

36 #define MICROPY_PY_BUILTINS_FROZENSET (0)

37 #define MICROPY_PY_BUILTINS_REVERSED (1)

38 #define MICROPY_PY_BUILTINS_SLICE (1)

39 #define MICROPY_PY_BUILTINS_PROPERTY (0)

40 #define MICROPY_PY_BUILTINS_MIN_MAX (1)

41 #define MICROPY_PY_BUILTINS_STR_COUNT (1)

42 #define MICROPY_PY_BUILTINS_STR_OP_MODULO (1)

43 #define MICROPY_PY___FILE__ (1)

44 #define MICROPY_PY_GC (1)

45 #define MICROPY_PY_ARRAY (1)

46 #define MICROPY_PY_ATTRTUPLE (1)

47 #define MICROPY_PY_COLLECTIONS (1)

48 #define MICROPY_PY_MATH (1)

49 #define MICROPY_PY_CMATH (1)

50 #define MICROPY_PY_IO (0)

51 #define MICROPY_PY_STRUCT (1)

52 #define MICROPY_PY_SYS (0)

53 #define MICROPY_MODULE_FROZEN_MPY (1)

54 #define MICROPY_MODULE_FROZEN_STR (1)

55 #define MICROPY_QSTR_BYTES_IN_HASH (1)

56 #define MICROPY_QSTR_EXTRA_POOL (mp_qstr_frozen_const_pool)

57 #define MICROPY_CPYTHON_COMPAT (0)

58 #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)

59 #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)

60 #define MICROPY_USE_INTERNAL_PRINTF (0)

61

62 // Extended modules

63 #define MICROPY_PY_UTIMEQ (1)

64 #define MICROPY_PY_UTIME_MP_HAL (1)

65 #define MODULE_EXAMPLE_ENABLED (1)

66 //#define MICROPY_PY_URANDOM (1)

67

68

69 #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)

70

71

72

73

74 #define MICROPY_PORT_BUILTIN_MODULES \

75 { MP_OBJ_NEW_QSTR(MP_QSTR_example), (mp_obj_t)&example_user_cmodule }, \

76 { MP_OBJ_NEW_QSTR(MP_QSTR_argex), (mp_obj_t)&mp_module_argex }, \

34 B. Micropython Configuration

77

78

79 #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))

80

81 // This port is intended to be 32-bit, but unfortunately, int32_t for

82 // different targets may be defined in different ways- either as int

83 // or as long. This requires different printf formatting specifiers

84 // to print such value. So, we avoid int32_t and use int directly.

85 #define UINT_FMT"%u"

86 #define INT_FMT"%d"

87 typedef int mp_int_t;// must be pointer size

88 typedef unsigned mp_uint_t;// must be pointer size

89

90

91

92 // extra modules available to uPy.

93 extern const struct _mp_obj_module_t mp_module_mymodule;

94 extern const struct _mp_obj_module_t mp_module_argex;

95

96

97 #define MP_STATE_PORT MP_STATE_VM

98 #define MICROPY_PORT_ROOT_POINTERS \

99 const char *readline_hist[8];\

100

101

102 typedef int mp_int_t;// must be pointer size

103 typedef unsigned int mp_uint_t;// must be pointer size

104

105 typedef long mp_off_t;

106

107 #include Listing B.1: Micropython configuration header : mpconfigport.h

35 C. Rodos Configuration

Listing C.1 and Listing C.2 show the RODOS build time configuration. The dosis.build defines the target environment including the cross compiler to use(arm-none-eabi-g++, version 8.2.1 20181213 (release) [gcc-8-branch revision 267074] in this case) and any other target specific options that are needed.

1 target_hw_flags = [’-mcpu=cortex-m4’,’-mthumb’,’-mfloat-abi=hard’,’-mfpu= fpv4-sp-d16’,’-fno-pic’]

2 target_c_args = target_hw_flags + [

3 ’-gdwarf-2’,

4 ’-DHSI_VALUE=16000000’,

5 ’-DSTM32F40_41xxx’,

6 ’-DUSE_STM32_DISCOVERY’,

7 ’-DUSE_STDPERIPH_DRIVER’,

8 ’-O3’

9 ]

10 target_cpp_args = target_c_args + [’-fno-rtti’,’-fno-exceptions’]

11 target_link_args = target_hw_flags + [

12 ’-T’ + meson.current_source_dir() +’/scripts/stm32_flash.ld’,

13 ’-nostartfiles’,

14 ’-nodefaultlibs’,

15 ’-nostdlib’,

16 ’-Xlinker’,

17 ’--gc-sections’,

18 ’-fno-unwind-tables’,

19 ’-fno-asynchronous-unwind-tables’

20 ]

21 target_file_ext =’.elf’ Listing C.1: Meson build configuration for RODOS

1 [binaries]

2 c =’/opt/arm-toolchain/latest/bin/arm-none-eabi-gcc’

3 cpp =’/opt/arm-toolchain/latest/bin/arm-none-eabi-g++’

4 ld =’/opt/arm-toolchain/latest/bin/arm-none-eabi-gcc’

5 ar =’/opt/arm-toolchain/latest/bin/arm-none-eabi-ar’

6 strip =’/opt/arm-toolchain/latest/bin/arm-none-eabi-strip’

7

36 C. Rodos Configuration

8 [host_machine]

9 system =’dosis’

10 cpu_family =’arm’

11 cpu =’armv7’

12 endian =’little’

13

14 [properties]

15 board =’dosis’ Listing C.2: The Development board target definition build file.

37 D. Example MicroPython C Module

1 // Include required definitions first.

2 #include "py/obj.h"

3 #include "py/runtime.h"

4 #include "py/builtin.h"

5

6 // This is the function which will be called from Python as example.add_ints( a,b).

7 STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {

8 // Extract the ints from the micropython input objects

9 int a = mp_obj_get_int(a_obj);

10 int b = mp_obj_get_int(b_obj);

11

12 // Calculate the addition and convert to MicroPython object.

13 return mp_obj_new_int(a + b);

14 }

15 // Definea Python reference to the function above

16 STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);

17

18 // Define all properties of the example module.

19 // Table entries are key/value pairs of the attribute name(a string)

20 // and the MicroPython object reference.

21 // All identifiers and strings are written as MP_QSTR_xxx and will be

22 // optimized to word-sized integers by the build system(interned strings).

23 STATIC const mp_rom_map_elem_t example_module_globals_table[] = {

24 { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) },

25 { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },

26 };

27 STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);

28

29 // Define module object.

30 const mp_obj_module_t example_user_cmodule = {

31 .base = { &mp_type_module },

32 .globals = (mp_obj_dict_t*)&example_module_globals,

33 };

38 D. Example MicroPython C Module

34

35 // Register the module to make it available in Python

36 MP_REGISTER_MODULE(MP_QSTR_example, example_user_cmodule, MODULE_EXAMPLE_ENABLED); Listing D.1: An example module which shows how to define a MicroPython module in C. The Module simply defines a function which adds 2 integers and returns the result,

39 List of Figures

2.1. MicroPython internals showing how the compiler, runtime and virtual machine interact with each other...... 4

4.1. The MicroPython application running inside RODOS...... 9 4.2. The Micropython build process...... 10

5.1. Logical architecture of the development board showing the microcontroller and the various sensors(Not to Scale)...... 13 5.2. Connections for CAN T1 on the development board...... 13 5.3. The onboard LMZM23601 DC-DC converter...... 14 5.4. 3 Development boards connected together. They are powered from a laboratory power supply connected at the top left...... 15

6.1. Total time required for parsing, compiling and executing Micropython code...... 20 6.2. The time spent(in %) in the various stages of Micropython code execution as a function of code size...... 20 6.3. Comparison of runtime of a 3x3 matrix multiplication implemented in MicroPython and RODOS...... 21 6.4. Comparison of runtime of sorting a 500 element array...... 23

40 Listings

2.1. A MicroPython function...... 5 2.2. The generated bytecode ...... 5

6.1. The MicroPython function used to test the parsing and compilation performance. The c = a + b line is repeated multiple times to generate a long script...... 18 6.2. MicroPython 3x3 matrix multiplication...... 19 6.3. C++ 3x3 matrix multiplication ...... 19 6.4. Bubble sort implemented in MicroPython and compiled using the native code emitter. . 21 6.5. C++ bubble sort implementation...... 22 6.6. Script for measuring worst case runtime for the garbage collector...... 23

B.1. Micropython configuration header : mpconfigport.h ...... 33

C.1. Meson build configuration for RODOS ...... 36 C.2. The Development board target definition build file...... 36

D.1. An example module which shows how to define a MicroPython module in C. The Module simply defines a function which adds 2 integers and returns the result, ...... 38

41 Bibliography

[1] V.Verma, T. Estlin, A. Jónsson, C. Pasareanu, R. Simmons, and K. Tso. “Plan execution interchange language (PLEXIL) for executable plans and command sequences”. In: International symposium on artificial intelligence, robotics and automation in space (iSAIRAS). 2005. [2] T. Estlin, A. Jónsson, C. Pasareanu, R. Simmons, K. Tso, and V.Verma. “Plan execution interchange language (PLEXIL)”. In: (2006). [3] A. Mehrparvar, D. Pignatelli, J. Carnahan, R. Munakat, W. Lan, A. Toorian, A. Hutputanasin, and S. Lee. “Cubesat design specification rev. 13”. In: The CubeSat Program, Cal Poly San Luis Obispo, US 1.2 (2014). [4] S. Rueckerl, D. Meßmann, N. Appel, J. Kiesbye, F. Schummer, M. Faehling, L. Krempel, T. Kale, A. Lill, G. Reina, P. Schnierle, S. Wuerl, M. Langer, and M. Luelf. “First Flight Results of the MOVE-II CubeSat”. In: Session I: A Look Back: Lessons Learned. Technical University of Munich. June 2019. url: https://digitalcommons.usu.edu/smallsat/2019/all2019/49/. [5] S. Montenegro and F. Dannemann. “RODOS-real time kernel design for dependability”. In: DASIA 2009-DAta Systems in Aerospace. Vol. 669. 2009. [6] MicroPython. MicroPython code statistics. 2019. url: http://micropython.org/resources/ code-dashboard/ (visited on 09/13/2019). [7] MicroPython. MicroPython inline assembler supported instructions. 2019. url: http://docs. micropython.org/en/v1.9.3/pyboard/reference/asm_thumb2_index.html#asm- thumb2-index (visited on 09/13/2019). [8] K. Gordon. A flexible attitude control system for three-axis stabilized nanosatellites. Vol. 2. Universitätsverlag der TU Berlin, 2018. [9] M. Barschke, K. Großekatthöfer, and S. Montenegro. “Implementation of a nanosatellite on-board software based on building-blocks”. In: Proceedings of the Small Satellites Systems and Services Symposium. Porto Pedro, Spain. 2014. [10] A. Stamminger, J. Ettl, J. Grosse, M. Hörschgen-Eggers, W. Jung, A. Kallenbach, G. Raith, W. Saedtler, S. Seidel, J. Turner, et al. “MAIUS-1—vehicle, subsystems design and mission operations”. In: Proceedings of the 22nd ESA Symposium on European Rocket and Balloon Programmes and Related Research. ESA Special Publication. 2015, pp. 183–190. [11] J.-S. Ardaens and G. Gaias. “Integrated Solution for Rapid Development of Complex GNC Software”. In: Proceedings of the Workshop on Simulation for European Space Programmes (SESP). European Space Agency, ESTEC Noordwijk, The Netherlands. 2015. [12] M. Wermuth, G. Gaias, and S. D’Amico. “Safe picosatellite release from a small satellite carrier”. In: Journal of Spacecraft and Rockets 52.5 (2015), pp. 1338–1347.

42 Bibliography

[13] S. Montenegro, Q. Ali, and N. Gageik. “A review on distributed control of cooperating mini UAVs”. In: (2015). [14] Q. Ali. “Distributed Control of Cooperating Mini UAVs”. In: (2016). [15] M. Holliday, A. Ramirez, C. Settle, T. Tatum, D. Senesky, and Z. Manchester. “PyCubed: An Open-Source, Radiation-Tested CubeSat Platform Programmable Entirely in Python”. In: (). [16] F. Sturesson, J. Gaisler, R. Ginosar, and T. Liran. “Radiation characterization of a dual core LEON3-FT processor”. In: 2011 12th European Conference on Radiation and Its Effects on Components and Systems. IEEE. 2011, pp. 938–944. [17] E. C. for Space Standardization. Spacecraft on-board control procedures. Apr. 2010. url: https://ecss.nl/standard/ecss-e-st-70-01c-on-board-control-procedures/. [18] D. George, D. Sanchez, and T. Jorge. “Porting of MicroPython to LEON Platforms”. In: Data Systems in Aerospace (2016). [19] P. A. Sabelhaus and J. E. Decker. “An overview of the James Webb space telescope (JWST) project”. In: Optical, Infrared, and Millimeter Space Telescopes. Vol. 5487. International Society for Optics and Photonics. 2004, pp. 550–563. [20] V. Balzano and D. Zak. “Event-driven James Webb Space Telescope Operations using on-board JavaScripts”. In: Advanced Software and Control for Astronomy. Vol. 6274. International Society for Optics and Photonics. 2006, 62740A. [21] S. Microelectronics. ARM Cortex-M4 32b MCU+FPU, 210DMIPS, up to 1MB Flash/192+4KB RAM. DocID022152. Rev. 8. ST Microelectronics. Sept. 2016. [22] T. Instruments. TCAN33x 3.3-V CAN Transceivers with CAN FD (Flexible Data Rate). SLLSEQ7D. Texas Instruments. Apr. 2016. [23] T. Instruments. LMZM23600 36-V, 0.5-A Step-Down DC/DC Power Module in 3.8-mm × 3-mm Package. SNVSB53B. Texas Instruments. May 2019. [24] T. Instruments. INA226 High-Side or Low-Side Measurement,Bi-Directional Current and Power Monitor with I2C Compatible Interface. SBOS547A. Texas Instruments. Aug. 2015. [25] B. Sensortec. BNO055, Intelligent 9-axis absolute orientation sensor. BST-BNO055-DS000-14. Rev 1.6. Bosch. June 2016. [26] B. Sensortec. BME680, Low power gas, pressure, temperature and humidity sensor. BST-BME680- DS001-03. Rev 1.3. Bosch. July 2019.

43