Hello World

Der FPGA wird vom SoC mit fünf GPIO-Pins gesteuert. Drei der Pins dienen als allgemeine I/O-Leitungen nach der Konfiguration des FPGA. Als Erstes schreibe ich eine Hello-World-Variante für einen FPGA. Es ist ein kleines Programm in MyHDL, das einen der I/O-Pins regelmäßig an- und ausschaltet. Ich benutze dafür die FPGA-Primitive STARTUP_SPARTAN6, die einen 50-Mhz-Taktgenerator aktiviert. Mit diesem Takt wird ein Zähler hochgezählt, bei einem Zähler-Überlauf wird das Signal am I/O-Pin geändert. Ich erzeuge das FPGA-Image mit dem Rhea-Build-System und benutze dann meinen FPGA-Linux-Treiber, um das Image auf dem FPGA einzuspielen.

Nachdem das Image geladen ist, verfolge ich mit meinem Linux-Pin-Treiber die Signaländerungen am I/O-Pin. Und der Pin ändert regelmäßig seinen Zustand, der FPGA funktioniert also.

FPGA-I/O-Pins einlesen

Der nächste Schritt besteht darin, alle I/O-Pins des FPGA als Eingänge mit Pull-up-Widerständen zu definieren und dann etwas MyHDL-Code zu schreiben, um die drei freien I/O-Pins der Konfigurationsschnittstelle für aussagekräftigere Meldungen zu verwenden.

Ein I/O-Pin dient jetzt als LOAD-Signal: Ändert der Pin am FPGA seinen Zustand von Low auf High, wird der Zustand der zirka 180 FPGA-Eingangspins in ein Register geladen. Der zweite I/O-Pin wird als Taktsignal (CLOCK) benutzt und der dritte als Datenüberträger vom FPGA (DATA OUTPUT). So kann ich die Daten aus dem FPGA-Register auf den SoC schieben, ein Bit pro Takt. Ich simuliere den Ablauf mit MyHDL und verfolge die Signalausgabe mit GtkWave und der Code macht, was er sollte.

In der Theorie sollte ich damit die gleichen Tests wie beim SoC durchführen und den Zustand eines jeden Pins erkennen können, der als Eingabe-Pin auf dem FPGA konfiguriert wurde. Leider funktioniert es nicht so gut wie beim SoC. Viele Pins ändern ständig ihren Zustand, ohne dass ich eine Ursache erkennen kann oder weiß, wo ich mit der Suche anfangen soll. Außerdem führt die Aktivierung der Pull-up-Widerstände an den FPGA-Pins zu einem instabilen System. Linux stürzt häufig ab, nachdem ich den FPGA mit meinem Image bespielt habe. Lasse ich die Pull-up-Widerstände weg, läuft das System stabil. Sehr merkwürdig, darüber werde ich noch nachdenken müssen.

Aufsteigende Flanken zählen

Mein nächster Versuch ist es, einen Zähler für jeden Pin hinzuzufügen, der die Anzahl der Zustandsänderungen des Pins von Low auf High mitzählt. Mit einem 32-Bit-Register, das einmal pro Sekunde ausgelesen wird, sollte ich bis zu vier Milliarden Änderungen pro Sekunde erfassen können. Mehr als genug, da der Spartan FPGA kaum schneller als 400 MHz takten kann. Da mein Zähler zur Signalprüfung mit einem 50 Mhz-Takt betrieben wird, könnte ich sowieso nicht schneller zählen. Ich kann nicht genug Zählregister für alle 180 Pins im FPGA anlegen, so begrenze ich die Erfassung jeweils auf eine Pin-Bank pro Testdurchlauf. Das funktioniert zum Teil. Einige Pins ändern sich überhaupt nicht, ein Pin ändert seinen Zustand zirka 50 Mal pro Sekunde, aber viele Pins ändern ihre Werte scheinbar willkürlich mit jedem Zähler-Durchlauf. Ich weiß nicht, ob das an meinem HDL-Code liegt oder die Ergebnisse einfach eine Vielzahl von Glitches sind. Die Signale sehen in einer Simulation korrekt aus, aber ich weiß nicht, ob die Testfälle tatsächlich alles abdecken, was in Wahrheit passiert.

Ich benutze einen Trick, um herauszufinden, ob die Zähler zumindest bei geringen Geschwindigkeiten funktionieren. Ich zähle die Anzahl der Impulse auf der Taktleitung, mit der ich die Registerdaten zum SoC übertrage. Gibt es 55 Zählerwerte zu übertragen und ist jeder Wert 32 Bit groß, so sollte ich, jedesmal wenn Daten übertragen werden, 55 * 32 = 1760 Flanken auf der Taktleitung sehen können. Doch ich zähle immer einige Flanken mehr, zum Beispiel 1765. Irgendetwas stimmt nicht.

Digitale Signale sind nicht binär

Programmierer betrachten digitale Signale meist als binär, ein Signal ist entweder High oder Low. Allerdings stimmt das nicht. In Wahrheit sind alle Signale analoge Signale. Ändert sich der Signalwert von 0 Volt auf 3,3 Volt, dauert das eine gewisse Zeitspanne. Wird das Signal während einer Änderung geprüft, kann es eine beliebige Zwischenspannung aufweisen. Dieses bekannte Problem wird als Metastabilität bezeichnet.

Die Korrektur ist recht einfach. Ich füge einen weiteren Flip-Flop hinzu, der die Ausgabe des ersten Flip-Flops prüft, dadurch wird das Risiko reduziert. Es eliminiert das Problem nicht komplett, aber in der Praxis sollte es nicht mehr auftreten. Jetzt zähle ich genau 1760 Flanken auf der Taktleitung, aber die anderen Zähler laufen weiterhin chaotische Resultate.

