De RISC-V instructieset heeft zijn vaste plaats ingenomen in de wereld van embedded systemen en microcontrollers (MCU). De handelsoorlogen die momenteel worden gevoerd laten zien hoe belangrijk een open instructieset kan zijn en welke voordelen het kan opleveren. Commerciële leveranciers van instructiesets, zoals ARM, hebben de licentieverlening van hun eigen instructie-architecturen aangepast aan de gratis RISC-V instructieset en het klantvriendelijker gemaakt. Zoals bekend stimuleert concurrentie de markt. Daarom is dit artikel bedoeld om je te helpen je eerste stappen te zetten met op RISC-V gebaseerde MCU's.

Wat gaan we maken?

De Canaan Kendryte K210 is een goedkope microcontroller met een RISC-V core. Het is te vinden op het Sipeed Maixduino of het Sipeed Maix-bit board (beide verkrijgbaar in de Elektor-shop), maar ook op andere boards en kan worden gekocht als kit met camera en LCD voor ongeveer €30. We zullen op deze microcontroller laten zien hoe een toolchain en de SDK voor het board onder Linux kunnen worden geïnstalleerd. Naast de klassieke 'hallo wereld' gaan we Quake 1, een 3D-schietspel uit het midden van de jaren negentig, gebruiken en laten zien hoe dit vertaald kan worden voor de K210. Als je Quake 1 gewoon wilt uitproberen en de broncode niet zelf wilt compileren, kun je een kant-en-klaar binair bestand downloaden van de GitHub-opslagruimte van elect-gombe [1] en flash het direct.
 
Speels beginnen met RISC-V: Sipeed Maixduino
Figuur 1: Sipeed Maixduino met display en camera.

RISC-V Hardware

Dit artikel gebruikt de Sipeed Maixduino (Figuur 1) en de Sipeed Maix Bit (Figuur 2), met een Canaan Kendryte K210 als microcontroller. Dit is een op RISC-V gebaseerde microcontroller die, volgens RISC-V-terminologie, is uitgerust met twee harten (processor cores).
 
Speels beginnen met RISC-V: Sipeed MAix Bit
Figuur 2: Sipeed MAix Bit met aangesloten display.

De exacte technische details zijn te vinden in Tabel 1. In de tabel staat de aanduiding RV64IMAFDC voor de processorkern. Iets dat opvalt is de aanduiding RV64 aan het begin - en ja, dit is een 64-bits microcontroller. 

Speels beginnen met RISC-V: Specification K210
Tabel 1: Specificaties K210

Er is ook de interne SRAM, die met 8 MB (6 MB gebruikers-RAM + 2 MB AI RAM) groter is dan de interne flash van veel andere MCU's. Net als bij de Maxim MAX78000 heeft ook de K210 een neurale netwerkversneller. Het gebruik ervan is ook al gepresenteerd in Elektor [2].

Ook op de andere zaken beknibbelden de boards niet. Bij beide boards wordt een camera en een LCD-scherm met 320 × 240 pixels meegeleverd. Degenen die de Maixduino gebruiken, moeten er rekening mee houden dat de WiFi-module via dezelfde interface is aangesloten als de SD-kaart.

Tijdens de tests gingen ten minste twee SD-kaarten in een ongedefinieerde status. Er zijn nog geen bevindingen voor de Maix Bit. Ook is niet elke SD-kaart hier geschikt, en het vereist een beetje vallen en opstaan ​​​​welke kaart uiteindelijk met de K210 wordt gebruikt.

Toolchain

Voor de ontwikkeling voor een Kendryte K210 gebruiken we Linux (Ubuntu 20.04). Als aanbeveling heeft de installatie in een virtuele machine zich ook hier bewezen. Snapshots maakten het mogelijk om het besturingssysteem in een gedefinieerde staat te herstellen zonder veel tijd te verliezen. Het gebruik van Windows is mogelijk, maar wordt in dit artikel niet behandeld.

