Das Processing System

Zynq FPGA

Der Zynq kombiniert ein FPGA und einen Dual Core ARM Prozessor. Beide Komponenten kann man unabhängig voneinander programmieren um sie so beliebig einsetzen zu können.
In diesem Artikel zeige ich euch wie ihr das Processing System (PS) des Zynq nutzen könnt und wie ihr mit dem PS auf das FPGA zugreifen könnt.

-> Das erste Blockschaltbild:

Für den Anfang erkläre ich euch wie ihr das PS mit den GPIOs verbindet.
Dafür wird in Vivado ein neues Projekt angelegt und dort wird anschließend über Create Block Design ein neues Blockschaltbild mit dem Namen System angelegt und geöffnet:

Processing_System(1)
Mit einem Klick auf Add IP werden nun folgende Blöcke eingefügt:

  • 2x AXI GPIO
  • 1x ZYNQ7 Processing System

Mit einem Klick auf einen der Blöcke erscheint links unten neben dem Blockschaltbild ein Fenster wo die Blöcke umbenannt werden können.
Auf diese Weise werden die GPIO Blöcke in LED und Schalter umbenannt.
Danach wird mit einem Klick auf Run Connection Automation ein am oberen Rand des Blockschaltbild ein Assistent gestartet werden, welcher die einzelnen Blöcke miteinander verbindet.
Im letzten Schritt klickt ihr bei einem der GPIO Blöcke mit der rechten Maustaste auf das Verbindungsstück des Anschlusses GPIO und über den Menüpunkt Make External wird diese Verbindung dann nach außen geführt:

Processing_System(2)
Durch einem Doppelklick kann der GPIO Block konfiguriert werden. Dort stellt ihr für den Wert GPIO Width den Wert 4 ein, sodass der Ausgang des Blocks 4 Bit breit ist:

Processing_System(2.5)
Diese Schritte werden anschließend für den zweiten GPIO Block wiederholt. Zuletzt benenne ich die Ausgangssignale noch um.
Die fertige Schaltung sieht am Ende dann so aus:

Processing_System(3)
Jetzt wird das PS konfiguriert, indem das Konfigurationsmenü mit einen Doppelklick auf den ZYNQ7 Processing System-Block geöffnet wird.
Über Import XPS Settings wird mit Hilfe der Datei System.xml die Grobkonfiguration durchgeführt:

Processing_System(4)
Dazu einfach die Auswahl der Datei mit einem Klick auf OK bestätigen und kurz warten.
Danach werden folgende Punkte abgewählt:

  1. PS-PL Configuration:
    General -> Enable Clock Resets -> FCLK_RESET0_N
  2. MIO Configuration:
    Memory Interfaces -> Quad SPI Flash
    I/O Peripherals -> ENET 0, USB 0, SD 0
    Application Processor Unit -> Timer 0

Mit einem Klick auf OK bestätigt ihr die Änderungen, woraufhin sich das PS verändert:

Processing_System(5)
Nun wird das Design gespeichert und mit einem Klick auf Project Manager öffnet ihr die Sources des Projektes.
Dort wählt ihr die System.bd Datei aus und öffnet mit einem Rechtsklick das Menü:

Processing_System(6)
Dort werden jetzt folgende Punkte ausgeführt:

  1. Generate Output Products…
  2. Create HDL Wrapper…

Diese beiden Schritte dauern etwas. Mit ihnen wird eine Datei kreiert die zum erstellen des Bitstreams notwendig ist und welche die Verbindung zwischen Peripherie und Prozessor beschreibt.
Sobald ihr den HDL Wrapper erstellt habt, wird der Name des aktuell aktiven Designs (in diesem Fall System.bd) fett hervorgehoben.
Nun klickt ihr auf Run Synthesis um die Hardwaresynthese zu starten.
Dieser Vorgang dauert etwa 3-4 Minuten und in dem sich danach öffnenden Fenster klickt ihr dann auf Open Synthesized Design, um das IO Planing zu starten:

Processing_System(7)
In diesem Fenster werden die Signale, welche eben nach außen geführt wurden, den I/Os des FPGAs zugeordnet.
In dem unteren Fenster werden den Signalen nun die I/Os zugewiesen:

Processing_System(8)
Die Zuweisung wird gespeichert und nun kann mit einem Klick auf Generate Bitstream der Bitstream erzeugt werden (eine eventuelle Warnung einfach mit einem Klick auf OK bestätigen). Sobald die Generierung des Bitstreams abgeschlossen ist, wird die sich öffnende Meldung mit OK bestätigt.
Damit wäre das PS hardwaretechnisch fertig. Nun geht es an die Software für den ARM Prozessor!

