Estensione C per MicroPython su Raspberry Pi Pico

Questa è una guida su come scrivere ed eseguire un'estensione C di base per MicroPython sul Raspberry Pi Pico. Tratterò le ragioni per estendere MicroPython, come scrivere il modulo di estensione, come compilarlo e come installarlo sul Pico. Se volete leggere di più su questo argomento, fate riferimento a https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Introduzione

Perché estendere MicroPython?

Ci possono essere molte ragioni per cui potreste voler estendere MicroPython. Poiché è una versione ridotta di Python, MicroPython non funziona molto bene quando si tratta di compiti computazionalmente pesanti (simili a Python). Il C, d'altra parte, è davvero adatto per questi compiti. Un'estensione C per Micropython permette di eseguire questi calcoli attraverso il linguaggio C e utilizzare i risultati in MicroPython. Questo può velocizzare alcuni processi di un ordine di grandezza.

Una seconda ragione potrebbe essere che volete interfacciare dell'hardware che usa un'API C dall'interno di MicroPython. 

Tipi di estensioni C di MicroPython

Ci sono due modi diversi per estendere MicroPython: moduli C esterni e codice macchina nativo in file .mpy.

Per eseguire un modulo C esterno è necessario ricompilarlo nel firmware MicroPython. Questo è un processo piuttosto complicato, ecco perché questa guida si concentrerà sulla seconda alternativa. Se siete comunque interessati a questo approccio, potete leggerne di più su queste pagine web:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

Il .mpy è un file che memorizza il codice macchina nativo compilato e può essere collegato dinamicamente. Questo lo rende molto più flessibile poiché non è necessario ricompilare l'intero firmware MicroPython.

Scrivere il modulo di estensione

Scrivere il modulo di estensione è la parte più semplice dell'estensione di MicroPython. Vi mostrerò come farlo guardando un semplice esempio. Per iniziare, creeremo una nuova directory chiamata factfib. Aprire una nuova finestra del terminale, entrare nella nuova directory e creare un nuovo file chiamato fattofib.c. Se avete creato la directory su un Raspberry Pi sotto Dekstop, il comando si presenta così.

cd ~/Desktop/factfib

toccare factfib.c

Aprire fattofib.c nel vostro editor di testo preferito e inserite il seguente codice

#include "py/dynruntime.h

STATIC mp_int_t factorial_helper(mp_int_t x) {
   se (x < 1) {
      ritorna 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);
   ritorna rslt;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

STATIC mp_int_t fibonacci_helper(mp_int_t x) {
   se (x <= 0) {
      ritorna 0;
   }
   else if (x == 1) {
      restituisce 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);
   ritorna 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
}

Lasciatemi spiegare il codice qui sopra: In MicroPython e Python, ogni variabile è un oggetto. Quindi in C le rappresentiamo come mp_obj_t. Ma un programma C può lavorare solo con variabili di tipo C, ecco perché abbiamo bisogno di trasformare l'oggetto in un tipo C. Questo si chiama Marshalling e MicroPython fornisce funzioni per estrarre qualsiasi tipo C da un oggetto.

Questa pagina web di Oliver Robson è davvero utile per Marshalling https://mpy-c-gen.oliverrobson.tech/. Inoltre potete trovare esempi di Marshalling nella documentazione di MicroPython https://docs.micropython.org/en/latest/develop/natmod.html. Vi consiglio di leggere questo articolo se avete bisogno di ulteriori spiegazioni.

Costruire l'estensione

Costruiamo l'estensione in un file .mpy usando un Makefile. Ma abbiamo bisogno di impostare alcune cose prima. Assicuratevi che il vostro terminale sia ancora aperto nella cartella factfib directory. Poi clonate il repository GitHub di MicroPython.

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

Queste installazioni richiederanno un po' di tempo, se volete risparmiare tempo e sapete cosa state facendo, avete solo bisogno di clonare le directory /py e /tools dal repository micropython e metterle dentro un micropython all'interno della cartella factfib (saltare il secondo comando).

Mentre l'installazione è in esecuzione possiamo usare il tempo per scrivere il Makefile. Eseguite semplicemente

toccare Makefile

e aprire il file appena creato in un editor di testo. 

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Avrete notato che abbiamo impostato il parametro ARCH variabile a armv7m anche se il pico è armv6m. Dobbiamo fare questo perché il armv6m non è (al momento in cui sto scrivendo questo articolo) supportata dall'architettura dynruntime.mk strumento.

Ma fortunatamente possiamo ancora compilare un'estensione funzionante per la Pico. Abbiamo solo bisogno di modificare il file dynruntime.mk che dovrebbe trovarsi sotto micropython/py/dynruntime.mkApritelo e sotto Architecture configuration in armv7m trovate la variabile CFLAGS (dovrebbe essere la linea 64). Cambiate -mcpu=cortex-m3-mcpu=cortex-m0 e salvare il file.

cambia -mcpu=cortex-m3 in -mcpu=cortex-m0

Poi, dopo che tutto è stato installato, eseguite

fare

e il fattofib.mpy sarà creato.

Installare e testare l'estensione

L'ultimo passo è l'installazione e il test. Per questo utilizziamo il filesystem che Micropython crea sul Raspberry Pi Pico. Il modo più semplice per farlo è usare l'IDE Thonny (preinstallato su Raspbian).

Se non state usando un Raspberry Pi per programmare il vostro Pico o se non avete mai usato MicroPython sul Pico prima d'ora, fate riferimento alla guida per iniziare con MicroPython di Raspberry Pi https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Se stai usando Windows dovresti dare un'occhiata a questo post sul Raspberry Pi Pico e MicroPython su Windows https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Chiudete Thonny dopo aver flashato la Pico con il firmware MicroPython e installate rshell. Usiamo rshell per accedere al filesystem dalla linea di comando.

sudo pip3 install rshell

rshell -versione

Questo stampa la versione rhsell se tutto è impostato correttamente. Poi scollegate la pico e collegatela di nuovo (senza tenere premuto il pulsante BOOTSEL) per assicurarvi che nulla stia cercando di accedere al file system. Ora abbiamo bisogno di eseguire

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

cp factfib.mpy /pyboard/factfib.mpy

Per testare l'installazione potreste usare rshell o l'IDE di Thonny per salvare il vostro .py sulla Pico, ma dimostrerò come usare l'interprete MicroPython sul minicom.

Quindi prima premi Ctrl+c per lasciare rshell e poi installare minicom tramite

sudo apt install minicom

ora possiamo accedere al REPL di Picos (ciclo Read-eval-print)

minicom -o -D /dev/ttyACM0

Le tre parentesi angolari di chiusura >>> indicano che l'interprete MicroPython è in esecuzione. Ora possiamo importare la nostra estensione e lavorare con essa come al solito.

>>> importa factfib come ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Congratulazioni! Avete creato la vostra prima estensione MicroPython C per la Pico! Il prossimo passo è imparare a scrivere e compilare moduli più complessi. Un buon modo per iniziare è testare come funziona il Marshalling di liste e dicts (vedi la pagina web Marshalling di cui sopra). Se hai qualche domanda su questo post, sentiti libero di scrivere un commento.

Addio e fino alla prossima volta

Nathan

2 commenti

  1. PeterB in Novembre 26, 2021 il 8:29 am

    A parte l'errore nel programma C, ha funzionato benissimo. Grazie.

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

Lascia un commento