Voor de Kendyte K210 is eenmalig een compiler en een SDK nodig. Aangezien de K210 een RV64 is, een 64-bit RISC-V, zou het logisch zijn om de huidige GCC te gebruiken voor de architectuur. Helaas zijn voor de K210 de RISC-V GCC-compiler en C-bibliotheken een paar jaar geleden aangepast door Kendryte en onderhouden in een aparte GitHub-opslagruimte. Deze gewijzigde combinatie van compiler en C-bibliotheek heeft een paar kleine aanpassingen die niet zijn teruggevoerd naar de hoofdtak van de RISC-V GCC en C-bibliotheek. Het maken van deze aanpassingen aan de huidige GCC is niet onmogelijk, maar maakt op dit moment geen deel uit van dit artikel. We zijn gefocust om te beginnen met de K210.

Een compiler samenstellen

De volgende opdrachten worden ingevoerd in een terminal of terminalvenster. We kunnen de juiste compiler klonen [3] met git clone --recursive https://github.com/kendryte/kendryte-gnu-toolchain op onze eigen computer. De toolchain wordt niet kant-en-klaar geleverd, maar als broncode, die we nu moeten vertalen zodat deze code genereert voor een RV64-processor.

Hiervoor hebben we een aantal pakketten onder Linux nodig. Deze kunnen worden geïnstalleerd met 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.

Nu alles klaar is, kunnen we met cd kendryte-gnu-toolchain veranderen naar de map die is gemaakt door de git-kloon. Hier configureren we de compiler met ./configure --prefix=/opt/kendryte-toolchain --with-cmodel=medany --with-arch=rv64imafc --with-abi=lp64f zodat deze code kan genereren die geschikt is voor de K210. Als de opdracht met succes wordt uitgevoerd, we kunnen de compiler compileren met sudo make -j8 waarbij de 8 staat voor het aantal processor cores van de eigen computer. De compiler is nu gecompileerd en geïnstalleerd in /opt/kendryte-toolchain. De compiler is nu klaar en klaar voor gebruik. De terminal kan nu worden gesloten.

SDK-installatie

Zodra de compiler is geïnstalleerd, komt nu de SDK voor de Kendryte K210. Hiervoor is weer een terminal of terminalvenster nodig. Voor de SDK zijn er twee keuzes, een met een FreeRTOS, die niet meer wordt onderhouden, en een variant zonder FreeRTOS. Voor de eerste stappen hebben we een SDK nodig zonder FreeRTOS. Dit wordt gekloond met git clone https://github.com/kendryte/kendryte-standalone-sdk.git. Met cd kendryte-standalone-sdk kunnen we nu naar die map overschakelen.

De SDK is gebaseerd op CMake en wordt hier bediend met behulp van de opdrachtregels. Als eerste test proberen we het hello world-project samen te stellen. Met mkdir build && cd build wordt de directory-build gemaakt en wordt er naar genavigeerd. De hello_world die bij de SDK wordt geleverd, kan nu worden gecompileerd met cmake ... -DPROJ=hello_world -DTOOLCHAIN=/opt/kendryte-toolchain/bin. Daarna kan het project worden gecompileerd voor de K210 met make.

In de build-map zie je dan twee bestanden - een keer een hello_world.bin en een keer een hello_world bestand. De hello_world.bin is bedoeld om te worden geüpload naar de K210; de hello_world bestanden kunnen worden gebruikt voor debuggen. Debuggen van de K210 is een onderwerp voor een meer diepgaand artikel.

Flash-tools en seriële terminal

Nu de eerste broncode voor de K210 met succes is vertaald, is het tijd om deze op het board te zetten. Hiervoor zijn kflash en de kflash_gui (Figuur 3) nodig. Net als in de vorige stappen wordt een terminal of terminalvenster gebruikt om de benodigde software te installeren. Ten eerste is Python3 nodig en kan worden geïnstalleerd met sudo apt install python3-pip.
Speels beginnen met RISC-V: kflash_gui ready to upload a binary
Figure 3: kflash_gui ready to upload a binary.

