C-Erweiterung für MicroPython auf Raspberry Pi Pico

Dies ist eine Anleitung, wie man eine einfache C-Erweiterung für MicroPython auf dem Raspberry Pi Pico schreibt und ausführt. Ich werde die Gründe für die Erweiterung von MicroPython behandeln, wie man das Erweiterungsmodul schreibt, wie man es kompiliert und wie man es auf dem Pico installiert. Wenn Sie mehr über dieses Thema lesen möchten, lesen Sie bitte https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Einführung

Warum MicroPython erweitern?

Es kann mehrere Gründe geben, warum Sie MicroPython erweitern möchten. Da es sich um eine abgespeckte Version von Python handelt, ist MicroPython nicht sehr leistungsfähig, wenn es um rechenintensive Aufgaben geht (ähnlich wie Python). C hingegen ist für solche Aufgaben sehr gut geeignet. Eine C-Erweiterung für Micropython ermöglicht es Ihnen, diese Berechnungen in C durchzuführen und die Ergebnisse in MicroPython zu verwenden. Dies kann einige Prozesse um Größenordnungen beschleunigen.

Ein zweiter Grund könnte sein, dass Sie Hardware, die eine C-API verwendet, von MicroPython aus ansprechen wollen. 

Arten von MicroPython C-Erweiterungen

Es gibt zwei verschiedene Möglichkeiten, MicroPython zu erweitern: externe C-Module und nativer Maschinencode in .mpy-Dateien.

Um ein externes C-Modul auszuführen, müssen Sie es in die MicroPython-Firmware rekompilieren. Dies ist ein ziemlich komplizierter Prozess, weshalb sich dieser Leitfaden auf die zweite Alternative konzentriert. Wenn Sie jedoch an diesem Ansatz interessiert sind, können Sie auf diesen Webseiten mehr darüber lesen:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

Die .mpy ist eine Datei, die kompilierten nativen Maschinencode enthält und dynamisch gelinkt werden kann. Das macht es viel flexibler, da Sie nicht die gesamte MicroPython-Firmware neu kompilieren müssen.

Schreiben Sie das Erweiterungsmodul

Das Schreiben des Erweiterungsmoduls ist der einfachste Teil der Erweiterung von MicroPython. Ich werde Ihnen anhand eines einfachen Beispiels zeigen, wie es geht. Zu Beginn erstellen wir ein neues Verzeichnis namens factfib. Öffnen Sie ein neues Terminalfenster, wechseln Sie in das neue Verzeichnis und erstellen Sie eine neue Datei namens factfib.c. Wenn Sie das Verzeichnis auf einem Raspberry Pi unter Dekstop erstellt haben, sieht der Befehl wie folgt aus.

cd ~/Desktop/factfib

touch factfib.c

Öffnen Sie factfib.c in Ihrem bevorzugten Texteditor und geben Sie den folgenden Code ein:

#include "py/dynruntime.h

STATIC mp_int_t factorial_helper(mp_int_t x) {
   if (x < 1) {
      return 1;
   }
   return x*factorial_helper(x-1);
}

STATIC mp_obj_t factorial(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = factorial_helper(x);
   return rslt;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

STATIC mp_int_t fibonacci_helper(mp_int_t x) {
   if (x <= 0) {
      return 0;
   }
   else if (x == 1) {
      return 1;
   }
   else {
      return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
   }
}

STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = fibonacci_helper(x);
   return mp_obj_new_int(rslt);
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
   MP_DYNRUNTIME_INIT_ENTRY

   mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
   mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));

   MP_DYNRUNTIME_INIT_EXIT
}

Lassen Sie mich den obigen Code erklären: In MicroPython und Python ist jede Variable ein Objekt. Daher stellen wir sie in C als mp_obj_t. Aber ein C-Programm kann nur mit Variablen vom Typ C arbeiten, weshalb wir das Objekt in einen C-Typ umwandeln müssen. Dies wird Marshalling genannt und MicroPython bietet Funktionen, um jeden C-Typ aus einem Objekt zu extrahieren.

