Rust sur Longan Nano

La Longan Nano est une petite carte de la taille d’un pouce munie d’un microcontrôleur à cœur RISC-V le GD32VF103CBT6. Processeur qui est un clone du fameux stm32 de chez ST, MAIS avec un cœur RISC-V (alors que le stm32 est à base de ARM).

Ce qui est bien avec la Longan Nano c’est que pour $4.90 il y a absolument tout pour faire du développement embarqué: en plus de l’écran oled couleurs et la LED RGB il y a une interface USB (connecteur usb-c) qui permet d’alimenter la carte, la programmer et communiquer par UART. Pour le JTAG par contre il faut un adaptateur externe qui peut cependant être très pratique pour utiliser un debugger.

Ce qui est moins bien par contre c’est qu’elle semble en rupture de stock depuis longtemps.

Bref, c’est une «vieille» carte mais qui est parfaite pour faire du développement embarqué sans rien d’autre qu’un PC et un câble USB.

Pourquoi ne pas tenter de faire du Rust avec alors ? En plus il semble exister des projets de support du langage pour cette carte. Voila qui pourrait démystifier rust pour l’embarqué !

Codons mon bon

La documentation officielle de la cagette nous demande de vérifier la version de rust :

$ rustup default stable
info: using existing install for 'stable-x86_64-unknown-linux-gnu'
info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'

  stable-x86_64-unknown-linux-gnu unchanged - rustc 1.58.0 (02072b482 2022-01-11)

Version 1.58, c’est bon on est supérieur à la 1.36 requise. Comme je veux travailler avec juste le câble usb j’utiliserais (ou tenterais d’utiliser) dfu-util pour programmer le micro.

Il faut juste se compiler une version des binutils comme indiqué dans la doc pour avoir l’utilitaire objcopy :

$ git clone https://github.com/sifive/riscv-binutils-gdb.git
$ cd riscv-binutils-gdb
$ ./configure --target=riscv64-unknown-elf --disable-werror --with-python=no --disable-gdb --disable-sim --disable-libdecnumber --disable-libreadline --with-expat=yes --with-mpc=no --with-mpfr=no --with-gmp=no
$ make

Ça prend un peut de temps avec ma vieille machine (T430) mais ça marche.

On aura également besoin d’une toolchain riscv:

$ wget https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.1.0-2019.01.0-x86_64-linux-ubuntu14.tar.gz
$ tar zxvf riscv64-unknown-elf-gcc-8.1.0-2019.01.0-x86_64-linux-ubuntu14.tar.gz

Et bien entendu, il faudra «descendre» le projet git hub d’exeexamplesmple:

$ git clone https://github.com/riscv-rust/longan-nano.git

Puisque visiblement j’ai une version B du microcontrôleur il faut modifier le fichier de configuration .cargo/config.

Et c’est parti mamie :

$ cargo build --examples --release --all-features

On extrait maintenant l’huile essentiel de notre binaire avec objcopy que l’on appelera firmware.bin :

../riscv64-unknown-elf-gcc-8.1.0-2019.01.0-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-objcopy -O binary target/riscv32imac-unknown-none-elf/release/examples/blinky firmware.bin

Puis on le télécharge dans la carte au moyen de dfu-util en ayant bien pris soin de mettre le microcontrôleur en mode «bootstrap» ( appui sur reset tout en gardant boot0 pressé).

$  dfu-util -a 0 -s 0x08000000:leave -D firmware.bin
dfu-util 0.10-dev

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Warning: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release
dfu-util: Cannot open DFU device 0a5c:21e6 found on devnum 3 (LIBUSB_ERROR_ACCESS)
Opening DFU capable USB device...
Device ID 28e9:0189
Device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash  "
Found GD32VF103, which reports a bad page size and count for its internal memory.
Fixed layout based on part number: page size 1024, count 128.
Downloading element to address = 0x08000000, size = 9388
Erase   	[=========================] 100%         9388 bytes
Erase    done.
Download	[=========================] 100%         9388 bytes
Download done.
File downloaded successfully

Et la led clignote \o/ !

Le code

Le code à proprement parler du clignotement de led est donné dans le fichier examples/blinky.rs

Et le cœur de la boucle de clignotement est donnée ci-dessous :

    let mut i = 0;
    loop {
        let inext = (i + 1) % leds.len();
        leds[i].off();
        leds[inext].on();
        delay.delay_ms(500);

        i = inext;
    }

Il y a trois leds (RGB), on se sert de l’index i pour parcourir le tableau de leds. On éteint la led courante puis on allume la suivante et on attend 500ms.

De cette manière, la led va changer de couleur toutes les demi-seconde et nous offrir un clignotement tricolore.

Si l’on trouve le clignotement on/off un peu trop violent, on peut, comme exercice faire en sorte que la couleurs s’allume et s’éteigne progressivement avec un code de ce genre :

    leds[0].off();
    leds[1].off();
    leds[2].off();

    let count_max:u32 = 1000;
    let mut count:u32 = 0;
    let mut decount: bool = true;
    let mut i:usize = 0;

    loop {
        leds[i].on();
        delay.delay_us(count);
        leds[i].off();
        delay.delay_us(count_max - count);
        if decount {
            if count == 0 {
                decount = false;
                i = (i + 1) % leds.len();
            } else {
                count = count - 1;
            }
        } else {
            if count < count_max {
                count = count + 1;
            }else{
                decount = true;
            }
        }
    }

On aura bien pris soin de descendre la granularité du délais à la microseconde puisque c’est disponible dans le HAL du microcontrôleur (GD32VF103).

Voila un clignotement plus doux des LEDs. Et on se rend compte par la même occasion que la LED verte est nettement plus puissante que les deux autres.

Il y a d’autres exemples dans le git du projet, notamment pour utiliser le lecteur microSD ainsi que l’écran, mais je laisse le soin au lecteur de les découvrir par lui même 😉

Pour conclure, grâce à ce projet, la prise en main de la Longan Nano avec du Rust est vraiment simple et très peu verbeuse. J’avais eu beaucoup plus de mal à la prendre en main en C avec tout le bazar de platformio et vscode à l’époque. Mais c’est peut-être tout simplement parce que la carte est plus mature aujourd’hui aussi 😉

Ressources

Ce contenu a été publié dans Non classé, avec comme mot(s)-clé(s) , , . Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.