Extension C pour MicroPython sur Raspberry Pi Pico

Ceci est un guide sur la façon d'écrire et d'exécuter une extension C de base pour MicroPython sur le Raspberry Pi Pico. Je couvrirai les raisons d'étendre MicroPython, comment écrire le module d'extension, comment le compiler et comment l'installer sur le Pico. Si vous voulez en savoir plus sur ce sujet, veuillez vous référer à https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Introduction

Pourquoi étendre MicroPython ?

Il peut y avoir plusieurs raisons pour lesquelles vous souhaitez étendre MicroPython. Étant donné qu'il s'agit d'une version allégée de Python, MicroPython n'est pas très performant lorsqu'il s'agit de tâches de calcul lourd (comme Python). En revanche, le langage C est parfaitement adapté à ce type de tâches. Une extension C pour Micropython vous permet d'effectuer ces calculs en langage C et d'utiliser les résultats dans MicroPython. Cela peut accélérer certains processus d'un ordre de grandeur.

Une deuxième raison pourrait être que vous souhaitez interfacer un matériel qui utilise une API C à partir de MicroPython. 

Types d'extensions C de MicroPython

Il existe deux façons différentes d'étendre MicroPython : les modules C externes et le code machine natif dans les fichiers .mpy.

Pour exécuter un module C externe, vous devez le recompiler dans le firmware MicroPython. Il s'agit d'un processus assez compliqué, c'est pourquoi ce guide se concentrera sur la seconde alternative. Si vous êtes toutefois intéressé par cette approche, vous pouvez en lire plus sur ces pages web :                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

Le fichier .mpy est un fichier qui contient le code machine natif compilé et qui peut être lié dynamiquement. Cela le rend beaucoup plus flexible puisque vous n'avez pas besoin de recompiler l'ensemble du firmware MicroPython.

Écrire le module d'extension

L'écriture du module d'extension est la partie la plus facile de l'extension de MicroPython. Je vais vous montrer comment le faire à l'aide d'un exemple simple. Pour commencer, nous allons créer un nouveau répertoire appelé factfib. Ouvrez une nouvelle fenêtre de terminal, allez dans le nouveau répertoire et créez un nouveau fichier appelé factfib.c. Si vous avez créé le répertoire sur un Raspberry Pi sous Dekstop, la commande ressemble à ceci.

cd ~/Desktop/factfib

touch factfib.c

Ouvrir factfib.c dans votre éditeur de texte favori et saisissez le code suivant :

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

Laissez-moi vous expliquer le code ci-dessus : Dans MicroPython et Python, chaque variable est un objet. Par conséquent, en C, nous les représentons comme mp_obj_t. Mais un programme C ne peut travailler qu'avec des variables de type C, c'est pourquoi nous devons transformer l'objet en un type C. Cela s'appelle le Marshalling. Ceci est appelé Marshalling et MicroPython fournit des fonctions pour extraire n'importe quel type C d'un objet.

Cette page web d'Oliver Robson est très utile pour le maréchalage. https://mpy-c-gen.oliverrobson.tech/. En outre, vous pouvez trouver des exemples de Marshalling dans la documentation de MicroPython. https://docs.micropython.org/en/latest/develop/natmod.html. Je vous conseille de lire cet article si vous avez besoin de plus d'explications.

Construire l'extension

Nous construisons l'extension dans un fichier .mpy en utilisant un Makefile. Mais nous devons d'abord mettre en place certaines choses. Assurez-vous que votre terminal est toujours ouvert en mode factfib répertoire. Puis clonez le dépôt GitHub de 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'

Ces installations prendront un certain temps, si vous voulez gagner du temps et que vous savez ce que vous faites, il vous suffit de cloner les répertoires /py et /tools à partir du dépôt micropython et de les placer dans un répertoire de type micropython dans le dossier factfib (ignorez la deuxième commande).

Pendant que l'installation est en cours, nous pouvons utiliser ce temps pour écrire le Makefile. Exécutez simplement

touch Makefile

et ouvrez le fichier nouvellement créé dans un éditeur de texte.

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Vous avez peut-être remarqué que nous avons défini le ARCH à la variable armv7m bien que le pico soit armv6m. Nous devons le faire parce que le armv6m n'est (au moment où j'écris cet article) pas supportée par l'architecture dynruntime.mk outil.

Mais heureusement, nous pouvons toujours compiler une extension fonctionnelle pour le Pico. Nous devons juste modifier le fichier dynruntime.mk qui doit être situé sous micropython/py/dynruntime.mk. Ouvrez-le et sous la rubrique Configuration de l'architecture dans armv7m, trouvez la variable CFLAGS (qui devrait être la ligne 64). Changez -mcpu=cortex-m3 à -mcpu=cortex-m0 et enregistrez le fichier.

chnge -mcpu=cortex-m3 to -mcpu=cortex-m0

Puis, une fois que tout est installé, exécutez

make

et le factfib.mpy sera créé.

Installer et tester l'extension

