Motivation

Bei einem Projekt ging es darum, pro Sekunde 10.000 Datenpakete mit einer Länge von 34 Byte über die serielle Schnittstelle zu übertragen. Das sind 340.000 Bytes pro Sekunde. Bei einem Prozessor-Takt von 240 MHz stehen somit pro Byte rund 700 Take zur Verfügung. Wenn man bedenkt, das neben der Übertragung, auch noch Daten ermittelt und aufbereitet werden müssen und einige der Zugriffe auf die internen Register über den APB-Bus mit einem Takt von nur 80 MHz erfolgen, ist das nicht viel.

Die Arduino Serial-Klasse ist mit viel Overhead implementiert. Aufgaben werden durch viele Schichten geleitet in denen mehrfach die gleichen Prüfungen auf zulässige Werte oder zulässige Zustände erfolgen. Ebenfalls versucht jede Schicht separat Thread-Sicherheit herzustellen. Damit geht die Performance deutlich in den Keller.

Andererseits sind die Hardware-UART-Module des ESP32 sehr leistungsfähig und können die Daten-Übertragung nahezu ohne zusätzliche Software-Unterstützung erledigen. Insbesondere besitzen sie einen internen FIFO-Sende- und FIFO-Empfangspuffer von jeweils 128 Byte.

Die im Folgenden dargestellte Schnittstelle verzichtet auf diesen Overhead. Insbesondere entfallen Prüfungen auf zulässige Werte, zulässige Zustände und Thread-Sicherheit. Es muss also sorgfältig programmiert werden, insbesondere bei Anwendungen mit Interrupts oder bei Multi-Threading oder Multi-Tasking.


Versionshistorie

Version Anpassungen
1.0 (2022-04-28) Basis-Version

Bibliothek UrsEsp32FastUart

Diese Arduino-Bibliothek implementiert eine UART-Schnittstelle ohne Overhead. Insbesondere entfallen Prüfungen auf zulässige Werte, zulässige Zustände und Thread-Sicherheit. Es muss also sorgfältig programmiert werden, insbesondere bei Anwendungen mit Interrupts oder bei Multi-Threading oder Multi-Tasking.

Die Klasse UrsEsp32FastUart implementiert zwei Sätze von Funktionen:

Initialisierung

Der ESP32 besitzt drei UART-Module (der ESP32C3 nur zwei). Die möglichen zu verwendenden Module werden über die  Enumeration UartModule festgelegt.

Das zu verwendende Modul und der Sende- und der Empfangs-Pin werden im Konstruktor festgelegt. Wenn die Pins nicht angegeben werden, werden die Standard-Pins verwendet:

    ESP32   ESP32S2 ESP32C3
UART RX TX RX TX RX TX
UART0 03 01 44 43 20 21
UART1 09* 10* 18 17 18 19
UART2 16 17 - - - -

*) Die Standard-Pins GPIO9 und GPIO10 können beim ESP32 nicht benutzt werden! Sie werden zum Betrieb des Flash-Speicher benötigt. Es müssen explizit andere Pins angegeben werden.

Die Methode begin legt die Baud-Rate fest und startet die Schnittstelle.

Schnelle Funktionen (raw...)

Diese Methoden sind kurz und zur Performance-Steigerung als inline deklariert.

Name Funktion Anmerkung
UrsEsp32FastUart(
UartModule uart,
int8_t rxPin = -1, int8_t txPin = -1)
Initialisiert die Schnittstelle. Siehe Abschnitt Initialisierung.
int rawAvailable() Ruft die Anzahl der Bytes (Zeichen) ab, die zum Lesen von der seriellen Schnittstelle verfügbar sind. Dies sind Daten, die bereits empfangen wurden und im Empfangspuffer (FIFO, 128 Byte) gespeichert sind.
uint8_t rawRead() Entnimmt dem FIFO ein Byte. Ob Daten verfügbar sind, muss vorher mit availableRaw abgeprüft werden. Ansonsten wird Müll zurück geliefert.
void rawReadBytes(
uint8_t* dest, int cnt)
Liest Zeichen von der seriellen Schnittstelle in einen Puffer. Die Funktion blockiert, bis die angegebene Anzahl Zeichen empfangen wurden.
String rawReadStringUntil(
char terminator)
Liest Zeichen aus dem seriellen Puffer in einen String. Die Funktion blockiert, bis das Abschlusszeichen erkannt wird.
Das Abschlusszeichen selbst wird nicht zurückgegeben.
int availableForWrite() Liefert die Anzahl freier Bytes im Sende-Puffer.  
void rawWrite(
const uint8_t byte)
Sendet ein Byte. Die Funktion blockiert bis das Byte im Sende-Puffer abgelegt werden konnte.
void rawWrite(
const uint8_t* buf, uint32_t len)
Sendet ein Byte-Array. Die Funktion blockiert bis die Daten im Sende-Puffer abgelegt werden konnten.
void rawWrite(
const String src)
Sendet einen String. Die Funktion blockiert bis die Daten im Sende-Puffer abgelegt werden konnten.

Stream-Funktionen

UrsEsp32FastUart ist von der Klasse Stream abgeleitet. Sämtliche Funktionen der Stream-Klasse mit Ausnahme von peek funktionieren definitionsgemäß. Für Details siehe Arduino-Referenz: Stream.

Download

Das ZIP-Archiv für Bibliothek UrsEsp32FastUart zum Download. Die entpackten Dateien ins Verzeichnis <user>\Documents\Arduino\libraries kopieren (siehe Installing Additional Arduino Libraries).