Ten eerste is kflash nu geïnstalleerd met sudo pip3 install kflash. Voor kflash_gui kan een gecompileerde versie worden gedownload van [4]. Na het uitpakken kan een terminal worden gebruikt om naar de map kflash_gui te gaan en ./kflash_gui om het programma te starten.

Om de kflash_gui uit de huidige broncode te compileren, wordt de huidige versie van de broncode opgehaald met git clone --recursive https:/ /github.com/sipeed/kflash_gui.git. Met sudo apt install python3 python3-pip wordt de noodzakelijke omgeving voor compilatie opgezet. Omdat de kflash_gui extra afhankelijkheden heeft, worden deze gedownload met cd kflash_gui && sudo pip3 install -r requirements.txt. De kflash_gui kan nu gestart worden met python3 kflash_gui.p

Naast de flash tool is het erg handig om een ​​seriële terminal bij de hand te hebben. CuteCom (Figuur 4) uit de Ubuntu-package biedt een gebruikersvriendelijke grafische seriële terminal. Voor installatie kan sudo apt install cutecom worden ingevoerd in een terminal of een terminalvenster. Na een succesvolle installatie is CuteCom beschikbaar als applicatie.

First, kflash is now installed with sudo pip3 install kflash. For kflash_gui, a compiled version can be downloaded from [4]. After unpacking, a terminal can be used to change to the kflash_gui folder and ./kflash_gui to start the program.

To compile the kflash_gui from the current source code the current version of the source code is fetched with git clone --recursive https://github.com/sipeed/kflash_gui.git. With sudo apt install python3 python3-pip the necessary environment for compilation is set up. Since the kflash_gui has additional dependencies, these are downloaded with cd kflash_gui && sudo pip3 install -r requirements.txt. The kflash_gui can now be started with python3 kflash_gui.p

Besides the flash tool, it is very handy to have a serial terminal at hand. CuteCom (Figure 4) from the Ubuntu package sources offers an easy-to-use graphical serial terminal. For installation, sudo apt install cutecom can be entered in a terminal or a terminal window. After successful installation CuteCom is available as an application.

Speels beginnen met RISC-V: CuteCom serial settings for microcontroller
Figure 4: CuteCom serial settings for the K210.

Een belangrijke stap betreft nu de seriële interfaces onder Linux. Normale gebruikers hebben niet het recht om seriële poorten te gebruiken. Om dit recht te verkrijgen, moet men lid worden van de gebruikersgroep door sudo adduser $(whoami) dialout in een terminal of terminalvenster in te voeren. Deze wijziging wordt pas van kracht na een herstart.

De eerste Hello World

Nadat de voorbereidingen zijn gedaan, is het tijd om de hello_world.bin te testen. Eerst moet de kflash_gui worden gestart. Dan moet het board met de K210 op de computer worden aangesloten. Afhankelijk van het board zouden een of twee seriële poorten moeten verschijnen (onder Linux /dev/ttyUSBx of /dev/ttyACMx). In de kflash_gui wordt de corresponderende seriële poort geselecteerd om te flashen en vervolgens de hello_world.bin. Alle andere instellingen hoeven niet te worden gewijzigd. Met de download moet de hello_world.bin nu naar het board worden geschreven. Als het proces met succes is voltooid, kan CuteCom worden gestart.

In CuteCom wordt de geschikte seriële interface (/dev/ttyUSBx of /dev/ttyACMx) geopend (115200 Baud, 8N1). Na een reset van de K210 verschijnt nu Core 0 Hello world en Core 1 Hello world. Hiermee is de eerste Hello world-demo klaar - we weten nu dat beide processorkernen code kunnen uitvoeren en we kunnen met succes code laden op de K210.

Compileer Quake 1 voor de K210

