Le jeu d'instructions RISC-V s'est fait une place dans le monde des systèmes embarqués et des microcontrôleurs. Les guerres commerciales qui se déroulent actuellement montrent à quel point un jeu d'instructions ouvert peut être important et quels avantages il procure. Les fournisseurs spécialisés dans les jeux d'instructions, notamment ARM, ont adapté les licences de leurs propres architectures d'instructions en réponse au jeu d'instructions RISC-V libre et les ont rendues plus conviviales pour les clients. Comme on le sait, la concurrence stimule le marché. Cet article a donc pour but de vous accompagner dans vos premiers pas avec les microcontrôleurs basés sur l'architecture RISC-V.

Que créons-nous ?

Le Canaan Kendryte K210 est un microcontrôleur peu coûteux, doté d'un cœur RISC-V. Il est présent, entre autres, sur les cartes Sipeed Maixduino ou Sipeed Maix Bit (l'une et l'autre disponibles dans l'e-choppe d'Elektor). Il est aussi possible de l'acquérir sous la forme d'un kit avec caméra et écran LCD pour environ 30 €. Nous allons montrer sur ce microcontrôleur comment installer le SDK et une chaîne d'outils pour la carte, sous Linux. En plus de l'exemple classique « hello world », nous utiliserons Quake 1, un jeu de tir en 3D du milieu des années 90 et nous montrerons comment le traduire pour le K210. Si vous voulez simplement essayer Quake 1 et que vous ne souhaitez pas compiler le code source vous-même, vous pouvez télécharger un binaire prêt à l'emploi depuis le référentiel GitHub d'elect-gombe [1] et le flasher directement.

 
Sipeed Maixduino
Figure 1 : Sipeed Maixduino avec écran et caméra.

Matériel

Cet article utilise les cartes Maixduino Sipeed (figure 1) et Maix Bit Sipeed (figure 2), dotées chacune d'un microcontrôleur Kendryte K210 de Canaan. Ce microcontrôleur est basé sur l'architecture RISC-V qui, selon la terminologie RISC-V, est équipé de deux cœurs de processeur.
 

Sipeed MAix Bit
Figure 2 : Carte Sipeed MAix Bit avec écran connecté.

Le tableau 1 donne des spécifications techniques précises sur la carte. Il contient la désignation RV64IMAFDC du cœur du processeur. Ce qui surprend, c'est la désignation RV64 en préfixe - il s'agit bien, en effet, d'un microcontrôleur 64 bits.
 

Specification K210
Tableau 1 : Spécification du K210.

Le composant possède aussi une SRAM interne, qui, avec 8 Mo (6 Mo de RAM utilisateur + 2 Mo de RAM IA), est plus vaste que la mémoire flash interne de nombreux autres microcontrôleurs. Comme le Maxim MAX78000, le K210 possède également un accélérateur de réseau neuronal. Son utilisation a également déjà été présentée dans Elektor [2].

Les cartes sont aussi très bien dotées concernant les autres équipements. L'une et l'autre possèdent une caméra et un écran LCD de 320 × 240 pixels. Les utilisateurs de la Maixduino doivent noter que le module WiFi est connecté par le biais de la même interface que la carte SD. Pendant les tests, au moins deux cartes SD sont passées dans un état fonctionnel indéfini. Nous n'avons pas encore de résultats pour la carte Maix Bit. En outre, toutes les cartes SD ne conviennent pas ici, et quelques essais sont nécessaires pour savoir laquelle convient au final pour le K210.

Chaîne d'outils

Pour le développement avec un Kendryte K210, nous utilisons Linux (Ubuntu 20.04). En guise de recommandation, l'installation dans une machine virtuelle a fait ses preuves ici aussi. Les snapshots (instantanés) ont permis de restaurer le système d'exploitation dans un état défini sans perte de temps, ou presque. L'utilisation de Windows est possible, mais n'est pas abordée dans cet article.

Un compilateur et un SDK sont nécessaires pour le Kendryte K210. Comme il s'agit d'un modèle RV64 (RISC-V 64 bits), il serait logique d'utiliser le compilateur GCC actuel pour cette architecture. Malheureusement, pour le K210, le compilateur RISC-V GCC et les bibliothèques C ont été modifiés par Kendryte il y a quelques années et maintenus dans un référentiel GitHub distinct. Cette combinaison modifiée de compilateur et de bibliothèque C comporte quelques personnalisations mineures qui n'ont pas été réintégrées dans la branche principale du compilateur GCC et de la bibliothèque C du RISC-V. Il n'est pas impossible d'appliquer ces ajustements au compilateur GCC actuel, mais l'article ne traite pas de ce sujet pour le moment. Nous allons pour commencer aborder le K210.