-> Die passende Software:

Im ersten Schritt wird die Hardware für das SDK exportiert.
Dazu klickt ihr auf File und dann auf Export:

Processing_System(9)
Danach klickt ihr auf Launch SDK um das Xilinx SDK zu starten.
Sobald das SDK geöffnet ist, solltet ihr im Project Explorer bereits einen Ordner namens System_wrapper_hw_plattform_0 sehen.
Dies ist der automatisch erzeugte Code für das Processing System im System Wrapper.
Über einen Klick auf File -> New -> Board Support Package werden die notwendigen Treiber und Informationen für die programmierbare Logik angelegt:

Processing_System(10)

Dieses Fenster einfach mit einem Klick auf Finish und OK schließen.
Anschließend legt ihr über File -> New -> New Application Projekt ein neues Projekt an:

Processing_System(11)
Über einen Klick auf Next könnt ihr Beispielprojekte auswählen. Da wir kein fertiges Beispielprojekt benötigen, wählen wir Empty Application aus und klicken auf Finish.
Der neu angelegte Ordner System wird nun geöffnet und das Verzeichnis src ausgewählt. Über File -> New -> Source File wird eine neue C-Datei mit dem Namen main.c erstellt:

Processing_System(12)
In diese Datei wird nun der C-Code rein geschrieben. Als erstes müssen ein paar Headerdateien eingefügt werden:

Die erste Headerdatei beinhaltet die IDs und Adressen jedes IP-Cores die in dem Design integriert sind.
Mit der zweiten Headerdatei werden spezielle Funktionen für den AXI GPIO Block eingefügt.
Bevor ein IP-Block verwendet werden kann muss er initialisiert werden. In dem Reiter system.mss finden sich alle aktiven IP-Blöcke und dort kann man zu jedem IP-Block eine Dokumentation öffnen. Dort kann man dann die einzelnen Funktionen eines IP-Blocks nachschlagen.
Der AXI GPIO Block wird über die Funktion

initialisiert. Die Variable Instanz ist ein Zeiger vom Typ XGpio der auf den fertig initialisierten GPIO Block zeigt und muss bei jeder weiteren Funktion mit angegeben werden.
Die Variable ID ist die eigentliche ID des Blockes. Sie dient der Identifikation und ist in der Datei xparameters.h zu finden.

Processing_System(13)
Die Codezeilen um beide GPIO Blöcke zu initialisieren lauten also wie folgt:

Im nächsten Schritt müssen die Blöcke als Ein- bzw. Ausgang gesetzt werden. Dies geschieht mit der Funktion

Dabei ist die Variable Instanz der vorhin initialisierte GPIO Block, die Variable Kanal der verwendete Kanal des GPIO Blocks (die Blöcke haben zwei Kanäle. Wir verwenden Kanal 1) und mit Direction gibt man an ob ein Pin ein Eingang oder ein Ausgang sein soll. Der Wert 1 setzt einen Pin als Ausgang und der Wert 0 setzt den Pin dann als Eingang:

Theoretisch braucht man nur die ersten vier Bits des GPIO Blocks zu konfigurieren, da wir die Breite der Signale der Blöcke im Schaltbild auf vier beschränkt haben. Ich konfiguriere der Einfachheit halber aber alle Bits.
Die GPIO Blöcke sind nun einsatzbereit. Mit dem Befehl

kann der Status der Eingänge abgefragt werden, was wir in einer while()-Schleife auch direkt machen:

Um Daten anschließend in den GPIO Block zu schreiben wird die Funktion

verwendet. Mit Hilfe dieser Funktion wollen wir die Daten, welche wir eben von den Schaltern eingelesen haben, nun auf den LEDs ausgeben:

Das fertige Programm sollte jetzt so aussehen:

Die fertigen Dateien können nun auf das Board übertragen werden. Über den Menüpunkt Xilinx Tools kann das FPGA direkt aus dem Xilinx SDK programmiert werden:

Processing_System(14)
Danach kann über einen Rechtsklick auf den Projektordner des C-Programmes der ARM-Prozessor programmiert werden:

Processing_System(15)
Sobald beide Teile programmiert sind kann die Anwendung getestet werden.
Dafür werden einfach die Schalter auf dem Board umgelegt und pro Schalter sollte dann eine LED aufleuchten.

Jetzt seid ihr in der Lage das Processing System des Zynq mit der Hardware des FPGAs zu verbinden und anschließen ein entsprechendes C-Programm für die Hardware zu schreiben.

 

Dokumentation:

 

-> Zurück zum FPGA + VHDL Tutorial

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.