Rust sur microcontrôleur
J'avais déjà fait quelques essais de rust mais exclusivement pour des outils cli. Cependant mon cœur de métier et ce que j'apprécie c'est programmer des microcontrôleurs. Donc, en ce début d'année je me suis motivé, je suis sorti de ma zone de confort et j'ai écrit un petit firmware pour un stm32 en rust. Quelque chose de tout simple, un programme qui fait juste clignoter une led (l'équivalent du traditionnel hello world pour l'embarqué).
J'ai suivi différents tuto mais la plupart se contentent d'indiquer des crates à utiliser et quelles fonctions appeler. Moi je voulais comprendre comment fonctionne la cross-compilation, comprendre comment fonctionne l'édition de liens, comprendre l'utilité de chaque crate utilisé…
J'ai donc écrit un petit mémo suite à ces essais: mémo
Ce n'est pas parfait, ce n'est pas exhaustif. Je n'ai, par exemple, pas approfondi l'initialisation de la mémoire, ni l'appel de la fonction main… Mais on ne sait jamais, ça peut peut-être aider d'autres personnes.

# dommage
Posté par ChocolatineFlying . Évalué à 1 (+0/-0).
le petit mémo aurait été un parfait journal ! plutôt qu'un lien vers ton site j'imagine que si tu donne ton accord il y a moyen de corrigé cela. sinon poste dans la rubrique lien ;)
1) poste un commentaire ici de ton mémo pour la mise en page linuxfr
2) si un modo se sent de le recopier a la place du journal
\o/
[^] # Re: dommage
Posté par Milo . Évalué à 1 (+0/-0).
Super idée, surtout que le site du mémo est bloqué par le proxy web de mon employeur … ;-)
# Mémo
Posté par uneTanche (site web personnel, Mastodon) . Évalué à 2 (+1/-0).
Sommaire
Suite au commentaire ChocolatineFlying, voici le texte original du mémo:
Intro
J'ai déjà pu expérimenter l'utilisation du langage rust et de son environnement
dans le cadre du dev d'outil cli, mais pas encore pour de l'embarqué bare metal.
Cet article va donc me servir de mémo quant à ces essais.
Pour ces tests, j'utiliserai une carte de dev ST nucleo stm32l031k6.
Pour ce qui est de la toolchain rust, j'utilise la version 1.89.0.
Vous pouvez retrouver le répertoire du projet ici.
Premièrement petit tour de la doc:
Système de recette
Première bonne surprise, cargo (l'utilitaire de construction rust), gère
nativement la cross-compilation. Pour cela, on peut soit lui passer l'option
--targetavec le code triple de la cible.Soit créer un fichier
.cargo/config.tomlà la racinede notre projet, dans lequel on spécifie lui indique la cible.
Donc pour le stm32l032k6, on utilse soit:
cargo build --target thumbv6m-none-eabitoml [build] target = thumbv6m-none-eabiAinsi lorsqu'on appelleracargo buildil utilisera la cible spécifier dans le fichier de configDescription du matériel
Contrairement au C, st ne fournis pas de HAL ou de LL rust. En revanche,
la communauté rust étant très active, on trouve des crates faisant un travail
équivalent.
On distingue trois niveaux d'intégration
Dans cette première partie, nous n'utiliserons pas de HAL.
Les crates
Les crates est le nom donné en rust aux dépendances du projet. Elles sont
la plupart du temps disponibles sur le site crates.io,
mais on peut aussi
spécifier des dépendances locales ou des répertoires git.
Pour utiliser une crate, il y a deux possibilités:
cargo add le_nom_du_crateCargo va alors chercher le crate en question sur crates.io et s'il existe, il va ajouter la dépendance dans le fichierCargo.tomlet la télécharger dans le cache local.Cargo.toml.Dans le cas de notre mcu, il s'agit d'un coeur cortex M0+, nous allons donc
utiliser les crates suivant:
Pour les crates cortex-m, stm32l0 nous devons
spécifier des options pour pouvoir les utiliser.
Ce qui nous donne la liste de dépendance suivante:
Édition de liens
Le crate cortex-m-rt fournis un script d'édition de liens par défaut. Il nous
réclame simplement de créer un fichier
memory.xà la racine du projetindiquant la configuration de la *RAM et la FLASH.
Pour ce qui est de la configuration de la table des vecteurs d'interruption,
le crate cortex-m-rt offre un mécanisme permettant à l'utilisateur ou à d'autre
crate d'insérer leur définition.
Dans notre cas c'est le crate stm32l0 qui s'en charge via la feature rt.
En ce qui concerne la configuration mémoire,
notre micro (stm32l031k6) dispose de 32ko de flash et 8ko de ram.
On va donc créer un fichier
memory.xcontenant:Il ne nous reste plus qu'à éditer le fichier de config de cargo (.cargo/config.toml)
pour ajouter un flag de compilation indiquant à rustc d'utiliser le script
d'édition de liens du crate cortex-m-rt nommé
link.x.Pour aller plus loin
objdumpce morceau de doc explicite les différentes sections.Un simple clignotement
Commençons par le hello world de l'embarqué: faire clignoter une led…
On commence par créer un dossier:
mkdir rust_stm32l031 && cd rust_stm32l031.Ensuite on initialise le projet avec cargo:
cargo init --bin. Cette commandeva créer les fichiers de config (Cargo.toml et Carlo.lock) ainsi qu'un répertoire
src et le fichier main.rs.
Mise en place de la fonction main
Pour pouvoir compiler notre projet pour la cible stm32l0, on doit
spécifier que le programme n'utilise pas la bibliothèque standard.
Pour cela on utilise la directive:
#![no_std]On doit aussi indiquer au compilateur que l'on souhaite utiliser
une fonction de démarrage custom (fonction qui initialise les
variables et appelle la fonction main). En effet, notre
main()sera appelée depuis la fonction
Resetimplémentée par cortex-m-rt.Pour ce faire on utilise la directive:
#![no_main].De son côté, le crate cortex-m-rt expose la directive
#[entry]pour spécifier la fonction d'entrée.
Enfin, on doit indiquer au compilateur comment la programme doit
réagir en cas de détection de comportement interdit (panic).
Pour ce faire, le compilateur attend une fonction:
Plutôt que de créer notre propre implémentation, on utilise le crate panic_abort
afin qu'en cas d'erreur on déclenche un hardfault.
On va donc avoir un fichier main.rs qui ressemble à ça:
Voila vous pouvez maintenant compiler et flasher ce programme sur
votre carte électronique. Ça n'a aucun intérêt puisque ce programme ne fait rien
mais ça fonctionne!
Configurer les périphériques
Nous avons mis en place notre chaîne de compilation, nous pouvons
maintenant attaquer la configuration des périphériques. Pour cela,
nous allons utiliser deux crates:
Les objectifs sont:
Ce qui donne le fichier main.rs suivant:
Et voilà un clignotement de led en bonne et due forme.
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.