Diese Webseite von Oliver Robson ist sehr hilfreich für Marshalling https://mpy-c-gen.oliverrobson.tech/. Außerdem finden Sie Marshalling-Beispiele in der MicroPython-Dokumentation https://docs.micropython.org/en/latest/develop/natmod.html. Ich empfehle Ihnen, diesen Artikel zu lesen, wenn Sie weitere Erklärungen benötigen.

Bauen Sie die Erweiterung

Wir bauen die Erweiterung mit Hilfe eines Makefiles in eine .mpy-Datei ein. Aber wir müssen zuerst ein paar Dinge einrichten. Stellen Sie sicher, dass Ihr Terminal noch im factfib Verzeichnis. Klonen Sie dann das MicroPython-GitHub-Repository.

sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi

git clone --recurse-submodules https://github.com/micropython/micropython.git

pip3 install 'pyelftools>=0.25'

Diese Installationen werden eine Weile dauern. Wenn Sie Zeit sparen wollen und wissen, was Sie tun, müssen Sie nur die Verzeichnisse /py und /tools aus dem Micropython-Repository klonen und sie in ein Mikropython Ordner innerhalb des factfib Ordner (überspringen Sie den zweiten Befehl).

Während die Installation läuft, können wir die Zeit nutzen, um das Makefile zu schreiben. Führen Sie einfach

touch Makefile

und öffnen Sie die neu erstellte Datei in einem Texteditor.

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Sie haben vielleicht bemerkt, dass wir die Option ARCH Variable zu armv7m obwohl der Pico armv6m. Wir müssen dies tun, weil die armv6m Architektur wird (zum Zeitpunkt, an dem ich diesen Artikel schreibe) nicht von der dynruntime.mk Werkzeug.

Aber zum Glück können wir immer noch eine funktionierende Erweiterung für den Pico kompilieren. Wir müssen nur die dynruntime.mk Datei, die sich unter micropython/py/dynruntime.mk. Öffnen Sie es und suchen Sie unter Architecture configuration in armv7m die Variable CFLAGS (sollte Zeile 64 sein). Ändern Sie -mcpu=cortex-m3 zu -mcpu=cortex-m0 und speichern Sie die Datei.

chnge -mcpu=cortex-m3 zu -mcpu=cortex-m0

Nachdem alles installiert ist, führen Sie

make

und die factfib.mpy Datei erstellt werden.

Installieren und testen Sie die Erweiterung

Der letzte Schritt ist das Installieren und Testen. Hierfür nutzen wir das Dateisystem, das Micropython auf dem Raspberry Pi Pico erstellt. Zuerst müssen wir den Pico mit der MicroPython-Firmware flashen. Der einfachste Weg, dies zu tun, ist die Verwendung der Thonny IDE (vorinstalliert auf Raspbian/Raspberry Pi OS).

Wenn Sie keinen Raspberry Pi zum Programmieren Ihres Pico verwenden oder wenn Sie MicroPython noch nie auf dem Pico verwendet haben, lesen Sie bitte die Anleitung "Erste Schritte mit MicroPython" von Raspberry Pi https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Wenn Sie Windows verwenden, sollten Sie sich diesen Blog-Beitrag über den Raspberry Pi Pico und MicroPython unter Windows ansehen https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Schließen Sie Thonny, nachdem Sie Ihren Pico mit der MicroPython-Firmware geflasht haben, und installieren Sie rshell. Wir verwenden rshell für den Zugriff auf das Dateisystem von der Kommandozeile aus.

sudo pip3 install rshell
rshell --version

Dies gibt die rhsell-Version aus, wenn alles richtig eingestellt ist. Ziehen Sie dann den Pico ab und stecken Sie ihn wieder ein (ohne die BOOTSEL-Taste zu halten), um sicherzustellen, dass nichts versucht, auf das Dateisystem zuzugreifen. Jetzt müssen wir Folgendes ausführen

rshell -p /dev/ttyACM0 --buffer-size 512

cp factfib.mpy /pyboard/factfib.mpy

