micropython — Zugriff auf und Steuerung von MicroPython-Interna

Funktionen

micropython.const(expr: int) int

Wird verwendet, um zu deklarieren, dass der Ausdruck eine Konstante ist, sodass der Compiler ihn optimieren kann. Diese Funktion sollte wie folgt verwendet werden:

from micropython import const

CONST_X = const(123)
CONST_Y = const(2 * CONST_X + 1)

Auf diese Weise deklarierte Konstanten sind nach wie vor als globale Variablen von außerhalb des Moduls zugänglich, in dem sie deklariert wurden. Beginnt eine Konstante dagegen mit einem Unterstrich, dann ist sie verborgen, steht nicht als globale Variable zur Verfügung und belegt während der Ausführung keinen Speicher.

Diese const-Funktion wird vom MicroPython-Parser direkt erkannt und wird als Teil des Moduls micropython hauptsächlich deshalb bereitgestellt, damit Skripte geschrieben werden können, die nach dem obigen Muster sowohl unter CPython als auch unter MicroPython laufen.

micropython.opt_level(level: int | None = None) int | None

Wenn level angegeben ist, legt diese Funktion die Optimierungsstufe für die anschließende Kompilierung von Skripten fest und gibt None zurück. Andernfalls gibt sie die aktuelle Optimierungsstufe zurück.

Die Optimierungsstufe steuert die folgenden Kompilierungsmerkmale:

  • Assertions: Auf Stufe 0 sind Assertion-Anweisungen aktiviert und werden in den Bytecode kompiliert; auf Stufe 1 und höher werden Assertions nicht kompiliert.

  • Eingebaute __debug__-Variable: Auf Stufe 0 wird diese Variable zu True ausgewertet; auf Stufe 1 und höher zu False.

  • Quellcode-Zeilennummern: Auf Stufe 0, 1 und 2 werden die Quellcode-Zeilennummern zusammen mit dem Bytecode gespeichert, sodass Exceptions die Zeilennummer melden können, an der sie aufgetreten sind; auf Stufe 3 und höher werden Zeilennummern nicht gespeichert.

Die Standard-Optimierungsstufe ist üblicherweise Stufe 0.

micropython.alloc_emergency_exception_buf(size: int) None

Reserviert size Bytes RAM für den Notfall-Exception-Puffer (eine gute Größe sind etwa 100 Bytes). Der Puffer wird verwendet, um Exceptions in Fällen zu erzeugen, in denen die normale RAM-Reservierung fehlschlagen würde (z. B. innerhalb eines Interrupt-Handlers), und liefert in diesen Situationen daher nützliche Traceback-Informationen.

Eine gute Möglichkeit, diese Funktion zu verwenden, besteht darin, sie an den Anfang Ihres Hauptskripts zu setzen (z. B. boot.py oder main.py); dann ist der Notfall-Exception-Puffer für den gesamten nachfolgenden Code aktiv.

micropython.mem_info(verbose: Any | None = None) None

Gibt Informationen über den aktuell verwendeten Speicher aus. Wenn das Argument verbose angegeben ist, werden zusätzliche Informationen ausgegeben.

Die ausgegebenen Informationen sind implementierungsabhängig, umfassen derzeit aber die Menge des verwendeten Stacks und Heaps. Im verbose-Modus wird der gesamte Heap ausgegeben, wobei angezeigt wird, welche Blöcke belegt und welche frei sind.

micropython.qstr_info(verbose: Any | None = None) None

Gibt Informationen über die aktuell internierten Strings aus. Wenn das Argument verbose angegeben ist, werden zusätzliche Informationen ausgegeben.

Die ausgegebenen Informationen sind implementierungsabhängig, umfassen derzeit aber die Anzahl der internierten Strings und die Menge des RAM, den sie belegen. Im verbose-Modus werden die Namen aller im RAM internierten Strings ausgegeben.

micropython.stack_use() int

Gibt eine Ganzzahl zurück, die die aktuell verwendete Menge an Stack darstellt. Der absolute Wert ist nicht besonders nützlich; vielmehr sollte er verwendet werden, um Unterschiede in der Stack-Nutzung an verschiedenen Punkten zu berechnen.

micropython.heap_lock() None