Compiler un compilateur

Les commandes suivantes sont saisies dans un terminal ou une fenêtre de terminal. Nous pouvons cloner le compilateur approprié [3] avec l'utilitaire git clone --recursive https://github.com/kendryte/kendryte-gnu-toolchain sur notre propre ordinateur. La chaîne d'outils n'est pas livrée prête à l'emploi, mais sous forme de code source. Nous devons donc le traduire afin qu'il génère le code nécessaire pour un processeur RV64.

Pour cela, nous avons besoin de quelques packages sous Linux. Il est possible de les installer avec la commande sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev.

Maintenant que tout est prêt, nous changeons avec cd kendryte-gnu-toolchain pour accéder au dossier créé par la commande git clone. Nous configurons ensuite le compilateur avec ./configure --prefix=/opt/kendryte-toolchain --with-cmodel=medany --with-arch=rv64imafc --with-abi=lp64f afin qu'il puisse générer du code adapté au K210. Si la commande s'exécute avec succès, nous pouvons compiler le compilateur avec sudo make -j8, le 8 représentant le nombre de cœurs du processeur de notre ordinateur. Le compilateur est maintenant compilé et installé dans /opt/kendryte-toolchain. Il est  prêt à être utilisé et le terminal peut être fermé.

Installation du SDK

Une fois le compilateur installé, venons-en maintenant au SDK pour le Kendryte K210. Cela nécessite à nouveau un terminal ou une fenêtre de terminal. Pour le SDK il y a deux choix possibles : l'un avec un FreeRTOS, qui n'est plus maintenu, et l'autre, une variante sans FreeRTOS. Pour les premières étapes, nous avons besoin d'un SDK sans FreeRTOS. Le clonage est effectué avec git clone https://github.com/kendryte/kendryte-standalone-sdk.git. Avec cd kendryte-standalone-sdk, nous pouvons maintenant basculer vers ce dossier.

Le SDK est basé sur CMake et est utilisé ici avec l'aide des lignes de commande. Comme premier test, nous essayons de compiler le projet hello world. Avec mkdir build && cd build, le répertoire build est créé et il est possible de le parcourir. Le code hello_world fourni avec le SDK peut maintenant être compilé avec cmake ... -DPROJ=hello_world -DTOOLCHAIN=/opt/kendryte-toolchain/bin. Il est ensuite possible de compiler le projet pour le K210 avec make.

Dans le dossier build, vous voyez alors deux fichiers - un fichier hello_world.bin et un fichier hello_world. Le fichier hello_world.bin est destiné à être téléchargé sur le K210 ; les fichiers hello_world peuvent être utilisés pour le débogage. Le débogage du K210 fera l'objet d'un article plus approfondi.

Outils de flashage et terminal série

Maintenant que le premier code source pour le K210 a été traduit avec succès, il est temps de l'installer sur la carte. Pour cela, kflash et l'interface kflash_gui (figure 3) sont nécessaires. Comme lors des étapes précédentes, on utilise un terminal ou une fenêtre de terminal pour installer les logiciels requis. Tout d'abord, Python3 peut être installé avec sudo apt install python3-pip.

kflash_gui ready to upload a binary
Figure 3 : kflash_gui prêt à transférer un binaire.

kflash est installé à l'aide de la commande sudo pip3 install kflash. Pour kflash_gui, il est possible de télécharger une version compilée depuis [4]. Après extraction, vous pouvez utiliser un terminal pour aller dans le dossier kflash_gui et ./kflash_gui afin de démarrer le programme.

Pour compiler le kflash_gui à partir du code source existant, la version présente du code source est récupérée avec git clone --recursive https://github.com/sipeed/kflash_gui.git. La commande sudo apt install python3 python3-pip permet de mettre en place l'environnement nécessaire à la compilation. Le kflash_gui ayant des dépendances supplémentaires, celles-ci sont téléchargées avec cd kflash_gui && sudo pip3 install -r requirements.txt. Le kflash_gui peut maintenant être lancé avec python3 kflash_gui.p

En plus de l'outil flash, il est très pratique d'avoir un terminal série à portée de main. CuteCom (figure 4), issu des sources du package Ubuntu, propose un terminal série graphique facile à utiliser. Pour l'installation, vous pouvez entrer sudo apt install cutecom sur un terminal ou dans une fenêtre de terminal. Une fois installé avec succès, CuteCom est disponible en tant qu'application.
 

CuteCom serial settings for microcontroller
Figure 4 : Paramétrage série de CuteCom pour le K210.

