MicroPython sur le M5Stack

Je vous avais parlé de l'ESP32 et du kit M5Stack dans un précédent article, dans lequel j'avais notamment indiqué qu'il était possible de développer en Python sur cette plateforme grâce à MicroPython. C'est donc ce sujet que je vais aborder ici.

Pour être clair, mon but est le suivant : injecter un firmware MicroPython dans la mémoire de l'ESP32. Ce firmware devra être capable de monter la carte SD si elle est présente, et de booter dessus (simplement lancer un script portant un nom prédéfini). L'avantage d'exécuter des scripts depuis la carte SD, c'est qu'il devient très facile à n'importe qui de mettre à jour le programme qui tourne sur le M5Stack puisqu'il n'y a plus besoin d'outils spécifique : un simple navigateur de fichier suffit.

Note

NOTE : Les instructions présentées dans cet article sont données pour Linux. Il est possible d'arriver au même résultat depuis Windows ou Mac OS X, mais il vous faudra adapter les instructions à votre OS.

Construction du firmware MicroPython

Pour commencer, il nous faut installer quelques dépendances. La commande suivante permet de les installer pour Debian et Ubuntu (à exécuter en root) :

apt install git wget make libncurses-dev flex bison gperf python python-serial

Il nous faut ensuite récupérer la version de MicroPython adaptée au M5Stack. Elle est disponible sur le dépôt Github du m5stack, il nous suffit donc de cloner le dépôt :

git clone https://github.com/m5stack/M5Stack_MicroPython.git

Une fois le dépôt récupéré, il faut nous rendre dans dossier de construction :

cd M5Stack_MicroPython/MicroPython_BUILD/

Et enfin lancer la compilation du firmware :

./BUILD.sh

La première fois que l'on lance cette commande, le script nous affiche une interface de configuration. Dans notre cas on va laisser tous les paramètres par défaut, donc on va sélectionner le bouton Exit à l'aide de la touche Tabulation puis valider avec Entrée.

Interface de configuration de MicroPython

Interface de configuration de MicroPython

Une fois l'interface de configuration quittée, la compilation commence, et ça va prendre un certain temps. Si tout s'est bien passé, le script devrait afficher "OK." avant de vous rendre la main.

Flasher le firmware

Maintenant que nous avons compilé le firmware, il ne reste plus qu'à le flasher sur le M5Stack. Branchez l'appareil à l'ordinateur à l'aide d'un câble USB type C, puis lancez la commande suivante pour envoyer le firmware :

./BUILD.sh flash

Si tout s'est bien déroulé, le script devrait cette fois encore vous afficher un "OK." avant de nous rendre la main. Le M5Stack devrait quant à lui avoir automatiquement redémarré sur le nouveau firmware...

À ce stade le M5Stack semble ne plus fonctionner, l'écran est noir et le rétroéclairage éteint... mais pas de panique, c'est tout à fait normal. Il est bien allumé, mais comme on ne lui a rien demandé d'afficher et qu'on a même pas initialisé l'appareil, et bien il ne fait juste rien.

Tester MicroPython en live

Pour s'assurer que tout fonctionne, nous allons nous connecter à la console Python du firmware MicroPython qui tourne sur le M5Stack. On pourra à partir de là accéder à toutes les fonctionnalités et tester rapidement tout ce que l'on souhaite.

Pour accéder à la console de MicroPython, il suffit de taper la commande suivante :

./BUILD.sh monitor

Si tout se passer bien, on se retrouve connecté à la console et on voit apparaitre le prompt du REPL de Python :

>>>