Um die Installation zu testen, können Sie entweder rshell oder die Thonny-IDE verwenden, um Ihre .py Dateien auf dem Pico, aber ich werde zeigen, wie man den MicroPython-Interpreter über das Minicom benutzt.

Drücken Sie also zuerst Strg+c um rshell zu verlassen und dann minicom über

sudo apt install minicom

jetzt können wir auf die Picos REPL zugreifen (Read-eval-print-Schleife)

minicom -o -D /dev/ttyACM0

Die drei schließenden spitzen Klammern >>> zeigen an, dass der MicroPython-Interpreter läuft. Jetzt können wir unsere Erweiterung importieren und wie gewohnt mit ihr arbeiten.

>>> import factfib as ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Herzlichen Glückwunsch! Sie haben Ihre erste MicroPython C-Erweiterung für den Pico erstellt! Der nächste Schritt ist zu lernen, wie man komplexere Module schreibt und kompiliert. Ein guter Anfang ist es, zu testen, wie das Marshalling von Listen und Dicts funktioniert (siehe die Marshalling-Webseite von oben).

Wenn Sie Fragen zu diesem Beitrag haben, können Sie gerne einen Kommentar schreiben.

7 Kommentare

  1. Veröffentlich von PeterB am November 26, 2021 um 8:29 am

    Abgesehen von dem Fehler im C-Programm hat es wunderbar funktioniert. Danke!

    STATIC mp_obj_t factorial(mp_obj_t x_obj) {
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_int_t rslt = factorial_helper(x);
    return mp_obj_new_int(rslt);
    }

    • Veröffentlich von raspi berry am November 27, 2021 um 5:56 pm

      Vielen Dank für Ihr Feedback 🙂

  2. Veröffentlich von XMC.pl am Juni 1, 2022 um 3:31 am

    Wie konfiguriere ich Joomla so, dass es die Daten von mysql abrufen kann?

  3. Veröffentlich von Lynggaard am Januar 8, 2023 um 8:09 pm

    Ich habe versucht, das oben beschriebene zu tun, aber verschiedene Dinge funktionieren nicht wie beschrieben:

    - Ich folgte den obigen Anweisungen, besorgte mir Micropython, änderte das Makefile wie beschrieben
    - Ich mache (aber ich erhalte eine Datei factfib.native.mpy anstelle von factfib.mpy)
    - Ich kopiere die Datei factfib.native.mpy auf den Pico als factfib.mpy
    (Ich habe es mit rshell versucht, aber ich bekam die Meldung "timed out or error in transfer to remote: b"", aber ich konnte es mit Thonny kopieren)
    - Ich kann das Modul (in thonny oder rshell - das gleiche) ohne Fehler importieren
    - Ich versuche, "ff.fibonacci(5)" auszuführen, aber dann erhalte ich:

    "Traceback (letzter Aufruf):
    Datei "", Zeile 1, in
    AttributeError: Das Objekt 'module' hat kein Attribut 'fibonacci'"

    Was mache ich falsch?

    • Veröffentlich von paopao69 am März 22, 2023 um 5:59 pm

      Haben Sie es schließlich zum Laufen gebracht?

  4. Veröffentlich von Paulo am Februar 9, 2024 um 1:44 am

    Jetzt kann man nach armv6 kompilieren, also ändert man einfach diese Zeile im Makefile und braucht den Micropython-Code nicht mehr zu ändern
    ARCH = armv6m

    Ich hatte ein paar Fehler beim Kompilieren der factfib.c, wo sind die Korrekturen:

    // Es fehlt das " am Ende.
    #include "py/dynruntime.h"

    // Konvertierung des Rückgabewerts in mp_obj_t
    STATIC mp_obj_t factorial(mp_obj_t x_obj) {
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_int_t rslt = factorial_helper(x);
    return mp_obj_new_int(rslt);
    }

    • Veröffentlich von Adam am Februar 9, 2024 um 9:22 am

      Vielen Dank für die Informationen, Paulo!

Hinterlassen Sie einen Kommentar