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)
Langage du code : JavaScript (javascript)
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
Langage du code : JavaScript (javascript)
Ç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
Langage du code : JavaScript (javascript)
Et bien entendu, il faudra «descendre» le projet git hub d’exemples:
$ git clone https://github.com/riscv-rust/longan-nano.git
$ cd longan-nano
$ rustup target add riscv32imac-unknown-none-elf
Langage du code : PHP (php)
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;
}
Langage du code : JavaScript (javascript)
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;
}
}
}
Langage du code : JavaScript (javascript)
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 😉