RTOS-Konzepte · Teil 2
Echtzeit- & Betriebssysteme — Lernplattform
LERNFORTSCHRITT{{ doneCount }}/{{ total }}
● KOMMUNIKATION & ZEITSTEUERUNG IM RTOS

Wie Tasks reden, warten & reagieren

Vier Kernkonzepte aus der Vorlesung — anschaulich erklärt, mit echten interaktiven Simulationen wie im RTOS-Simulator, kommentiertem Code, Glossar und Quiz. Alles zum Lernen für die Klausur.

4Konzepte + Sim
Quiz & Fragen
A文Glossar EN→DE
🎛️
Simulationen bedienen
Regler ziehen, LEDs & Balken live beobachten — genau wie im rtos-edu-Simulator.
Quiz korrigiert sich
Antwort wählen, prüfen — richtig/falsch mit Erklärung sofort.
💡
Selbst antworten
Offene Fragen erst selbst beantworten, dann Musterlösung aufdecken.
00 · Wiederholung

Rückblick — was bisher geschah

Teil 2 baut auf den früheren Terminen auf. Klapp die Themen auf, die du auffrischen möchtest — dann geht es weiter mit den neuen Konzepten.

⚙️ Betriebssystem vs. EchtzeitbetriebssystemDurchsatz & Fairness — oder Determinismus & Fristen?
🖥️ Betriebssystem (OS)
Abstraktionsschicht + Ressourcenmanager. Verwaltet CPU, Speicher, Dateisystem. Ziel: hoher Datendurchsatz, Multitasking, flüssige Benutzererfahrung — Ressourcen werden „fair“ verteilt.
⏱️ Echtzeitbetriebssystem (RTOS)
Spezialisiert auf Determinismus (Vorhersehbarkeit) und strikte Einhaltung von Fristen (Hard Real-Time). Statt Fairness: strikt prioritätsbasiertes Scheduling, minimale Latenz.
🎯Kern: Ein RTOS ist nicht „schneller“, sondern pünktlicher. Es garantiert, dass eine kritische Aufgabe rechtzeitig fertig wird — auch wenn das insgesamt weniger Durchsatz bedeutet.
🗂️ Scheduling, Task-Lebenszyklus & TicksWer darf auf die CPU — und wann?

Ein CPU-Kern kann nur einen Task gleichzeitig ausführen. Der Scheduler entscheidet, welcher das ist. Zwei Grundmodelle:

Kooperativ
Tasks geben die CPU freiwillig ab.
lange, ungeteilte Blöcke
Präemptiv ← FreeRTOS
Das OS entzieht die CPU aktiv (nach Priorität/Zeit).
feine Zeitscheiben (Time Slicing)
Lebenszyklus eines Tasks
Neu Bereit Laufend Wartend (I/O) Suspendiert Beendet
„Bereit ⇄ Laufend“: Der Scheduler kann einen laufenden Task jederzeit zurück in die Ready Queue schieben (Preemption), sobald ein wichtigerer Task bereit ist.
💓
Ticks — der Herzschlag des OS. Ein Timer-Interrupt „tickt“ regelmäßig. In rtos-edu ist configTICK_RATE_HZ = 1000 → 1 Tick = 1 ms. Zeiten werden in Ticks gezählt — deterministisch & ohne teure Berechnungen mit echten Zeiteinheiten.
🧩 Der Simulator (rtos-edu) & TracingFreeRTOS · Pigweed · LVGL · Wayland — und Perfetto

Die Simulationsumgebung läuft ohne echte Hardware auf dem Linux-Rechner und stapelt vier Bausteine:

FreeRTOSEchtzeit-Kernel — Scheduler, Tasks, Semaphore, Timer
PigweedMiddleware-Abstraktion — typsichere C++-Schnittstelle über dem Kernel
LVGLGrafikbibliothek — das GUI (LEDs, Balken, Slider)
WaylandDisplay-Server-Protokoll — bringt das Fenster auf den Schirm
Tracing & Ablaufverfolgung → Perfetto
tasks_trace trace.bin decode_trace.py + ELF trace.json ui.perfetto.dev
Damit lassen sich Task-Wechsel, CPU-Auslastung, Sleep-Phasen und Signalzustände visuell auf einer Zeitachse analysieren. → Details im Abschnitt Tracing & Perfetto.
🔒 Konzepte aus Teil 1Tasks · Binäre Semaphore · Mutex · Counting Semaphore
🧵
Tasks / Threads
Ermöglichen Multitasking — scheinbar gleichzeitiges Ausführen. Der Scheduler bestimmt, wer wann läuft.
🔫
Binäre Semaphore
Warten auf ein Ereignis — wie ein Startschuss. Zustand rein binär: 0 nicht verfügbar, 1 verfügbar.
🚻
Mutex
Exklusiver Zugriff auf eine geteilte Ressource — wie ein Toilettenschlüssel. Besitzprinzip: nur wer sperrt, darf freigeben.
🅿️
Counting Semaphore
Verwaltet einen Pool aus mehreren identischen Ressourcen. Ein Zähler hält fest, wie viele noch frei sind.
01 · Überblick

