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. Aprite una nuova finestra di terminale, fate un cd nella nuova directory e create 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
touch factfib.c
Aprire fattofib.c nell'editor di testo preferito e inserire il seguente codice:
#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
}
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 install '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
touch 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.mk. Apritelo e sotto Architecture configuration in armv7m trovate la variabile CFLAGS (dovrebbe essere la linea 64). Cambiate -mcpu=cortex-m3 a -mcpu=cortex-m0 e salvare il file.
Poi, dopo che tutto è stato installato, eseguite
make
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. Per prima cosa dobbiamo flashare il Pico con il firmware MicroPython. Il modo più semplice per farlo è usare l'IDE Thonny (preinstallato su Raspbian/Raspberry Pi OS).
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 --version
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.
>>> import factfib as ff
>>> ff.factorial(5)
>>> 120
>>> ff.fibonacci(7)
>>> 13
Congratulazioni! Avete creato la vostra prima estensione MicroPython C per Pico! Il passo successivo è imparare a scrivere e compilare moduli più complessi. Un buon modo per iniziare è quello di testare il funzionamento del Marshalling di liste e detti (vedere la pagina web Marshalling di cui sopra).
Se avete domande su questo post, non esitate a scrivere un commento.
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);
}
Grazie per il tuo feedback 🙂
Come configurare joomla che può recuperare i dati da mysql?
Ho provato a fare quanto sopra, ma diverse cose non funzionano come descritto:
- Ho seguito le istruzioni di cui sopra, ho preso micropython, ho modificato il makefile come descritto
- Lo faccio (ma ottengo un file factfib.native.mpy invece di factfib.mpy)
- Copio il file factfib.native.mpy nel pico come factfib.mpy
(Ho provato con rshell ma ho ottenuto un "timed out o errore nel trasferimento a remote: b"", ma ho potuto copiarlo usando Thonny)
- Posso importare il modulo (in thonny o in rshell - lo stesso) senza errori
- Provo ad eseguire "ff.fibonacci(5)" ma ottengo:
"Traceback (ultima chiamata):
File "", riga 1, in
AttributeError: l'oggetto 'modulo' non ha l'attributo 'fibonacci'".
Cosa sbaglio?
Alla fine sei riuscito a farlo funzionare?
Ora è possibile compilare per armv6, quindi basta cambiare questa riga nel Makefile e non c'è bisogno di cambiare il codice micropython
ARCH = armv6m
Ho avuto alcuni errori nella compilazione di factfib.c, dove sono le correzioni:
// manca il " alla fine.
#include "py/dynruntime.h"
// convertire il valore di ritorno 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);
ritorna mp_obj_new_int(rslt);
}
Grazie per le informazioni, Paulo!
Ho seguito tutte le istruzioni e mi sono ritrovato con un file facfib.mpy costruito. Ho usato
ARCH = armv6m
Quando viene caricato nel Pico ottengo questo errore:
ValueError: file .mpy incompatibile
Il mio Pico richiede i seguenti valori di mpy:
versione mpy: 6
mpy sotto-versione: 2
flag di mpy: -march=armv6m
Controllando i primi due byte del file si ottiene la versione 6 e la sottoversione 6.
C'è un modo per correggere questo problema?