Sperrt den Heap. Während er gesperrt ist, kann keine Speicherreservierung erfolgen, und ein MemoryError wird ausgelöst, wenn eine Heap-Reservierung versucht wird.

Sperren sind verschachtelbar: Ein mehrfacher Aufruf von heap_lock() erhöht die Sperrtiefe. Der Heap bleibt gesperrt, bis heap_unlock() gleich oft aufgerufen wurde.

Wenn die REPL aktiv wird, während der Heap gesperrt ist, wird er zwangsweise entsperrt.

micropython.heap_unlock() int

Verringert die Heap-Sperrtiefe um eins und gibt die neue Tiefe als nichtnegative Ganzzahl zurück. Ein Rückgabewert von 0 bedeutet, dass der Heap nicht mehr gesperrt ist und Reservierungen wieder erlaubt sind.

micropython.heap_locked() int

Gibt die aktuelle Heap-Sperrtiefe als nichtnegative Ganzzahl zurück; 0 bedeutet, dass der Heap nicht gesperrt ist.

Hinweis: Diese Funktion ist auf der OpenMV Cam nicht verfügbar.

micropython.kbd_intr(chr: int) None

Legt das Zeichen fest, das eine KeyboardInterrupt-Exception auslöst. Standardmäßig ist dies während der Skriptausführung auf 3 gesetzt, was Strg-C entspricht. Die Übergabe von -1 an diese Funktion deaktiviert die Erfassung von Strg-C, und die Übergabe von 3 stellt sie wieder her.

Diese Funktion kann verwendet werden, um die Erfassung von Strg-C im eingehenden Zeichenstrom zu verhindern, der normalerweise für die REPL verwendet wird, falls dieser Strom für andere Zwecke genutzt wird.

micropython.schedule(func: Callable[[Any], Any], arg: Any) None

Plant die Funktion func zur Ausführung „sehr bald“. Der Funktion wird der Wert arg als ihr einziges Argument übergeben. „Sehr bald“ bedeutet, dass die MicroPython-Laufzeitumgebung ihr Bestes tut, die Funktion zum frühestmöglichen Zeitpunkt auszuführen, wobei sie auch versucht, effizient zu sein, und sofern die folgenden Bedingungen gelten:

  • Eine geplante Funktion wird niemals eine andere geplante Funktion verdrängen.

  • Geplante Funktionen werden stets „zwischen Opcodes“ ausgeführt, was bedeutet, dass alle grundlegenden Python-Operationen (wie etwa das Anhängen an eine Liste) garantiert atomar sind.

  • Ein bestimmter Port kann „kritische Bereiche“ definieren, innerhalb derer geplante Funktionen niemals ausgeführt werden. Funktionen können innerhalb eines kritischen Bereichs geplant werden, aber sie werden erst ausgeführt, wenn dieser Bereich verlassen wird. Ein Beispiel für einen kritischen Bereich ist ein verdrängender Interrupt-Handler (ein IRQ).

  • Innerhalb von Native-Code-Funktionen werden geplante Funktionen nicht aufgerufen, es sei denn, der Native-Code ruft eine Funktion auf, die dies ausdrücklich tut.

  • Bestimmte Funktionen wie poll.poll, poll.ipoll, time.sleep und time.sleep_ms (einschließlich Sleeps mit der Dauer null) rufen geplante Funktionen auf.

Eine Verwendungsmöglichkeit dieser Funktion besteht darin, einen Callback aus einem verdrängenden IRQ heraus zu planen. Ein solcher IRQ legt Einschränkungen für den im IRQ ausgeführten Code fest (zum Beispiel kann der Heap gesperrt sein), und das Planen einer Funktion zur späteren Ausführung hebt diese Einschränkungen auf.

Auf Ports mit mehreren Threads hängt das Verhalten der geplanten Funktion davon ab, ob das Global Interpreter Lock (GIL) für den jeweiligen Port aktiviert ist:

  • Wenn das GIL aktiviert ist, kann die Funktion jeden Thread verdrängen und in dessen Kontext laufen.

  • Wenn das GIL deaktiviert ist, verdrängt die Funktion nur den Haupt-Thread und läuft in dessen Kontext.