La dernière étape est l'installation et le test. Pour cela, nous utilisons le système de fichiers que Micropython crée sur le Raspberry Pi Pico. Tout d'abord, nous devons flasher le Pico avec le firmware MicroPython. La façon la plus simple de le faire est d'utiliser l'IDE Thonny (préinstallé sur Raspbian/Raspberry Pi OS).

Si vous n'utilisez pas un Raspberry Pi pour programmer votre Pico ou si vous n'avez jamais utilisé MicroPython sur le Pico auparavant, veuillez vous reporter au guide de démarrage avec MicroPython de Raspberry Pi. https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Si vous utilisez Windows, vous devriez consulter cet article de blog sur le Raspberry Pi Pico et MicroPython sous Windows. https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Fermez Thonny après avoir flashé votre Pico avec le firmware MicroPython et installez rshell. Nous utilisons rshell pour accéder au système de fichiers à partir de la ligne de commande.

sudo pip3 install rshell
rshell --version

Cela imprime la version rhsell si tout est configuré correctement. Ensuite, débranchez le pico et rebranchez-le (sans maintenir le bouton BOOTSEL) pour vous assurer que rien n'essaie d'accéder au système de fichiers. Maintenant, nous devons exécuter

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

cp factfib.mpy /pyboard/factfib.mpy

Pour tester l'installation, vous pouvez utiliser soit rshell, soit l'IDE Thonny pour enregistrer votre .py sur le Pico mais je vais démontrer comment utiliser l'interpréteur MicroPython sur le minicom.

Alors, appuyez d'abord sur Ctrl+c pour quitter rshell et ensuite installer minicom via

sudo apt install minicom

maintenant nous pouvons accéder au REPL de Picos (boucle Read-eval-print)

minicom -o -D /dev/ttyACM0

Les trois crochets de fermeture >>> indiquent que l'interpréteur MicroPython est en cours d'exécution. Nous pouvons maintenant importer notre extension et travailler avec elle comme d'habitude.

>>> import factfib as ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Félicitations ! Vous avez créé votre première extension MicroPython C pour le Pico ! L'étape suivante consiste à apprendre à écrire et à compiler des modules plus complexes. Une bonne façon de commencer est de tester le fonctionnement du Marshalling de listes et de dicts (voir la page web Marshalling ci-dessus).

Si vous avez des questions concernant cet article, n'hésitez pas à écrire un commentaire.

8 commentaires

  1. PeterB sur novembre 26, 2021 à 8:29 am

    A part l'erreur dans le programme c, ça a marché à merveille. Merci.

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

  2. XMC.pl sur juin 1, 2022 à 3:31 am

    Comment configurer joomla pour qu'il puisse récupérer les données de mysql ?

  3. Lynggaard sur janvier 8, 2023 à 8:09 pm

    J'ai essayé de faire ce qui précède, mais plusieurs choses ne fonctionnent pas comme décrit :

    - J'ai suivi les instructions ci-dessus, obtenu micropython, modifié le makefile comme décrit
    - Je fais (mais j'obtiens un fichier factfib.native.mpy au lieu de factfib.mpy)
    - Je copie le fichier factfib.native.mpy sur le pico comme factfib.mpy
    (J'ai essayé rshell mais j'ai eu un "timed out or error in transfer to remote : b"", mais j'ai pu le copier en utilisant Thonny)
    - Je peux importer le module (dans thonny ou rshell - c'est pareil) sans erreur.
    - J'essaie d'exécuter "ff.fibonacci(5)" mais j'obtiens alors :

    " Traceback (dernier appel le plus récent) :
    Fichier "", ligne 1, dans
    AttributeError : L'objet 'module' n'a pas d'attribut 'fibonacci'".

    Qu'est-ce que je fais de mal ?

    • paopao69 sur mars 22, 2023 à 5:59 pm

      Avez-vous réussi à le faire fonctionner ?

  4. Paulo sur février 9, 2024 à 1:44 am

    Maintenant vous pouvez compiler pour armv6, il suffit de changer cette ligne dans le Makefile et il n'est pas nécessaire de changer le code micropython.
    ARCH = armv6m

    J'ai eu quelques erreurs en compilant le factfib.c, où sont les correctifs :

    // il manque le " à la fin.
    #include "py/dynruntime.h"

    // convertir la valeur de retour en mp_obj_t
    STATIQUE 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) ;
    retourner mp_obj_new_int(rslt) ;
    }

    • Adam sur février 9, 2024 à 9:22 am

      Merci pour ces informations, Paulo !

  5. Dr_Phil sur mai 24, 2024 à 7:36 am

    J'ai suivi toutes les instructions et j'ai obtenu un fichier facfib.mpy construit. J'ai utilisé
    ARCH = armv6m
    Lorsqu'il est chargé dans le Pico, j'obtiens cette erreur :

    ValueError : fichier .mpy incompatible

    Mon Pico a besoin des valeurs mpy suivantes :
    version mpy : 6
    sous-version mpy : 2
    drapeaux mpy : -march=armv6m

    La vérification des deux premiers octets du fichier donne la version 6 et la sous-version 6.
    Existe-t-il un moyen de corriger ce problème ?

Laissez un commentaire