C uitbreiding voor MicroPython op Raspberry Pi Pico

Dit is een gids over hoe een basis C uitbreiding voor MicroPython te schrijven en te draaien op de Raspberry Pi Pico. Ik zal de redenen voor het uitbreiden van MicroPython behandelen, hoe de uitbreidingsmodule te schrijven, hoe het te compileren en hoe het te installeren op de Pico. Als u meer wilt lezen over dit onderwerp, raadpleeg dan https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Inleiding

Waarom MicroPython uitbreiden?

Er kunnen meerdere redenen zijn waarom u MicroPython zou willen uitbreiden. Omdat het een afgeslankte versie van Python is, presteert MicroPython niet erg goed als het aankomt op rekenkundig zware taken (vergelijkbaar met Python). C daarentegen is zeer geschikt voor dergelijke taken. Een C extensie voor Micropython maakt het mogelijk om die berekeningen in de C taal uit te voeren en de resultaten in MicroPython te gebruiken. Dit kan sommige processen met een orde van grootte versnellen.

Een tweede reden kan zijn, dat u hardware die een C API gebruikt vanuit MicroPython wilt koppelen. 

Soorten MicroPython C-uitbreidingen

Er zijn verschillende manieren om MicroPython uit te breiden: externe C modules en native machine code in .mpy bestanden.

Om een externe C-module te kunnen gebruiken, moet u deze hercompileren in de MicroPython firmware. Dit is een nogal gecompliceerd proces, daarom zal deze gids zich richten op het tweede alternatief. Als u echter geïnteresseerd bent in deze aanpak, kunt u er meer over lezen op deze webpagina's:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

De .mpy is een bestand dat gecompileerde native machine code opslaat en dynamisch kan worden gelinkt. Dit maakt het veel flexibeler omdat je niet de hele MicroPython firmware hoeft te hercompileren.

Schrijf de uitbreidingsmodule

Het schrijven van de uitbreidingsmodule is het gemakkelijkste deel van het uitbreiden van MicroPython. Ik zal je laten zien hoe je dat doet aan de hand van een eenvoudig voorbeeld. Om te beginnen maken we een nieuwe directory aan genaamd factfib. Open een nieuw terminalvenster, cd naar de nieuwe map en maak een nieuw bestand met de naam factfib.c. Als je de directory op een Raspberry Pi onder Dekstop hebt aangemaakt, ziet het commando er als volgt uit.

cd ~/Desktop/factfib

touch factfib.c

Open factfib.c in je favoriete teksteditor en voer de volgende code in:

#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
}

Laat me de code hierboven uitleggen: In MicroPython en Python, is elke variabele een object. Daarom stellen we ze in C voor als mp_obj_t. Maar een C programma kan alleen werken met C type variabelen, daarom moeten we het object omzetten in een C type. Dit heet Marshalling en MicroPython biedt functies om elk C type uit een object te halen.

Deze webpagina van Oliver Robson is echt nuttig voor Marshalling https://mpy-c-gen.oliverrobson.tech/. Verder kunt u Marshalling voorbeelden vinden in de MicroPython documentatie https://docs.micropython.org/en/latest/develop/natmod.html. Ik raad u aan dit artikel te lezen als u meer uitleg nodig hebt.

Bouw de uitbreiding

We bouwen de extensie in een .mpy bestand met behulp van een Makefile. Maar we moeten eerst een paar dingen instellen. Zorg ervoor dat je terminal nog steeds geopend is in de factfib map. Kloon dan de 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'

Deze installaties zullen een tijdje duren, als je tijd wilt besparen en je weet wat je doet, hoef je alleen maar de /py en /tools directory van de micropython repository te clonen en ze in een micropython map in de factfib map (sla het tweede commando over).

Terwijl de installatie loopt, kunnen we de tijd gebruiken om de Makefile te schrijven. Voer gewoon

touch Makefile

en open het nieuw aangemaakte bestand in een tekstverwerker.

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Je hebt misschien gemerkt dat we de ARCH variabele naar armv7m hoewel de pico armv6m. We moeten dit doen omdat de armv6m architectuur wordt (op het moment dat ik dit artikel schrijf) niet ondersteund door de dynruntime.mk gereedschap.

Maar gelukkig kunnen we nog steeds een werkende uitbreiding compileren voor de Pico. We hoeven alleen maar de dynruntime.mk bestand, dat zich moet bevinden onder micropython/py/dynruntime.mk. Open het en zoek onder Architectuur configuratie in armv7m naar de CFLAGS variabele (zou regel 64 moeten zijn). Verander -mcpu=cortex-m3 naar -mcpu=cortex-m0 en sla het bestand op.

chnge -mcpu=cortex-m3 naar -mcpu=cortex-m0

Dan nadat alles geïnstalleerd is, voer

make