Teil 2 im Überblick

Vier neue Konzepte — jeweils mit ihrer nativen FreeRTOS-API und der typsicheren Pigweed-Abstraktion, die im Simulator verwendet wird.

Konzept FreeRTOS (Native API) Pigweed-Abstraktion Beschreibung
Queues / Messaging xQueueSend() / xQueueReceive() pw_channel / pw_ring_buffer Module wie Channels für Datenströme statt generischer Queues
Timeouts / Delay vTaskDelay() pw_chrono::SystemClock std::chrono-ähnliche Typen für typsichere Zeitangaben (ms vs. Ticks)
Interrupts xSemaphoreGiveFromISR() pw_interrupt Vereinheitlicht das Handling von Interrupt-Kontexten
Software Timer xTimerCreate() pw_chrono::SystemTimer Objektorientierte Schnittstelle für Callbacks nach Zeitablauf
02 · Konzept · Queues

Queues / Messaging

Sicherer Datenaustausch zwischen Tasks — ein Task legt Nachrichten ab, ein anderer liest sie aus.

Das Konzept

Eine Queue (Warteschlange) ist ein Puffer, durch den zwei Tasks Nachrichten austauschen, ohne sich direkt zu kennen. Sie arbeitet nach dem FIFO-Prinzip: First In, First Out — was zuerst hineinkommt, geht zuerst wieder heraus.

Der Producer schreibt, der Consumer liest. Der Puffer entkoppelt beide: ist der Consumer kurz langsamer, füllt sich die Queue, statt dass Daten verloren gehen.

🏭 Analogie · Fließband
🤖
Producer
📦 📦 📦
📥
Consumer

Ein Roboter legt Bauteile aufs Band, ein anderer nimmt sie am Ende ab. Das Band puffert, wenn der Verpacker kurz langsamer ist.

Interaktive Simulation pw::InlineQueue Messaging ▶ läuft live
🏭Producer
idle
Prio 2 · push()
▸ IN · tail (neu)head (alt) · OUT ▸
message_queue · FIFO · cap 8 · verworfen: 0
data_ready0 binäre Semaphore · Klingel
📥Consumer
idle
Prio 1 · pop()
Queue Fill Level0 / 8
Received Value0
Aktivität — Zeitachse läuft nach links ▮ send▮ receive▮ drop
P
C
Send-Period500 ms
Processing300 ms
💡 Probier's aus: Stell Send-Period klein (schneller Producer) und Processing groß (langsamer Consumer) — die Queue füllt sich. Ist sie voll (8/8), verwirft der Producer neue Werte, statt zu überschreiben.
👨‍💻

Der Code — Schritt für Schritt

messaging.cc — Deklarationen1 / 4
static constexpr size_t kQueueCapacity = 8;

struct Message {
  int value;
  uint32_t seq;      // fortlaufende Nummer
};