Hinweis: Wenn schedule() aus einem verdrängenden IRQ heraus aufgerufen wird, wenn keine Speicherreservierung erlaubt ist und der an schedule() zu übergebende Callback eine gebundene Methode ist, schlägt die direkte Übergabe fehl. Das liegt daran, dass das Erstellen einer Referenz auf eine gebundene Methode eine Speicherreservierung verursacht. Eine Lösung besteht darin, im Klassenkonstruktor eine Referenz auf die Methode zu erstellen und diese Referenz an schedule() zu übergeben. Dies wird ausführlich hier in der Referenzdokumentation unter „Creation of Python objects“ behandelt.

Es gibt eine endliche Warteschlange für die geplanten Funktionen, und schedule() löst einen RuntimeError aus, wenn die Warteschlange voll ist.

Klassen

class micropython.RingIO(size: int)
class micropython.RingIO(buffer: bytes | bytearray | memoryview)

Stellt einen Ringpuffer fester Größe für Bytes mit einer Stream-Schnittstelle bereit. Kann als FIFO-Warteschlangenvariante von io.BytesIO betrachtet werden. Die beiden Konstruktorformen unterscheiden sich nur darin, wie der zugrunde liegende Puffer bereitgestellt wird:

  • RingIO(size) reserviert den zugrunde liegenden Puffer intern. Der klassische Ringpuffer-Algorithmus reserviert ein Byte zur Nachverfolgung, sodass der reservierte Puffer ein Byte größer als size ist und die Instanz die vollen size Bytes an Daten aufnehmen kann. Zum Beispiel reserviert RingIO(16) einen 17-Byte-Puffer und nimmt 16 Bytes an Daten auf.

  • RingIO(buffer) verwendet den bereitgestellten buffer direkt, anstatt einen zu reservieren. Da ein Byte zur Nachverfolgung reserviert ist, kann die Instanz len(buffer) - 1 Bytes an Daten aufnehmen. Zum Beispiel nimmt RingIO(bytearray(16)) 15 Bytes an Daten auf.

Eine RingIO-Instanz ist IRQ-/Thread-sicher, wenn sie verwendet wird, um Daten in eine einzige Richtung zu übergeben (zum Beispiel aus einem IRQ heraus beschrieben und von einer Nicht-IRQ-Funktion gelesen oder umgekehrt). Dies gilt nicht, wenn eine einzelne Instanz sowohl aus IRQ- als auch aus Nicht-IRQ-Kontexten beschrieben wird, was häufig zu Datenkorruption führen würde.

any() int

Gibt eine Ganzzahl zurück, die die Anzahl der Zeichen zählt, die gelesen werden können.

read(nbytes: int | None = None) bytes

Liest verfügbare Zeichen. Dies ist eine nicht blockierende Funktion. Wenn nbytes angegeben ist, werden höchstens so viele Bytes gelesen, andernfalls werden so viele Daten wie möglich gelesen.

Rückgabewert: ein Bytes-Objekt, das die gelesenen Bytes enthält. Es ist ein Bytes-Objekt der Länge null, wenn keine Daten verfügbar sind.

readline(nbytes: int | None = None) bytes

Liest eine Zeile, die mit einem Zeilenumbruchzeichen endet, oder gibt zurück, falls ein solches im Puffer existiert, andernfalls werden die im Puffer verfügbaren Bytes zurückgegeben. Wenn nbytes angegeben ist, werden höchstens so viele Bytes gelesen.

Rückgabewert: ein Bytes-Objekt, das die gelesene Zeile enthält.

readinto(buf: bytearray | memoryview, nbytes: int | None = None) int

Liest verfügbare Bytes in den bereitgestellten buf. Wenn nbytes angegeben ist, werden höchstens so viele Bytes gelesen. Andernfalls werden höchstens len(buf) Bytes gelesen.

Rückgabewert: Ganzzahl, die die Anzahl der in buf gelesenen Bytes angibt.

write(buf: bytes | bytearray | memoryview) int

Nicht blockierendes Schreiben von Bytes aus buf in den Ringpuffer, begrenzt durch den verfügbaren Platz im Ringpuffer.

Rückgabewert: Ganzzahl, die die Anzahl der geschriebenen Bytes angibt.

close() None

No-Op, das als Teil der Standard-stream-Schnittstelle bereitgestellt wird. Hat keine Auswirkung auf die Daten im Ringpuffer.