Xilinx stellt mit PetaLinux ein komplettes, auf Yocto basierendes, Embedded Linux Entwicklungspaket zur Verfügung, welches es dem Nutzer erlaubt, mit vergleichsweise wenig Aufwand ein eigenes Linux-Betriebssystem mit entsprechenden Hardware-Treibern für das ZYNQ SoC zu erstellen. In diesem Artikel möchte ich zeigen, wie ein minimales Linux-Betriebssystem mit XADC- und GPIO-Support für das ZYBO gebaut werden kann.
Die Erstellung des Linux-Systems:
Für dieses Tutorial wird ein minimales Hardwaredesign, bestehend aus zwei AXI-GPIO IP-Blöcken, dem XADC und dem Processing System, genutzt.
Aus diesem Design wird ein Bitstream erzeugt und eine XSA-Datei erzeugt. Als nächstes wird ein neues PetaLinux-Projekt angelegt und die verwendete Hardware eingelesen:
$ source <PetaLinux-Pfad>/settings.sh $ petalinux-create --type project --template zynq --name MinimalLinux $ petalinux-config --get-hw-description ../hardware/System_wrapper.xsa
Über die sich öffnende Systemkonfiguration können bei Bedarf verschiedene Einstellungen an dem Projekt vorgenommen werden (wie z. B. der Hostname oder das root-Passwort).
Für dieses Tutorial werden die Standardeinstellungen verwendet. Damit Linux den Zugriff über die XADC-Kanäle 6, 7, 14 und 15 erlaubt muss der Device-Tree des Systems erweitert werden. Dazu findet sich in dem Verzeichnis project-spec/meta-user/recipes-bsp/device-tree/files
eine fertige Vorlage namens system-user.dtsi
, die für benutzerspezifische Anpassungen an dem Device-Tree genutzt werden kann. Diese Datei wird folgendermaßen erweitert:
/include/ "system-conf.dtsi" / { }; &XADC{ xlnx,channels { #address-cells = <0x1>; #size-cells = <0x0>; channelJA1@7 { reg = <7>; xlnx,bipolar; }; channelJA2@8 { reg = <8>; xlnx,bipolar; }; channelJA3@15 { reg = <15>; xlnx,bipolar; }; channelJA4@16 { reg = <16>; xlnx,bipolar; }; }; };
Als nächstes wird der Build-Prozess gestartet:
$ petalinux-build INFO: Sourcing build tools [INFO] Building project [INFO] Sourcing build environment [INFO] Generating workspace directory INFO: bitbake petalinux-image-minimal Loading cache: 100% |#########################################################################################################################################################################################################| Time: 0:00:01 Loaded 4264 entries from dependency cache.
Dieser Vorgang dauert i. d. R. ein paar Minuten und sobald er abgeschlossen ist, werden die benötigten Dateien zum Booten des Linux-Systems erzeugt:
$ petalinux-package --force --boot --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/system.bit --u-boot INFO: Sourcing build tools INFO: File in BOOT BIN: "/var/development/Git/ZYBO/linux/MinimalLinux/petalinux/images/linux/zynq_fsbl.elf" INFO: File in BOOT BIN: "/var/development/Git/ZYBO/linux/MinimalLinux/petalinux/images/linux/system.bit" INFO: File in BOOT BIN: "/var/development/Git/ZYBO/linux/MinimalLinux/petalinux/images/linux/u-boot.elf" INFO: File in BOOT BIN: "/var/development/Git/ZYBO/linux/MinimalLinux/petalinux/images/linux/system.dtb" INFO: Generating Zynq binary package BOOT.BIN... ****** Xilinx Bootgen v2020.2 **** Build date : Nov 15 2020-06:11:24 ** Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. [INFO] : Bootimage generated successfully INFO: Binary is ready.
Aus dem Verzeichnis images/linux
werden nun die folgenden Dateien auf eine bootfähige FAT32 formatierte Partition einer SD-Karte kopiert:
- BOOT.bin
- boot.scr
- image.ub
Die SD-Karte wird dann in das ZYBO eingelegt und das Board eingeschaltet, worauf das Linux bootet.
Hinweis:
In der Standardkonfiguration lautet das Passwort root.
Auslesen des XADC:
Über das IIO-Subssystem des Linux-Kernels kann auf die einzelnen Kanäle des XADC zugegriffen werden. Die entsprechenden Einträge sind unter /sys/bus/iio/devices/iio:device0
(Standardkanäle), bzw. /sys/bus/iio/devices/iio:device1
(zusätzlichen Kanäle) zu finden. Diese können z. B. mit einem Shell-Skript ausgelesen werden:
#!/bin/bash while true do Raw=$(cat /sys/bus/iio/devices/iio:device1/in_voltage10_vaux14_raw) echo "Raw: ${Raw}" sleep 1 done
$ ./ReadADC.sh Raw: 323 Raw: 514 Raw: 899 Raw: 1194 Raw: 1424
Verwendung der GPIO:
Die GPIO (sowohl die AXI-GPIO, als auch die EMIO oder MIO) sind unter /sys/class/gpio
zu finden. Dieses Verzeichnis beinhaltet bei diesem System drei verschiedene Verzeichnisse, wobei jeder Eintrag für einen GPIO-Block steht:
- gpiochip1012
- gpiochip1016
- gpiochip1020
Jedes Verzeichnis beinhaltet eine Datei namens label
, welche den Namen des Knotens im Device-Tree enthält und über die Datei base
lässt sich der Basispin des GPIO-Blocks, in diesem Beispiel für den LED-Block, ermitteln:
$ cd /sys/class/gpio $ ls export gpiochip1012 gpiochip1016 gpiochip1020 gpiochip894 unexport $ cd gpiochip1012/ $ cat label /amba_pl/gpio@41210000 $ cat base 1012
Der Basispin wird als Offset für die Berechnung des zu schaltenden Pins benötigt. Soll z. B. der GPIO 0 des ausgewählten GPIO-Blocks geschaltet, so lautet die I/O-Nummer 1012. Die einzelnen I/O-Nummern müssen in die Datei export
geschrieben werden um den I/O anzulegen und bedienen zu können. Anschließend können Die I/O über die Dateien direction
und value
gesteuert werden.
Achtung:
Auch wenn die GPIO-Blöcke im Vivado als Output only konfiguriert wurden müssen die I/O im Linux als Ausgang konfiguriert werden!
$ echo 1012 > /sys/class/gpio/export $ echo out > /sys/class/gpio/gpio1012/direction $ echo 1 > /sys/class/gpio/gpio1012/value
Über das nachfolgende Skript werden die I/O für die LEDs konfiguriert und in einer Endlosschleife nacheinander ein- und wieder ausgeschaltet:
#!/bin/bash for i in 0 1 2 3 do Base=$((1012 + i)) echo ${Base} > /sys/class/gpio/export echo out > /sys/class/gpio/gpio${Base}/direction done while true do for i in 0 1 2 3 do Base=$((1012 + i)) echo 1 > /sys/class/gpio/gpio${Base}/value sleep 1 done for i in 0 1 2 3 do Base=$((1012 + i)) echo 0 > /sys/class/gpio/gpio${Base}/value sleep 1 done sleep 10 done
Die Taster und Schalter werden auf ähnliche Weise ausgelesen, wobei bei diesen GPIO-Blöcken direction
auf in
gesetzt werden muss.
#!/bin/bash for i in 0 1 2 3 do SwitchBase=$((1016 + i)) ButtonBase=$((1020 + i)) echo ${SwitchBase} > /sys/class/gpio/export echo in > /sys/class/gpio/gpio${SwitchBase}/direction echo ${ButtonBase} > /sys/class/gpio/export echo in > /sys/class/gpio/gpio${ButtonBase}/direction done while true do for i in 0 1 2 3 do SwitchBase=$((1016 + i)) ButtonBase=$((1020 + i)) Value=$(cat /sys/class/gpio/gpio${SwitchBase}/value) echo "Switch ${i}: ${Value}" Value=$(cat /sys/class/gpio/gpio${ButtonBase}/value) echo "Button ${i}: ${Value}" done echo "-------------" sleep 1 done
Aufsetzen der Toolchain:
Als letztes möchte ich noch zeigen, wie die Vitis Entwicklungsumgebung genutzt werden kann um eine eigene Anwendung für das erzeugte Linux-System zu programmieren und zu kompilieren. Dazu wird ein entsprechendes SDK benötigt, welches das rootfs und die benötigten Bibliotheken des Zielsystems beinhaltet. Dieses SDK kann über PetaLinux erstellt werden:
$ petalinux-build --sdk INFO: Sourcing build tools [INFO] Building project [INFO] Sourcing build environment [INFO] Generating workspace directory INFO: bitbake petalinux-image-minimal -c do_populate_sdk Loading cache: 100% |#########################################################################################################################################################################################################| Time: 0:00:01 Loaded 4264 entries from dependency cache.
Am Ende des Vorgangs findet sich im Ordner images/linux
ein Installationsskript namens sdk.sh
welches für die Installation des SDKs genutzt werden kann:
$ ./script/sdk.sh PetaLinux SDK installer version 2020.2 ====================================== Enter target directory for SDK (default: /opt/petalinux/2020.2): /var/development/Git/ZYBO/linux/MinimalLinux/sdk You are about to install the SDK to "/var/development/Git/ZYBO/linux/MinimalLinux/sdk". Proceed [Y/n]? y Extracting SDK..................
Nach der Installation wird in Vitis ein neues Plattformprojekt angelegt und als Linux-Projekt konfiguriert:
In diesem Projekt müssen nun der Pfad für das rootfs des erzeugen Linux-Systems und der Pfad für das sysroot des SDKs eingetragen werden:
Hinweis:
In diesem Beispiel werden keine Bootkomponenten erzeugt. Daher können die entsprechenden Felder ausgelassen werden.
Das fertige Projekt wird dann kompiliert und ein neues Anwendungsprojekt, welches die erstellte Plattform als Basis verwendet, erstellt.
Das Anwendungsprogramm ließt den Kanal 14 des XADC über den IIO-Treiber aus und gibt die gemessene Spannung in der Konsole aus.
#include <stdio.h> #include <unistd.h> #include <stdlib.h> float Voltage; float Scale; FILE* File; char Buffer[32]; int main(void) { File = fopen("/sys/bus/iio/devices/iio:device1/in_voltage10_vaux14_scale", "r"); if(File == NULL) { printf("[ERROR] Can not open file!"); return -1; } fgets(Buffer, 12, File); fclose(File); Scale = atof(Buffer); printf("[INFO] Scale: %4.9f mV / Bit\n\r", Scale); while(1) { File = fopen("/sys/bus/iio/devices/iio:device1/in_voltage10_vaux14_raw", "r"); if(File != NULL) { while(fgets(Buffer, sizeof(Buffer), File)); Voltage = (float)atoi(Buffer) * Scale / 1000.0; fclose(File); printf("[INFO] Raw: %s", Buffer); printf("[INFO] Voltage: %4.2f V\n\r", Voltage); } else { printf("[ERROR] Can not open file!"); return -1; } sleep(1); } return 0; }
Die Berechnung der Spannung erfolgt mit Hilfe des Skalierungsfaktors aus der entsprechenden Datei und dem ausgelesenen Analogwert.
Achtung:
Bei dem ausgelesenen Wert handelt es sich um den Wert in Millivolt!
Für die Ausführung, bzw. zum Debuggen der Anwendung wird das Target (also das ZYBO) im Projekt angelegt, wodurch die Anwendung bequem per Ethernet auf das ZYBO übertragen und ausgeführt, bzw. debuggt werden kann. Dazu wir das Menü Debug (oder die Run) Configurations geöffnet und über die Schaltfläche New im Reiter Main eine neue Verbindung angelegt.
Jetzt kann die Anwendung gestartet werden. Sämtliche Konsolenausgaben werden in Vitis ausgegeben
[INFO] Scale: 0.244140625 mV / Bit [INFO] Raw: 0 [INFO] Voltage: 0.00 V [INFO] Raw: 790 [INFO] Voltage: 0.19 V [INFO] Raw: 1673 [INFO] Voltage: 0.41 V [INFO] Raw: 1744 [INFO] Voltage: 0.43 V [INFO] Raw: 2047 [INFO] Voltage: 0.50 V
Integration der App in den PetaLinux Build-Prozess:
Die fertige Anwendung soll abschließend noch in den Build-Prozess von PetaLinux integriert werden, sodass die Anwendung automatisch kompiliert und in das erstellte Dateisystem integriert wird. Dazu wird als erstes ein neues Anwendungsprojekt erstellt:
$ petalinux-create -t apps --name adc-reader-app --template c INFO: Create apps: ADC-Reader INFO: New apps successfully created in /var/development/Git/ZYBO/linux/MinimalLinux/petalinux/project-spec/meta-user/recipes-apps/adc-reader-app
Die eigentliche Anwendung ist in dem Unterverzeichnis files
zu finden und wird durch das bereits erstellte Programm ersetzt. Anschließend wird die Anwendung in das rootfs integriert, indem die entsprechende Anwendung (app) aktiviert wird:
$ petalinux-config -c rootfs
Die vorgenommenen Einstellungen werden gespeichert und das Image mit der Anwendung gebaut:
$ petalinux-build -c adc-reader-app INFO: Sourcing build tools [INFO] Building adc-reader-app [INFO] Sourcing build environment [INFO] Generating workspace directory INFO: bitbake adc-reader-app ... INFO: Successfully copied built images to tftp dir: /tftpboot [INFO] Successfully built adc-reader-app $ petalinux-build ... [INFO] Successfully built project $ petalinux-package --force --boot --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/system.bit --u-boot ... INFO: Binary is ready.
Alle neu erstellten Daten werden anschließend erneut auf die SD-Karte kopiert und das Board gebootet. Die Anwendung ist im Verzeichnis /usr/bin
zu finden:
root@MinimalLinux:~# /usr/bin/adc-reader-app [INFO] Scale: 0.244140625 mV / Bit [INFO] Raw: 437 [INFO] Voltage: 0.11 V [INFO] Raw: 436 [INFO] Voltage: 0.11 V [INFO] Raw: 489 [INFO] Voltage: 0.12 V [INFO] Raw: 99 [INFO] Voltage: 0.02 V [INFO] Raw: 284 [INFO] Voltage: 0.07 V [INFO] Raw: 968 [INFO] Voltage: 0.24 V [INFO] Raw: 1135 [INFO] Voltage: 0.28 V [INFO] Raw: 1130 [INFO] Voltage: 0.28 V
Das komplette Projekt steht in meinem GitHub-Repository zum Download bereit.
Schreibe einen Kommentar