Quake 1 [5] is een 3D-schietspel uit het midden van de jaren 90 en heeft het genre gevormd met zijn graphics en gamedesign. De broncode voor Quake 1 werd eind 1999 vrijgegeven onder de GPL2-licentie en heeft sindsdien gediend als de bron van verschillende ports.

De broncode bevat alleen de engine zelf, maar geen andere bestanden zoals afbeeldingen of niveaus. Deze gegevens kunnen worden overgenomen van de Quake 1 shareware-versie [6], of van een geïnstalleerde volledige versie. Quake 1 kan nog steeds legaal DRM-vrij worden gekocht op GOG.com [7].

Voor de K210 deed elect_gombe (Twitter @elect_gombe) nu twee jaar geleden een port. Gedurende deze tijd zijn er aanpassingen en bugfixes gemaakt aan de SDK voor de K210, wat er helaas toe heeft geleid dat de broncode niet meer direct op deze manier draait. Daarom volgt hier een introductie en de nodige aanpassingen. Voorafgaand hieraan moet een back-up worden gemaakt van de map kendryte-sdk-standalone (aangezien de wijzigingen die volgen nu toelaten om Quake 1 te compileren, maar niet noodzakelijkerwijs geschikt zijn voor andere broncode).

Om Quake 1 te vertalen, moeten we de broncode uit de Git-opslagruimte [8] van elect_gombe klonen. Hiervoor openen we een terminal of terminalvenster en navigeren we met cd ~/kendryte-standalone-sdk/src/ naar de projectmap van de K210 SDK. Hier klonen we nu de broncode met git clone https://github.com/elect-gombe/quake-k210.git, zodat er een quake-k210 map wordt aangemaakt.

Nu moeten we enkele bestanden van de SDK daarmee overschrijven uit de map quake-k210. In de nog steeds open terminal kopiëren we een aangepaste file link naar de SDK met cp quake-k210/additionalparts/kendryte.ld ../lds/kendryte.ld. Met cp quake-k210/additionalparts/compile-flags.cmake ../cmake/compile-flags.cmake worden gewijzigde compiler flags (dwz parameters voor het compileren van de broncode) gekopieerd naar de SDK. Dit is nodig omdat de broncode van Quake 1 nog steeds codedelen bevat die niet gecompileerd kunnen worden met de moderne instellingen van de hedendaagse compilers. In de map ./quake-k210/additionalparts/ staat een crt.S-replace-bestand. Dit heeft een paar aanpassingen nodig, zodat we het kunnen gebruiken met de huidige SDK. Met nano ~/kendryte-standalone-sdk/src/quake-k210/additionalparts/crt.S-replace wordt de crt.S-replace geopend. In dit bestand staan ​​de eerste paar regels broncode, hier assembler, die de K210 uitvoert. Bovendien worden hier enkele interrupts afgehandeld. Aangezien dit bestand is gewijzigd in een tijd dat Standalone SDK en FreeRTOS SDK nog met elkaar verweven waren, zijn er hier een paar vermeldingen die fouten veroorzaken bij het compileren en koppelen. Het is noodzakelijk om de assembler instructies in de trap_entry section van regel 166 naar regel 160 te verwijderen. Tussen regel 133 en regel 140 mag alleen het volgende staan:

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

Wanneer het bestand hierop is aangepast, moet dit worden opgeslagen met CTRL+O. De editor wordt dan afgesloten met CTRL+X. Nu wordt het bestand gekopieerd naar de juiste plaats in de SDK. Voer hiervoor in cp ~/kendryte-standalone-sdk/src/quake-k210/additionalparts/crt.S-replace ~/kendryte-standalone-sdk/lib/bsp/crt.S in de terminal.

