Ausgabe 2026. Ein umfassender Leitfaden zu MicroPython für Mikrocontroller. Lernen Sie, wie man einen vollständigen Python 3 Interpreter auf Bare-Metal-Hardware ausführt.
Entdecken Sie, wie MicroPython einen vollständigen Python 3 Interpreter in Bare-Metal-Mikrocontroller quetscht. Wir untersuchen seine Kernidentität, die Unterschiede zu CPython und wie es gelingt, in stark eingeschränkten Umgebungen zu laufen.
4m 07s
2
Die Hardware-Brücke: Das machine Modul
Lernen Sie, wie Sie Mikrocontroller-Peripheriegeräte direkt aus Python steuern. Wir tauchen in das machine Modul ein und untersuchen, wie man mit Pins, PWM und rohem Speicher interagiert.
4m 00s
3
Live-Coding der MCU: REPL und mpremote
Revolutionieren Sie Ihren Embedded-Entwicklungs-Workflow. Wir behandeln die MicroPython REPL und das mpremote Kommandozeilen-Tool zur Automatisierung serieller Verbindungen und Live-Ausführung.
4m 03s
4
Drei Zeilen zum WiFi: Das network Modul
Verwandeln Sie einen Mikrocontroller in einen vernetzten IoT-Knoten. Wir erkunden das network Modul und erklären im Detail, wie man sich als Station mit dem WiFi verbindet oder einen eigenen Access Point hostet.
4m 10s
5
Die Einschränkungen überleben: RAM und der GC
Meistern Sie die Kunst, speichereffizientes Python zu schreiben. Wir diskutieren Heap Fragmentation, das Vorab-Zuweisen von Buffern und manuelle Garbage Collection, damit Ihr Mikrocontroller reibungslos läuft.
4m 03s
6
Kompiliert vs. Frozen: Deployment für die Produktion
Lernen Sie, wie Sie massive Anwendungen deployen, ohne dass Ihnen der RAM ausgeht. Wir untersuchen vorkompilierte .mpy-Dateien und das Einfrieren von Bytecode direkt in den Flash-Speicher des Mikrocontrollers.
4m 18s
7
Determinismus in Python: Timer und Interrupts
Erreichen Sie Echtzeitverhalten in MicroPython durch die Verwendung von Hardware-Timern und Interrupt Service Routines. Wir behandeln die strengen Regeln für das Schreiben von ISRs und die Vermeidung von Speicherzuweisungen.
4m 06s
Episoden
1
Das Python, das in 256K passt
4m 07s
Entdecken Sie, wie MicroPython einen vollständigen Python 3 Interpreter in Bare-Metal-Mikrocontroller quetscht. Wir untersuchen seine Kernidentität, die Unterschiede zu CPython und wie es gelingt, in stark eingeschränkten Umgebungen zu laufen.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 1 von 7. Desktop-Python benötigt normalerweise Megabytes an Arbeitsspeicher allein zum Starten. Versuch mal, das auf einen winzigen Zwei-Dollar-Chip zu packen, und dem System gehen sofort die Ressourcen aus. Um Python für Microcontroller zu schreiben, brauchst du einen Interpreter, der in einen Bruchteil dieses Platzes passt, ohne die Kernfunktionen der Sprache zu verlieren, auf die du dich verlässt. Genau das bietet MicroPython.
MicroPython ist eine schlanke, hocheffiziente Implementierung der Programmiersprache Python 3. Es wurde speziell für den Einsatz in ressourcenbeschränkten Umgebungen entwickelt. Standard-Python, oft auch CPython genannt, setzt voraus, dass es auf einem vollständigen Betriebssystem wie Linux oder Windows mit Gigabytes an Speicherplatz und ausreichend RAM läuft. MicroPython stellt diese Annahme auf den Kopf. Es ist dafür gebaut, Bare Metal zu laufen. Es gibt kein zugrundeliegendes Betriebssystem, das die Hardware verwaltet. Stattdessen fungiert MicroPython selbst als Betriebssystem. Es kommuniziert direkt mit der Hardware, sodass du High-Level-Scripts schreiben kannst, um physische Geräte zu steuern.
Das Engineering dahinter konzentriert sich komplett auf extreme Ressourcenbeschränkungen. MicroPython kann komplett in nur 256 Kilobyte Compiled Code Space laufen. Noch beeindruckender ist, dass es zum Laufen gerade mal 16 Kilobyte RAM braucht. Innerhalb dieser engen Grenzen liefert es eine voll funktionsfähige Python-Umgebung. Standard-Python bringt eine riesige Standard Library mit, bekannt als der Batteries-Included-Ansatz. MicroPython reduziert das auf ein sorgfältig ausgewähltes Subset von Modulen und behält nur das, was für ein Embedded System sinnvoll ist.
Trotz dieser starken Optimierungen bleibt die Sprache selbst authentisches Python 3. Das bedeutet, dass der Code, den du auf deinem Desktop schreibst, sich direkt auf das Embedded Device übertragen lässt. MicroPython unterstützt fortgeschrittene Language Features wie Closures, List Comprehensions, Generators und Standard Exception Handling. Es verarbeitet sogar Arbitrary Precision Integers. Wenn deine Logik das Multiplizieren riesiger Zahlen erfordert, skaliert MicroPython den Memory dynamisch, um dir die richtige Antwort zu geben, ohne gegen ein hartes architektonisches Limit zu crashen – genau wie Desktop-Python.
Hier ist der entscheidende Punkt. Da die komplette Python-Engine auf den Chip passt, bekommst du einen interaktiven Live-Prompt direkt auf der Hardware. Dieser Read-Eval-Print-Loop verändert, wie du Embedded Code schreibst. Normalerweise bedeutet das Programmieren eines Microcontrollers, dass du Code in C schreibst, ihn auf deinem Desktop kompilierst, ihn auf das Board flashst und darauf wartest, dass er läuft. Mit MicroPython schließt du das Board an deinen Computer an, öffnest ein Serial Terminal und tippst Python-Commands direkt in den Chip ein. Du kannst sofort Logik testen, Sensorwerte auslesen oder Aktionen triggern.
Um das möglich zu machen, enthält MicroPython spezielle Built-in Modules, die über Standard-Python hinausgehen. Da Standard-Python nichts darüber weiß, wie man physische Pins ausliest oder Hardware-Timer konfiguriert, stellt MicroPython spezialisierte, hochoptimierte Interfaces für diese Tasks bereit. Diese sind direkt in die Firmware deines spezifischen Chips eingebaut und geben dir die rohe Kontrolle über die physische Welt, ohne den Memory Footprint aufzublähen.
Indem das Betriebssystem weggelassen und der Interpreter auf 256 Kilobyte geschrumpft wird, verwandelt MicroPython billige, ressourcenarme Hardware in eine dynamische, interaktive Development Environment. Wenn du die Show unterstützen möchtest, findest du uns, indem du auf Patreon nach DevStoriesEU suchst. Danke fürs Einschalten! Bis zum nächsten Mal!
2
Die Hardware-Brücke: Das machine Modul
4m 00s
Lernen Sie, wie Sie Mikrocontroller-Peripheriegeräte direkt aus Python steuern. Wir tauchen in das machine Modul ein und untersuchen, wie man mit Pins, PWM und rohem Speicher interagiert.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 2 von 7. Hör auf, C-Code neu zu kompilieren und Firmware zu flashen, nur um einen Sensor zu testen oder einen Schalter umzulegen. Du willst direkte Kontrolle über deinen Mikrocontroller ohne die ganze Boilerplate, und genau das bietet dir das machine module.
Das machine module ist deine Hardware-Brücke. Es übersetzt Python-Code in elektrische Signale, die die physischen Pins auf deinem Board ansteuern. Es bietet Zugriff auf zentrale Hardware-Features wie CPU-Frequenz, Sleep-Modes und digitale Inputs und Outputs. Aber weil es so nah an der Hardware arbeitet, bringt es eine Warnung mit sich. Dieses Modul nimmt dich nicht an die Hand. Wenn du das falsche Hardware-Register konfigurierst oder an eine geschützte Speicheradresse schreibst, stürzt dein Board ab und rebootet.
Die Grundlage dieses Moduls ist die Pin-Klasse. Ein Pin ist ein physischer Anschluss am Mikrocontroller, der elektrische Spannungen senden oder empfangen kann. Um eine einfache Komponente wie eine LED zu steuern, musst du Spannung an einen bestimmten Pin anlegen. Das machst du, indem du das machine module importierst und ein Pin-Objekt erstellst. Du übergibst die physische Pin-Nummer und definierst, ob der Pin als Input oder Output fungieren soll. Für eine LED konfigurierst du ihn als Output, indem du eine Output-Konstante übergibst. Sobald das Objekt erstellt ist, nutzt du es, um den State zu setzen. Ein Wert von eins setzt die Hardware-Leitung auf High und schaltet die LED ein. Ein Wert von null setzt sie auf Low und schaltet sie aus. Du manipulierst den digitalen State der Hardware in Echtzeit über einen Python-Prompt.
Manchmal reichen einfache On- und Off-States nicht aus. Wenn du diese LED dimmen oder die Geschwindigkeit eines Motors steuern willst, brauchst du Pulse Width Modulation, oder PWM. Das machine module hat dafür eine eigene PWM-Klasse. Statt eines konstanten Spannungsflusses schaltet PWM den Pin extrem schnell an und aus. Du erstellst ein PWM-Objekt, indem du ihm das Pin-Objekt übergibst, das du bereits konfiguriert hast. Dann setzt du zwei Hardware-Parameter: Frequency und Duty Cycle.
Hier ist die entscheidende Erkenntnis. Die Frequency bestimmt, wie oft pro Sekunde das Signal durchläuft, während der Duty Cycle vorgibt, wie viel Prozent dieser Zeit das Signal tatsächlich an ist. Wenn du den Duty Cycle auf fünfzig Prozent setzt, bekommt die LED nur die halbe Zeit Strom, wodurch sie für das menschliche Auge nur halb so hell wirkt. Indem du diesen Duty-Cycle-Wert innerhalb eines Loops schrittweise änderst, weist du die Hardware an, einen sanften Fading-Effekt zu erzeugen.
Für fortgeschrittene Use Cases bietet das machine module direkten Zugriff auf die zugrundeliegenden Hardware-Register über Objekte namens mem8, mem16 und mem32. Diese erlauben es dir, Raw Bytes, Half-Words oder 32-Bit-Words direkt an bestimmten Speicheradressen zu lesen und zu schreiben. Dafür benutzt du kein Pin-Objekt. Du nutzt die Standard-Bracket-Notation und übergibst die physische Speicheradresse, auf die du zugreifen willst, genau wie beim Nachschlagen eines Keys in einem Dictionary. Die Zuweisung eines Wertes an eine mem32-Adresse überschreibt dieses Hardware-Register sofort. So interagierst du mit obskuren Mikrocontroller-Features, die MicroPython noch nicht explizit in einer Klasse gewrappt hat. Das gibt dir die absolute Kontrolle über das Silizium.
Die wahre Stärke des machine modules ist nicht nur, dass es Hardware zugänglich macht, sondern dass es die Barriere zwischen dem Schreiben von High-Level-Software-Logik und dem Manipulieren physischer Spannung komplett beseitigt.
Danke fürs Zuhören. Macht's gut, Leute.
3
Live-Coding der MCU: REPL und mpremote
4m 03s
Revolutionieren Sie Ihren Embedded-Entwicklungs-Workflow. Wir behandeln die MicroPython REPL und das mpremote Kommandozeilen-Tool zur Automatisierung serieller Verbindungen und Live-Ausführung.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 3 von 7. Vergiss den mühsamen Compile-, Flash- und Reboot-Zyklus. In einem typischen Embedded-Projekt änderst du eine Variable, wartest minutenlang auf den Build, schreibst in den Flash-Speicher und hoffst, dass es funktioniert. MicroPython umgeht das komplett, indem du direkt und in Echtzeit mit dem Chip kommunizieren kannst. In dieser Folge geht es um Live Coding der MCU mit der REPL und mpremote.
REPL steht für Read-Eval-Print Loop. Das ist ein interaktiver Prompt, der direkt auf deinem Mikrocontroller läuft. Du verbindest dein Board über USB, öffnest ein serielles Terminal, tippst Python-Code ein, und der Chip führt ihn sofort aus. Die Standard-REPL ist für Menschen gemacht. Sie bietet Auto-Indentation, Command History und grundlegende Auto-Completion. Sie ist perfekt, um mal eben einen Hardware-Pin zu toggeln.
Es gibt aber noch einen zweiten Modus, die Raw REPL. Leute verwechseln das oft mit einer eingeschränkten Version von MicroPython, aber eigentlich ist es nur ein anderer Input-Modus, der getriggert wird, indem man ein bestimmtes Control Character über Serial sendet. Die Raw REPL deaktiviert Character Echo und Auto-Indentation. Tools nutzen die Raw REPL, um große Codeblöcke programmatisch in den Mikrocontroller zu injecten. Wenn ein Script versuchen würde, Text in die Standard-REPL zu pasten, würde die menschenfreundliche Auto-Indentation kaskadieren und die Python-Formatierung komplett zerschießen. Die Raw REPL garantiert, dass der Code exakt so reingeht, wie er geschrieben wurde.
Das bringt uns zu mpremote. Das ist das offizielle Command-Line-Tool für die Interaktion mit MicroPython-Devices, und es steuert unter der Haube die Raw REPL, um das Heavy Lifting zu übernehmen. Für Live Coding bietet mpremote zwei mächtige Commands: run und mount.
Den run Command nutzt du, um ein lokales Script von deinem Computer direkt auf dem Board auszuführen. Du schreibst deinen Code in deinem Lieblings-Texteditor, öffnest dein Terminal und rufst mpremote run gefolgt von deinem Dateinamen auf. Hier ist der entscheidende Punkt. Der Code wird über die Serial Line gesendet und komplett im RAM des Mikrocontrollers ausgeführt. Er wird niemals in den Flash-Speicher des Devices geschrieben. Wenn du einen schlechten Loop schreibst und das Board crasht, machst du einfach einen Hard Reset am Chip. Der Flash bleibt unberührt, das spart Write Cycles, und dein Development Loop dauert nur Sekunden.
Wenn dein Projekt über ein einzelnes Script hinauswächst, nutzt du den mount Command. Dieser Command sagt mpremote, dass es ein lokales Directory auf deinem PC nehmen und über die Serial Connection mappen soll. Der Mikrocontroller überschreibt temporär seinen eigenen Storage und behandelt diesen Ordner auf deinem Computer, als wäre er sein internes Filesystem.
Stell dir ein Szenario vor, in dem du einen komplexen Display Driver schreibst. Normalerweise müsstest du das Driver File auf das Board kopieren, dein Main Script ausführen, einen Screen Glitch beobachten, das File auf deinem PC editieren und es wieder rüberkopieren. Mit dem mount Command führt der Mikrocontroller den Driver direkt von deinem PC-Storage aus. Du drückst Save in deinem Texteditor auf dem Laptop, startest das Script auf dem Board neu, und die Änderungen greifen sofort. Du iterierst so schnell, wie du tippen kannst, und eliminierst den Flashing-Schritt komplett aus deinem Workflow.
Die wahre Power von MicroPython ist nicht nur die Python-Syntax selbst, sondern wie Tools wie mpremote die Grenze zwischen deiner lokalen Development Environment und der physischen Embedded-Hardware auflösen. Das war's für diese Folge. Danke fürs Zuhören und keep building!
4
Drei Zeilen zum WiFi: Das network Modul
4m 10s
Verwandeln Sie einen Mikrocontroller in einen vernetzten IoT-Knoten. Wir erkunden das network Modul und erklären im Detail, wie man sich als Station mit dem WiFi verbindet oder einen eigenen Access Point hostet.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 4 von 7. Einen Mikrocontroller mit herkömmlichem C-Code in ein WLAN-Netzwerk einzubinden, erfordert normalerweise Hunderte von Zeilen Boilerplate-Code allein für die Initialisierung des Funkmoduls und den Handshake. Das ist mühsam und fehleranfällig. In MicroPython kannst du eine drahtlose Verbindung in buchstäblich drei Zeilen aufbauen. Das ist der Job des network Moduls, genauer gesagt der WLAN Klasse.
Das network Modul abstrahiert die zugrundeliegenden Hardware-Netzwerkschnittstellen. Für WLAN-Operationen verlässt du dich auf die network Punkt WLAN Klasse. Ein Standard-WLAN-Chip kann in zwei verschiedenen Rollen arbeiten. Du musst explizit festlegen, welche Rolle du haben willst, wenn du das WLAN Objekt erstellst.
Die erste Rolle ist der Station Mode, der mit der Konstante STA underscore IF angegeben wird. Du verwendest den Station Mode, wenn sich deine Hardware als Client mit einem Upstream-Router verbinden muss, genau wie ein Smartphone, das sich mit einem Heimnetzwerk verbindet. Die zweite Rolle ist der Access Point Mode, angegeben durch AP underscore IF. In diesem Modus fungiert der Mikrocontroller selbst als Router und sendet sein eigenes drahtloses Netzwerk aus, sodass sich externe Geräte direkt damit verbinden können. Der Access Point Mode ist unglaublich nützlich, wenn du Hardware an abgelegenen Orten deployest, wo kein externes Netzwerk existiert, sodass du dich zur Konfiguration lokal verbinden kannst.
Um dein Board online zu bringen, ist eine bestimmte Abfolge erforderlich. Zuerst erstellst du das WLAN Objekt mit der Station Mode Konstante. Standardmäßig ist das physische WLAN-Modul heruntergefahren, um Energie zu sparen. Du musst es einschalten, indem du True an die active Methode deines WLAN Objekts übergibst. Sobald das Interface aktiv ist, rufst du die connect Methode mit deinem WLAN-Namen und Passwort auf.
Hier ist die wichtigste Erkenntnis. Die connect Methode ist strikt non-blocking. Wenn du sie aufrufst, übergibt MicroPython die Credentials an den Netzwerkprozessor und führt dein Script sofort weiter aus. Es wartet bewusst nicht darauf, dass die Netzwerkauthentifizierung abgeschlossen ist. Dieses Design erlaubt es deiner Hauptanwendung, ein Display zu updaten oder einen Sensor auszulesen, während das Funkmodul im Hintergrund mit dem Router verhandelt. Wenn dein Code jedoch versucht, sofort nach dem Aufruf von connect Daten zu senden, wird die Operation crashen, weil das Board eigentlich noch gar keine Verbindung hat.
Du managst das, indem du das Interface pollst. Das WLAN Objekt bietet eine Methode namens isconnected, die einen einfachen Boolean-Wert zurückgibt. Das Standard-Pattern ist, eine while-Schleife zu schreiben, die auswertet, ob isconnected false ist. Innerhalb dieser Schleife baust du ein kurzes Delay ein, zum Beispiel einen Sleep von einer halben Sekunde. Die Ausführung pausiert hier und checkt wiederholt den Hardware-Status, bis der Router die Verbindung endlich akzeptiert und isconnected true zurückgibt.
Sobald die Schleife terminiert, ist die Hardware offiziell online. Um die Netzwerkdetails zu verifizieren, rufst du die ifconfig Methode auf deinem WLAN Objekt auf. Diese Methode gibt eine Collection von vier spezifischen Elementen aus: die zugewiesene IP-Adresse, die Subnetzmaske, das Gateway und den primären DNS-Server. Du kannst das erste Element aus dieser Collection extrahieren und in der Konsole printen, um genau zu sehen, welche IP-Adresse der Router deinem Board zugewiesen hat.
Die non-blocking Natur der connect Methode bedeutet, dass du immer dafür verantwortlich bist, den Hardware-Status zu verifizieren, bevor du versuchst, Daten über das Netzwerk zu routen.
Das war's für heute. Danke fürs Zuhören – geh und bau etwas Cooles.
5
Die Einschränkungen überleben: RAM und der GC
4m 03s
Meistern Sie die Kunst, speichereffizientes Python zu schreiben. Wir diskutieren Heap Fragmentation, das Vorab-Zuweisen von Buffern und manuelle Garbage Collection, damit Ihr Mikrocontroller reibungslos läuft.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 5 von 7. Python liebt es, Speicher dynamisch zu allokieren und für jede Berechnung neue Objekte zu erstellen. Auf einem Server funktioniert das perfekt, aber auf einem Microcontroller wird diese Angewohnheit dein Board irgendwann zum Absturz bringen, sodass du auf einen Memory Error starrst, selbst wenn du scheinbar noch RAM übrig hast. Heute konzentrieren wir uns auf das Thema: Überleben der Constraints – RAM und der GC.
Der Speicher, in dem deine Python-Objekte leben, wird Heap genannt. In MicroPython ist der Heap extrem klein. Wenn du Objekte erstellst, belegen sie Speicherblöcke. Wenn diese Objekte nicht mehr gebraucht werden, werden sie abgeräumt. Das hinterlässt Lücken in deinem Speicher. Mit der Zeit, wenn Objekte unterschiedlicher Größe erstellt und zerstört werden, sieht dein Heap aus wie ein Schweizer Käse. Das ist Heap-Fragmentierung. Hier ist die entscheidende Erkenntnis. Wenn du ein neues Objekt allokieren musst, braucht MicroPython einen einzigen, zusammenhängenden Speicherblock dafür. Wenn dein Heap stark fragmentiert ist, hast du vielleicht insgesamt zwanzig Kilobyte freien RAM, aber keine einzige Lücke, die größer als ein Kilobyte ist. Wenn du zwei Kilobyte anforderst, stürzt dein Programm ab.
Du musst aufhören, RAM zu verschwenden, angefangen bei deinen globalen Variablen. Wenn du Integer-Werte hast, die sich nie ändern, wie Pin-Nummern oder Hardware-Adressen, weise sie nicht normal zu. MicroPython bietet eine spezielle Deklaration namens const. Wenn du deinen Integer in diese const-Deklaration packst, ersetzt der Compiler den Variablennamen während der Kompilierung überall in deinem Code durch die tatsächliche Zahl. Das verhindert komplett, dass überhaupt eine Variable im RAM angelegt wird.
Schau dir als Nächstes deine Loops an. Dynamische Objekterstellung innerhalb eines schnell laufenden Loops ist die Hauptursache für Fragmentierung. Du liest einen Sensor hundertmal pro Sekunde über einen SPI-Bus aus. Wenn du einen Standard-Read-Command verwendest, erzeugt MicroPython für jeden einzelnen Lesevorgang eine brandneue Byte-Sequenz im Speicher. Diese Objekte häufen sich schnell an, füllen die Lücken und zerstören deinen zusammenhängenden Speicherplatz.
Anstatt neue Objekte zu erstellen, verwende die wieder, die du schon hast. Bevor dein Loop beginnt, erstelle ein bytearray in der richtigen Größe. Ein bytearray ist ein mutable Speicherblock. Verwende dann innerhalb deines Loops eine Hardware-Methode namens readinto. Du übergibst dein bereits existierendes bytearray an readinto. Die Hardware schreibt die Sensordaten direkt in denselben Speicherblock und überschreibt die alten Daten. Du verarbeitest die Daten, der Loop wiederholt sich, und es wird null neuer Speicher allokiert.
Selbst bei sorgfältigem Coding lässt sich die Erstellung einiger Objekte nicht vermeiden, was uns zum Garbage Collector bringt. Standardmäßig läuft der Garbage Collector automatisch, wenn die Memory Allocation fehlschlägt. Er scannt nach ungenutzten Objekten und gibt deren Speicherplatz frei. Dieser Prozess braucht jedoch Zeit. Wenn er während einer zeitkritischen Operation automatisch triggert, wird dein Code unvorhersehbar pausieren. Um das zu beheben, übernimmst du die Kontrolle. Rufe die collect-Funktion aus dem gc-Modul explizit auf. Suche dir eine sichere Stelle in deinem Code, wie das Ende deines Main-Loops, und triggere die Collection dort. Das hält den Heap nach deinem Zeitplan sauber und verhindert unerwartete Verzögerungen.
In Desktop-Python ist Speicher etwas, das die Sprache für dich übernimmt, aber in MicroPython ist Speicher ein physischer Container, den du von Hand packen musst.
Das war's für diese Folge. Danke fürs Zuhören, und keep building!
6
Kompiliert vs. Frozen: Deployment für die Produktion
4m 18s
Lernen Sie, wie Sie massive Anwendungen deployen, ohne dass Ihnen der RAM ausgeht. Wir untersuchen vorkompilierte .mpy-Dateien und das Einfrieren von Bytecode direkt in den Flash-Speicher des Mikrocontrollers.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 6 von 7. Du lädst eine einwandfreie Python-Datei auf deinen Mikrocontroller, tippst import ein, und das Board stürzt sofort mit einem Out of Memory Error ab. Der Code selbst ist in Ordnung, aber allein der Ladevorgang hat deinen gesamten verfügbaren Speicher belegt. Um das zu beheben, musst du den On-Device-Compiler umgehen, was uns zum Thema Compiled versus Frozen Code für Production Deployments bringt.
Wenn du ein Standard-Python-Skript auf einem Desktop ausführst, ist der Speicher praktisch unbegrenzt. Auf einem Mikrocontroller ist der Speicher hingegen streng begrenzt. Wenn du eine Standard-Python Source File auf dein Gerät ziehst und den import-Befehl ausführst, liest MicroPython die Datei nicht einfach nur ein. Der Compiler startet direkt dort auf dem Mikrocontroller. Er parst den Text, baut einen Abstract Syntax Tree und generiert Bytecode. Jeder einzelne dieser Schritte allokiert Speicher im RAM.
Stell dir ein großes IoT-Framework vor, das Networking, Security und Sensordaten verarbeitet. Wenn du versuchst, dieses riesige Modul aus einer Standard Source File zu importieren, wird der Compiler wahrscheinlich den verfügbaren Heap Memory erschöpfen, bevor die erste Zeile deiner eigentlichen Anwendung überhaupt ausgeführt wird. Der Spike in der RAM-Auslastung während der Compilation-Phase killt den Prozess.
Um das zu umgehen, musst du den Compilation-Schritt vom Mikrocontroller entfernen. Das machst du, indem du deinen Code mit einem Desktop-Tool namens Cross-Compiler oder mpy-cross vorkompilierst. Du führst dieses Tool auf deinem Hauptrechner aus. Es liest deine Python Source File ein und gibt eine kompilierte Datei mit der Endung M-P-Y aus. Diese Datei enthält den vorab generierten Bytecode.
Wenn du diese kompilierte Datei auf den Mikrocontroller überträgst und importierst, erkennt MicroPython das Format und überspringt die Compilation-Phase komplett. Du vermeidest so komplett den Memory Spike, der durch den Compiler verursacht wird. Hier wird es interessant. Obwohl dich das Vorkompilieren vor dem Compilation Memory Spike bewahrt, lädt der Mikrocontroller den eigentlichen Bytecode immer noch aus dem File System in den RAM, um ihn auszuführen. Wenn dein IoT-Framework groß genug ist, verbraucht allein der Bytecode immer noch zu viel RAM, sodass dir nur sehr wenig Platz für deine Application-Variablen und Daten bleibt.
Wenn vorkompilierte Dateien nicht ausreichen, ist der letzte Schritt das Freezing des Bytecodes. Freezing bedeutet, den kompilierten Code direkt in die MicroPython Firmware einzubacken. Anstatt die kompilierte Datei in das File System des Boards zu kopieren, legst du sie in ein bestimmtes Modules Directory innerhalb des MicroPython Source Codes auf deinem Computer. Anschließend baust du das gesamte MicroPython Firmware Image von Grund auf neu und flashst diese Custom Firmware auf dein Board.
Das ändert genau, wie der Code ausgeführt wird. Wenn du ein Frozen Module importierst, kopiert MicroPython den Bytecode überhaupt nicht in den RAM. Weil der Code in die Firmware eingebacken ist, liegt er permanent im Flash Memory des Mikrocontrollers. MicroPython führt den Bytecode direkt aus dem Flash aus. Durch die Ausführung aus dem Flash sinkt der RAM Footprint beim Importieren dieses riesigen IoT-Frameworks auf nahezu null. Dein gesamter RAM bleibt komplett frei für die Verarbeitung von Real-Time-Daten.
Der grundlegende Unterschied liegt darin, wo dein Code während der Runtime lebt. Vorkompilieren spart Memory während des Import-Schritts, aber Freezing spart Memory für die gesamte Lebensdauer des Programms, indem es die Ausführung komplett in den Flash Memory zwingt. Wenn du die Show unterstützen möchtest, kannst du auf Patreon nach DevStoriesEU suchen. Das war's für diese Folge. Danke fürs Zuhören und keep building!
7
Determinismus in Python: Timer und Interrupts
4m 06s
Erreichen Sie Echtzeitverhalten in MicroPython durch die Verwendung von Hardware-Timern und Interrupt Service Routines. Wir behandeln die strengen Regeln für das Schreiben von ISRs und die Vermeidung von Speicherzuweisungen.
Hallo, hier ist Alex von DEV STORIES DOT EU. MicroPython, Folge 7 von 7. Eine Hardware Interrupt Service Routine in einer High-Level, garbage-collected Sprache zu schreiben, klingt, als würde man um einen sofortigen Systemabsturz betteln. Doch MicroPython erlaubt das tatsächlich, solange du eine unumstößliche Regel befolgst: Zero Memory Allocation. Diese Folge behandelt Determinismus in Python: Timer und Interrupts.
Wenn du einen Sensor genau tausendmal pro Sekunde auslesen musst, wird eine Standard-Loop mit einer Sleep-Funktion versagen. Garbage Collection und Background Tasks verursachen zufällige Verzögerungen und zerstören dein Timing. Um deterministisches Verhalten zu bekommen, brauchst du einen Hardware-Timer. Mit dem machine-Modul konfigurierst du ein Timer-Objekt so, dass es periodisch feuert und eine bestimmte Callback-Funktion ausführt. Dieser Callback ist deine Interrupt Service Routine, oder kurz ISR.
Timer lösen entweder Soft- oder Hard-Interrupts aus. Ein Soft-Interrupt wird von der MicroPython Virtual Machine gescheduled, sobald das sicher möglich ist. Du schreibst eine Soft-ISR genau wie normalen Python-Code. Sie kann Objekte erstellen, an Listen appenden und Floats verarbeiten. Der Nachteil ist die Latenz. Wenn der Garbage Collector gerade läuft, während der Timer feuert, wartet dein Soft-Interrupt einfach in der Warteschlange.
Wenn du strikte Timing-Genauigkeit brauchst, konfigurierst du den Timer so, dass er einen Hard-Interrupt auslöst. Ein Hard-Interrupt stoppt den Prozessor sofort. Er umgeht die Virtual Machine und führt deinen Callback sofort aus. Hier ist die entscheidende Erkenntnis: Weil ein Hard-Interrupt den aktuellen Systemzustand unterbricht, könnte er den Memory Manager selbst unterbrechen. Wenn deine ISR versucht, Memory auf dem Heap zu allokieren, während der Heap gerade verändert wird, stürzt der Microcontroller ab.
Diese Einschränkung diktiert genau, wie du Hard-ISRs schreibst. Du darfst keinen Memory allokieren. Keine Listen erstellen. Keine Dictionaries bauen. Keine String-Manipulation. Selbst Floating-Point-Mathematik ist strengstens verboten, denn in Python ist jeder Float ein neu allokiertes Objekt auf dem Heap. Dein Code muss schnell ausführen, auf Integer-Mathematik setzen und bereits existierende Memory-Strukturen nutzen.
Stell dir ein Szenario vor, in dem ein Hardware-Timer mit 1000 Hertz feuert. Jede Millisekunde liest die Hard-ISR einen Sensorwert. Da du den Messwert nicht an eine Liste appenden kannst, musst du deinen Speicher pre-allokieren, bevor du den Timer startest. Du erstellst ein bytearray von tausend Bytes in deinem Main-Programm. Außerdem definierst du eine globale Index-Variable.
Wenn der Timer feuert, liest die ISR den Sensor. Sie updatet den globalen Index, speichert den rohen Integer an dieser Position im bytearray und beendet sich. Der Memory-Space wurde komplett im Voraus reserviert. Der Interrupt updatet ihn einfach in-place, was eine jitter-freie Ausführung garantiert. Sobald der Buffer voll ist, muss die ISR die Daten an das Main-Programm übergeben. Du kannst eine komplexe Datenverarbeitungsfunktion nicht direkt aus der Hard-ISR triggern. Stattdessen nutzt du micropython dot schedule. Diese Funktion nimmt eine Referenz auf einen Callback und reiht ihn in die Queue ein, damit er ausgeführt wird, sobald das System in einen sicheren Soft-Execution-State zurückkehrt.
Das Handling von Hardware-Interrupts zwingt dich dazu, aufzuhören, Python als unendlichen Ressourcen-Pool zu betrachten, und stattdessen genau zu tracken, wann und wo dein Memory zugewiesen wird. Check die offizielle MicroPython-Dokumentation für das spezifische Interrupt-Verhalten deines Hardware-Ports, und versuch mal absichtlich die Memory-Regeln auf deinem eigenen Board zu brechen, um zu sehen, wie das System reagiert. Wenn du Themen für unsere nächste Serie vorschlagen willst, schau auf devstories dot eu vorbei. Ich möchte mir kurz die Zeit nehmen, dir fürs Zuhören zu danken – das hilft uns sehr. Mach's gut!
Tap to start playing
Browsers block autoplay
Share this episode
Episode
—
Copy this episode in another language:
Diese Website verwendet keine Cookies. Unser Hosting-Anbieter protokolliert möglicherweise deine IP-Adresse zu Analysezwecken. Mehr erfahren.