<rss version="2.0">
 <channel>
  <title>Une Tanche</title>
  <link>https://ylbn.fr/</link>
  <description>Recent content</description>
  <generator>Zine -- https://zine-ssg.io</generator>
  <language>fr-fr</language>
  <lastBuildDate>Thu, 16 Apr 2026 11:57:27 +0000</lastBuildDate>
  
   <item>
    <title>Rust sur mcu: Découverte</title>
    <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;&lt;p&gt;J’ai déjà pu expérimenter l’utilisation du langage rust et de son environnement dans le cadre du dev d’outil &lt;em&gt;cli&lt;/em&gt;, mais pas encore pour de l’embarqué &lt;em&gt;bare metal&lt;/em&gt;. Cet article va donc me servir de mémo quant à ces essais.&lt;/p&gt;&lt;p&gt;Pour ces tests, j’utiliserai une carte de dev ST &lt;em&gt;nucleo&lt;/em&gt; stm32l031k6. Pour ce qui est de la toolchain rust, j’utilise la version 1.89.0. Vous pouvez retrouver le &lt;a href=&quot;https://codeberg.org/tanche/embedded_rust_test&quot; target=&quot;_blank&quot;&gt;répertoire du projet ici&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Premièrement petit tour de la doc:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/stable/book&quot; target=&quot;_blank&quot;&gt;le rustbook générique&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/stable/embedded-book/index.html&quot; target=&quot;_blank&quot;&gt;le rustbook embarqué&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rust-embedded.org/embedonomicon/preface.html&quot; target=&quot;_blank&quot;&gt;embedonomicon&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/stable/cargo/index.html&quot; target=&quot;_blank&quot;&gt;le rustbook de cargo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://rust-training.ferrous-systems.com/latest/book/ferrocene-installing&quot; target=&quot;_blank&quot;&gt;ferrous system&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 id=&quot;recette&quot;&gt;Système de recette&lt;/h1&gt;&lt;p&gt;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 &lt;code&gt;--target&lt;/code&gt; avec le &lt;em&gt;code triple&lt;/em&gt; de la cible. Soit créer un fichier &lt;code&gt;.cargo/config.toml&lt;/code&gt; à la racine de notre projet, dans lequel on spécifie lui indique la cible.&lt;/p&gt;&lt;p&gt;Donc pour le stm32l032k6, on utilse soit:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;cargo build --target thumbv6m-none-eabi&lt;/code&gt;&lt;/li&gt;&lt;li&gt;le fichier de config cargo avec:&lt;pre&gt;&lt;code class=&quot;toml&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;thumbv6m-none-eabi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