In de open terminal, gaan we nu naar de build-directory van de SDK met cd ~/kendryte-standalone-sdk/build/. Om geen resten van eerdere projecten in de build directory te hebben, maken we deze leeg met rm * -r. Met cmake ... -DPROJ=quake-k210 -DTOOLCHAIN=/opt/kendryte-toolchain/bin is het project nu voorbereid. Als we nu make zouden typen, wordt de compilatie afgebroken met een fout. Dit wordt gegenereerd door de nieuwe compiler flags, en het meest voor de hand liggende zou zijn om de vlaggen aan te passen zodat de compilatie succesvol verloopt.

De huidige fout komt van de NNCASE-bibliotheek, die wordt gebruikt voor neurale netwerken, dwz AI. Aangezien Quake 1 deze bibliotheek niet gebruikt en we AI RAM voor Quake nodig hebben, kunnen we deze bibliotheek uitsluiten van de compilatie. Hiervoor veranderen we met cd ~/kendryte-standalone-sdk/lib/. Met nano CMakeLists.txt moeten nu aanpassingen aan het bestand worden gedaan. De CMakeLists.txt bevat in regel 5 ADD_SUBDIRECTORY(nncase) dit wordt becommentarieerd door een # en resulteert in #ADD_SUBDIRECTORY(nncase). In regel 45 moet TARGET_LINK_LIBRARIES(kendryte PUBLIC nncase) ook worden uitgeschakeld, zodat er #TARGET_LINK_LIBRARIES(kendryte PUBLIC nncase) in regel 45 staat. CTRL+O slaat de aanpassingen op en vervolgens verlaat CTRL+X de editor.

Dit zou nu de broncode compileren en wat geheugen besparen. Helaas is dit niet voldoende. Als we nu de broncode zouden compileren, zou Quake 1 nu proberen te starten en na een korte tijd zou een "Error: OUT of MEMORY!" op de seriële interface geven. Hoewel 8 MB SRAM beschikbaar is, is dit erg schaars voor Quake 1. Daarom moet de geheugendistributie worden aangepast.

Voor de aanpassing openen we een terminal of terminalvenster als dat nog niet is gebeurd. Met nano ~/kendryte-standalone-sdk/src/quake-k210/source/sys_ctr.c wordt het bestand met de quake_main geopend. In lijn 378 en lijn 379 is 5,5 MB RAM toegewezen. Hier moeten we de waarde verlagen. Als minimumwaarde kunnen we hier MINIMUM_MEMORY gebruiken. Deze waarde is gedefinieerd in de Quake-broncode en bepaalt de kleinste hoeveelheid geheugen waarmee Quake begint. Voor Quake 1 en de shareware-versie is dit voldoende. Regel 378 is dan parms.memsize = MINIMUM_MEMORY;. Met CTRL+O kan het bestand worden opgeslagen en met CTRL+X wordt de editor gesloten.

Nu kan Quake worden gecompileerd. Om dit te doen, gaan we naar de build-directory in de nog open terminal met cd ~/kendryte-standalone-sdk/build/. Met make clean worden de restanten van de mislukte compilatie één keer opgeruimd en een volgende make start een nieuwe compilatie. Het resultaat is een quake-k210.bin in de build directory die nu naar de K210 kan worden geschreven. Hiervoor wordt de klash_gui gebruikt. Maar zo start het spel niet. Je moet nog steeds een SD-kaart voorbereiden door de id1-map van Quake 1 te kopiëren. Steek de SD-kaart in de K210 in een spanningsloze toestand; het SD-card slot is niet hot-pluggable. Als alles met succes is gekopieerd, geflashed en geassembleerd, zou Quake 1 na het invoeren moeten starten en de demo's zouden moeten werken.

Een moderne gamepad aansluiten op een microcontroller

Voor veel toepassingen of games op de microcontroller is het handig om een ​​invoercontroller aan te sluiten. Een muis en toetsenboard via de PS/2-interface zijn één variant. Een andere, net zo geschikt voor games en experimenten, is een gamepad. Als je aan iets simpels denkt, zoals de gamepad van het Nintendo Entertainment System (NES) (Figuur 5), kunnen een paar extra knoppen nooit kwaad.

