Rust fait irruption dans le monde de l'embarqué : pourquoi C n'est plus roi

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : L'ère du « matériel » change de langage

\n\n

Si vous avez déjà écrit un firmware pour microcontrôleur en C, vous connaissez cette sensation. Cette sensation où, après trois heures de débogage, vous trouvez un plantage — un pointeur parti dans le vide, et le watchdog a tout encaissé. Le développement embarqué a longtemps été le territoire du C et de l'assembleur. Mais ces dernières années, un nouvel acteur est entré en scène — Rust. Et ce n'est pas juste « un langage de plus », mais une véritable avancée pour les systèmes embarqués.

\n\n

Dans cet article, nous verrons pourquoi le développement embarqué en Rust n'est pas un effet de mode, mais une nécessité. Nous examinerons des exemples de code réels, comparerons avec le C et comprendrons par où commencer. Si vous programmez sur STM32, ESP32 ou ARM Cortex-M, cet article est pour vous.

\n\n

Pourquoi Rust pour l'embarqué est un mariage idéal

\n\n

Les systèmes embarqués sont un monde de contraintes. Peu de mémoire, pas d'OS, pas de heap, pas d'exceptions. Une erreur de compilation, c'est bien ; une erreur à l'exécution, c'est grave. Rust a été conçu précisément pour ces conditions.

\n\n

Sécurité mémoire sans ramasse-miettes

\n\n

Le principal problème du développeur embarqué en C, ce sont les use-after-free, les doubles libérations mémoire et les dépassements de tampon. Rust résout cela au niveau des types. Le modèle de possession (ownership) et d'emprunt (borrowing) fonctionne même dans un environnement no_std — sans allocateur, sans OS, sans GC.

\n\n

Imaginez que vous écrivez un pilote pour une LED. En C, vous écririez :

\n\n
// Code C\nvoid led_on(GPIO_TypeDef *gpio, uint16_t pin) {\n    gpio->BSRR = pin;\n}
\n\n

Tout va bien, jusqu'à ce que quelqu'un passe un pointeur nul. Rust ne vous permettra pas de faire cela :

\n\n
// Code Rust\nfn led_on(gpio: &mut GpioRegisters, pin: u16) {\n    gpio.bsrr.write(|w| w.bits(pin.into()));\n}
\n\n

Ici, &mut GpioRegisters est une garantie que la référence est valide et que l'accès aux registres est exclusif. Le compilateur ne laissera tout simplement pas passer le code dangereux.

\n\n

Abstractions à coût zéro

\n\n

L'une des principales craintes des développeurs embarqués est qu'un langage de haut niveau « bouffe » des cycles processeur. Rust adhère au principe des abstractions à coût zéro : vous ne payez que pour ce que vous utilisez. Itérateurs, fermetures, traits — tout cela se compile en un code machine aussi efficace que le déroulement manuel de boucles en C.

\n\n

De plus, dans l'écosystème embarqué de Rust, il existe des crates qui fonctionnent au niveau des instructions individuelles. Par exemple, cortex-m-rt génère le vecteur d'interruptions et le code de démarrage sans une seule instruction superflue.

\n\n

Projet réel : faire clignoter une LED en Rust (STM32)

\n\n

Écrivons un programme simple pour la carte STM32F3Discovery. Nous utiliserons cortex-m-quickstart et le HAL de la communauté rust embarqué.

\n\n

Étape 1 : Configuration du projet

\n\n

Assurez-vous d'avoir installé Rust et la chaîne d'outils pour ARM Cortex-M :

\n\n
rustup target add thumbv7em-none-eabihf\ncargo install cargo-generate
\n\n

Créons un projet à partir du modèle :

\n\n
cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
\n\n

Étape 2 : Écrire le code

\n\n

Ouvrons src/main.rs et écrivons le classique Blinky :

\n\n
#![no_std]\n#![no_main]\n\nuse cortex_m_rt::entry;\nuse panic_halt as _;\nuse stm32f3xx_hal::{pac, prelude::*};\n\n#[entry]\nfn main() -> ! {\n    // Accès aux périphériques\n    let dp = pac::Peripherals::take().unwrap();\n    let mut rcc = dp.RCC.constrain();\n    let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);\n\n    // Configuration de la broche PE9 en sortie (LED LD1)\n    let mut led = gpioe\n        .pe9\n        .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);\n\n    loop {\n        led.set_high().unwrap();\n        cortex_m::asm::delay(8_000_000);\n        led.set_low().unwrap();\n        cortex_m::asm::delay(8_000_000);\n    }\n}
\n\n

Que se passe-t-il ici ?

\n
    \n
  • #![no_std] — nous n'utilisons pas la bibliothèque standard
  • \n

Blogs

Book Recommendations