Den ULP (Ultra Low Power) Co-Prozessor des ESP32 nutzen ist eine der effektivsten Methoden, um extrem stromsparende Projekte zu bauen, ohne auf regelmäßige Messungen und intelligente Entscheidungen verzichten zu müssen. Der ULP läuft, während die Haupt-CPU im Deep Sleep ist, und kann in diesem Zustand ausgewählte Aufgaben erledigen: Sensorwerte aufnehmen, Schwellwerte prüfen, Zähler erhöhen, RTC-GPIOs schalten oder die Haupt-CPU nur dann wecken, wenn wirklich ein relevantes Ereignis eintritt. Genau das ist der Unterschied zwischen „Sensor sendet alle 5 Minuten“ und „Sensor sendet nur, wenn sich etwas ändert“ – ein enormer Gewinn für Akkulaufzeit, Solarprojekte und wartungsarme Installationen im Außenbereich. In der Praxis gibt es jedoch zwei wichtige Varianten, die oft für Verwirrung sorgen: Beim klassischen ESP32 ist der ULP als einfache FSM (Finite State Machine) ausgelegt und wird typischerweise mit ULP-Assembly bzw. Makros programmiert. Neuere Chips wie ESP32-S2 und ESP32-S3 bieten zusätzlich einen ULP RISC-V, der deutlich flexibler ist und in C programmiert werden kann. Diese Anleitung führt Sie strukturiert durch beide Ansätze: von den Voraussetzungen über die Speicher- und Build-Mechanik bis hin zu typischen Mustern wie ADC-Messung mit Schwellwertlogik, GPIO-Wakeup und sauberem Datenaustausch zwischen ULP und Hauptanwendung.
Was der ULP wirklich ist: Aufgabenbereich und Grenzen
Der ULP ist kein „zweiter ESP32“, sondern ein bewusst minimalistischer Co-Prozessor, der auf extrem niedrigen Energieverbrauch optimiert ist. Er eignet sich hervorragend für kleine, wiederkehrende Aufgaben, die keine schnelle Netzwerkkommunikation benötigen. Das Ziel ist, die Haupt-CPU möglichst selten zu wecken und die Aktivzeit zu verkürzen.
- Typische ULP-Aufgaben: periodische ADC-Messungen, einfache Grenzwertprüfungen, Zählen/Logik, Schalten von RTC-GPIOs, Wecken der Haupt-CPU bei Ereignissen.
- Ungeeignet: WLAN/Bluetooth-Stacks, komplexe Protokolle, große Datenverarbeitung, umfangreiche Bibliotheken.
- Merksatz: ULP entscheidet „muss ich die CPU wecken?“, die CPU erledigt „alles Komplexe“.
Die offizielle Übersicht und API-Referenz finden Sie in der ESP-IDF-Dokumentation: ESP-IDF: ULP Coprocessor (ESP32).
ULP-FSM vs. ULP RISC-V: Welche ESP32-Variante unterstützt was?
Für die Planung ist entscheidend, welche Hardware Sie einsetzen. Der klassische ESP32 nutzt traditionell den ULP-FSM-Ansatz (ULP als einfache Zustandsmaschine, häufig in Assembly/Makros). Auf ESP32-S2 und ESP32-S3 ist zusätzlich ein ULP RISC-V verfügbar, der deutlich angenehmer in C programmiert wird und komplexere Logik erlaubt. Das beeinflusst Werkzeugkette, Projektstruktur und Wartbarkeit erheblich.
- ESP32 (klassisch): ULP-FSM (Makro-/Assembly-basierte Programme), ideal für sehr einfache Mess- und Triggerlogik.
- ESP32-S2 / ESP32-S3: ULP-FSM und zusätzlich ULP RISC-V (C-Programmierung möglich, höhere Flexibilität).
Eine aktuelle Referenz zur ULP-Unterstützung auf ESP32-S3 finden Sie hier: ESP-IDF: ULP Coprocessor (ESP32-S3).
Voraussetzungen: Warum ESP-IDF für ULP-Projekte praktisch Pflicht ist
Für ernsthafte ULP-Entwicklung ist ESP-IDF der Standard, weil die Build-Integration (ULP-Binary einbetten, Symbole generieren, RTC-Speicher konfigurieren) dort sauber gelöst ist. In Arduino-Umgebungen lassen sich ULP-Ansätze zwar teils umsetzen, aber die komfortable Nutzung des ULP RISC-V ist in der Praxis meist ESP-IDF-gebunden, und Debugging/Beispiele sind deutlich besser dokumentiert.
- ESP-IDF installiert: passendes Toolchain-Setup und Beispielprojekte verfügbar.
- Target korrekt gesetzt: ESP32 vs. ESP32-S2/S3 beeinflusst ULP-Optionen.
- Strommessung vorbereitet: Wenn Sie ULP nutzen, ist Ruhestrommessung Teil des Workflows.
Speicher und Daten-Austausch: RTC Slow Memory als Brücke
ULP-Programme und gemeinsame Daten liegen typischerweise im RTC-Speicher (häufig „RTC slow memory“). Dieser bleibt während Deep Sleep erhalten und ist sowohl für die Haupt-CPU als auch den ULP zugänglich. Genau das macht den ULP so nützlich: Er kann Werte ablegen, die die CPU beim Aufwachen ausliest, ohne dass Flash-Schreibzyklen oder externe Speicher nötig sind.
Wichtiger Praxispunkt: Datenformat und Maskierung
Beim klassischen ULP-FSM auf ESP32 werden Werte oft in 32-Bit-Slots abgelegt, wobei je nach Zugriff/Instruktionsformat obere Bits „unerwartet“ belegt sein können. In der Praxis liest die Hauptanwendung daher häufig nur die unteren 16 Bit aus, indem sie maskiert. Das ist kein „Bug“, sondern eine typische Eigenheit des ULP-Datenzugriffs, die Sie bei Messwerten, Zählern und Flags konsequent berücksichtigen sollten. Eine Beschreibung dieses Mechanismus findet sich in älteren, aber weiterhin hilfreichen ULP-Programmierguides: ESP-IDF v4.3: ULP Coprocessor Programming (ESP32).
Schritt-für-Schritt: ULP im Projekt aktivieren und RTC-Speicher reservieren
Bevor Sie überhaupt ULP-Code schreiben, muss das Projekt so konfiguriert sein, dass RTC-Speicher für ULP-Code und -Daten reserviert wird. In ESP-IDF geschieht das über die Projektkonfiguration. Der genaue Menüpunkt kann sich je nach ESP-IDF-Version leicht unterscheiden, das Prinzip bleibt aber gleich: ULP aktivieren und ausreichend RTC-Speicher einplanen.
- ULP-Unterstützung aktivieren: ULP-Option einschalten, damit der Buildprozess ULP-Binaries verarbeitet.
- RTC-Speichergröße festlegen: groß genug für ULP-Programm + Variablen (konservativ planen, später optimieren).
- Deep Sleep aktiv einplanen: ULP ist vor allem sinnvoll, wenn die Haupt-CPU wirklich schläft.
Konzeptionell hängt ULP stark an den Sleep-Modi – eine gute Ergänzung ist daher die Sleep-Dokumentation: ESP-IDF: Sleep Modes.
Schritt-für-Schritt: ULP-FSM (ESP32) in der Praxis nutzen
Beim klassischen ESP32 schreiben Sie ULP-FSM-Programme häufig in einer speziellen Assembly-Form oder mittels ULP-Makros. Die ESP-IDF-Buildkette assembliert und linkt das ULP-Programm, erzeugt daraus ein Binär-Blob und bindet diesen in Ihre Firmware ein. Die Hauptanwendung lädt dieses Blob in den RTC-Speicher und startet den ULP an einem definierten Entry-Point.
Projektstruktur und Build-Mechanik verstehen
In der Praxis besteht ein ULP-FSM-Projekt aus zwei Teilen: (1) der normalen Anwendung (C/C++), (2) dem ULP-Teil (ULP-Assembly/Makros). Der Build erzeugt zusätzlich Header/Linker-Informationen, damit Sie aus der Hauptanwendung heraus ULP-Variablen referenzieren können. Ein Kernprinzip ist: Die Hauptanwendung lädt und startet den ULP per API-Funktionen, die in mehreren ESP-IDF-Guides beschrieben sind, etwa über ESP-IDF Guide: ULP laden und starten.
Ein bewährtes Muster: ADC messen, Schwellwert prüfen, CPU nur bei Bedarf wecken
Ein klassisches ULP-Szenario im Gartenbau oder Smart Home ist: Der ULP misst regelmäßig einen Analogwert (z. B. Bodenfeuchte), vergleicht ihn mit einem Grenzwert und weckt die CPU nur dann, wenn „trocken“ erkannt wird oder wenn eine Veränderung groß genug ist. Das spart drastisch Funkzeit und CPU-Laufzeit. Als Referenz eignet sich ein offizielles Beispiel aus dem ESP-IDF-Repository, das ADC-Messung mit ULP-FSM demonstriert: ESP-IDF Beispiel: ULP ADC (Code-Referenz).
- ULP macht: Timer-basiertes Aufwachen, ADC lesen, einfachen Vergleich durchführen, Ergebnis in RTC-Speicher schreiben.
- CPU macht: bei Wake-up: Werte auslesen, kalibrieren, senden/loggen, ggf. Aktorik steuern.
- Optimierung: Messintervall und Schwellwert-Hysterese so wählen, dass „Flattern“ vermieden wird.
Schritt-für-Schritt: ULP RISC-V (ESP32-S2/ESP32-S3) in C programmieren
Der ULP RISC-V ist ein großer Fortschritt: Sie können den ULP-Teil in C schreiben, was Entwicklung, Wartung und Testbarkeit deutlich verbessert. Der Buildprozess kompiliert den ULP-Code separat, linkt ihn zu einem Binärformat und bettet ihn ebenfalls in die Firmware ein. Die Hauptanwendung lädt und startet den ULP ähnlich wie beim FSM, aber die ULP-Logik ist wesentlich ausdrucksstärker.
Typisches Projektmuster: ULP-C-Code plus Wake-on-Interrupt
Ein sehr praxisnahes Muster ist: Der ULP reagiert auf RTC-IO-Interrupts statt nur auf einen Timer. Das ermöglicht „ereignisgetriebene“ Systeme, z. B. ein Türkontakt, ein Regen-Impulsgeber oder ein Vibrationssensor, der nur dann die Haupt-CPU weckt, wenn ein Ereignis wirklich eintritt. Ein offizielles Beispiel zeigt genau dieses Vorgehen: ESP-IDF Beispiel: ULP RISC-V GPIO Interrupt.
- ULP RISC-V macht: wartet auf RTC-IO-Interrupt, prüft ggf. zusätzliche Bedingungen, weckt die CPU gezielt.
- CPU macht: Ereignis verarbeiten, Daten übertragen, anschließend wieder in Deep Sleep wechseln.
- Mehrwert: keine regelmäßigen Wake-ups nötig, wenn selten Ereignisse auftreten.
Timer, Sampling und Hysterese: So vermeiden Sie „zu viele Wake-ups“
ULP-Projekte scheitern selten daran, dass „es nicht funktioniert“, sondern daran, dass es zu oft funktioniert: zu viele Messungen, zu viele CPU-Wake-ups, zu wenig Hysterese und damit unnötiger Energieverbrauch. Der ULP ist ideal, um eine Vorfilterung zu übernehmen: Erst wenn ein Wert über/unter einem Grenzwert liegt und diese Bedingung über mehrere Messungen stabil bleibt, wird die CPU geweckt.
- Messintervall: so groß wie möglich, so klein wie nötig (Pflanzenklima oft Minuten statt Sekunden).
- Mehrfachmessung: z. B. 3 Messungen in Folge, bevor ein Ereignis als „echt“ gilt.
- Hysterese: zwei Schwellwerte nutzen (Ein-/Ausschaltgrenze), um Flattern zu verhindern.
- Änderungsdetektion: CPU nur wecken, wenn sich Werte ausreichend verändert haben (Delta-Schwelle).
ULP und Sensorik: ADC, I2C und RTC-GPIO in der Praxis
Der ULP ist besonders stark bei einfachen Messpfaden: ADC lesen, GPIO schalten, einfache I2C-Abfragen (je nach ULP-Variante und Chip). Für viele Sensorszenarien reicht das: Bodenfeuchte (ADC), Batteriespannung (ADC über Teiler), Regen-Impulse (GPIO), Türkontakt (GPIO), Minimalsteuerung einer Pumpe oder eines Ventils (RTC-GPIO). Eine praxisorientierte Beispielbeschreibung, die ULP in einem Bewässerungs-Szenario nutzt, finden Sie in Espressif-nahen Lösungen: ULP Beispiel: Watering Device (Konzept).
- Batteriemessung: ULP misst Zellspannung periodisch und weckt CPU nur bei „Low Battery“.
- Feuchte-Trigger: ULP misst Bodenfeuchte, weckt CPU nur bei Trockenheit.
- Alarmkontakt: ULP reagiert auf RTC-GPIO-Event (z. B. Türkontakt), CPU wird sofort geweckt.
Zusammenspiel mit Deep Sleep: Architektur „ULP filtert, CPU handelt“
Damit ULP wirklich Energie spart, müssen Sie die Hauptanwendung konsequent auf kurze Aktivphasen auslegen. Nach dem Wake-up sollte die CPU schnell entscheiden, was zu tun ist, und danach wieder in den Schlaf gehen. Typischerweise ist die Reihenfolge: Wake-Grund lesen, ULP-Variablen aus RTC-Speicher auslesen, ggf. Netzwerkverbindung herstellen, Daten senden, ULP neu konfigurieren, Deep Sleep starten.
- Wake-Grund auswerten: Timer vs. ULP-Trigger vs. externer Pin.
- ULP-Werte lesen: Messwerte, Flags, Zähler, Stabilitätsmarker.
- Netzwerk nur bei Bedarf: Nicht jedes Wake führt zu WLAN/HTTPS.
- ULP neu starten: Je nach Design ULP-Programm erneut initialisieren oder Parameter aktualisieren.
Fehlersuche und typische Stolperfallen
ULP-Entwicklung ist low-level. Viele Probleme haben einfache Ursachen, wirken aber zunächst „mystisch“, weil Debug-Ausgaben im Deep Sleep fehlen. Eine strukturierte Vorgehensweise spart viel Zeit: zuerst Speicher/Build prüfen, dann Wake-Logik, dann Messpfade und schließlich Strommessung.
- ULP läuft nicht: RTC-Speicher nicht reserviert oder ULP nicht aktiviert; Build erzeugt kein ULP-Binary.
- CPU wacht ständig auf: Grenzwert/Hysterese fehlt, Eingänge floaten, Interrupt-Quelle ist instabil.
- Messwerte sind „komisch“: Datenformat/Maskierung nicht berücksichtigt, ADC-Setup unvollständig, Warm-up/Teiler falsch.
- Kein Low-Power-Effekt: Board-Ruhestrom zu hoch (LED, USB-UART, Regler), Sensoren ziehen weiter Strom, falscher Sleep-Modus.
- GPIO-Wakeup unzuverlässig: Falsche RTC-GPIOs genutzt, Pullups/Pulldowns fehlen, Kontaktprellen wird nicht abgefangen.
Strombilanz verstehen: ULP lohnt sich, wenn er CPU-Wake-ups reduziert
Der ULP selbst ist sehr sparsam, aber der eigentliche Gewinn entsteht dadurch, dass die Haupt-CPU weniger oft aufwacht und weniger oft Funk nutzt. Ob sich ULP lohnt, können Sie mit einer einfachen Durchschnittsrechnung abschätzen: Wie viel Zeit verbringt das Gerät aktiv mit hohem Strom, wie viel Zeit im Sleep mit niedrigem Strom? ULP verschiebt diese Bilanz, indem er „unnötige Aktivphasen“ eliminiert.
Wenn der ULP es schafft,
Outbound-Links zu relevanten Informationsquellen
- ESP-IDF: ULP Coprocessor (ESP32) – API-Referenz und Überblick
- ESP-IDF: ULP Coprocessor (ESP32-S3) – inkl. ULP RISC-V Hinweise
- ESP-IDF: Sleep Modes – Deep Sleep als Basis für ULP-Designs
- ESP-IDF Beispiel: ULP-FSM ADC – Referenz für Mess- und Wake-Logik
- ESP-IDF Beispiel: ULP RISC-V GPIO Interrupt – ereignisgetriebene ULP-Wakeup-Strategie
- ESP-IDF v4.3: ULP Coprocessor Programming – Hintergrund zu ULP-FSM, Laden/Starten, Datenformat
IoT-PCB-Design, Mikrocontroller-Programmierung & Firmware-Entwicklung
PCB Design • Arduino • Embedded Systems • Firmware
Ich biete professionelle Entwicklung von IoT-Hardware, einschließlich PCB-Design, Arduino- und Mikrocontroller-Programmierung sowie Firmware-Entwicklung. Die Lösungen werden zuverlässig, effizient und anwendungsorientiert umgesetzt – von der Konzeptphase bis zum funktionsfähigen Prototyp.
Diese Dienstleistung richtet sich an Unternehmen, Start-ups, Entwickler und Produktteams, die maßgeschneiderte Embedded- und IoT-Lösungen benötigen. Finden Sie mich auf Fiverr.
Leistungsumfang:
-
IoT-PCB-Design & Schaltplanerstellung
-
Leiterplattenlayout (mehrlagig, produktionstauglich)
-
Arduino- & Mikrocontroller-Programmierung (z. B. ESP32, STM32, ATmega)
-
Firmware-Entwicklung für Embedded Systems
-
Sensor- & Aktor-Integration
-
Kommunikation: Wi-Fi, Bluetooth, MQTT, I²C, SPI, UART
-
Optimierung für Leistung, Stabilität & Energieeffizienz
Lieferumfang:
-
Schaltpläne & PCB-Layouts
-
Gerber- & Produktionsdaten
-
Quellcode & Firmware
-
Dokumentation & Support zur Integration
Arbeitsweise:Strukturiert • Zuverlässig • Hardware-nah • Produktorientiert
CTA:
Planen Sie ein IoT- oder Embedded-System-Projekt?
Kontaktieren Sie mich gerne für eine technische Abstimmung oder ein unverbindliches Angebot. Finden Sie mich auf Fiverr.