Une étape importante concerne maintenant les interfaces série sous Linux. Les utilisateurs normaux n'ont pas le droit d'utiliser les ports série. Pour obtenir ce droit, il faut devenir membre du groupe d'utilisateurs en entrant sudo adduser $(whoami) dialout sur un terminal ou dans une fenêtre de terminal. Cette modification ne sera effective qu'après redémarrage.

Le premier message « Hello World »

Une fois les préparatifs terminés, il est temps de tester l'exemple hello_world.bin. Tout d'abord, il est nécessaire de lancer le kflash_gui. La carte doit être ensuite être connectée à l'ordinateur avec le K210. Selon la carte, un ou deux ports série doivent apparaître (sous Linux /dev/ttyUSBx ou /dev/ttyACMx). Dans le kflash_gui, on sélectionne le port série correspondant pour le flashage, puis le fichier hello_world.bin. Les autres paramètres n'ont pas besoin d'être modifiés. Suite au téléchargement, hello_world.bin devrait maintenant être écrit sur la carte. Si le processus est terminé avec succès, le CuteCom peut être démarré.

Dans le CuteCom, l'interface série appropriée (/dev/ttyUSBx ou /dev/ttyACMx) est ouverte (115200 Baud, 8N1). Après réinitialisation du K210, apparaissent maintenant Core 0 Hello world et Core 1 Hello world. La première démo Hello world est ainsi terminée - nous savons maintenant que les deux cœurs de processeur peuvent exécuter du code et nous pouvons charger avec succès du code sur le K210.

Compiler Quake 1 pour le K210

Quake 1 [5] est un jeu de tir 3D datant du milieu des années 90 qui a marqué le genre par ses graphismes et son style de jeu. Le code source de Quake 1 a été publié sous licence GPL2 à la fin de l'année 1999 et a depuis servi de source à différents portages.

Le code source ne contient que le moteur lui-même, mais aucun autre fichier tel que les graphiques ou les niveaux. Ces données peuvent être extraites de la version shareware de Quake 1 [6], ou d'une version complète installée. Quake 1 peut toujours être acheté légalement sans DRM sur GOG.com [7].

Pour le K210, elect_gombe (Twitter @elect_gombe) a fait un portage il y a deux ans maintenant. Pendant cette période, des ajustements et des corrections de bogues ont été apportés au SDK pour le K210, ce qui a malheureusement conduit à ce que le code source ne fonctionne plus directement de cette manière. Voici donc une introduction, assortie des ajustements nécessaires. Avant cela, il convient de faire une sauvegarde du dossier kendryte-sdk-standalone (car les modifications qui suivent permettent maintenant de compiler Quake 1, mais ne sont pas nécessairement adaptées à d'autres codes source).

Pour traduire Quake 1, nous devons cloner le code source à partir du référentiel Git [8] d'elect_gombe. Pour cela nous ouvrons un terminal ou une fenêtre de terminal et nous naviguons avec cd ~/kendryte-standalone-sdk/src/ dans le dossier projet du SDK K210. Ici, nous clonons maintenant le code source avec git clone https://github.com/elect-gombe/quake-k210.git, ce qui permet de créer un dossier quake-k210..

Nous devons ensuite écraser certains fichiers du SDK à l'aide de ceux du dossier quake-k210. Dans le terminal encore ouvert, nous copions un fichier linker modifié dans le SDK avec cp quake-k210/additionalparts/kendryte.ld ../lds/kendryte.ld. Avec cp quake-k210/additionalparts/compile-flags.cmake ../cmake/compile-flags.cmake, les drapeaux de compilation modifiés (c'est-à-dire les paramètres servant à compiler le code source) sont copiés dans le SDK. Ceci est nécessaire parce que le code source de Quake 1 contient encore des parties qui ne peuvent pas être compilées avec les paramètres des compilateurs d'aujourd'hui. Dans le dossier ./quake-k210/additionalparts/, il y a un fichier crt.S-replace. Celui-ci nécessite quelques modifications pour que nous puissions l'utiliser avec le SDK actuel. Avec nano ~/kendryte-standalone-sdk/src/quake-k210/additionalparts/crt.S-replace, le fichier crt.S-replace est ouvert. Dans ce fichier se trouvent les premières lignes de code source, ici en assembleur, que le K210 exécute. De plus, certaines interruptions y sont traitées. Comme ce fichier a été modifié à un moment où les SDK Standalone et FreeRTOS étaient encore imbriqués, certaines entrées provoquent des erreurs lors de la compilation et de l'édition de liens. Il est nécessaire de supprimer les instructions en assembleur dans la section trap_entry de la ligne 166 à la ligne 160. Entre la ligne 133 et la ligne 140 il ne devrait y avoir que ce qui suit :

