Added mkdocs skript with corresponding build instruction in the README

This commit is contained in:
tims
2025-10-15 12:16:58 +02:00
parent 95b0db1977
commit 3b52bd9e15
86 changed files with 1647 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
# 3. Grundlagenwissen
## 3.1. Echtzeitsysteme
Ein Echtzeitsystem wird nicht durch seine Schnelligkeit definiert, sondern durch das Einhalten von Zeitschranken und damit verbundene Rechtzeitigkeit. Das Ergebnis der Berechnung eines Echtzeitsystems ist nur dann brauchbar, wenn es rechtzeitig vorliegt. Echtzeitanforderungen können in harte und weiche Echtzeitanforderungen unterschieden werden. Entsprechend Ihrer Betitelung sind harte Anforderungen unter allen Umständen einzuhalten, da sonst das Ergebnis des Systems als nicht brauchbar gilt. Als Beispiel hierfür gilt die Auslösung des Airbags im Auto. Weiche Echtzeitanforderungen hingegen werden durch die bei ihrer Verletzung verursachten Kosten definiert. Je stärker die vorgegebene Zeitschranke verletzt wird, desto höher fallen die damit verbundenen Kosten in Form
von Rechenzeit oder materiellem Verlust aus. Die Eigenschaft der Gleichzeitigkeit impliziert die korrekte Verarbeitung paralleler Arbeitsabläufe. Als Beispiel kann die Regelung der Lage des im Praktikum verwendeten Roboters gesehen werden, der Bewegungssensordaten und Motorsteuerung gleichzeitig bearbeiten muss. Diese Aufgaben werden in Form
von Tasks umgesetzt. Wichtig ist dabei, dass ein höherpriorer Prozess einen niederprioren Prozess verdrängen kann (preemptiv), und dass das System nicht überlastet ist. So wird Vorhersagbarkeit garantiert.
## 3.2. Debugging
Es gibt nicht nur eine bestimmte Methode des Debuggings, sondern mehrere Möglichkeiten. Sie unterscheiden sich in ihrer Leistungsfähigkeit, dem Anwendungsgebiet, den
Kosten, den Anforderungen an die Hardware und auch in der Pinanzahl. Außerdem gibt
es große Unterschiede in ihrem Einfluss auf das Zeitverhalten des Debugger (zu debuggendes System). Die einfachste Möglichkeit einen Einblick in ein laufendes Programm zu
bekommen, ist die Ausgabe von Variablen zur Laufzeit über eine serielle Schnittstelle. Das
Printf Debugging ist simpel und reicht für einfache kleine Programme ohne Taskstruktur und ohne strikte Anforderungen an Echtzeitfähigkeit aus. Die nächst-mächtigere Methode des Debuggings stellt JTAG-Debugging dar. Es ermöglicht die Steuerung des Programmablaufs via Single-Stepping, also das kontrollierte Anhalten des Programms und
das Setzen von Halte-, Verfolgungs- und Überwachungspunkten. Außerdem ermöglicht es
den vollständigen Lese- und Schreibzugriff auf den Speicher des Programms. Mit diesen
Werkzeugen lassen sich einfach Fehler finden und beheben. Problematisch wird es dann,
wenn unvorhergesehene Fehler zur Laufzeit auftreten, deren Ursprung und Wirkung im
Code entweder zeitlich oder programmierhierarchisch weit auseinander liegen. Die bisher bekannten Debugmethoden können ihre Möglichkeiten aufgrund für den Menschen
schwierig erkennbarer Zusammenhänge nicht ausspielen, was die Fehlersuche sehr erschwert. Außerdem ist es auch hier nahezu unmöglich, das Zeitverhalten des Programms
umfangreich zu analysieren. An dieser Stelle hilft es Trace-Tools als Debugmethode zu
verwenden. Zusätzlich zur Steuerung der CPU wird nun der Programmablauf teilweise
oder vollständig aufgezeichnet. Aus diesem kann dann wahlweise auf Assemblerebene
bis hin zum Ablauf in der Hochsprache nachvollzogen werden in welcher Reihenfolge
das Programm ablief. Diese Daten helfen zu rekonstruieren wo das Programm anders
als gewünscht ablief und ermöglichen es den Stand des Programms vor dem Absturz zu
betrachten und damit auch eine mögliche Fehlerquelle zurück zuschließen.
## 3.2.1 Debugging-Prozess
Um Programme zu debuggen, sollte zunächst definiert sein, was ein Fehler ist und wie
an ihn herangegangen wird. Der Begriff Fehler ist im Deutschen mehrdeutig belegt und
lässt sich mit Hilfe der englischen Begriffe differenzierter betrachten (siehe Abbildung
3.1). Ein Error ist ein nicht korrekt programmierter Code oder eine falsch implementierte
Nutzeranforderung. Dieser Error im Programmcode kann einen Fault auslösen. Es kann
sich zum Beispiel um einen Speicherüberlauf handeln. Der Fault muss nicht nach außen
sichtbar sein. Das extern zu beobachtende Fehlverhalten des Systems wird Failure genannt.
Ist ein Failure erkannt worden, muss die Stelle im Quellcode gefunden werden, die den
Fault auslöst und den Error beschreibt. Die Ursache des Fault muss analysiert und korrigiert werden. Sollten mehrere Fehlverhalten gleichzeitig auftreten, deren Symptome sich
überlagern, kann es vorkommen, dass die Betrachtung eines einzelnen nicht funktionierenden Programmteils alleine nicht zur Lösung des Problems führt. An dieser Stelle kann
viel Zeit gespart werden, indem nicht sofort versucht wird herauszufinden was nicht rich-
tig arbeitet, sondern was überhaupt funktioniert. Je konsequenter das Programm in modularisierter Form geschrieben wurde, desto einfacher und schneller geht dieser Schritt
vonstatten. Es ist möglich Eingabedaten in ihrer Größe oder in ihrem Inhalt zu variieren,
um ihren Einfluss auf Fehler zu untersuchen. Es sollten Hypothesen zur Fehlerursache
aufgestellt und das Programm systematisch darauf getestet werden. Sofern es sich nicht
um triviale Fehler handelt, ist es sinnvoll, das Wissen um die Ursache des Fault festzuhalten, um den Hergang des Problems sowie seine Lösung zu dokumentieren.
## 3.2.2 Grundlagen des Debuggens eingebetteter Systeme
Debugging in der Softwareentwicklung für Desktopanwendungen ist wesentlich zugänglicher und komfortabler als im Kontext der eingebetteten Systeme. So programmieren
die meisten Anwendungsentwickler auf den Systemen, auf denen die von ihnen entwickelte Software später auch ausgeführt wird. Die Steuerung des Programmablaufs, das
Betrachten von Variablen und andere Debugwerkzeuge sind ohne große Umwege nutzbar. Um eingebettete Systeme zu programmieren, kommt oft die Technik des Cross-Compilings und des Cross-Debuggings zum Einsatz. Es wird also nicht auf der Zielhardware
kompiliert und debuggt, sondern auf einem Anwendungscomputer. Das zu programmierende System hat eventuell nicht ausreichend leistungsfähige Hardware, um ein Anwenderbetriebssystem samt Entwicklungsumgebung auszuführen oder es ist schlicht nicht
gewünscht das System zu beeinflussen. Auch die Architektur der Systeme unterscheidet
sich für gewöhnlich. Diese Trennung von Entwicklungsplattform und Laufzeitplattform
erschwert die Beobachtbarkeit und Steuerbarkeit eingebetteter Systeme und verkompliziert somit deren Debugging. Dennoch ist die Anwendung von Debugging notwendig,
weil es unter Umständen zu Fehlern kommt, die erst während der Laufzeit des Systems
auftreten, deren Entstehung aus dem Code nicht ersichtlich ist oder das Projekt zu umfangreich ist.
![Screenshot](img/png/error-fault-failure.png) Abbildung 3.1.: Entwicklung eines Fehlers: Error->Fault->Failure