

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Grundlagen zum FreeRTOS-Kernel
<a name="dev-guide-freertos-kernel"></a>

Der FreeRTOS-Kernel ist ein Echtzeitbetriebssystem, das zahlreiche Architekturen unterstützt. Die Grundlagen sind ideal für den Aufbau eingebetteter Mikrocontroller-Anwendungen. Es bietet:
+ Einen Multitasking-Scheduler.
+ Mehrere Speicherzuweisungsoptionen (einschließlich der Möglichkeit, vollständig statisch zugeordnete Systeme zu erstellen). 
+ Primitiven für die Koordination zwischen den Tasks, einschließlich Task-Benachrichtigungen, Nachrichtenwarteschlangen, verschiedenen Arten von Semaphoren sowie Stream- und Nachrichtenpuffer.
+ Support für symmetrisches Multiprocessing (SMP) auf Mehrkern-Mikrocontrollern.

Der FreeRTOS-Kernel führt keine nicht-deterministischen Operationen aus (z. B. das Durchlaufen einer verknüpften Liste, innerhalb eines kritischen Abschnitts oder Interrupts). Der FreeRTOS-Kernel enthält eine effiziente Software-Timer-Implementierung, die keine CPU-Zeit verbraucht – es sei denn, ein Timer benötigt ein Servicing. Blockierte Aufgaben erfordern keine zeitaufwändige regelmäßige Wartung. Direct-to-taskBenachrichtigungen ermöglichen eine schnelle Signalisierung von Aufgaben, praktisch ohne RAM-Overhead. Sie können in den meisten Szenarien zwischen Aufgaben und interrupt-to-task Signalisierung verwendet werden.

Der FreeRTOS-Kernel ist so konzipiert, dass er klein, einfach und leicht einzusetzen ist. Ein typisches binäres RTOS-Kernel-Image ist zwischen 4000 bis 9000 Byte groß.