Speels beginnen met RISC-V: NES gamepad
Figuur 5: NES gamepad.

En de NES-gamepad is echt geen uitblinker op het gebied van ergonomie. Een optie is een Nintendo WII Classic Gamepad (Figuur 6), die kan worden bestuurd via I²C. Hiervoor is nog wel een geschikt adapterboard nodig.

Wii classic controller
Figuur 6: Wii classic controller.

Een andere optie, die speciaal is ontworpen voor gebruik met het evaluatieboard, maakt gebruik van een Playstation 2-compatibele gamepad (Figuur 7). Deze is vervaardigd door het bedrijf Joy-IT en wordt direct geleverd met de juiste aansluitkabels om hem aan te sluiten op een microcontroller.

Joy-IT Wireless Gamepad.
Figuur 7: Draadloze Joy-IT gamepad.

De gamepad, hoewel enigszins verborgen om te lezen, gebruikt een SPI-interface. De aanduiding uit de datasheet kan met Tabel 2 worden vertaald in de bijbehorende pinnen van een SPI-interface. Als je een Arduino-compatibele controller gebruikt, kunt je de Arduino-PS2X-bibliotheek [9] gebruiken. Hierdoor zou iedereen ook een gamepad voor zijn eigen projecten moeten kunnen aansluiten. Zo kan een robotarm, een auto of een GUI bestuurd worden met een gamepad.

PS2 Gamepad pins to SPI pins
Table 2: PS2 Gamepad pins to SPI pins.

Bedrading en proefdraaien met Quake 1 met Gamepad

De Gamepad is verbonden met het K210-board (dwz de Sipeed Maixduino of MAix Bit). Als alles klaar is en de SD-kaart is geplaatst, staat er niet veel meer in de weg van een spelletje Quake 1. Als een Maixduino wordt gebruikt, heeft deze tot nu toe een paar SD-kaarten in een ongedefinieerde toestand gebracht tussen functioneel en defect tijdens de testen. Aangezien de ESP32, die op dit board als wifi-interface kan fungeren, op dezelfde SPI-bus zit als de SD-kaart, kan worden aangenomen dat deze onbedoeld de communicatie verstoort. Het resultaat is te zien in figuur 8.

Quake on K210 microcontroller
Figuur 8: Quake draaien op K210 met gamepad.
 
Quake 1 Demo running on K210
Kleine demonstratie van Quake 1 op de K210.

Quake 1 op een RISC-V microcontroller

Hoewel Quake 1 niet naar ieders smaak is wat betreft games, demonstreert deze game de kracht van de microcontroller. Met de SDK en compiler ingesteld, kunnen Quake 1 en de eerste Hello World nu worden gecompileerd. Dit biedt een ontwikkelomgeving voor verdere experimenten met de K210 en broncode waaruit je kunt zien hoe de periferie van de K210 wordt aangestuurd.

Na het eerste contact met een op RISC-V gebaseerde microcontroller werd er nog weinig vermeld over RISC-V, de architectuur en de benamingen. Een RV64IMAFC (aanduiding van de processorkernen in de K210) klinkt op het eerste moment als iets dat veel punten oplevert in Scrabble, anders had je niets beters kunnen bedenken om het spel te winnen. Om die aanduidingen te ontcijferen — en meer te weten te komen over de voordelen van RISC-V — kunt je het Elektor-artikel raadplegen [10] van Stuart Cording. Daarnaast geeft het artikel “Geïntegreerde systeemontwikkeling met RISC-V-processors” van Allan He (gepubliceerd in Elektor Industry 01/2021) je een goed overzicht van het RISC-V ecosysteem.

Vragen of opmerkingen?

Heb je technische vragen of opmerkingen over dit artikel? E-mail de auteur op mathias.claussen@elektor.com of neem contact op met Elektor via: redacteur@elektor.com.

Vertaling: Hans Adams