static pw::InlineQueue<Message, kQueueCapacity> message_queue;
static pw::sync::Mutex           queue_mutex;   // schützt die Queue
static pw::sync::BinarySemaphore data_ready;    // Ereignis-Signal
message_queue
Die eigentliche FIFO-Warteschlange mit fester Kapazität 8 (kein Heap — statisch reserviert).
queue_mutex
Ein Mutex sichert die Queue: nur ein Task greift gleichzeitig darauf zu (keine Datenkorruption).
data_ready
Eine binäre Semaphore als Klingel: „Es liegt etwas bereit!“ — weckt den Consumer.
producer_loop() — schreibt2 / 4
while (true) {
  // 1) warten (Sende-Periode aus dem Slider)
  pw::this_thread::sleep_for(
    pw::chrono::SystemClock::for_at_least(
      std::chrono::milliseconds(slider_produce.get_value())));

  value = (value + 13) % 101;      // Pseudowert 0..100

  // 2) unter Mutex-Schutz in die Queue legen
  {
    std::lock_guard lock(queue_mutex);
    if (!message_queue.full()) {
      message_queue.push(Message{value, seq++});
      queue_fill_bar.set_value(message_queue.size());
    }
  }

  data_ready.release();            // 3) Consumer wecken
  led_producer.on(0x0d, 0x6e, 0xfd);   // blau leuchten
}
1
Schlafen statt blockieren. sleep_for gibt die CPU frei — andere Tasks laufen währenddessen. Die Wartezeit kommt live vom Slider.
2
Kritischer Abschnitt. std::lock_guard sperrt den Mutex und gibt ihn beim Verlassen des { }-Blocks automatisch frei (RAII). full() verhindert Überlauf.
3
Signal geben. release() setzt die Semaphore auf 1 — der wartende Consumer wird aufgeweckt. In der Simulation siehst du data_ready kurz auf 1 springen.
consumer_loop() — liest3 / 4
while (true) {
  data_ready.acquire();            // 1) auf Signal warten (blockiert)

  Message msg{};
  bool got = false;
  {
    std::lock_guard lock(queue_mutex);
    if (!message_queue.empty()) {
      msg = message_queue.front();  // 2) ältestes Element (FIFO)
      message_queue.pop();
      got = true;
      queue_fill_bar.set_value(message_queue.size());
    }
  }

  if (got) {
    led_consumer.on(0x1a, 0xc2, 0x55);   // grün
    value_bar.set_value(msg.value);      // 3) anzeigen
  }
}
1
Warten auf die Klingel. acquire() blockiert den Consumer, bis der Producer release() ruft. Solange verbraucht er keine CPU.
2
FIFO auslesen. front() liefert das älteste Element, pop() entfernt es — alles wieder unter Mutex-Schutz.
!
Merke: Eine binäre Semaphore zählt nicht mit. Legt der Producer mehrere Werte ab, bevor der Consumer wach wird, „verschmelzen“ die Signale — der Consumer holt pro Signal genau ein Element. Für exaktes Mitzählen nutzt man eine Counting Semaphore.
main() — Tasks starten4 / 4
// Producer: höhere Priorität (2), Consumer: niedriger (1)
prod_opts.set_name("Producer").set_priority(2);
cons_opts.set_name("Consumer").set_priority(1);

pw::thread::DetachedThread(prod_opts, [] { producer_loop(); });
pw::thread::DetachedThread(cons_opts, [] { consumer_loop(); });

vTaskStartScheduler();   // ab hier übernimmt der Scheduler
🎚️
Prioritäten & Scheduler. Beide Tasks werden als DetachedThread gestartet. vTaskStartScheduler() übergibt die Kontrolle an FreeRTOS — ab jetzt entscheidet der präemptive Scheduler nach Priorität, wer läuft.
03 · Konzept · Timeouts

Timeouts / Delay

Zeitgesteuert pausieren — und begrenzt warten: „Ich warte eine Weile, aber nicht ewig.“

Das Konzept

Delay (sleep_for): Ein Task legt sich für eine feste Zeit schlafen und gibt die CPU frei — kein „Busy Waiting“, das Rechenzeit verschwendet.

Timeout (try_acquire_for): Ein Task wartet auf ein Signal — aber höchstens eine gewählte Zeit. Kommt es rechtzeitig → weiter. Sonst → Timeout-Reaktion (z. B. Alarm).

🩺 Analogie · Watchdog
💓
Signal alle 2 s?

Ein Herzschlag-Monitor schlägt Alarm, wenn nicht rechtzeitig ein Signal kommt. Oder: die Kaffeemaschine, die nach Inaktivität in den Standby wechselt.

Interaktive Simulation pw_chrono Timeouts & Delay ▶ läuft live
📤Sender
idle
Prio 2 · release()
Signal nach
400 ms
Watcher
wartet
Prio 1 · try_acquire_for
🏁 Rennen: Signal vs. TimeoutWatcher wartet …
0 ms0 / 600 msTimeout ▮
0
✓ rechtzeitig
0
✗ Timeout
Verlauf
Timeout (Watcher)600 ms
Delay (Sender)400 ms
💡 Delay < Timeout → Signal kommt rechtzeitig (grün). Delay > Timeout → der Watcher gibt auf, bevor das Signal da ist (rot).
👨‍💻

Der Code — Schritt für Schritt