133 trap_entry:

134   addi sp, sp, -REGBYTES

135   sd t0, 0x0(sp)

136

137 .handle_other:

138   ld   t0, 0x0(sp)

139   addi sp, sp, REGBYTES

140   addi sp, sp, -64*REGBYTES

Lorsque le fichier a été ajusté en conséquence, il faut le sauvegarder avec CTRL+O. L'éditeur est ensuite fermé avec CTRL+X. Le fichier est copié à l'endroit approprié dans le SDK. Pour ce faire, entrez cp ~/kendryte-standalone-sdk/src/quake-k210/additionalparts/crt.S-replace ~/kendryte-standalone-sdk/lib/bsp/crt.S sur le terminal.

Dans le terminal toujours ouvert, nous passons maintenant au répertoire de compilation du SDK avec cd ~/kendryte-standalone-sdk/build/. Pour ne pas avoir d'éléments résiduels de projets précédents dans le répertoire build, nous le vidons à l'aide de la commande rm * -r. Avec cmake ... -DPROJ=quake-k210 -DTOOLCHAIN=/opt/kendryte-toolchain/bin, le projet est maintenant prêt. Si nous entrons make à ce stade, la compilation s'arrête avec une erreur. Celle-ci provient des nouveaux indicateurs du compilateur, et le mieux à faire serait de les régler pour que la compilation se déroule avec succès.

L'erreur présente provient de la bibliothèque NNCASE, utilisée pour les réseaux neuronaux, c'est-à-dire l'IA. Comme Quake 1 n'utilise pas cette bibliothèque et que nous avons besoin de la RAM d'IA pour Quake, nous pouvons exclure cette bibliothèque de la compilation. Nous allons donc modifier la commande ainsi : cd ~/kendryte-standalone-sdk/lib/. Concernant nano CMakeLists.txt, il faut maintenant faire des ajustements dans le fichier. La ligne 5 du fichier CMakeLists.txt indique ADD_SUBDIRECTORY(nncase) ; elle contient un signe de commentaire #, ce qui donne #ADD_SUBDIRECTORY(nncase). À la ligne 45, TARGET_LINK_LIBRARIES(kendryte PUBLIC nncase) doit également être mis en commentaire, de sorte que la ligne contienne #TARGET_LINK_LIBRARIES(kendryte PUBLIC nncase). CTRL+O permet d'enregistrer les ajustements et CTRL+X de quitter ensuite l'éditeur.

Il devrait alors être possible de compiler le code source et d'économiser un peu de mémoire. Malheureusement, ce n'est pas suffisant. Si nous compilons maintenant le code source, Quake 1 essaiera de démarrer et donnera rapidement un message « Error : OUT of MEMORY ! » sur l'interface série. Bien que 8 Mo de mémoire SRAM soient disponibles, c'est très peu pour Quake 1. Il faut donc adapter la répartition de la mémoire.

Pour les ajustements, nous ouvrons un terminal ou une fenêtre de terminal s'il n'y en a pas déjà un. Avec nano ~/kendryte-standalone-sdk/src/quake-k210/source/sys_ctr.c, on ouvre le fichier  contenant quake_main. Selon les lignes 378 et 379, 5,5 Mo de mémoire RAM sont alloués. Ici, nous devons réduire la valeur. Comme valeur minimale nous pouvons utiliser MINIMUM_MEMORY. Cette valeur est définie dans le code source de Quake et détermine la plus petite quantité de mémoire nécessaire à Quake pour démarrer. Pour Quake 1 et la version shareware, c'est suffisant. La ligne 378 contient donc parms.memsize = MINIMUM_MEMORY;. CTRL+O permet de sauvegarder le fichier et CTRL+X de fermer l'éditeur.

Il est maintenant possible de compiler Quake. Pour ce faire, nous passons au répertoire de compilation dans le terminal toujours ouvert avec la commande cd ~/kendryte-standalone-sdk/build/. Avec make clean, les éléments résiduels de la compilation en échec sont nettoyés et le make suivant permettra de lancer une nouvelle compilation. Nous obtenons un fichier quake-k210.bin dans le répertoire build qui peut maintenant être écrit sur le K210. À cet effet, nous utilisons le klash_gui. Mais ce n'est pas comme cela que le jeu va démarrer. Vous devez encore préparer une carte SD en copiant le dossier id1 depuis Quake 1. Insérez la carte SD dans le K210 hors tension ; la fente de la carte SD ne permet pas une connexion à chaud. Une fois tous les éléments copiés, flashés et assemblés avec succès, Quake 1 devrait démarrer après insertion et les démos fonctionner.

