Utiliser Rust pour le développement embarqué


  • FrançaisFrançais


  • Au cours des dernières années, Rust a gagné un public passionné parmi les programmeurs. Les tendances technologiques vont et viennent, il peut donc être difficile de séparer l’enthousiasme simplement parce que quelque chose est nouveau et l’enthousiasme pour les mérites d’une technologie, mais je pense que Rust est un langage vraiment bien conçu. Il vise à aider les développeurs à créer des logiciels fiables et efficaces, et il a été conçu à cet effet dès le départ. Il existe des fonctionnalités clés dont vous entendrez parler à propos de Rust, et dans cet article, je démontre que bon nombre de ces fonctionnalités expliquent exactement pourquoi Rust est également idéal pour les systèmes embarqués. Voici quelques exemples:

    • Hautes performances : c’est rapide, avec une utilisation élevée de la mémoire
    • Fiabilité : les erreurs de mémoire peuvent être éliminées lors de la compilation
    • Productivité : excellente documentation, un compilateur convivial avec des messages d’erreur utiles et des outils de premier ordre. Il existe un gestionnaire de packages et un outil de construction intégrés, une prise en charge multi-éditeurs intelligente avec saisie automatique et inspections de type, un formateur automatique, etc.

    Pourquoi utiliser Rust pour le développement embarqué ?

    Rust est conçu pour garantir à la fois la sécurité et des performances élevées. Les logiciels embarqués peuvent avoir des problèmes, principalement dus à la mémoire. Rust est, d’une certaine manière, un langage orienté compilateur, vous pouvez donc être sûr que vous utilisez la mémoire en toute sécurité lors de la compilation. Voici quelques-uns des avantages de l’utilisation de Rust pour développer sur des appareils embarqués :

    • Analyse statique puissante
    • Mémoire flexible
    • Concurrence intrépide
    • Interopérabilité
    • Portabilité
    • Axé sur la communauté

    Dans cet article, j’utilise l’open source Système d’exploitation RT-Thread pour montrer comment utiliser Rust pour le développement embarqué.

    Comment appeler Rust en C

    Lorsque vous appelez du code Rust en code C, vous devez empaqueter le code source Rust en tant que fichier de bibliothèque statique. Lorsque le code C se compile, associez-le.

    Créer une bibliothèque statique avec Rust

    Il y a deux étapes dans ce processus.

    1. Utiliser cargo init --lib rust_to_c pour construire une bibliothèque lib dans Clion. Ajoutez le code suivant au lib.rs. La fonction suivante évalue la somme de deux valeurs de type i32 et renvoie le résultat :

    #![no_std]
    use core::panic::PanicInfo;

    #[no_mangle]
    pub extern "C" fn sum(a: i32, b: i32) -> i32 {
        a + b
    }

    #[panic_handler]
    fn panic(_info:&PanicInfo) -> !{
        loop{}
    }

    2. Ajoutez le code suivant à votre Cargo.toml fichier pour indiquer à Rustc quel type de bibliothèque générer :

    [lib]
    name = "sum"
    crate-type = ["staticlib"]
    path = "src/lib.rs"

    Compilation croisée

    Vous pouvez effectuer une compilation croisée pour votre cible. En supposant que votre système embarqué soit basé sur Arm, les étapes sont simples :

    $ rustup target add armv7a-none-eabi

    2. Générez le fichier de bibliothèque statique :

    $ cargo build --target=armv7a-none-eabi --release --verbose
    Fresh rust_to_c v0.1.0
    Finished release [optimized] target(s) in 0.01s

    Générer un fichier d’en-tête

    Vous avez également besoin de fichiers d’en-tête.

    1. Installer cbindgen. Les cbindgen L’outil génère un fichier d’en-tête C ou C++11 à partir de la bibliothèque Rust :

    $ cargo install --force cbindgen

    2. Créez un nouveau cbindgen.toml fichier sous votre dossier de projet.

    3. Générez un fichier d’en-tête :

    $ cbindgen --config cbindgen.toml --crate rust_to_c --output sum.h

    Appelez le fichier de bibliothèque Rust

    Vous pouvez désormais appeler vos bibliothèques Rust.

    1. Mettez le généré sum.h et sum.a fichiers dans le rt-thread/bsp/qemu-vexpress-a9/applications annuaire.

    2. Modifiez le SConscript fichier et ajoutez une bibliothèque statique :

       from building import *
       
       cwd     = GetCurrentDir()
       src     = Glob('*.c') + Glob('*.cpp')
       CPPPATH = [cwd]
       
       LIBS = ["libsum.a"]
       LIBPATH = [GetCurrentDir()]
       
       group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, LIBS = LIBS, LIBPATH = LIBPATH)
       
       Return('group')

    3. Appelez le somme fonction dans la fonction principale, obtenez la valeur de retour, et printf la valeur.

       #include <stdint.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <rtthread.h>
       #include "sum.h"
       
       int main(void)
       {
           int32_t tmp;
       
           tmp = sum(1, 2);
           printf("call rust sum(1, 2) = %dn", tmp);
       
           return 0;
       }

    4. Dans le fil RT Env environnement, utilisation scons pour compiler le projet et exécuter :

    $ scons -j6
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    [...]
    scons: done building targets.

    $ qemu.sh
      | /
    - RT -     Thread Operating System
     / |     4.0.4 build Jul 28 2021
    2006 - 2021 Copyright by rt-thread team
    lwIP-2.1.2 initialized!
    [...]
    call rust sum(1, 2) = 3

    Additionner, soustraire, multiplier et diviser

    Vous pouvez implémenter des mathématiques compliquées dans Rust. Dans le lib.rs fichier, utilisez le langage Rust pour implémenter l’addition, la soustraction, la multiplication et la division :

    #![no_std]
    use core::panic::PanicInfo;

    #[no_mangle]
    pub extern "C" fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    #[no_mangle]
    pub extern "C" fn subtract(a: i32, b: i32) -> i32 {
        a - b
    }

    #[no_mangle]
    pub extern "C" fn multiply(a: i32, b: i32) -> i32 {
        a * b
    }

    #[no_mangle]
    pub extern "C" fn divide(a: i32, b: i32) -> i32 {
        a / b
    }

    #[panic_handler]
    fn panic(_info:&PanicInfo) -> !{
        loop{}
    }

    Créez vos fichiers de bibliothèque et vos fichiers d’en-tête et placez-les dans le répertoire de l’application. Utilisation scons compiler. Si des erreurs apparaissent lors de la liaison, trouvez la solution sur le site officiel Page Github.

    Modifier le rtconfig.py fichier et ajoutez le paramètre de lien --allow-multiple-definition:

           DEVICE = ' -march=armv7-a -marm -msoft-float'
           CFLAGS = DEVICE + ' -Wall'
           AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ -I.'
           LINK_SCRIPT = 'link.lds'
           LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors,--allow-multiple-definition'+
                             ' -T %s' % LINK_SCRIPT
       
           CPATH = ''
           LPATH = ''

    Compilez et exécutez QEMU pour voir votre travail.

    Appelez C dans Rust

    Rust peut être appelé en code C, mais qu’en est-il d’appeler C dans votre code Rust ? Ce qui suit est un exemple d’appel du rt_kprintf Fonction C en code Rust.

    Tout d’abord, modifiez le lib.rs déposer:

        // The imported rt-thread functions list
        extern "C" {
            pub fn rt_kprintf(format: *const u8, ...);
        }
       
        #[no_mangle]
        pub extern "C" fn add(a: i32, b: i32) -> i32 {
            unsafe {
                rt_kprintf(b"this is from rustn" as *const u8);
            }
            a + b
        }

    Ensuite, générez le fichier de bibliothèque :

    $ cargo build --target=armv7a-none-eabi --release --verbose
    Compiling rust_to_c v0.1.0
    Running `rustc --crate-name sum --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type staticlib --emit=dep-info,link -C opt-level=3 -C embed-bitcode=no -C metadata=a
    Finished release [optimized] target(s) in 0.11s

    Et maintenant, pour exécuter le code, copiez les fichiers de bibliothèque générés par Rust dans le répertoire de l’application et reconstruisez :

    $ scons -j6 scons: Reading SConscript files ... scons: done reading SConscript files. [...]
    scons: Building targets ... scons: done building targets.

    Exécutez à nouveau QEMU pour voir les résultats dans votre image intégrée.

    Tu peux tout avoir

    L’utilisation de Rust pour votre développement intégré vous offre toutes les fonctionnalités de Rust sans sacrifier la flexibilité ou la stabilité. Essayez Rust sur votre système embarqué dès aujourd’hui. Pour plus d’informations sur le processus de Rust intégré (et sur RT-Thread lui-même), consultez le projet RT-Thread Chaîne Youtube. Et n’oubliez pas que l’embarqué peut aussi être ouvert.

    Source

    La Rédaction

    L'équipe rédactionnnelle du site

    Pour contacter personnellement le taulier :

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Copy code