Ainsi lorsqu’on appellera &lt;code&gt;cargo build&lt;/code&gt; il utilisera la cible spécifier dans le fichier de config&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;pac&quot;&gt;Description du matériel&lt;/h2&gt;&lt;p&gt;Contrairement au C, &lt;em&gt;st&lt;/em&gt; ne fournis pas de &lt;em&gt;HAL&lt;/em&gt; ou de &lt;em&gt;LL&lt;/em&gt; rust. En revanche, la communauté rust étant très active, on trouve des crates faisant un travail équivalent.&lt;/p&gt;&lt;p&gt;On distingue trois niveaux d’intégration&lt;/p&gt;&lt;ol&gt;&lt;li&gt;les crates &lt;em&gt;cortex-m&lt;/em&gt; et &lt;em&gt;cortex-m-rt&lt;/em&gt; réalisant l’abstraction des périphériques standard des coeur &lt;em&gt;arm cortex-m&lt;/em&gt;&lt;/li&gt;&lt;li&gt;les crates de description matériel (PAC pour Peripherals Abstraction Crate). Ils gèrent le mapping des périphériques du microcontrôleur. Ils sont donc spécifique à la cible. ils nous permettent d’accéder aux registres de chaque périphérique par un ensemble de fonction/structure de données plutôt qu’en spécifiant des adresses mémoire.&lt;/li&gt;&lt;li&gt;Les crates d’abstraction matériel (HAL pour Hardware Abstraction Layer). Ils sont basés sur les &lt;em&gt;PAC&lt;/em&gt; et offrent une interface &lt;em&gt;haut niveau&lt;/em&gt; et standardisée pour configurer et intéragire avec les périphériques.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Dans cette première partie, nous n’utiliserons pas de HAL.&lt;/p&gt;&lt;h2 id=&quot;crates&quot;&gt;Les crates&lt;/h2&gt;&lt;p&gt;Les crates est le nom donné en rust aux dépendances du projet. Elles sont la plupart du temps disponibles sur le site &lt;a href=&quot;https://crates.io&quot; target=&quot;_blank&quot;&gt;crates.io&lt;/a&gt;, mais on peut aussi spécifier des dépendances locales ou des répertoires git.&lt;/p&gt;&lt;p&gt;Pour utiliser une crate, il y a deux possibilités:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;via cargo avec &lt;code&gt;cargo add le_nom_du_crate&lt;/code&gt; Cargo va alors chercher le crate en question sur &lt;a href=&quot;https://crates.io&quot; target=&quot;_blank&quot;&gt;crates.io&lt;/a&gt; et s’il existe, il va ajouter la dépendance dans le fichier &lt;code&gt;Cargo.toml&lt;/code&gt; et la télécharger dans le cache local.&lt;/li&gt;&lt;li&gt;En éditant le fichier &lt;code&gt;Cargo.toml&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Dans le cas de notre mcu, il s’agit d’un coeur cortex M0+, nous allons donc utiliser les crates suivant:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rs/cortex-m/latest/cortex_m&quot;&quot; target=&quot;_blank&quot;&gt;cortex-m&lt;/a&gt; pour la description des périphériques liés au coeur arm.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rs/cortex-m-rt/latest/cortex_m_rt/&quot; target=&quot;_blank&quot;&gt;cortex-m-rt&lt;/a&gt; pour la gestion de la compilation et de l’édition de liens.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rs/panic-abort/latest/panic_abort/&quot; target=&quot;_blank&quot;&gt;panic-abort&lt;/a&gt; pour avoir une implémentation par défaut de la gestion des erreurs non recouvrable.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rs/stm32l0/latest/stm32l0/&quot; target=&quot;_blank&quot;&gt;stm32l0&lt;/a&gt; pour la description des périphériques du stm32l031.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.rs/crate/stm32l0xx-hal/latest&quot; target=&quot;_blank&quot;&gt;stm32l0xx-hal&lt;/a&gt; pour la HAL (nous l’utiliserons dans un second temps).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Pour les crates &lt;em&gt;cortex-m&lt;/em&gt;, &lt;em&gt;stm32l0&lt;/em&gt; nous devons spécifier des options pour pouvoir les utiliser.&lt;/p&gt;&lt;p&gt;Ce qui nous donne la liste de dépendance suivante:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;toml&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;cortex-m-rt&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;0.7.5&amp;quot;&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;panic-abort&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;0.3.2&amp;quot;&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;cortex-m&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;0.7.7&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;critical-section-single-core&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;stm32l0&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;0.16.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;property&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;stm32l0x1&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;rt&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;linker&quot;&gt;Édition de liens&lt;/h2&gt;&lt;p&gt;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 &lt;code&gt;memory.x&lt;/code&gt; à la racine du projet indiquant la configuration de la &lt;em&gt;RAM&lt;/em&gt; et la &lt;em&gt;FLASH&lt;/em&gt;. Pour ce qui est de la configuration de la table des vecteurs d’interruption, le crate &lt;em&gt;cortex-m-rt&lt;/em&gt; offre un mécanisme permettant à l’utilisateur ou à d’autre crate &lt;a href=&quot;https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#incorporating-device-specific-interrupts&quot; target=&quot;_blank&quot;&gt;d’insérer leur définition.&lt;/a&gt; Dans notre cas c’est le crate &lt;em&gt;stm32l0&lt;/em&gt; qui s’en charge via la feature &lt;em&gt;rt&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;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 &lt;code&gt;memory.x&lt;/code&gt; contenant:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;MEMORY
{
  RAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
  FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;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 &lt;em&gt;cortex-m-rt&lt;/em&gt; nommé &lt;code&gt;link.x&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;toml&quot;&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;thumbv6m-none-eabi&amp;quot;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# flag pour l&amp;apos;édition de lien&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;thumbv6m-none-eabi&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;property&quot;&gt;rustflags&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&amp;quot;-C&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&amp;quot;link-arg=-Tlink.x&amp;quot;&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Pour aller plus loin&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Si on le souhaite, on peut aussi utiliser un script de liens personnel (&lt;a href=&quot;https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#custom-linker-script&quot; target=&quot;_blank&quot;&gt;doc&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;Si on souhaite analyser le fichier elf avec &lt;code&gt;objdump&lt;/code&gt; &lt;a href=&quot;https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#inspection&gt;&quot; target=&quot;_blank&quot;&gt;ce morceau de doc&lt;/a&gt; explicite les différentes sections.&lt;/li&gt;&lt;li&gt;script de liens par défaut: &lt;a href=&quot;https://github.com/rust-embedded/cortex-m/blob/master/cortex-m-rt/link.x.in&quot; target=&quot;_blank&quot;&gt;link.x&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 id=&quot;helloworld&quot;&gt;Un simple clignotement&lt;/h1&gt;&lt;p&gt;Commençons par le &lt;em&gt;hello world&lt;/em&gt; de l’embarqué: faire clignoter une led…&lt;/p&gt;&lt;p&gt;On commence par créer un dossier: &lt;code&gt;mkdir rust_stm32l031 &amp;amp;&amp;amp; cd rust_stm32l031&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Ensuite on initialise le projet avec cargo: &lt;code&gt;cargo init --bin&lt;/code&gt;. Cette commande va créer les fichiers de config (Cargo.toml et Carlo.lock) ainsi qu’un répertoire &lt;em&gt;src&lt;/em&gt; et le fichier &lt;em&gt;main.rs&lt;/em&gt;.&lt;/p&gt;&lt;h2 id=&quot;blinky_main&quot;&gt;Mise en place de la fonction main&lt;/h2&gt;&lt;p&gt;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: &lt;code&gt;#![no_std]&lt;/code&gt;&lt;/p&gt;&lt;p&gt;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 &lt;em&gt;main&lt;/em&gt;). En effet, notre &lt;code&gt;main()&lt;/code&gt; sera appelée depuis la fonction &lt;code&gt;Reset&lt;/code&gt; implémentée par &lt;em&gt;cortex-m-rt&lt;/em&gt;. Pour ce faire on utilise la directive: &lt;code&gt;#![no_main]&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;De son côté, le crate &lt;em&gt;cortex-m-rt&lt;/em&gt; expose la directive &lt;code&gt;#[entry]&lt;/code&gt; pour spécifier la fonction d’entrée.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;rust&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;panic_handler&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;constructor constant function&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;constructor constant variable_parameter&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;type&quot;&gt;PanicInfo&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; -&amp;gt; !&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plutôt que de créer notre propre implémentation, on utilise le crate &lt;em&gt;panic_abort&lt;/em&gt; afin qu’en cas d’erreur on déclenche un &lt;em&gt;&lt;a href=&quot;https://doc.rust-lang.org/core/intrinsics/fn.abort.html&quot; target=&quot;_blank&quot;&gt;hardfault&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;On va donc avoir un fichier &lt;em&gt;main.rs&lt;/em&gt; qui ressemble à ça:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;rust&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;no_main&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;attribute&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;no_std&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;constructor constant type&quot;&gt;cortex_m_rt&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;constructor constant&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;panic_abort&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;type&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;attribute&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;constructor constant function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; -&amp;gt; ! &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;keyword&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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!&lt;/p&gt;&lt;h2 id=&quot;blinky_run&quot;&gt;configuration des périphériques&lt;/h2&gt;&lt;p&gt;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:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;cortex-m&lt;/em&gt; pour l’accès aux périphériques &lt;em&gt;arm&lt;/em&gt;, par exemple: systick, nvic …&lt;/li&gt;&lt;li&gt;&lt;em&gt;stm32l0&lt;/em&gt; pour l’accès aux périphériques stm32, par exemple: adc, gpio …&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Les objectifs sont:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;configurer l’horloge pour utiliser le HSI 16MHz comme source&lt;/li&gt;&lt;li&gt;configurer le GPIO B3 en sortie pour faire clignoter une led&lt;/li&gt;&lt;li&gt;configurer le Systick pour cadencer le clignotement de la led&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Ce qui donne le fichier &lt;em&gt;main.rs&lt;/em&gt; suivant:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;rust&quot;&gt;&lt;span class=&quot;attribute&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;no_std&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;attribute&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;no_main&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;cortex_m&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;constructor constant&quot;&gt;Peripherals&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;constructor constant type&quot;&gt;cortex_m_rt&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;panic_abort&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;constructor constant type&quot;&gt;stm32l0&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant&quot;&gt;stm32l0x1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;attribute&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;constructor constant attribute&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;punctuation_bracket attribute&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;constructor constant function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; -&amp;gt; ! &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// acces aux périphériques&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;peripherals&lt;/span&gt; = &lt;span class=&quot;constructor constant type&quot;&gt;stm32l0x1&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant type&quot;&gt;Peripherals&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// on récupère le périphérique d&amp;apos;horloge et on configure le HSI&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt; = &lt;span class=&quot;constructor constant&quot;&gt;peripherals&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;RCC&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;apb2enr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;syscfgen&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;cr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;hsi16on&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;cr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;hsi16rdyf&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;bit_is_clear&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;cfgr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;hsi16&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment&quot;&gt;// configuration du Systick pour une clock à 16 MHz et&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// utilisation de la structure delay de cortex-m&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;peripheral&lt;/span&gt; = &lt;span class=&quot;constructor constant type&quot;&gt;Peripherals&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;unwrap&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;delay&lt;/span&gt; = &lt;span class=&quot;constructor constant type&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant type&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;constructor constant function&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constructor constant&quot;&gt;peripheral&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;SYST&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constant_builtin&quot;&gt;16_000_000&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment&quot;&gt;// on active l&amp;apos;horloge pour le GPIOB&lt;/span&gt;
    &lt;span class=&quot;constructor constant&quot;&gt;rcc&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;iopenr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;iopben&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;comment&quot;&gt;// On configure le GPIOB3 en sortie push-pull&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;gpiob&lt;/span&gt; = &lt;span class=&quot;constructor constant&quot;&gt;peripherals&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property&quot;&gt;GPIOB&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;constructor constant&quot;&gt;gpiob&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;moder&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;mode3&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;keyword&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;punctuation_bracket&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;comment&quot;&gt;// on commence par lire l&amp;apos;état de la sortie via &amp;apos;r&amp;apos; -&amp;gt; r.od3().bit()&lt;/span&gt;
        &lt;span class=&quot;comment&quot;&gt;// On inverse la valeur à écrire par rapport à la valeur lu via &amp;apos;!&amp;apos;&lt;/span&gt;
        &lt;span class=&quot;comment&quot;&gt;// et on écrit met à jour la sortie &amp;apos;w&amp;apos; -&amp;gt; w.od3().bit(x)&lt;/span&gt;
        &lt;span class=&quot;constructor constant&quot;&gt;gpiob&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;odr&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;modify&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;|&lt;span class=&quot;constructor constant&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;| &lt;span class=&quot;constructor constant&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;od3&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;!&lt;span class=&quot;constructor constant&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;od3&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;comment&quot;&gt;// attente de 500 ms&lt;/span&gt;
        &lt;span class=&quot;constructor constant&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;property function_method&quot;&gt;delay_ms&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;constant_builtin&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;punctuation_bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;punctuation_delimiter&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;punctuation_bracket&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Et voilà un clignotement de led en bonne et due forme.&lt;/p&gt;</description>
    <link>https://ylbn.fr/blog/rust_embedded_1/</link>
    <pubDate>Fri, 06 Mar 2026 00:00:00 +0000</pubDate>
    <guid>https://ylbn.fr/blog/rust_embedded_1/</guid>
   </item>
  
   <item>
    <title>Linker scripts</title>
    <description>&lt;h1 id=&quot;intro&quot;&gt;Intro&lt;/h1&gt;&lt;p&gt;Dans les grandes lignes, le linker script (fichier .ld) permet d’indiquer au programme “&lt;em&gt;ld&lt;/em&gt;” comment le contenu des fichiers objet (.o) doit être assemblé pour créer le fichier ELF.&lt;/p&gt;&lt;p&gt;Dans le cas qui m’intéresse - les firmwares ciblant des microcontrôleurs - le fichier elf sera soit converti en fichier hexa ou binaire soit directement utilisé par openocd pour programmer le MCU.&lt;/p&gt;&lt;p&gt;Un exemple de linker script est disponible &lt;a href=&quot;https://ylbn.fr/blog/linker_script/sample.ld&quot;&gt;ici sample.ld&lt;/a&gt;.&lt;/p&gt;&lt;h1 id=&quot;archi&quot;&gt;Architecture du fichier &lt;em&gt;.ld&lt;/em&gt;&lt;/h1&gt;&lt;p&gt;Les fichiers &lt;em&gt;.ld&lt;/em&gt; sont de simples fichiers texte. On peut y écrire des commentaires via la syntaxe &lt;code&gt;/* mon commentaire */&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Pour indiquer à l’éditeur de liens comment agencer les objets en mémoire, nous avons à disposition quelques mots-clés (liste non exhaustive, je me contente ici des mots-clés qui me sont utiles):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;MEMORY&lt;/code&gt; Déclare les zones mémoire utilisables, leurs adresses et leurs tailles.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SECTIONS&lt;/code&gt; Permet de déclarer les différentes sections, où les &lt;em&gt;ranger&lt;/em&gt; et dans quel ordre.&lt;/li&gt;&lt;li&gt;&lt;code&gt;.&lt;/code&gt; Le point n’est pas un mot-clé à proprement parler mais une variable spéciale. Elle enregistre la dernière adresse mémoire utilisée durant &lt;em&gt;l’assemblage&lt;/em&gt; des objets. Elle nous permet donc de récupérer la position actuelle de *l’assemblage en mémoire: &lt;code&gt;_myvar = .&lt;/code&gt;. Elle permet aussi de forcer la position d’une section: &lt;code&gt;. = 0xFF&lt;/code&gt; (semblable à l’instruction &lt;code&gt;AT(x)&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;code&gt;KEEP&lt;/code&gt; Indique à l’éditeur de liens de garder cette section même si elle est vide. Ce mot-clé a toute son importance lorsque l’on passe l’option &lt;code&gt;--gc-sections&lt;/code&gt; à l’éditeur.&lt;/li&gt;&lt;li&gt;&lt;code&gt;AT(x)&lt;/code&gt;: Est un attribut de section (optionnel) qui permet de spécifier l’adresse à laquelle doit être placé la section.&lt;/li&gt;&lt;li&gt;&lt;code&gt;&amp;gt; Y AT &amp;gt; X&lt;/code&gt;: Cette utilisation de &lt;code&gt;AT&lt;/code&gt; diffère de la précédente. Dans ce cas, on l’utilise pour indiquer la zone mémoire de &lt;em&gt;stockage&lt;/em&gt; (Y) et la zone mémoire dans laquelle la section doit être chargée (X).&lt;/li&gt;&lt;li&gt;&lt;code&gt;ALIGN(x)&lt;/code&gt; spécifie l’alignement en mémoire, x étant le nombre d’octets&lt;/li&gt;&lt;li&gt;&lt;code&gt;NOLOAD&lt;/code&gt; Indique au sein du fichier ELF que la section n’a pas besoin d’être chargée au démarrage du système. Ce mot-clé ne semble pas pertinent dans notre cas puisque le démarrage n’est pas fait à partir du fichier ELF mais cela nous permet de &lt;em&gt;décrire&lt;/em&gt; les sections.&lt;/li&gt;&lt;li&gt;&lt;code&gt;LOADADDR&lt;/code&gt; permet de récupérer l’adresse d’une section en mémoire.&lt;/li&gt;&lt;li&gt;&lt;code&gt;PROVIDE&lt;/code&gt; Il y a deux manières de définir un symbole, soit par un assignement, soit via &lt;code&gt;PROVIDE&lt;/code&gt;. &lt;code&gt;PROVIDE&lt;/code&gt; permet de définir le symbole s’il n’est pas déjà défini dans les fichiers objets à assembler.&lt;/li&gt;&lt;li&gt;&lt;code&gt;PROVIDE_HIDDEN&lt;/code&gt; Permet de définir une variable mais sans l’exporter ; donc définir une variable locale plutôt que globale.&lt;/li&gt;&lt;li&gt;&lt;code&gt;ASSERT&lt;/code&gt; assertion classique permet de déclencher une erreur si le résultat du test est égal à zéro.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SIZEOF&lt;/code&gt; permet de récupérer la taille d’une section.&lt;/li&gt;&lt;li&gt;&lt;code&gt;SORT&lt;/code&gt; permet de trier une liste&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;De manière naïve, nous pouvons dire que ces scripts sont découpés en trois parties:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;La déclaration des variables Via l’assignation &lt;code&gt;=&lt;/code&gt; ou &lt;code&gt;PROVIDE&lt;/code&gt;, on peut assigner une valeur à une variable que l’on pourra réutiliser plus tard dans le script. Dans notre exemple, on s’en sert pour définir la taille maximale de la stack.&lt;/li&gt;&lt;li&gt;La description de la mémoire du périphérique. Grâce au mot-clé &lt;code&gt;MEMORY&lt;/code&gt;, on indique l’adresse des zones mémoire à utiliser et leurs tailles.&lt;/li&gt;&lt;li&gt;La description de &lt;em&gt;comment ranger le code en mémoire&lt;/em&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h1 id=&quot;desc&quot;&gt;Description de la mémoire&lt;/h1&gt;&lt;p&gt;Cette section permet de décrire la zone mémoire utilisable. Dans notre exemple, nous avons trois zones, la RAM, le BOOTLOADER et la FLASH.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;FLASH_SIZE = 0x10000000
RAM_SIZE = 0x30000

MEMORY{
    FLASH(rx) : ORIGIN = 0x00000000, LENGTH = FLASH_SIZE
    RAM(rwx) : ORIGIN = 0x20000000, LENGTH = RAM_SIZE
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On remarque que la déclaration de variable et leur assignement nous permet de facilement &lt;em&gt;séparer&lt;/em&gt; une même mémoire physique en deux mémoires virtuelles (BOOTLOADER et FLASH).&lt;/p&gt;&lt;p&gt;La déclaration des zones mémoire nous permet aussi d’indiquer les droits d’accès pour chacune de ces zones.&lt;/p&gt;&lt;h1 id=&quot;section&quot;&gt;La gestion des sections&lt;/h1&gt;&lt;p&gt;Le mot-clé &lt;code&gt;SECTIONS{}&lt;/code&gt; permet de définir plus finement l’organisation du code dans les différentes zones mémoire.&lt;/p&gt;&lt;h2 id=&quot;vector_table&quot;&gt;La table des vecteurs d’interruption&lt;/h2&gt;&lt;p&gt;Dans le cas d’un MCU basé sur l’architecture ARM Cortex-M, la première section &lt;strong&gt;doit&lt;/strong&gt; être la table des vecteurs d’interruption.&lt;/p&gt;&lt;p&gt;Nous allons donc commencer le script avec:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;SECTIONS{
  /* force la position à l&amp;apos;adresse relative 0 */
  . = 0x0;
  .vectors : {
  /* indique que les données doivent être
     alignées sur 4 octets */
  . = ALIGN(4);
    KEEP(*(.vectors))
  } &amp;gt; BOOTLOADER;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Attention, il ne faut pas oublier d’ajouter  &lt;code&gt;__attribute__ ((section(&amp;quot;.vectors&amp;quot;)))&lt;/code&gt; à la déclaration de la table des vecteurs d’interruption afin de spécifier son lieu de stockage.&lt;/p&gt;&lt;p&gt;En ce qui concerne l’appellation des objets et des sections, GCC génère trois formes de “&lt;em&gt;section&lt;/em&gt;” différentes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;mysection&lt;/code&gt;: la classique&lt;/li&gt;&lt;li&gt;&lt;code&gt;mysection.mafonction&lt;/code&gt; &lt;code&gt;mysection.mydata&lt;/code&gt; : générée automatiquement si l’on compile le programme avec les options &lt;code&gt;-ffunction-sections&lt;/code&gt; ou &lt;code&gt;-fdata-sections&lt;/code&gt;. Ces options permettent de générer une section par fonction/data. Cela peut être pratique pour placer précisément une donnée ou une fonction dans une zone particulière : par exemple en SRAM pour réduire les temps d’accès.&lt;/li&gt;&lt;li&gt;&lt;code&gt;gnu.linkonce.{type}.{nom}&lt;/code&gt; : liée au &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html&quot; target=&quot;_blank&quot;&gt;Vague Linkage&lt;/a&gt; Cette section ne semble concerner que le code C++&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;usuelle&quot;&gt;Les sections usuelles&lt;/h2&gt;&lt;p&gt;Les sections usuelles servent à stocker le code et les variables. On y retrouve :&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;.text&lt;/code&gt;: le code&lt;/li&gt;&lt;li&gt;&lt;code&gt;.rodata&lt;/code&gt;: les données en lecture seule&lt;/li&gt;&lt;li&gt;&lt;code&gt;.data&lt;/code&gt;: les données en lecture/écriture initialisées avec une valeur&lt;/li&gt;&lt;li&gt;&lt;code&gt;.bss&lt;/code&gt;: les données en lecture/écriture non initialisées&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Notons que les sections &lt;code&gt;.data&lt;/code&gt; et &lt;code&gt;.bss&lt;/code&gt; doivent être, respectivement, copiées et initialisées en RAM au démarrage du MCU. Dans notre cas de figure, cette opération est réalisée dans la fonction de démarrage (fonction appelée par l’interruption de &lt;em&gt;Reset&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;Ce sont les quatre sections que l’on retrouve systématiquement. Nous pouvons aussi y ajouter nos propres sections pour stocker une partie spécifique du programme à un emplacement donné.&lt;/p&gt;&lt;p&gt;Par exemple on pourrait vouloir que certaines fonctions soient exécutées depuis une autre zone mémoire (ex: SRAM) afin d’optimiser la vitesse d’exécution. On aurait alors le linker script suivant:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;SECTIONS{
    .text : {
     
    } &amp;gt; FLASH
    .data : {
     
    } &amp;gt; RAM
    .bss : {
     
    } &amp;gt; RAM

    .superImportanteSection {
      speed_function.o
    } &amp;gt; SRAM AT &amp;gt; FLASH
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;L’indication &lt;code&gt;&amp;gt; SRAM AT &amp;gt; FLASH&lt;/code&gt; permet d’indiquer que ces données sont stockées en FLASH mais doivent être chargées en SRAM au démarrage. Attention, ce n’est pas fait automatiquement : il faut adapter la fonction de démarrage (dans le cas d’un MCU) pour copier la section (cf: &lt;code&gt;bss&lt;/code&gt; et &lt;code&gt;data&lt;/code&gt;).&lt;/p&gt;&lt;h2 id=&quot;specific&quot;&gt;Les sections spécifiques&lt;/h2&gt;&lt;p&gt;On retrouve ici les sections utilisées par le compilateur pour stocker les constructeurs et destructeurs d’objets (&lt;code&gt;new&lt;/code&gt; et &lt;code&gt;delete&lt;/code&gt; en C++ et &lt;code&gt;__attribute__((constructor))&lt;/code&gt; en C). N’utilisant pas le C++ en embarqué, l’étude de ce fonctionnement n’a pas été poussée.&lt;/p&gt;&lt;p&gt;Ce que j’ai pu en comprendre, c’est que ces sections sont utilisées par le compilateur pour stocker des pointeurs de fonction permettant d’initialiser/déinitialiser des variables.&lt;/p&gt;&lt;p&gt;Ces fonctions sont appelées via &lt;code&gt;__libc_init_array&lt;/code&gt; durant la phase de démarrage et via &lt;code&gt;__libc_fini_array&lt;/code&gt; à la fin de l’exécution (ce qui n’arrive jamais en embarqué). (cf &lt;a href=&quot;https://github.com/picolibc/picolibc/blob/main/doc/init.md&quot; target=&quot;_blank&quot;&gt;picolibc&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Les sections d’initialisation et destruction sont:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;preinit_array : générer par le compilateur pour les classes C++ (vtable) (je n’ai pas creusé davantage)&lt;/li&gt;&lt;li&gt;init_array : les fonctions avec l’attribut &lt;em&gt;constructor&lt;/em&gt;. &lt;strong&gt;ATTENTION&lt;/strong&gt; les constructeurs sont initialisés avec un ordre de priorité. Donc &lt;em&gt;init_array&lt;/em&gt; doit être trié avec &lt;em&gt;SORT&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;fini_array : les fonctions avec l’attribut &lt;em&gt;destructeur&lt;/em&gt;&lt;/li&gt;&lt;li&gt;ctors: déprécié&lt;/li&gt;&lt;li&gt;dtors: déprécié&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;section_debug&quot;&gt;Les sections ARM Debug&lt;/h2&gt;&lt;p&gt;Pour pouvoir utiliser la fonction &lt;em&gt;backtraces&lt;/em&gt; en debug, if faut fournir deux sections:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;exidx&lt;/em&gt; : qui contient l’index permettant de décoder la stack&lt;/li&gt;&lt;li&gt;&lt;em&gt;extab&lt;/em&gt; : qui contient le nom des sections contenant des infos sur les exceptions en cours ??? &lt;strong&gt;pas clair&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Ressource:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/21527256/when-is-arm-exidx-is-used/57463515#57463515&quot; target=&quot;_blank&quot;&gt;stackoverflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/kernel/unwind.c&quot; target=&quot;_blank&quot;&gt;linux use&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Il semble que ces sections permettent d’analyser et restaurer la stack sans passer par le frame_pointer (fp). Ils parlent - sur so - d’utilisation pour les fonctions asynchrones. Freertos need it ?&lt;/p&gt;&lt;h1 id=&quot;ram&quot;&gt;Organisation de la RAM&lt;/h1&gt;&lt;p&gt;Une des raisons m’ayant poussé à comprendre plus finement le fonctionnement des scripts de liens et de leurs éditeurs est de pouvoir modifier l’agencement de la RAM pour éviter que la pile déborde sur la stack ou que la stack descende sur la pile. Ces bugs sont particulièrement pénibles à résoudre…&lt;/p&gt;&lt;p&gt;L’idée ici est d’organiser la RAM de la manière suivante:&lt;/p&gt;&lt;p&gt;&lt;figure&gt;&lt;img src=&quot;https://ylbn.fr/blog/linker_script/ram.png&quot; width=&quot;246&quot; height=&quot;432&quot;&gt;
&lt;figcaption&gt;ram orga&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Ainsi, la pile, qui est descendante sur ARM Cortex-M, viendra déborder sur la section “NoMansLand”. Donc en configurant le périphérique de protection mémoire (MPU) correctement, on pourra “normalement” détecter le débordement de la stack.&lt;/p&gt;&lt;p&gt;Idem pour la HEAP, qui elle est croissante et viendra déborder sur une adresse non accessible en écriture et nous permettra de détecter le dépassement rapidement.&lt;/p&gt;&lt;p&gt;Cet &lt;a href=&quot;https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-1-calculating-stack-size/&quot; target=&quot;_blank&quot;&gt;article&lt;/a&gt; explique clairement l’intérêt de cette configuration.&lt;/p&gt;&lt;h1 id=&quot;mold&quot;&gt;Autre linker&lt;/h1&gt;&lt;p&gt;J’ai voulu voir s’il était possible de remplacer &lt;code&gt;ld&lt;/code&gt; par &lt;code&gt;mold&lt;/code&gt; mais &lt;code&gt;mold&lt;/code&gt; ne supporte qu’un tout petit sous-ensemble de la syntaxe des linker-scripts. Il est donc impossible de l’utiliser pour l’embarqué en &lt;em&gt;none-eabi&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Il me reste à tester avec lld de clang.&lt;/p&gt;&lt;h1 id=&quot;ref&quot;&gt;Références&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://allthingsembedded.com/post/2020-04-11-mastering-the-gnu-linker-script/&quot; target=&quot;_blank&quot;&gt;allthingsembedded&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.thea.codes/the-most-thoroughly-commented-linker-script/&quot; target=&quot;_blank&quot;&gt;thea.codes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://ylbn.fr/blog/linker_script/DUI0101A_Elf.pdf&quot;&gt;Document de référence ARM ELF&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://wiki.osdev.org/Linker_Scripts&quot; target=&quot;_blank&quot;&gt;linker script syntax&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://home.cs.colorado.edu/~main/cs1300/doc/gnu/ld_3.html&quot; target=&quot;_blank&quot;&gt;https://home.cs.colorado.edu/~main/cs1300/doc/gnu/ld_3.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description>
    <link>https://ylbn.fr/blog/linker_script/</link>
    <pubDate>Sun, 01 Dec 2024 00:00:00 +0000</pubDate>
    <guid>https://ylbn.fr/blog/linker_script/</guid>
   </item>
  
 </channel>
</rss>