Connecter une manette de jeu moderne à un microcontrôleur

Pour nombre d'applications ou de jeux fonctionnant sur le microcontrôleur, il est utile de connecter un périphérique d'entrée. À titre de variante, il est possible de raccorder une souris et un clavier via l'interface PS/2. Il en existe une autre, tout aussi adaptée aux jeux et aux expériences : une manette de jeu. Si vous envisagez quelque chose de simple comme la manette de la NES (Nintendo Entertainment System) (figure 5), vous profiterez de quelques boutons supplémentaires, une ressource toujours très appréciée.
 

NES gamepad
Figure 5 : Manette de jeu de la NES.

Et la manette de jeu de la NES ne se distingue par vraiment par son ergonomie. Une possibilité serait la manette Nintendo WII Classic (figure 6), commandée en I²C, mais au prix d'une carte d'adaptation appropriée.
 

Wii classic controller
Figure 6 : Contrôleur Wii classique.

Autre possibilité, spécialement conçue pour la carte d'évaluation, une manette de jeu compatible avec la Playstation 2 (figure 7). Celle-ci est fabriquée par la société Joy-IT et livrée immédiatement avec les câbles de connexion appropriés pour la relier à un microcontrôleur.
 

Joy-IT Wireless Gamepad.
Figure 7 : Manette sans fil Joy-IT.

La manette de jeu, dont la lecture est quelque peu cachée, utilise une interface SPI. La désignation de la fiche technique peut être traduite avec le tableau 2 en broches correspondantes d'une interface SPI. Si vous utilisez un contrôleur compatible Arduino, vous pouvez utiliser la bibliothèque Arduino-PS2X [9]. Cela devrait permettre à quiconque de connecter une manette de jeu pour ses propres projets également. Il est ainsi possible de commander un bras de robot, une voiture ou une interface graphique à l'aide d'une manette de jeu.
 

PS2 Gamepad pins to SPI pins
Tableau 2 : Correspondance des broches des manettes PS2 - SPI.

Câblage et test de Quake 1 avec manette

La manette est connectée à la carte K210 (Maixduino Sipeed ou MAix Bit). Une fois que tout est prêt et que la carte SD est insérée, il ne manque presque rien pour se lancer dans une partie de Quake 1. Avec le modèle Maixduino, quelques cartes SD ont été mises, au cours des tests, dans un état indéfini, entre fonctionnel et défectueux. Comme l'ESP32, qui peut servir d'interface Wi-Fi sur cette carte, se trouve sur le même bus SPI que la carte SD, on peut supposer que cela interfère involontairement avec la communication. Le résultat apparaît sur la figure 8.
 

Quake on K210 microcontroller
Figure 8 : Quake sur K210 avec une manette de jeu.
 
Quake 1 Demo running on K210
Petite démonstration de Quake 1 sur le K210.

Quake 1 sur microcontrôleur

Même si Quake 1 n'est pas nécessairement du goût de tous, ce jeu est une démonstration de la puissance du microcontrôleur. Le SDK et le compilateur étant mis en place, Quake 1 et le premier exemple Hello World peuvent maintenant être compilés. Vous disposez ainsi d'un environnement de développement pour d'autres expériences avec le K210 et d'un code source à partir duquel vous pouvez voir comment contrôler la périphérie du microcontrôleur.

Suite au premier contact avec un microcontrôleur basé sur la spécification RISC-V, il y avait encore peu d'informations sur l'architecture et les désignations des processeurs. Un RV64IMAFC (qui désigne les cœurs de processeur du K210) sonne au premier abord comme un bon moyen d'acquérir des points au Scrabble, et l'on n'aurait pas trouvé mieux pour gagner la partie. Pour décoder ces désignations - et en savoir plus sur les avantages du RISC-V - vous pouvez consulter l'article de Stuart Cording dans Elektor [10]. En outre, l'article « Développement de systèmes embarqués avec des processeurs RISC-V (en anglais) » d'Allan He (publié dans Elektor Industry 01/2021) vous donnera une bonne vue d'ensemble de l'écosystème RISC-V.


Des questions ? Des commentaires ?

Avez-vous des questions ou des commentaires techniques à propos de cet article ? N'hésitez pas à envoyer un courrier électronique à l'auteur à l'adresse mathias.claussen@elektor.com ou contactez Elektor à l'adresse editor@elektor.com.

Traduction : Pascal Godart