sender_loop() — sendet nach Delay1 / 2
while (true) {
  // warten (Delay aus dem Slider) — CPU wird freigegeben
  pw::this_thread::sleep_for(
    pw::chrono::SystemClock::for_at_least(
      std::chrono::milliseconds(slider_delay.get_value())));

  signal.release();                 // Semaphore 0 -> 1
  led_sender.on(0x0d, 0x6e, 0xfd);  // blau
}
i
release(). Gibt den Semaphor frei: war der Zustand vorher 0, wird er jetzt auf 1 gesetzt. Der wartende Watcher darf weiterlaufen.
watcher_loop() — wartet mit Timeout2 / 2
while (true) {
  const auto timeout = pw::chrono::SystemClock::for_at_least(
      std::chrono::milliseconds(slider_timeout.get_value()));

  const bool acquired = signal.try_acquire_for(timeout);

  if (acquired) {
    led_watcher.on(0x1a, 0xc2, 0x55);   // grün: rechtzeitig
  } else {
    led_watcher.on(0xe5, 0x39, 0x35);   // rot: Timeout
  }
}
try_acquire_for(timeout) ist der „Ich warte eine Weile, aber nicht ewig“-Versuch, den Semaphor zu sperren. Du übergibst eine maximale Wartezeit. Rückgabe true = rechtzeitig bekommen, false = Timeout. Genau diese beiden Fälle siehst du oben als grün/rot.
04 · Konzept · Interrupts

Interrupts

Sofort auf externe Ereignisse reagieren — die Hardware unterbricht die CPU, ohne dass ständig „nachgefragt“ werden muss.

Das Konzept

Statt in einer Schleife immer wieder zu fragen „Ist schon was passiert?“ (Polling) meldet sich die Hardware selbst. Ein Interrupt unterbricht sofort den laufenden Code und springt in eine ISR (Interrupt Service Routine).

Die goldene Regel: eine ISR muss extrem kurz sein. Sie erledigt nur das Nötigste und delegiert die eigentliche Arbeit an einen normalen Task — über eine Semaphore (…FromISR()).

📖 Analogie · Lesen & Telefon
📖
Task läuft
📞
Interrupt!
🔖
merken & weiter

Du liest ein Buch. Das Telefon klingelt — du merkst dir die Seite (Kontext sichern), gehst kurz ran (ISR), legst auf und liest weiter. Die lange Aufgabe („zurückrufen & plaudern“) machst du später in Ruhe.

Interaktive Simulation ISR → deferred Handler-Task ▶ läuft live
⚙️Main-Task
läuft
preempt
Hardware
🔔
IRQ-Quelle
ISR
AUS
kurz! …FromISR()
give
FromISR
Handler-Task
AUS
macht die Arbeit
0
offen (pending)
0
bearbeitet
🧵 CPU-Zeitachse — wer rechnet gerade?Zeit →
Main
ISR
Handler
Main rechnet — bis ein Interrupt ihn unterbricht. Die ISR ist nur ein kurzer Strich: sie signalisiert, dann übernimmt der Handler-Task die eigentliche Arbeit — danach läuft Main weiter.
Auto-IRQ-Periode1400 ms
💡 Drück ⚡ Interrupt auslösen mehrfach schnell: Die ISR blinkt jeweils nur ganz kurz, staut die Ereignisse als pending — und der Handler-Task arbeitet sie danach in Ruhe ab.
👨‍💻

Der Code — Schritt für Schritt

isr.cc — die Interrupt-Routine1 / 2
// Läuft im Interrupt-Kontext — MUSS extrem kurz sein!
void OnButtonInterrupt() {
  BaseType_t higher_prio_woken = pdFALSE;

  // NUR signalisieren — keine langen Berechnungen hier!
  xSemaphoreGiveFromISR(event_signal, &higher_prio_woken);

  // Falls ein wichtigerer Task geweckt wurde: sofort umschalten
  portYIELD_FROM_ISR(higher_prio_woken);
}
⚠️
Sonder-API im ISR-Kontext. Aus einer ISR heraus darf man nur die …FromISR()-Varianten aufrufen. Die normalen (blockierenden) Funktionen würden das System im Interrupt-Kontext zum Absturz bringen.
portYIELD_FROM_ISR. Weckt give einen höher-priorisierten Task, sorgt dieser Aufruf dafür, dass der Scheduler direkt nach der ISR zu ihm wechselt — statt erst zum nächsten Tick zu warten. Minimale Latenz.
handler_task() — die eigentliche Arbeit2 / 2
while (true) {
  // Blockiert, bis die ISR das Signal gibt (0 % CPU beim Warten)
  event_signal.acquire();

  // Ab hier: normaler Task-Kontext — hier darf es dauern
  led_handler.on(0x12, 0xa1, 0x50);
  process_event();             // lange Berechnung ist ok
}
🔐
SpinLock — für Daten, die ISR & Task teilen. Ein Mutex darf im ISR-Kontext nicht verwendet werden (er kann blockieren). Für kurze kritische Abschnitte, die auch eine ISR betreten kann, nimmt man einen pw::sync::InterruptSpinLock: er blockiert nicht, sondern deaktiviert kurz die Interrupts und „dreht Leerlaufrunden“, bis er frei ist.
05 · Konzept · Software Timer