Asynchroner Zähler-Durchlauf

Was wäre, wenn die Eingaben an den Pins sich schneller änderten als mit der 50 MHz Frequenz des Taktgebers? Das könnte die merkwürdigen Resultate erklären. Ich überarbeite die Zähler erneut. Statt die Signalpegel an den Pins regelmäßig auszulesen, sollen die Signale selbst die Zählung takten. Die Xilinx-Werkzeuge kreiden mir das als Fehler an. Es ist eine schlechte Angewohnheit, Signale an Pins als Taktgeber zu nutzen, die nicht explizit als Taktpins definiert wurden. Ich muss erst einmal nachlesen, wie ich den Werkzeugen sagen kann: "Schnauze, ich weiß, was ich tue!" Ich weiß es zwar nicht wirklich, aber wenigstens funktioniert jetzt die Synthese, die Umwandlung des Codes in ein Image für den FPGA.

Dass die Zähler nun asynchron zum internen Takt im FPGA laufen, bringt aber auch neue Probleme mit sich. Lese ich den binären Zähler mit einem anderen Takt als dem Zählertakt aus, habe ich wieder das Problem der Metastabilität, oder womöglich sind noch nicht alle Bits im Zähler bereits auf dem neuen Stand. Ein binärer Zähler, der von 01 (Dezimal: 1) auf 10 (Dezimal: 2) inkrementiert wird, hat vielleicht gerade das niedrigere Bit von 1 auf 0 geändert, während das höherwertige Bit gerade noch von 1 auf 0 wechselt. Beim Lesen würde der Zähler dann einen Wert von 00 (Dezimal: 0) aufweisen, hätte also rückwärts gezählt. Das passiert mir natürlich. Auch das ist ein bekanntes Thema, der allgemeine Begriff dafür lautet Clock Domain Crossing. Er beschreibt allgemein die Probleme, die auftreten, wenn mit Signalen von zwei verschiedenen Taktquellen (Domains) gearbeitet wird.

Es gibt eine Reihe von bekannten Techniken, um Signale zwischen verschiedenen Domains auszutauschen. Eine davon wird als Gray-Code bezeichnet. Eine Änderung um +1 oder -1 führt nur zu einer einzelnen Bitänderung und vermeidet das Problem mit binären Zählern, bei dem sich mehrere Bits auf einmal ändern können. Ich füge einen Gray-Encoder zu meinen Zählern hinzu, der den Wert in Gray-Code umwandelt. Dieser Code wird dann in das Register zum Senden des Wertes eingefügt und zum SoC gesendet, wo der Gray-Code wieder dekodiert wird. Jetzt läuft kein Zähler mehr rückwärts.

Bitte aktivieren Sie Javascript.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
  • ohne Werbung
  • mit ausgeschaltetem Javascript
  • mit RSS-Volltext-Feed
 Reverse Engineering: Was ein FPGA-Baustein steuertDie Auswertung wird beschleunigt 
  1.  
  2. 1
  3. 2
  4. 3
  5.  


Lasse Bierstrom 26. Nov 2016

Einsynchronisieren ist quasi im hello World für FPGA's mit drin. Alles andere ist (bis...

Lasse Bierstrom 26. Nov 2016

Wenn es um Oszilloskope geht wird idR kräftig in der Trickkiste gerührt. Schneller...

x-beliebig 25. Nov 2016

wir haben die Erfahrung gemacht, dass es Softwareleute gibt, die durchaus meinen, man...

gelöscht 25. Nov 2016

was vielen nicht klar ist: ein fpga ist inhärent echtzeitfähig.



Aktuell auf der Startseite von Golem.de
Update für Google Maps
Google Street View kehrt nach Deutschland zurück

Nach 13 Jahren aktualisiert Google die Straßenfotos für Street View. Dafür verschwindet zuerst das gesamte alte Bildmaterial.

Update für Google Maps: Google Street View kehrt nach Deutschland zurück
Artikel
  1. Porsche Mission X: Elektrisches Hypercar mit Flügeltüren vorgestellt
    Porsche Mission X
    Elektrisches Hypercar mit Flügeltüren vorgestellt

    Sollte der Mission X in Serie gehen, soll er laut Porsche das schnellste Serienauto auf der Nordschleife sein. Und doppelt so schnell laden wie ein Taycan.

  2. Polaris: Bundeswehr will neues Aerospike-Raketentriebwerk
    Polaris
    Bundeswehr will neues Aerospike-Raketentriebwerk

    Den Auftrag für das neue Triebwerk hat die Bundeswehr an das deutsche Start-up Polaris gegeben, das damit in die Luftfahrtgeschichte eingehen kann.

  3. Pharo: Guter Einstieg in die objektorientierte Programmierung
    Pharo
    Guter Einstieg in die objektorientierte Programmierung

    Pharo ist eine von Smalltalk abgeleitete Programmiersprache und gut für alle, die sich mit objektorientierter Programmierung vertraut machen wollen. Eine Einführung.
    Eine Anleitung von Christophe Leske

Du willst dich mit Golem.de beruflich verändern oder weiterbilden?
Zum Stellenmarkt
Zur Akademie
Zum Coaching
  • Schnäppchen, Rabatte und Top-Angebote
    Die besten Deals des Tages
    • Daily Deals • MindStar: Corsair Crystal 570X RGB Mirror 99€, be quiet! Pure Base 500 59€, Patriot Viper VENOM RGB DDR5-6200 32 GB 109€ • Acer XZ322QUS 259€ • Corsair RM750x 108€ • Corsair K70 RGB PRO 135€ • PS5-Spiele & Zubehör bis -75% • Chromebooks bis -32% • NBB: Gaming-Produkte bis -50% [Werbung]
    •  /