en de factfib.mpy bestand zal worden aangemaakt.

Installeer en test de uitbreiding

De laatste stap is installeren en testen. Hiervoor maken we gebruik van het bestandssysteem dat Micropython aanmaakt op de Raspberry Pi Pico. Eerst moeten we de Pico flashen met de MicroPython firmware. De eenvoudigste manier om dit te doen is door de Thonny IDE te gebruiken (voorgeïnstalleerd op Raspbian/Raspberry Pi OS).

Als u geen Raspberry Pi gebruikt om uw Pico te programmeren of als u MicroPython nog nooit op de Pico hebt gebruikt, raadpleeg dan de handleiding "Aan de slag met MicroPython" van Raspberry Pi https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Als u Windows gebruikt, kijk dan eens naar deze blogpost over de Raspberry Pi Pico en MicroPython op Windows https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Sluit Thonny nadat je je Pico hebt geflashed met de MicroPython firmware en installeer rshell. We gebruiken rshell om toegang te krijgen tot het bestandssysteem vanaf de commandoregel.

sudo pip3 install rshell
rshell --version

Dit drukt de rhsell versie af als alles juist is ingesteld. Trek dan de stekker van de pico uit het stopcontact en steek hem er weer in (zonder de BOOTSEL knop ingedrukt te houden) om er zeker van te zijn dat niets toegang probeert te krijgen tot het bestandssysteem. Nu moeten we het volgende uitvoeren

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

cp factfib.mpy /pyboard/factfib.mpy

Om de installatie te testen kunt u rshell of de Thonny IDE gebruiken om uw .py bestanden op de Pico, maar ik zal demonstreren hoe je de MicroPython interpreter over de minicom gebruikt.

Dus druk eerst op Ctrl+c om rshell te verlaten en dan minicom te installeren via

sudo apt install minicom

nu hebben we toegang tot de Picos REPL (Read-eval-print loop)

minicom -o -D /dev/ttyACM0

De drie afsluitende haakjes >>> geven aan dat de MicroPython-interpreter draait. Nu kunnen we onze extensie importeren en er zoals gewoonlijk mee werken.

>>> import factfib as ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Gefeliciteerd! Je hebt je eerste MicroPython C-extensie voor de Pico gemaakt! De volgende stap is om complexere modules te leren schrijven en compileren. Een goede manier om te beginnen is door te testen hoe Marshalling van lijsten en dicts werkt (zie de Marshalling webpagina van hierboven).

Als je vragen hebt over deze post, schrijf dan gerust een reactie.

7 Opmerkingen

  1. PeterB op november 26, 2021 op 8:29 am

    Afgezien van de fout in het c-programma werkte het prima. Bedankt.

    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);
    geef mp_obj_new_int(rslt) terug;
    }

    • raspi berry op november 27, 2021 op 5:56 pm

      Hartelijk dank voor uw feedback 🙂 Dank u.

  2. XMC.pl op juni 1, 2022 op 3:31 am

    Hoe kan ik joomla configureren om de gegevens van mysql op te halen?

  3. Lynggaard op januari 8, 2023 op 8:09 pm

    Ik heb geprobeerd het bovenstaande te doen, maar verschillende dingen werken niet zoals beschreven:

    - Ik volgde de bovenstaande instructies, kreeg micropython, wijzigde de makefile zoals beschreven
    - Ik maak wel (maar ik krijg een factfib.native.mpy bestand in plaats van factfib.mpy)
    - Ik kopieer het factfib.native.mpy bestand naar de pico als factfib.mpy
    (Ik heb rshell geprobeerd, maar ik kreeg een "timed out of error in transfer to remote: b"", maar ik kon het kopiëren met Thonny)
    - Ik kan de module importeren (in thonny of rshell - hetzelfde) zonder fouten
    - Ik probeer de "ff.fibonacci(5)" uit te voeren, maar dan krijg ik:

    "Traceback (most recent call last):
    Bestand "", regel 1, in
    AttributeError: 'module' object heeft geen attribuut 'fibonacci'".

    Wat doe ik verkeerd?

    • paopao69 op maart 22, 2023 op 5:59 pm

      Heb je het uiteindelijk aan de praat gekregen?

  4. Paulo op februari 9, 2024 op 1:44 am

    Nu kun je compileren naar armv6 dus verander gewoon deze regel in de Makefile en je hoeft de micropython code niet te veranderen
    ARCH = armv6m

    Ik had een paar fouten bij het compileren van factfib.c, waar zijn de oplossingen:

    // de " aan het einde ontbreekt.
    #include "py/dynruntime.h"

    // de retourwaarde converteren naar 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);
    geef mp_obj_new_int(rslt) terug;
    }

    • Adam op februari 9, 2024 op 9:22 am

      Bedankt voor de informatie, Paulo!

Laat een reactie achter