[Die meiste up-to-date Dokumentation zum FreeRTOS-Kernel finden Sie unter FreeRTOS.org.](https://freertos.org/) [*FreeRTOS.org bietet eine Reihe detaillierter Tutorials und Anleitungen zur Verwendung des FreeRTOS-Kernels, darunter eine FreeRTOS FreeRTOS *[Kernel-Schnellstartanleitung und die ausführlichere RTOS-Implementierung in der FreeRTOS-Dokumentation](https://freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/02-Quick-start-guide).](https://freertos.org/Documentation/02-Kernel/05-RTOS-implementation-tutorial/01-RTOS-implementation)

# Der FreeRTOS-Kernel-Scheduler
<a name="freertos-kernel-scheduler"></a>

Eine Embedded-Anwendung, die RTOS verwendet, kann als eine Reihe von unabhängigen Tasks strukturiert werden. Jeder Task wird in einem eigenen Kontext ausgeführt, ohne Abhängigkeit von anderen Tasks. In der Anwendung wird immer nur ein Task gleichzeitig ausgeführt. Der Echtzeit-RTOS-Scheduler bestimmt, wann die einzelnen Tasks ausgeführt werden sollen. Jeder Task ist mit einem eigenen Stack ausgestattet. Wenn ein Task ausgelagert wird, damit ein anderer Task ausgeführt werden kann, wird der Ausführungskontext des Tasks im Task-Stack gespeichert, sodass er wiederhergestellt werden kann, wenn derselbe Task später wieder zur Ausführung geladen wird. 

Um ein deterministisches Echtzeitverhalten zu ermöglichen, ermöglicht der FreeRTOS Task-Scheduler, dass Tasks strikte Prioritäten zugewiesen werden. RTOS stellt sicher, dass der ausführbare Task mit der höchsten Priorität Verarbeitungszeit erhält. Dies erfordert die Aufteilung der Verarbeitungszeit zwischen Tasks mit gleicher Priorität, wenn diese gleichzeitig ausgeführt werden können. FreeRTOS erstellt außerdem einen Leerlauf-Task, der nur ausgeführt wird, wenn keine anderen Tasks zur Ausführung bereit sind.

# Zuweisung von Kernelspeicher
<a name="kernel-memory-allocation"></a>

Der RTOS-Kernel benötigt RAM, wenn ein Task, eine Warteschlange oder ein anderes RTOS-Objekt erstellt wird. Das RAM kann folgendermaßen zugewiesen werden:
+ Statisch zur Kompilierungszeit
+ Dynamisch aus dem RTOS-Heap, über die RTOS-API-Objekterstellungsfunktionen

Bei der dynamischen Erstellung von RTOS-Objekten ist die Verwendung der Funktionen `malloc()` und `free()` aus der der Standard-C-Bibliothek aus verschiedenen Gründen nicht immer sinnvoll:
+ Sie sind möglicherweise auf Embedded-Systemen nicht verfügbar
+ Sie beanspruchen wertvollen Code-Speicherplatz
+ Sie sind in der Regel nicht Thread-sicher
+ Sie sind nicht deterministisch

Aus diesen Gründen befindet sich Speicherzuweisungs-API im portablen Layer von FreeRTOS. Der portable Layer befindet sich außerhalb der Quelldateien, die die Kern-RTOS-Funktionalität implementieren. So können Sie eine anwendungsspezifische Implementierung bereitstellen, die für das von Ihnen entwickelte Echtzeit-System geeignet ist. Wenn der RTOS-Kernel RAM benötigt, ruft er `pvPortMalloc()` statt `malloc()`() auf. Wenn RAM freigegeben wird, ruft der RTOS-Kernel `vPortFree()` statt `free()` auf.

# Anwendungsspeicher verwalten
<a name="application-memory-management"></a>

Wenn Anwendungen Speicher benötigen, können sie ihn aus dem FreeRTOS-Heap zuweisen. FreeRTOS bietet mehrere Heap-Management-Schemata an, die sich in ihrer Komplexität und ihren Funktionen unterscheiden. Sie können außerdem Ihre eigene Heap-Implementierung bereitstellen.

Der FreeRTOS-Kernel enthält fünf Heap-Implementierungen:

**`heap_1`**  
Dies ist die einfachste Implementierung. Sie erlaubt nicht, dass Speicher freigegeben wird.

**`heap_2`**  
Lässt die Freigabe des Speichers zu, lässt jedoch keine Zusammenführung benachbarter freier Blöcke zu.

**`heap_3`**  
Wrapper für die Standardfunktionen `malloc()` und `free()` (aus Gründen der Thread-Sicherheit).

**`heap_4`**  
Führt benachbarte freie Blöcke zusammen, um Fragmentierung zu vermeiden. Enthält eine Option zur absoluten Platzierung von Adressen.

**`heap_5`**  
Ist ähnlich wie heap\$14. Kann den Heap über mehrere, nicht benachbarte Speicherbereiche verteilen.

# Inter-Task-Koordination
<a name="inter-task-coordination"></a>

Dieser Abschnitt enthält Informationen über FreeRTOS-Primitiven.

**Topics**
+ [Warteschlangen](#inter-task-queues)
+ [Semaphoren und Mutexe](#inter-task-semaphones)
+ [Direct-to-task Benachrichtigungen](#direct-task-notifications)
+ [Stream-Puffer](#rtos-stream-buffer)
+ [Nachrichtenpuffer](#rtos-message-buffer)

## Warteschlangen
<a name="inter-task-queues"></a>

Warteschlangen sind die primäre Form der Inter-Task-Kommunikation. Sie können verwendet werden, um Nachrichten zwischen Tasks und zwischen Interrupts und Tasks zu senden. In den meisten Fällen werden sie als Thread-sichere First In First Out (FIFO)-Puffer verwendet, wobei neue Daten an das Ende der Warteschlange gesendet werden. (Daten können auch an den Anfang der Warteschlange gesendet werden.) Nachrichten werden als Kopie über Warteschlangen gesendet. Das heißt, die tatsächlichen Daten (die ein Zeiger auf größere Puffer sein können) werden in die Warteschlange kopiert – und nicht nur ein Verweis auf die Daten.

In APIs der Warteschlange kann eine Blockzeit angegeben werden. Wenn ein Task versucht, aus einer leeren Warteschlange zu lesen, wird der Task in den Status "Blocked" versetzt, bis Daten in der Warteschlange verfügbar sind oder die Blockierungsdauer abgelaufen ist. Tasks im Status "Blocked" verbrauchen keine CPU-Zeit, sodass andere Tasks ausgeführt werden können. Ähnlich verhält es sich, wenn ein Task versucht, in eine volle Warteschlange zu schreiben. Dann wird der Task in den Status "Blocked" versetzt, bis Platz in der Warteschlange verfügbar wird oder die Blockierungsdauer verstrichen ist. Wenn sich mehr als ein blockierter Task in einer Warteschlange befindet, wird zuerst der Task mit der höchsten Priorität freigegeben. 

Andere FreeRTOS-Primitive, wie direct-to-task Benachrichtigungen und Stream- und Nachrichtenpuffer, bieten in vielen gängigen Entwurfsszenarien einfache Alternativen zu Warteschlangen. 

## Semaphoren und Mutexe
<a name="inter-task-semaphones"></a>

Der FreeRTOS-Kernel bietet binäre Semaphoren, zählende Semaphoren und Mutexe für den gegenseitigen Ausschluss und für Synchronisationszwecke.

Binärsemaphore können nur zwei Werte haben. Sie sind eine gute Wahl bei der Implementierung der Synchronisation (entweder zwischen Tasks oder zwischen Tasks und einem Interrupt). Zählende Semaphoren haben mehr als zwei Werte. Sie ermöglichen es vielen Tasks, Ressourcen gemeinsam zu nutzen oder komplexere Synchronisationsoperationen durchzuführen.

Mutexe sind binäre Semaphoren, die einen Vererbungsmechanismus für Prioritäten beinhalten. Das bedeutet Folgendes: Wenn ein Task mit hoher Priorität blockiert ist, währen er versucht einen derzeit von einem Task mit niedrigerer Priorität gehaltenen Mutex zu erhalten, wird die Priorität des Tasks, der das Token hält, vorübergehend auf die des blockierten Tasks erhöht. Dieser Mechanismus wurde entwickelt, um sicherzustellen, dass der Task mit höherer Priorität so kurz wie möglich im Status "Blocked" gehalten wird. So wird die aufgetretene Prioritätsumkehrung minimiert.

## Direct-to-task Benachrichtigungen
<a name="direct-task-notifications"></a>

Aufgabenbenachrichtigungen ermöglichen es Aufgaben, mit anderen Aufgaben zu interagieren und sich mit Interrupt-Serviceroutinen (ISRs) zu synchronisieren, ohne dass ein separates Kommunikationsobjekt wie eine Semaphore erforderlich ist. Jeder RTOS-Task hat einen 32-Bit-Benachrichtigungswert. Dieser wird verwendet, um den Inhalt der Benachrichtigung zu speichern (falls vorhanden). Eine RTOS-Task-Benachrichtigung ist ein Ereignis, das direkt an einen Task gesendet wird, der die Blockierung des empfangenden Tasks aufheben und optional den Benachrichtigungswert des empfangenden Tasks aktualisieren kann.

RTOS-Task-Benachrichtigungen können als schnellere und einfachere Alternative zu binären und zählenden Semaphoren und in einigen Fällen zu Warteschlangen verwendet werden. Task-Benachrichtigungen haben sowohl Geschwindigkeits- als auch RAM-Footprint-Vorteile gegenüber anderen FreeRTOS-Funktionen zur Ausführung gleichwertiger Funktionalitäten. Task-Benachrichtigungen können jedoch nur verwendet werden, wenn es nur einen Task als Empfänger des Ereignisses gibt.

## Stream-Puffer
<a name="rtos-stream-buffer"></a>

Stream-Puffer ermöglichen die Übergabe eines Bytestroms von einer Interrupt-Serviceroutine an einen Task oder von einem Task an einen anderen. Ein Bytestrom kann eine beliebige Länge haben und muss nicht unbedingt einen Anfang oder ein Ende haben. Es können beliebig viele Bytes auf einmal geschrieben und beliebig viele Bytes auf einmal gelesen werden. Die Stream-Pufferfunktionalität wird durch die Einbindung der Quelldatei `stream_buffer.c` in Ihr Projekt aktiviert.

Stream-Puffer gehen davon aus, dass es nur einen Task oder Interrupt gibt, der in den Puffer schreibt (der Writer) und nur einen Task oder Interrupt, der aus dem Puffer liest (der Reader). Writer und Reader können unterschiedliche Tasks oder Interrupt-Serviceroutinen sein. Es darf jedoch nicht mehrere Writer oder Reader geben.

Die Stream-Buffer-Implementierung verwendet direct-to-task Benachrichtigungen. Daher kann der Aufruf einer Stream-Puffer-API, die den aufrufenden Task in den Status "Blocked" versetzt, den Benachrichtigungsstatus und -wert des aufrufenden Tasks ändern.

### Senden von Daten
<a name="rtos-stream-buffer-send"></a>

`xStreamBufferSend()` wird verwendet, um Daten an einen Stream-Puffer in einen Task zu senden. `xStreamBufferSendFromISR()` wird verwendet, um Daten in einer Interrupt-Serviceroutine (ISR) an einen Stream-Puffer zu senden.

`xStreamBufferSend()` ermöglicht die Angabe einer Blockierungsdauer. Wenn `xStreamBufferSend()` mit einer Blockierungsdauer ungleich Null aufgerufen wird, um in einen Stream-Puffer zu schreiben und der Puffer voll ist, wird der Task in den Status "Blocked" versetzt, bis Platz verfügbar wird oder die Blockierungsdauer abläuft.

`sbSEND_COMPLETED()` und `sbSEND_COMPLETED_FROM_ISR()` sind Makros, die (intern von der FreeRTOS-API) aufgerufen werden, wenn Daten in einen Stream-Puffer geschrieben werden. Sie nehmen das Handle des Stream-Puffers entgegen, der aktualisiert wurde. Beide Makros prüfen, ob ein blockierter Task im Stream-Puffer auf Daten wartet. Wenn dies der Fall ist, wird Status "Blocked" für den Task entfernt.

Sie können dieses Standardverhalten ändern, indem Sie Ihre eigene Implementierung von `sbSEND_COMPLETED()` in [`FreeRTOSConfig.h`](freertos-config.md) bereitstellen. Dies ist hilfreich, wenn ein Stream-Puffer verwendet wird, um Daten zwischen den Kernen auf einem Mehrkern-Prozessor zu übertragen. In diesem Szenario kann `sbSEND_COMPLETED()` implementiert werden, um einen Interrupt im anderen CPU-Kern zu erzeugen. Die Serviceroutine des Interrupts kann dann die `xStreamBufferSendCompletedFromISR()`-API verwenden, um einen Task, der auf die Daten wartet, zu überprüfen und gegebenenfalls freizugeben.

### Empfangen von Daten
<a name="rtos-stream-buffer-receive"></a>

`xStreamBufferReceive()` wird verwendet, um Daten aus einem Stream-Puffer in einen Task zu lesen. `xStreamBufferReceiveFromISR()` wird verwendet, um Daten aus einem Streambuffer in eine Interrupt-Serviceroutine (ISR) zu lesen.

`xStreamBufferReceive()` ermöglicht die Angabe einer Blockierungsdauer. Wenn `xStreamBufferReceive()` mit einer Blockierungsdauer ungleich Null zum Lesen aus einem Stream-Puffer aufgerufen wird und der Puffer leer ist, wird der Task in den Status "Blocked" versetzt, bis entweder eine bestimmte Datenmenge im Stream-Puffer verfügbar ist oder die Blockierungsdauer abläuft.

Die Datenmenge, die sich im Stream-Puffer befinden muss, bevor ein Task freigegeben wird, wird als Triggerlevel des Stream-Puffers bezeichnet. Ein mit einem Triggerlevel von 10 blockierter Task wird freigegeben, wenn mindestens 10 Bytes in den Puffer geschrieben werden oder die Blockierungsdauer des Tasks abläuft. Wenn die Blockierungsdauer eines lesenden Tasks vor Erreichen des Triggerlevels abläuft, erhält der Task alle in den Puffer geschriebenen Daten. Das Triggerlevel eines Tasks muss auf einen Wert zwischen 1 und der Größe des Stream-Puffers festgelegt werden. Das Triggerlevel eines Stream-Puffers wird beim Aufruf von `xStreamBufferCreate()` festgelegt. Es kann durch Aufruf von `xStreamBufferSetTriggerLevel()` geändert werden.

`sbRECEIVE_COMPLETED()` und `sbRECEIVE_COMPLETED_FROM_ISR()` sind Makros, die (intern von der FreeRTOS-API) aufgerufen werden, wenn Daten aus einem Stream-Puffer gelesen werden. Die Makros prüfen, ob ein Task im Stream-Puffer blockiert ist, der darauf wartet, dass Platz im Puffer verfügbar wird. Wenn dies der Fall ist, wird der Task aus dem Zustand „Blocked“ entfernt. Sie können das Standardverhalten von `sbRECEIVE_COMPLETED()` ändern, indem Sie in [`FreeRTOSConfig.h`](freertos-config.md) eine alternative Implementierung bereitstellen.

## Nachrichtenpuffer
<a name="rtos-message-buffer"></a>

Nachrichtenpuffer ermöglichen die Übergabe diskreter Nachrichten variabler Länge von einer Interrupt-Serviceroutine an einen Task oder von einem Task an einen anderen. Beispielsweise können Nachrichten der Länge 10, 20 und 123 Byte in denselben Nachrichtenpuffer geschrieben und aus aus demselben Nachrichtenpuffer gelesen werden. Eine 10-Byte-Nachricht kann nur als 10-Byte-Nachricht gelesen werden, nicht als einzelne Bytes. Nachrichtenpuffer bauen auf der Stream-Pufferimplementierung auf. Sie können die Nachrichtenpufferfunktionalität aktivieren, indem Sie die `stream_buffer.c`-Quelldatei in Ihr Projekt einfügen.

Nachrichtenpuffer gehen davon aus, dass es nur einen Task oder Interrupt gibt, der in den Puffer schreibt (der Writer) und nur einen Task oder Interrupt, der aus dem Puffer liest (der Reader). Writer und Reader können unterschiedliche Tasks oder Interrupt-Serviceroutinen sein. Es darf jedoch nicht mehrere Writer oder Reader geben.

Die Implementierung des Nachrichtenpuffers verwendet direct-to-task Benachrichtigungen. Daher kann der Aufruf einer Stream-Puffer-API, die den aufrufenden Task in den Status "Blocked" versetzt, den Benachrichtigungsstatus und -wert des aufrufenden Tasks ändern. 

Um Nachrichtenpuffern die Verarbeitung von Nachrichten variabler Größe zu ermöglichen, wird die Länge jeder Nachricht vor der Nachricht selbst in den Nachrichtenpuffer geschrieben. Die Länge wird in einer Variablen vom Typ `size_t` gespeichert, die bei einer 32-Byte-Architektur typischerweise 4 Byte groß ist. Daher verbraucht das Schreiben einer 10-Byte-Nachricht in einen Nachrichtenpuffer tatsächlich 14 Byte Pufferspeicher. Ebenso verbraucht das Schreiben einer 100-Byte-Nachricht in einen Nachrichtenpuffer tatsächlich 104 Byte Pufferspeicher.

### Senden von Daten
<a name="rtos-message-buffer-send"></a>

`xMessageBufferSend()` wird verwendet, um Daten von einem Task an einen Nachrichtenpuffer zu senden. `xMessageBufferSendFromISR()` wird verwendet, um Daten von einer Interrupt-Serviceroutine (ISR) an einen Nachrichtenpuffer zu senden.

`xMessageBufferSend()` ermöglicht die Angabe einer Blockierungsdauer. Wenn `xMessageBufferSend()` mit einer Blockierungsdauer ungleich Null für das Schreiben in den Nachrichtenpuffer aufgerufen wird und der Puffer voll ist, wird der Task in den Status "Blocked" versetzt, bis entweder Platz im Nachrichtenpuffer verfügbar wird oder die Blockierungsdauer abläuft.

`sbSEND_COMPLETED()` und `sbSEND_COMPLETED_FROM_ISR()` sind Makros, die (intern von der FreeRTOS-API) aufgerufen werden, wenn Daten in einen Stream-Puffer geschrieben werden. Sie nehmen einen einzigen Parameter entgegen, der das Handle des aktualisierten Stream-Puffers darstellt. Beide Makros prüfen, ob ein blockierter Task im Stream-Puffer auf Daten wartet. Wenn dies der Fall ist, entfernen sie den Status "Blocked" des Tasks.

Sie können dieses Standardverhalten ändern, indem Sie Ihre eigene Implementierung von `sbSEND_COMPLETED()` in [`FreeRTOSConfig.h`](freertos-config.md) bereitstellen. Dies ist hilfreich, wenn ein Stream-Puffer verwendet wird, um Daten zwischen den Kernen auf einem Mehrkern-Prozessor zu übertragen. In diesem Szenario kann `sbSEND_COMPLETED()` implementiert werden, um einen Interrupt im anderen CPU-Kern zu erzeugen. Die Serviceroutine des Interrupts kann dann die `xStreamBufferSendCompletedFromISR()`-API verwenden, um einen auf die Daten wartenden Task zu überprüfen und gegebenenfalls freizugeben.

### Empfangen von Daten
<a name="rtos-message-buffer-receive"></a>

`xMessageBufferReceive()` wird verwendet, um Daten aus einem Nachrichtenpuffer in einem Task zu lesen. `xMessageBufferReceiveFromISR()` wird verwendet, um Daten aus einem Nachrichtenpuffer in einer Interrupt-Serviceroutine (ISR) zu lesen. `xMessageBufferReceive()` ermöglicht die Angabe einer Blockierungsdauer. Wenn `xMessageBufferReceive()` mit einer Blockierungsdauer ungleich Null zum Lesen aus einem Nachrichtenpuffer aufgerufen wird und der Puffer leer ist, wird der Task in den Status "Blocked" versetzt, bis entweder Daten verfügbar werden oder die Blockierungsdauer abläuft.

`sbRECEIVE_COMPLETED()` und `sbRECEIVE_COMPLETED_FROM_ISR()` sind Makros, die (intern von der FreeRTOS-API) aufgerufen werden, wenn Daten aus einem Stream-Puffer gelesen werden. Die Makros prüfen, ob ein Task im Stream-Puffer blockiert ist, der darauf wartet, dass Platz im Puffer verfügbar wird. Wenn dies der Fall ist, wird der Task aus dem Zustand „Blocked“ entfernt. Sie können das Standardverhalten von `sbRECEIVE_COMPLETED()` ändern, indem Sie in [`FreeRTOSConfig.h`](freertos-config.md) eine alternative Implementierung bereitstellen.

# Unterstützung für symmetrisches Multiprocessing (SMP)
<a name="smp-support"></a>

[Die SMP-Unterstützung im FreeRTOS-Kernel](https://freertos.org/symmetric-multiprocessing-introduction.html) ermöglicht es einer Instanz des FreeRTOS-Kernels, Aufgaben über mehrere identische Prozessorkerne hinweg zu planen. Die Kernarchitekturen müssen identisch sein und sich denselben Speicher teilen.

[Die FreeRTOS-API bleibt zwischen Single-Core- und SMP-Versionen im Wesentlichen gleich, mit Ausnahme dieser zusätzlichen. APIs](https://freertos.org/symmetric-multiprocessing-introduction.html#smp-specific-apis) Daher sollte eine Anwendung, die für die FreeRTOS-Single-Core-Version geschrieben wurde, mit minimalem bis gar keinem Aufwand mit der SMP-Version kompiliert werden. Es kann jedoch einige funktionale Probleme geben, da einige Annahmen, die für Single-Core-Anwendungen zutrafen, für Multicore-Anwendungen möglicherweise nicht mehr zutreffen.

Eine gängige Annahme ist, dass eine Aufgabe mit niedrigerer Priorität nicht ausgeführt werden kann, während eine Aufgabe mit höherer Priorität ausgeführt wird. Dies galt zwar für ein Single-Core-System, gilt aber nicht mehr für Multi-Core-Systeme, da mehrere Aufgaben gleichzeitig ausgeführt werden können. Wenn sich die Anwendung auf relative Aufgabenprioritäten stützt, um sich gegenseitig auszuschließen, kann es in einer Multicore-Umgebung zu unerwarteten Ergebnissen kommen.

Eine weitere verbreitete Annahme ist, dass sie nicht gleichzeitig miteinander oder mit anderen Aufgaben ausgeführt werden ISRs kann. In einer Multicore-Umgebung ist dies nicht mehr der Fall. Der Anwendungsautor muss beim Zugriff auf Daten, die zwischen Aufgaben und ISRs gemeinsam genutzt werden, für einen ordnungsgemäßen gegenseitigen Ausschluss sorgen.

# Software-Timer
<a name="software-timers"></a>

Ein Software-Timer ermöglicht die Ausführung einer Funktion zu einem bestimmten Zeitpunkt. Die vom Timer ausgeführte Funktion wird als *Callback-Funktion* des Timers bezeichnet. Die Zeit zwischen dem Start eines Timers und der Ausführung seiner Callback-Funktion wird als *Periode* des Timers bezeichnet. Der FreeRTOS-Kernel bietet eine effiziente Software-Timer-Implementierung. Dies liegt an folgenden Dingen:
+ Sie führt keine Timer-Callback-Funktionen aus einem Interrupt-Kontext aus
+ Sie verbraucht keine Verarbeitungszeit, es sei denn, ein Timer ist tatsächlich abgelaufen
+ Sie fügt dem Tick-Interrupt keinen Verarbeitungsaufwand hinzu
+ Sie durchläuft keine Linklistenstrukturen, während Interrupts deaktiviert sind

# Energiesparunterstützung
<a name="low-power-support"></a>

Wie die meisten Embedded-Betriebssysteme nutzt der FreeRTOS-Kernel einen Hardware-Timer, um periodische Tick-Interrupts zu erzeugen, die zur Zeitmessung verwendet werden. Die Energieeinsparung bei regulären Hardware-Timer-Implementierungen wird durch die Notwendigkeit begrenzt, den Energiesparzustand für die Verarbeitung der Tick-Interrupts periodisch zu verlassen und dann wieder in den Energiesparzustand zurückzukehren. Wenn die Frequenz des Tick-Interrupts zu hoch ist, überwiegt der Energie- und Zeitaufwand für das Wechseln in und aus dem Energiesparzustand für jeden Tick die möglichen Energiespargewinne in allen Stromsparmodi. 

Um dieser Einschränkung entgegenzuwirken, bietet FreeRTOS einen Tick-freien Timer-Modus für Low-Power-Anwendungen. Der FreeRTOS-Tickless-Idle-Modus stoppt den periodischen Tick-Interrupt während der Leerlaufzeiten (Perioden, in denen es keine Anwendungs-Tasks gibt, die ausgeführt werden können) und nimmt eine korrigierende Anpassung des RTOS-Tick-Count-Wertes vor, wenn der Tick-Interrupt neu gestartet wird. Das Stoppen des Tick-Interrupts ermöglicht dem Mikrocontroller, im Stromsparzustand zu bleiben, bis entweder ein Interrupt eintritt oder der RTOS-Kernel einen Task in den Ready-Status überführt.

# Konfiguriere den Kernel (Free RTOSConfig .h)
<a name="freertos-config"></a>

Sie können den FreeRTOS-Kernel für ein bestimmtes Board und eine bestimmte Anwendung über die `FreeRTOSConfig.h` Header-Datei konfigurieren. Jede Anwendung, die auf dem Kernel basiert, muss eine `FreeRTOSConfig.h` -Header-Datei im Präprozessorofad enthalten. `FreeRTOSConfig.h` ist anwendungsspezifisch und sollte in einem Anwendungsverzeichnis und nicht in einem der FreeRTOS-Kernel-Quellcode-Verzeichnisse gespeichert werden.

Die `FreeRTOSConfig.h` Dateien für die FreeRTOS-Demo- und Testanwendungen befinden sich unter `freertos/vendors/vendor/boards/board/aws_demos/config_files/FreeRTOSConfig.h` und. `freertos/vendors/vendor/boards/board/aws_tests/config_files/FreeRTOSConfig.h`

Die Liste der verfügbaren Konfigurationsparameter, die in `FreeRTOSConfig.h` angegeben werden müssen, finden Sie unter [FreeRTOS.org](https://www.freertos.org/a00110.html).