Files
sdes_lab/sdes_skipt_mkdocs/docs/5_aufgabe1.md

171 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 5. Aufgabe 1 - Makefile
Die in dem Skript stehenden Aufgaben dienen der Anweisung was programmiert werden soll. Zusätzlich zu den Programmieraufgaben halten Sie Ihre Ergebnisse in dem vorgefertigten Dokument doku.odt fest. Dieses finden Sie im Repository, welches Sie im
Folgenden für alle Aufgaben verwenden. Die Dokumentation dient als Hilfestellung für
Sie in den Kolloquien, um die Schritte Ihrer Lösung erklären zu können.
## 5.1. Wissen
### 5.1.1. Toolchain
Jedes in Hochsprache geschriebenes Programm muss in Maschinencode übersetzt werden. Die Toolchain ist eine Aneinanderreihung von Routinen zur Erstellung eines ausführbaren Programms aus dem Code einer Hochsprache wie zum Beispiel der Sprache C.
Damit der Code unserer Hochsprache auf unserem Zielsystem ausgeführt werden kann,
muss er zuerst in die dem Zielsystem entsprechende Maschinensprache übersetzt werden. Der Compiler unserer Toolchain übersetzt den von uns geschriebenen Code aus der
Hochsprache in Assembler-Code. Dieser Code hängt bereits von dem verwendeten Ziel
ab. Je nach Befehlssatz des Zielarchitektur (ARM, AVR, x86, ...) sieht der Assemblercode
verschieden aus. Der vom Compiler erstellte Assembly-Code wird vom Assembler in Maschinencode umgewandelt. Als Basis für das weitere Verständnis zur Toolchain kann das
Dokument How a Compiler Works [[RS14](references.md), Kapitel 2, S. 2] genutzt werden. In dem Diagramm
5.1 können zum Verständnis die Arbeitsschritte der
Toolchain eingetragen werden. Nutzen Sie dafür das zur Verfügung gestellte .odt Dokument.
### 5.1.2 Makefile
Das Programm Make wird verwendet, um den Buildprozess zu automatisieren. Dafür
liest Make die Makefile aus und gibt die entsprechenden Anweisungen an die Toolchain
weiter (z.b. Compiler, Linker, ...). Dies ist besonders bei größeren Projekten hilfreich, da
der Buildprozess aus vielen Einzelanweisungen bestehen kann. Außerdem können unterschiedliche Build-Konfigurationen und Targets benutzt werden. Eine Erklärung von
Makefiles bietet die Website [[mak](references.md)]. Schauen Sie sich den Inhalt an und verinnerlichen Sie den Sinn und die Arbeitsweise von Makefiles.
![Screenshot](img/jpg/toolchain-leer.png) Abbildung 5.1.: Toolchain Diagramm zum Ausfüllen und zur Vorbereitung auf das Prekolloquium
![Screenshot](img/png/makefile.png) Abbildung 5.2.: Beispiel zum Aufbau einer Makefile
### 5.1.3 Printf-Debugging
#### Funktionsdefinition
Eine intuitive und einfache Methode des Debuggens ist die Ausgabe von Werten oder
Nachrichten über eine serielle Schnittstelle. Zum Lesen solcher Nachrichten auf der Entwicklungsplattform ist es meist nötig, einen Seriell-zu-USB Adapter einzusetzen. Diese
sind günstig und weit verbreitet. Als Software dient ein serieller Monitor.
#### Anwendung
Möchte man die Implementierung einer Berechnung überprüfen, so kann dies über einen
Printf-Befehl getan werden, der das Ergebnis ausgibt. Auch eignet sich diese Debugging-Methode gut als Indikator, ob bestimmte Stellen im Programmcode erreicht werden. Besonders hilfreich ist diese Methode zum Überprüfen von Variablenwerten in Schleifendurchläufen. Auf die gleiche Art und Weise können falsche Übergabe- oder Rückgabeparameter erkannt werden.
#### Grenzen
Der Rahmen in dem Printf-Debugging zum Erfolg führt, ist stark begrenzt. Es bietet keinerlei Hilfe bei Problemen, die mit Speicherallozierung oder Interrupts zu tun haben.
Printf nutzt die langsame serielle Schnittelle und verändert das Zeitverhalten des Programmes stark. Das kann dazu führen, dass sich Fehler in einem auf Echtzeitfähigkeit
ausgelegten System anders verhalten, wenn eine Printf-Anweisung in den Code eingefügt
wurde. Es ist dadurch nicht möglich zeitkritische Anwendungen zu debuggen. Als Beispiel
dafür gilt die Kommunikation über Bussysteme. Dazu kommt der Aufwand und die Dauer des wiederkehrenden Build-Prozesses, da nach dem Verschieben der Printf-Anweisung
an eine andere Stelle im Programm, das Programm erneut kompiliert werden muss. Vor
allem bei großen Projekten bedeutet dies lange Wartezeiten und ist nicht praktikabel.
## 5.2. Pre-Kolloquium
Für das Kolloquium sollte klar sein, wie die Toolchain funktioniert und welche Werkzeuge in den Programmbau involviert sind. Als Visualisierung sollen Sie das Diagramm zur
Toolchain ausfüllen. Machen Sie sich mit den einzelnen Schritten vertraut. Die Regeln,
nach denen das Programm gebaut wird, finden sich in dem Makefile. Sie sollten erklären
können welche Teile im Makefile welche Funktion erfüllen. In der folgenden Aufgabe
werden Sie unterschiedliche Fehler im Code aber auch im gegebenen Makefile finden
müssen. Die Fehler im Makefile sollten Sie durch genaue Analyse des Makefiles bereits
zum Teil finden können. Die Datei toolchain.odt enthält das Diagramm aus dem Skript,
welches den exemplarischen Ablauf einer Toolchain zeigt. Füllen Sie die Lücken der Dateien und Tools und erklären Sie was in welchem Schritt passiert. Machen Sie sich zudem
mit den Linux Befehlen find und grep vertraut.
## 5.3. Aufgabenstellung
### 5.3.1. Toolchain
Die erste Aufgabe formt den Einstieg in die Programmierung des Praktikumsboards. Es
wird sich mit der Ordnerstruktur und der Entwicklungsumgebung vertraut gemacht und
die Struktur des Gits verstanden. Es soll das erste Programm gebaut und geflasht sowie der
Umgang mit Makefiles geübt werden. Außerdem soll die Funktionsweise der Toolchain
verinnerlicht werden.
Erstellen Sie zunächst einen Fork des Repository von
```
https://git.ida.ing.tu-bs.de/IDA_Lehre/lab_sdes_student
```
Dazu clonen Sie zunächst Ihren Fork mit dem angezeigten Link aus dem Webinterface in
Ihren lokalen Ordner.
Zusätzlich sollten Sie einen neuen Branch in folgender Form anlegen:
```
git checkout -b praktikum
```
Es kommt vor, dass der Betreuer im Praktikumsverlauf Änderungen am Master vorneh-
men muss, dies führt häufig zu Konflikten. Durch den Branch werden diese vermieden.
Sie arbeiten in ihrem Fork auf dem angelegten Branch.
In dem bereitgestellten git Repository finden sich alle für die Aufgabe benötigten Dateien. In dem Ordner src/APP befinden sich der Quellcode der Aufgaben des Praktikums.
Der Ordner src/APP/Aufgabe1/ps7/core0/ enthält den Quellcode der Aufgabe 1 für
den die Architektur ps7 und den Kern 0. In ihm finden sich weitere Unterordner. In
Aufgabe1/ps7/core0/src findet man alle .c-Dateien außer der main.c.
Nach dem Klonen des Gits ist die Entwicklungsumgebung einzurichten:
- Terminal in Verzeichnis der Wahl (außer innerhalb des Repository) öffnen
- Eine Integrated Development Environment (IDE) bzw. Texteditor Ihrer Wahl starten
(z.B. VSCode)
- Falls gewünscht, kann das Makefile-Projekt eingerichtet werden, um den Buildprozess aus der IDE heraus zu starten
Ihre Aufgabe ist es, das Programm zu kompilieren und in die Laufzeitumgebung zu
laden. Dabei auftretende Fehler sind zu beheben und der **Arbeitsvorgang zu dokumentieren**. Zunächst ist es sinnvoll sich den Programmcode der Datei main.c anzusehen und zu
verstehen. Um das Programm zu kompilieren gehen sie in den Repositoryordner, öffnen
ein Terminal und führen den Befehl make aus. Es ist nötig dem Programm make mitzu-
teilen, für welche Aufgabe und Architektur das Programm kompiliert werden soll. Die
Syntax des Aufrufs ist folgende:
```
make ARCH=ps7 APP=Aufgabe1 CORE=0
```
Falls Fehler auftreten, analysieren Sie diese und versuchen Sie ihre Gründe herauszufinden. Es lohnt sich die Ausgabe genauer anzusehen und mit dem Wissen über die
Toolchain und Makefile zu verknüpfen. So kann der Ursprung des Fehlers schnell eingegrenzt werden. Nutzen sie die Ausgabe des Kompiliervorgangs und lösen Sie die auftretenden Fehler, um den Build-Prozess zu ermöglichen.
Tipp: Alle von der Toolchain benötigten Abhängigkeiten finden sich in dem Ordner
Aufgabe1/ps7/core0/build. Suchen Sie auch in dem Makefile nach Fehlern und achten
Sie auf Groß- und Kleinschreibung!
Der Ordner Aufgabe1/ps7/core0/cfg enthält die Header-Dateien und der Ordner
linker das Linkerscript.
Wichtig ist außerdem der Aufgabe1/ps7/core0/build Ordner. In den Dateien config.mk,
includes.mk und sources.mk festgelegt, welche Pfade beim Build-Prozess überhaupt
berücksichtigt und welche Compilerflags gesetzt werden. Neue Dateien in bisher nicht
inkludierten Pfaden müssen in den entsprechenden Dateien eingetragen werden. In dem
Ordner out finden sich geordnet nach den Aufgaben, Architektur und Core die entsprechenden Zielpfade für die aus dem Build-Prozess entstehenden Objekt-Dateien.
Immer wenn eine neue Terminal-Session gestartet wird müssen zunächst einige Umgebungsvariablen gesetzt werden, damit die benötigten Tools gefunden werden. Dazu
dienen hier die “setup-lm” Befehle, die die PATH-Variable um die gewünschten Tool-
Verzeichnisse erweitern und bei Bedarf Lizenzserver zu setzen.
```
setuplm lauterbach r_2020_09
setuplm gcc gccarmnoneeabi72018q2
```
Der Ordner Debug/ps7 im Oberverzeichnis enthält das Skript "start_amp_session.sh",
welches die Debug-Umgebung lädt. Zur Anwendung des Skripts wird ein Terminal in dem
Ordner ps7 geöffnet und der Befehl
```
./ start_amp_session.sh lauterbach[Lauterbachnummer]
```
ausgeführt. Die [Lauterbachnummer] muss angepasst werden und entspricht der Gruppennummer.
**Achtung:** Es kommt vor, dass die vorherige Lauterbach-Session auf dem Debugger nicht
ordnungsgemäß beendet wurde oder der Lauterbach von einem anderen Nutzer belegt
war. Dann wirft der Befehl zunächst den Fehler: Selected device already in use by... Dann bitte einmal prüfen ob wirklich der richtige Lauterbach angesprochen ist und nicht der einer
anderen Gruppe. Ein erneutes Ausführen dauert länger, sollte dann aber erfolgreich sein.
Nach dem erfolgreichen Kompilieren muss das Programm auf das Board geflasht werden. Dafür starten wir die Lauterbach Software ”Trace 32” wie oben beschrieben. Für jede
Aufgabe gibt es im Ordner Debug/ps7/ einen entsprechenden Unterordner, welcher ein
Lauterbach-Skript enthält. Diese kann über die Befehlszeile in Trace32 ausgeführt werden:
```
do Aufgabe1/zc706_onchip_trace.cmm
```
Generell arbeitet Trace32 vollständig skript-basiert und jedes GUI Kommando kann auch
in einem Skript eingesetzt werden. Dies können Sie sich für spätere Aufgaben merken um
wiederkehrende Befehle zu automatisieren.
Das zu Aufgabe 1 gehörige Skript sorgt dafür, dass das Board durch die Software geflasht
wird, sich aber keine weiteren Fenster in der Software öffnen. Ziel dieser Aufgabe ist das
Debuggen über printf. Nachdem Sie das den Befehl zum Flashen im richtigen Verzeichnis
ausgeführt haben, sollte sich ein Fenster ähnlich der Abbildung 5.3 öffnen. Das Programm
wird nun durch einen Klick auf “Go” gestartet. Sie können dieses Fenster nun ignorieren
und in einer freien Konsole die Verbindung zur Ausgabe des Boards aufbauen:
```
telnet idaser2net 800X
```
Der Port hängt von Ihrer Gruppennummer und dem verwendeten Lauterbach ab. Erset-
zen Sie das X durch die Nummer ihres Lauterbach-Debuggers. Das Board sollte Ihnen
jetzt jede Sekunde ein “ILL BE BACK” ausgeben.
Bei Überprüfung der Arbeitsergebnisse sollten Sie auftretende Fehler dem Linker oder
dem Compiler zuordnen können.
![Screenshot](img/jpg/lauterbach-aufgabe1-1.png) Abbildung 5.3.: Lauterbachumgebung zum Flashen des Boards in Aufgabe 1