C-förlängning för MicroPython på Raspberry Pi Pico

Det här är en guide för hur man skriver och kör ett grundläggande C-tillägg för MicroPython på Raspberry Pi Pico. Jag kommer att behandla skälen till att utöka MicroPython, hur man skriver tilläggsmodulen, hur man kompilerar den och hur man installerar den på Pico. Om du vill läsa mer om det här ämnet kan du läsa följande https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Introduktion

Varför utöka MicroPython?

Det kan finnas flera anledningar till varför du vill utöka MicroPython. Eftersom MicroPython är en nedbantad version av Python fungerar det inte särskilt bra när det gäller beräkningstunga uppgifter (som Python). C å andra sidan är verkligen väl lämpad för sådana uppgifter. Ett C-förlängningstillägg för Micropython gör det möjligt att utföra dessa beräkningar med hjälp av C-språket och använda resultaten i MicroPython. Detta kan påskynda vissa processer med en storleksordning.

En annan anledning kan vara att du vill koppla ihop en maskinvara som använder ett C API från MicroPython. 

Typer av MicroPython C-tillägg

Det finns två olika sätt att utöka MicroPython: externa C-moduler och inhemsk maskinkod i .mpy-filer.

För att köra en extern C-modul måste du kompilera om den till MicroPython-firmware. Detta är en ganska komplicerad process, vilket är anledningen till att den här guiden kommer att fokusera på det andra alternativet. Om du dock är intresserad av detta tillvägagångssätt kan du läsa mer om det på dessa webbsidor:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

.mpy är en fil som lagrar kompilerad maskinprogramkod och kan länkas dynamiskt. Detta gör den mycket mer flexibel eftersom du inte behöver kompilera om hela MicroPython firmware.

Skriva tilläggsmodulen

Att skriva tilläggsmodulen är den enklaste delen av att utöka MicroPython. Jag kommer att visa dig hur du gör det genom att titta på ett enkelt exempel. Till att börja med skapar vi en ny katalog som heter factfib. Öppna ett nytt terminalfönster, cd till den nya katalogen och skapa en ny fil som heter factfib.c. Om du har skapat katalogen på en Raspberry Pi under Dekstop ser kommandot ut så här.

cd ~/Desktop/factfib

touch factfib.c

Öppna factfib.c i din favorittextredigerare och skriv in följande kod

#include "py/dynruntime.h

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

STATISKT 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;
}

STATISKT MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

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

STATISKT 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);
}

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

Låt mig förklara koden ovan: I MicroPython och Python är varje variabel ett objekt. I C representerar vi dem därför som mp_obj_t. Men ett C-program kan bara arbeta med variabler av C-typ, vilket är anledningen till att vi måste omvandla objektet till en C-typ. Detta kallas Marshalling och MicroPython tillhandahåller funktioner för att extrahera vilken C-typ som helst från ett objekt.

Den här webbsidan av Oliver Robson är till stor hjälp för Marshalling. https://mpy-c-gen.oliverrobson.tech/. Dessutom kan du hitta exempel på Marshalling i MicroPython-dokumentationen. https://docs.micropython.org/en/latest/develop/natmod.html. Jag rekommenderar att du läser den här artikeln om du behöver ytterligare förklaringar.

Bygg utbyggnaden

Vi bygger upp tillägget till en .mpy-fil med hjälp av en Makefile. Men vi måste ställa in några saker först. Se till att din terminal fortfarande är öppen i factfib katalog. Klona sedan MicroPython GitHub-förrådet.

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 installera 'pyelftools>=0.25'

Dessa installationer kommer att ta ett tag, men om du vill spara tid och vet vad du gör behöver du bara klona katalogerna /py och /tools från micropython-förrådet och lägga dem i en micropython i mappen factfib mapp (hoppa över det andra kommandot).

Medan installationen pågår kan vi använda tiden till att skriva Makefilen. Exekvera helt enkelt

touch Makefile

och öppna den nyskapade filen i en textredigerare. 

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Du kanske har lagt märke till att vi har satt ARCH variabeln till armv7m även om pico är armv6m. Vi måste göra detta eftersom armv6m arkitekturen (när jag skriver denna artikel) inte stöds av dynruntime.mk verktyg.

Men som tur är kan vi fortfarande kompilera ett fungerande tillägg för Pico. Vi behöver bara ändra dynruntime.mk filen, som bör finnas under micropython/py/dynruntime.mkÖppna den och leta under Architecture configuration i armv7m efter variabeln CFLAGS (bör vara rad 64). Ändra -mcpu=cortex-m3 till -mcpu=cortex-m0 och spara filen.

ändra -mcpu=cortex-m3 till -mcpu=cortex-m0

När allt är installerat, kör du sedan

göra

och faktafib.mpy filen kommer att skapas.

Installera och testa tillägget

Det sista steget är installation och testning. För detta använder vi filsystemet som Micropython skapar på Raspberry Pi Pico. Först måste vi flasha Pico med MicroPythons firmware. det enklaste sättet att göra detta är att använda Thonny IDE (förinstallerad på Raspbian).

Om du inte använder en Raspberry Pi för att programmera din Pico eller om du aldrig har använt MicroPython på Pico tidigare, se guiden Kom igång med MicroPython från Raspberry Pi. https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Om du använder Windows bör du läsa detta blogginlägg om Raspberry Pi Pico och MicroPython på Windows. https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Stäng Thonny efter att du har flashat din Pico med MicroPython-firmware och installera rshell. Vi använder rshell för att komma åt filsystemet från kommandoraden.

sudo pip3 install rshell

rshell -version

Detta skriver ut rhsell-versionen om allt är korrekt inställt. Koppla sedan ur pico och koppla in den igen (utan att hålla BOOTSEL-knappen intryckt) för att se till att inget försöker komma åt filsystemet. Nu måste vi utföra

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

cp factfib.mpy /pyboard/factfib.mpy

För att testa installationen kan du använda antingen rshell eller Thonny IDE för att spara din .py filer på Pico, men jag kommer att visa hur man använder MicroPython-tolken på minicom.

Tryck därför först på Ctrl+c för att lämna rshell och sedan installera minicom via

sudo apt install minicom

Nu kan vi få tillgång till Picos REPL (Read-eval-print-slinga).

minicom -o -D /dev/ttyACM0

De tre avslutande hakparenteserna >>> visar att MicroPython-tolken körs. Nu kan vi importera vårt tillägg och arbeta med det som vanligt.

>>> importera factfib som ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Grattis! Du har skapat ditt första MicroPython C-tillägg för Pico! Nästa steg är att lära dig att skriva och kompilera mer komplexa moduler. Ett bra sätt att börja är att testa hur Marshalling av listor och dicts fungerar (se webbsidan Marshalling från ovan). Om du har några frågor om det här inlägget är du välkommen att skriva en kommentar.

Adjö och till nästa gång

Nathan

2 Kommentarer

  1. PeterB den november 26, 2021 kl 8:29 f m

    Bortsett från felet i c-programmet fungerade det utmärkt. Tack.

    STATISKT 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);
    }

    • raspi berry den november 27, 2021 kl 5:56 e m

      Tack för din feedback 🙂

Lämna en kommentar