Histoire de tester que tout va bien, on va importer la bibliothèque m5stack (ce qui va initialiser l'appareil) :

>>> import m5stack

puis afficher quelque chose sur l'écran :

>>> m5stack.lcd.print("Hello from Python\n")

Normalement, l'écran devrait à présent être allumé et afficher "Hello from Python".

Accès à la carte SD

Comme je l'ai dit au début de cet article, mon but est de pouvoir exécuter des scripts depuis une carte SD. Nous allons donc voir comment on y accède.

Pour commencer, il vous faut une carte micro SD formatée en FAT32. Sur cette carte SD, on va placer un petit script Python, nommé hello.py que l'on va placer à la racine de la carte. Voici le contenu de ce script :

import m5stack

m5stack.lcd.print("Hello, I'm a test script on the SD card!\n")

À présent on va insérer la carte SD dans le M5Stack et essayer d'y accéder. Pour ce faire il faut importer le module uos qui donne accès aux fonctionnalités internes de MicroPython :

>>> import uos

Ensuite, on va indiquer à MicroPython comment accéder à la carte SD. Cette étape dépend du matériel et de comment le lecteur de carte SD est relié à l'ESP32... Dans le cas du M5Stack, le lecteur est relié via le bus SPI, et le brochage est le suivant :

  • broche 18 : CLK,
  • broche 23 : MOSI,
  • broche 19 : MISO,
  • broche 4 : CS.

On va donc indiquer cela à MicroPython à l'aide de l'instruction suivante :

>>> uos.sdconfig(uos.SDMODE_SPI, clk=18, mosi=23, miso=19, cs=4)

Et enfin on va monter la carte SD :

>>> uos.mountsd(True)

Ici on passe True en paramètre afin que le dossier courant devienne celui de la carte SD (comme si on avait fait un "cd /sd").

À présent il ne nous reste plus qu'à exécuter notre script hello.py qui se trouvait à la racine de la carte SD (soit dans le dossier courant). Pour ce faire, il nous suffit de l'importer :

>>> import hello

Et voilà, on a pu accéder à la carte SD et exécuter un script depuis celle-ci. Il ne nous reste plus qu'à voir comment automatiser le montage de la carte SD et l'exécution du script.

Injection d'un script « boot.py » personnalisé

Le firmware MicroPython contient un mini système de fichier sur lequel se trouve un fichier boot.py qui est automatiquement lu au démarrage. C'est ce fichier que l'on doit modifier pour automatiser le montage de la carte SD.

Pour modifier les fichiers du firmware, on va utiliser ampy, un petit outil créé par Adafruit, qui nous permettra d'envoyer une version modifiée du fichier boot.py.

Warning

ATTENTION : Déconnectez votre console Python interactive avant d'utiliser ampy, sinon il ne pourra pas fonctionner. Si vous n'arrivez pas à quitter la console, débranchez le M5Stack du PC, faites Ctrl+C, puis rebranchez le M5stack.

On va donc commencer par installer ampy via pip :

pip install adafruit-ampy

On va ensuite utiliser l'outil que l'on vient d'installer pour trouver le fichiers boot.py et voir ce qu'il contient :

$ ampy -p /dev/ttyUSB0 ls /
/flash

$ ampy -p /dev/ttyUSB0 ls /flash
/flash/boot.py

$ ampy -p /dev/ttyUSB0 get /flash/boot.py
# This file is executed on every boot (including wake-boot from deepsleep)
import sys
sys.path[1] = '/flash/lib'

Ici on peut remarquer que la partition se trouvant dans le firmware MicroPython est montée dans le dossier /flash (contrairement à la carte SD qui elle, est montée dans /sd) et qu'elle contient un unique fichier, boot.py qui est justement celui que l'on cherche à modifier.

Note

NOTE : L'option -p de ampy permet d'indiquer le port série à utiliser. Si vous ne savez pas quel est le vôtre, débranchez le M5Stack du PC, et exécutez la commande "ls /dev | grep tty". Rebranchez ensuite le M5Stack et réexécutez la même commande. Le port à utiliser est celui apparut entre les deux commandes. Dans mon cas il s'agit de /dev/ttyUSB0.

On va donc écrire une version modifiée de ce fichier pour qu'il monte la carte SD et qu'il exécute automatiquement le fichier hello.py se trouvant sur la carte SD :

import sys
import uos

sys.path[1] = "/flash/lib"

# Mount SD Card
uos.sdconfig(uos.SDMODE_SPI, clk=18, mosi=23, miso=19, cs=4)
uos.mountsd(True)

# Run /sd/hello.py
import hello

On enregistre ce script dans le dossier courant sous le nom que l'on souhaite (dans mon cas je vais l'appeler new_boot.py), et on l'envoie à l'aide de la commande suivante :

ampy -p /dev/ttyUSB0 put new_boot.py /flash/boot.py

Et voilà, si on redémarre le M5Stack, on devrait voir apparaitre à l'écran la ligne que l'on voulait voir affichée dans notre script hello.py que l'on avait placé sur la carte SD.

Évidemment, il s'agit là d'un exemple simpliste. Pour bien faire les choses, il faudrait gérer les erreurs. Notamment indiquer à l'utilisateur qu'il a oublié d'insérer la carte SD ou que cette dernière est illisible. Il faudrait aussi lui indiquer si le fichier hello.py est absent de la carte SD ou s'il contient des erreurs.

C'est tout pour cette fois

Au final je suis arrivé assez vite au résultat que je souhaitais, le plus dur a été de trouver comment configurer MicroPython pour lire la carte SD... et je n'ai pas eu à chercher bien longtemps. :)

Je vous mets quelques liens ci-dessous pour approfondir le sujet :