Software Timer

Eine Funktion (Callback) nach Ablauf einer Zeit ausführen — ohne dafür einen ganzen Task zu blockieren.

Das Konzept

Ein Software Timer ruft nach Ablauf einer Frist automatisch einen Callback auf. Der Clou: es läuft keine eigene Warteschleife — der Timer-Dienst des Kernels verwaltet viele Timer effizient gemeinsam.

🔁 Periodisch
feuert immer wieder (z. B. Blinken, Sensor pollen)
1️⃣ One-Shot
feuert genau einmal (z. B. Timeout, Debounce)
⏰ Analogie · Wecker
Du stellst den Wecker und schläfst weiter — du musst nicht selbst auf die Uhr starren. Er klingelt von allein. „Snooze“ = periodisch, einmal aufstehen = One-Shot.

Der große Vorteil: dein Task kann in der Zwischenzeit etwas völlig anderes tun (oder schlafen) — die CPU ist frei.

Interaktive Simulation pw_chrono::SystemTimer ▶ läuft live
2.0s
bis Callback
Callback
AUS
🔔 fired!
0
Auslösungen
läuft periodisch …
Auslösungen über die Zeit▮ = 1× Callback
jetzt
Timer-Periode2000 ms
💡 Im periodischen Modus füllt sich der Ring immer wieder und der Callback feuert erneut. Im One-Shot-Modus feuert er genau einmal und stoppt.
👨‍💻

Der Code — Schritt für Schritt

timer.cc — anlegen & starten1 / 2
// Der Callback — wird vom Timer-Dienst aufgerufen
void OnTimerExpired(pw::chrono::SystemClock::time_point) {
  fire_count++;
  led_callback.toggle();          // z.B. LED umschalten
}

// Timer anlegen (SystemTimer bindet den Callback)
pw::chrono::SystemTimer timer(OnTimerExpired);

// EINMALIG nach 2 s feuern (One-Shot):
timer.InvokeAfter(std::chrono::milliseconds(2000));
i
InvokeAfter plant den Callback einmalig nach einer relativen Zeit. InvokeAt(time_point) plant ihn zu einem absoluten Zeitpunkt.
periodisch nachlegen2 / 2
// Für periodisches Verhalten: im Callback neu planen
void OnTick(pw::chrono::SystemClock::time_point) {
  do_periodic_work();
  timer.InvokeAfter(kPeriod);   // sich selbst neu einplanen
}

// Laufenden Timer vorzeitig abbrechen:
timer.Cancel();
🧠
Callback ≠ Task. Der Callback läuft im Kontext des Timer-Dienstes und sollte deshalb — wie eine ISR — kurz sein und nicht blockieren. Lange Arbeit delegiert man an einen Task (Semaphore geben), genau wie bei Interrupts.
06 · Werkzeug · Tracing

Tracing & Perfetto

Was passiert wirklich zur Laufzeit? Mit Tracing zeichnest du Task-Wechsel & Ereignisse auf und analysierst sie auf einer Zeitachse.

Ein tasks_trace-Demo schreibt zur Laufzeit tokenisierte Trace-Ereignisse in eine kompakte Binärdatei. Weil die Ereignisnamen nur als Zahlen (Token) gespeichert werden, ist das extrem sparsam — die Klartext-Namen stecken in der .elf-Datei und werden erst beim Dekodieren wieder zusammengeführt.

Die Tracing-Pipeline
▶️
1 · Aufnehmen
Demo läuft, sammelt Events
tasks_trace
💾
2 · Rohdaten
tokenisierte Binärdatei
trace.bin
🔓
3 · Dekodieren
Token + ELF → Klartext
decode_trace.py
📊
4 · Analysieren
Zeitachse im Browser
ui.perfetto.dev
# 1) Demo bauen & laufen lassen → schreibt trace.bin # 2) Binärdatei mit Hilfe der ELF-Symbole dekodieren python scripts/decode_trace.py trace.bin build/tasks_trace.elf > trace.json # 3) trace.json auf ui.perfetto.dev öffnen (per Drag & Drop)
So sieht ein Trace in Perfetto aus (schematisch)
Producer
Consumer
Idle
0 ms50 ms100 ms
Jede Zeile ist ein Task, jeder Balken eine „laufend“-Phase. So erkennst du sofort, wer wann rechnet, wie lange Tasks warten und wie viel Zeit im Idle-Task verbracht wird (CPU-Auslastung).
PW_TRACE_INSTANT
Ein Zeitpunkt-Marker — „hier ist etwas passiert“ (z. B. ISR gefeuert).
PW_TRACE_START / END
Markiert Beginn und Ende einer Phase → wird zum Balken auf der Zeitachse.
PW_TRACE_SCOPE
Bequemer Automatismus: misst eine Phase über den Gültigkeitsbereich (RAII) — Start/Ende automatisch.
…_DATA
Wie oben, aber mit Nutzdaten (z. B. dem übertragenen Wert) fürs spätere Auswerten.
07 · Nachschlagen

Fachwort-Glossar

Englischer Fachbegriff, deutsche Übersetzung und eine kurze Erklärung. Durchsuch- und filterbar.

🔍 {{ glossCount }} Treffer
{{ g.en }}
🇩🇪{{ g.de }}
{{ g.descEl }}
08 · Testen

Quiz

Antwort wählen, prüfen — du bekommst sofort richtig/falsch mit Erklärung.

{{ quizCorrect }}/{{ quizTotal }}
richtig
{{ quizAnswered }} beantwortet
{{ qq.n }} {{ qq.tag }}
{{ qq.q }}
{{ qq.resultIcon }}
{{ qq.resultTitle }}
{{ qq.exp }}
09 · Vertiefen

Offene Fragen

Formuliere zuerst selbst eine Antwort — dann decke die Musterlösung auf und vergleiche. Ideal fürs Klausurtraining.

{{ oq.n }} {{ oq.tag }}
{{ oq.q }}
✓ Musterlösung
{{ oq.a }}
10 · Anwenden

Übungsaufgaben

Der Übungszettel zu Teil 2 — implementiere die Konzepte selbst im RTOS-Simulator und analysiere sie mit Perfetto.

🎯
Ziel der Übung: Queues, Timeouts, Interrupt-Behandlung und Software-Timer in kleinen Projekten selbst implementieren — und dabei verstehen, wie diese Mechanismen funktionieren.
1
Implementierung der RTOS-Konzepte
Je ein eigenes kleines Projekt im Simulator, orientiert an den Vorlesungsbeispielen
🏭 Queues / Messaging
Eine Task schreibt Nachrichten über eine Queue, ein anderer Task liest sie aus. → Konzept
⏳ Timeouts / Delay
Eine Task periodisch schlafen lassen. → Konzept
📞 Interrupts
Einen wartenden Task aus einem Interrupt-Kontext heraus signalisieren. → Konzept
⏰ Software Timer
Einen einmaligen oder periodischen Timer erstellen, der einen Callback ausführt. → Konzept
💡
Tipp: Mach deine Implementierungen gut nachvollziehbar — z. B. durch gezielte Bildschirmausgaben oder das Verändern von Anzeigewerten (LEDs, Balken) im Simulator.
2
Trace-Aufnahme & Analyse mit Perfetto
Zeitliches Verhalten der neuen Konzepte untersuchen
1
Tracing aktivieren. Ergänze deine Implementierungen aus Aufgabe 1 so, dass Trace-Ereignisse aufgezeichnet werden (falls noch nicht geschehen).
2
Aufnahme. Starte den Simulator mit deinem Projekt und führe eine kurze Aufnahme durch.
3
Analyse in Perfetto. Lade die Aufnahmedatei in Perfetto hoch und analysiere die Ausführungszeiten.
🔎 Leitfrage: Lassen sich Queue-Transfers, Timer-Callbacks und die Reaktionszeit auf Interrupts im Zeitstrahl klar voneinander abgrenzen? → siehe Tracing & Perfetto.
🎓
Geschafft — du kennst jetzt alle vier Konzepte

Queues, Timeouts, Interrupts und Software Timer — mit Simulationen, Code und Quiz. Für die Klausur: geh das Quiz und die offenen Fragen so oft durch, bis du dir sicher bist.