Ingenieure, die Testanwendungen mit nicht unterstützten oder benutzerdefinierten digitalen Kommunikationsprotokollen entwickeln, können das LabVIEW FPGA-Modul verwenden, um verschiedene Kommunikationsschnittstellen auf FPGA-basierter rekonfigurierbarer I/O-Hardware der R-Serie schnell zu implementieren oder zu prototypisieren. Im Gegensatz zum Entwickeln und Erstellen von benutzerdefinierter Hardware wie einem ASIC oder dem Schreiben von eigenem VHDL-Code zur Ausführung auf einem FPGA können Sie mit dem LabVIEW FPGA Module neue Funktionen einfach testen und auf Fehler untersuchen, ohne dass spezielle Entwicklungswerkzeuge erforderlich sind.
Ein häufiges Bedürfnis bei der Entwicklung von Testsystemen in der Automobil-, Luftfahrt- und einer Reihe anderer Branchen ist die Entwicklung oder Implementierung von Schnittstellen für die digitale Kommunikation zwischen dem Testsystem und anderen Geräten. Diese Geräte umfassen andere Testsysteme oder Computer, Instrumente, Prüflinge, Low-Level-Systemkomponenten wie ECUs und mehr.
Idealerweise verfügen Sie bei der Entwicklung eines neuen Testsystems über eine vorgefertigte Schnittstelle für Ihr digitales Kommunikationsprotokoll, die einen einfach zu bedienenden Treiber für Ihr Entwicklungswerkzeug enthält. In vielen Fällen ist dies jedoch nicht die Realität. Möglicherweise müssen Sie eine Karte oder eine andere Schnittstelle zur Kommunikation mit Ihrem externen Gerät entwickeln. Dies kann dadurch erreicht werden, dass Sie Ihre eigene benutzerdefinierte Hardware entwickeln, die bis ins Extrem geht, z. B. Ihren eigenen ASIC entwerfen oder zumindest eine neue Karte auf Basis handelsüblicher Komponenten miteinander verlöten. Mit rekonfigurierbarer I/O-Hardware und dem LabVIEW FPGA Module können Sie jedoch nur mit LabVIEW und seinen grafischen Programmierwerkzeugen Ihre benutzerdefinierte Hardware entwerfen. Ihr benutzerdefinierter Hardwareentwurf wird auf den FPGA der rekonfigurierbaren I/O-Hardware geladen, um Ihre benutzerdefinierte Schnittstellenkarte für Ihre Anforderungen zu erstellen.
Wir beschreiben, wie Sie mit dem LabVIEW FPGA Module eine Vielzahl von Kommunikationsprotokollen auf Ihrer eigenen benutzerdefinierten Schnittstellenkarte implementieren können. Diese Verfahren sind sowohl auf die rekonfigurierbaren Plugin-PCI- und PXI-I/O-Karten (R-Serie) als auch auf die CompactRIO-Plattform anwendbar, die ein robustes, industrietaugliches Gehäuse bietet.
In Testsystemen gibt es eine Vielzahl von Kommunikationsprotokollen, die von extrem gängigen Schnittstellen wie RS-232 und GPIB bis hin zu benutzerdefinierten Protokollen reichen, die von einzelnen Anbietern und Anwendungsentwicklern implementiert werden. Gängige, jedoch weniger bekannte Schnittstellen sind SPI (Serial Peripheral Interface) und I2C (Inter-Integrated Circuit) zur Kommunikation innerhalb und zwischen elektronischen Geräten und Systemen. Diese Protokolle sind zwar in Anwendungen üblich, werden aber nicht immer von Kommunikationsschnittstellen unterstützt, die in einer Vielzahl von Plattformen und Softwareumgebungen verfügbar sind. LabVIEW FPGA und die rekonfigurierbare I/O-Plattform sind ein ideales Werkzeug, um eine kostengünstige Lösung zu bieten.
Digitale Kommunikationsprotokolle können nach Anwendungsbereichen oder Branchen sowie nach Art und technischen Spezifikationen des Protokolls selbst gruppiert werden. In den folgenden Abschnitten besprechen wir die technischen Details und die Art der verschiedenen Protokolle und zeigen, wie LabVIEW diese implementiert. Im Folgenden finden Sie grundlegende Kategorien und Beispielprotokolle mit Kommunikationsschnittstellen, die mit LabVIEW FPGA gelöst wurden.
Digitale Kommunikationsprotokolle können aufgrund ihrer technischen Definition und Anforderungen klassifiziert werden. Diese anwendungsunabhängige Betrachtungsweise eines Protokolls hilft, sich auf die Details zu konzentrieren, die bei der Auswahl der optimalen Implementierung mit den vorhandenen Entwicklungswerkzeugen wichtig sind. Der Rest dieses Dokuments konzentriert sich auf diese Klassifizierungskriterien und wie verschiedene Gruppen von Protokollen auf dem FPGA implementiert werden.
Die meisten digitalen Kommunikationsschnittstellen fallen in eine von zwei sehr allgemeinen Kategorien, seriell und parallel, je nach Anzahl der Datensignale zwischen Sender und Empfänger. Wenn Daten auf einer einzigen Datenleitung übertragen werden, handelt es sich um eine serielle Datenverbindung, da alle Datenbits nacheinander oder seriell übertragen werden. Eine parallele Datenverbindung hat mehr als eine Datenleitung und oft ein Vielfaches von acht Datenleitungen. Daten werden parallel übertragen, in der Regel jeweils ein Byte oder Wort. Traditionell werden sowohl serielle (z. B. RS-232) als auch parallele (z. B. GPIB) Kommunikationsverbindungen mit parallelen Kommunikationsverbindungen verwendet, die höhere Datenübertragungsraten bei gleicher Taktrate bieten. Da die Bitraten, die auf einer einzelnen Datenleitung möglich sind, in den Megabit- und Gigabit-Bereich gestiegen sind, sind serielle Verknüpfungen viel häufiger und dominanter im Markt geworden, da sie eine kostengünstigere Lösung bieten, die die Kosten für Schnittstellenkomponenten (z. B. Leitungstreiber) und die Kosten für die Verkabelung reduziert. Sowohl bei seriellen als auch bei parallelen Kommunikationsschnittstellen können zusätzliche Signalleitungen zur Taktung und Triggerung sowie zur Steuerungs- und Befehlskommunikation vorhanden sein.
Eine zweite grundlegende Klassifikation der physikalischen Kommunikationsschnittstelle sind die Spannungspegel und die Masse, die für die digitalen Signalleitungen verwendet werden. Datenbits und andere Informationen werden durch die unterschiedlichen Spannungspegel der Signalleitungen übertragen, aber es kann erhebliche Unterschiede in den Spannungspegeln zwischen verschiedenen Arten von Schnittstellen geben. Bei einem gegen Masse geschalteten Digitalsignal wird der Spannungspegel einer Signalleitung relativ zu einer gemeinsamen Masse gemessen. Ein differentielles Digitalsignal besteht aus zwei nicht referenzierten Signalen und der Spannungspegel zwischen den beiden Signalleitungen stellt den Signalwert dar. Differentielle Signale sind immuner gegen von den Signalleitungen aufgenommenes Rauschen und können normalerweise zur Übertragung von Signalen über größere Entfernungen verwendet werden. Spezifische Spannungspegel, die in der digitalen Kommunikation verwendet werden, werden von Standards wie TTL, CMOS und LVDS referenziert und in der Protokollimplementierung auf dem FPGA nicht adressiert. Die digitalen Ein- und Ausgänge der rekonfigurierbaren I/O-Hardware verwenden TTL/CMOS-kompatible Spannungspegel. Wenn andere Pegel als ein Signalwandler erforderlich sind, muss zwischen der Schnittstellenhardware und der Kommunikationsverbindung ein Signalwandler eingefügt werden.
Wenn wir ein Protokoll analysieren und über seine Implementierung in LabVIEW FPGA nachdenken, müssen wir die verschiedenen Signalleitungen identifizieren, die vom Protokoll verwendet werden, und den Zweck jedes Signals. Die Anzahl der vom Protokoll verwendeten Signalleitungen bestimmt, wie viele Hardwareressourcen im LabVIEW Projekt konfiguriert werden müssen und wie viele digitale Leitungen im LabVIEW Diagramm verwendet werden. Das folgende Timing-Diagramm (Abbildung 1), das das SPI-Protokoll (Serial Peripheral Interface) zeigt, veranschaulicht die Verwendung von drei Signalleitungen, die wir bei der Implementierung dieses Protokolls verwalten müssen.
Abbildung 1: Einfaches Timing-Diagramm des SPI-Protokolls mit einer Datenleitung
Wenn wir mit der Implementierung beginnen, stellen wir fest, dass es uns bei der Umwandlung des Timing-Diagramms in den entsprechenden LabVIEW FPGA-Code um zwei Dinge geht: das Ein- und Ausschalten digitaler Leitungen und das Warten zwischen dem Festlegen des Zustands der verschiedenen digitalen Leitungen. In Anwendungen, in denen wir ein digitales Protokoll lesen, geht es darum, den Zustand digitaler Leitungen zu lesen und die Zeit zwischen Übergängen auf jeder Signalleitung zu notieren. In der Regel ist die Ausgabe eines digitalen Protokolls einfacher zu implementieren. Daher werden wir uns zuerst mit diesem Fall befassen.
Eines der nächsten Kriterien zur Klassifizierung eines Protokolls ist die Taktquelle, die vom Protokoll verwendet wird. Die zwei Hauptkategorien sind synchrone und asynchrone Protokolle. Synchrone Protokolle enthalten ein bestimmtes Timing-Signal, während asynchrone Protokolle mit einer definierten Bitrate getaktet werden.
Ein typisches Beispiel für ein synchrones Protokoll ist das SPI-Protokoll im Timing-Diagramm. Das Protokoll enthält ein dediziertes Taktsignal, so dass jeder Empfänger die Taktleitung als Zeitbasis zum Lesen oder Schreiben der Datenleitung verwenden kann. Das wohl bekannteste asynchrone Protokoll ist der serielle (RS-232)-Bus, der auf vielen PCs verwendet wird. Bei Verwendung des seriellen Busses geben wir die Baudrate (Bit pro Sekunde) des Geräts an, mit dem wir kommunizieren. Die Baudrate wird von Sender und Empfänger verwendet, um das Datensignal mit der gleichen Rate zu aktualisieren oder zu lesen. Da die Zeitquelle an beiden Enden der Kommunikation nicht genau gleich ist, sind asynchrone Kommunikationsdatenpakete begrenzt, um Bitfehler zu vermeiden. Die asynchrone Kommunikation muss häufig neu synchronisiert werden, um geringfügige Zeitunterschiede zu ermöglichen. Synchrone Kommunikationsprotokolle können dagegen kontinuierlich kommunizieren, da sie an jedem Datenbit synchronisiert sind.
Wenn wir ein Taktsignal als Teil eines synchronen Protokolls implementieren, wird der FPGA-Takt verwendet, um die Zeitbasis des Protokolls zu bestimmen und das Taktsignal entsprechend zu aktualisieren.
Abbildung 2: LabVIEW FPGA Diagramm zur Erzeugung eines 10 μs (100 kHz) Taktsignals
Bei einem asynchronen Protokoll wird kein separates Taktsignal erzeugt, sondern anhand des FPGA-Takts und der definierten Baudrate bestimmt, wann die Datensignale aktualisiert oder gelesen werden sollen.
Abbildung 3: LabVIEW FPGA-Diagramm zur Aktualisierung der Datenleitung bei 4800 Baud
(8333 FPGA-Taktperioden = 208,3 μs = 1/4800 Hz)
Basierend auf der durch das Taktsignal oder die Timing-Spezifikation angegebenen Rate werden Daten auf dem Datensignal codiert oder aus dem Datensignal gelesen und anschließend dekodiert. Die Kodierung der Daten kann in verschiedenen Formaten erfolgen. Die gängigste Methode besteht darin, den Wert eines Datenbits durch einen oder mehrere Zustände des Datensignals darzustellen. Diese allgemeine Klasse von Kodierungsverfahren wird Pulse Code Modulation (PCM) genannt.
Die Teile der PCM-Verfahren, bei denen das Datenbit durch einen Zustand des Datensignals dargestellt wird, werden als "Non-Return to Zero" (NRZ) bezeichnet. Ein High-Datensignal steht beispielsweise für ein '1'-Bit, während ein Low-Datensignal für ein '0'-Bit steht. Diese Methode wird NRZ-L genannt, da der Pegel des Datensignals das Datenbit darstellt. Bei einigen Protokollen (z. B. RS-232) ist diese Logik umgekehrt, wobei der High-Zustand '0' und der Low-Zustand '1' ist. Dies wird NRZ-I (invers) genannt. Weitere NRZ-Untertypen sind NRZ-M (Marke) und NRZ-S (Leerzeichen), wobei der '1'-Datenbitwert durch eine Änderung des Datensignals (NRZ-M) oder eine '0' durch eine Änderung des Datensignals (NRZ-S) dargestellt wird.
Abbildung 4: NRZ-Kodierungsverfahren (Non Return to Zero)
Die Pulscodemodulation enthält einen weiteren Satz von Kodierungsschemata, die das Taktsignal und das Datensignal in einer Datenleitung zusammenfassen. Jedes Bit wird durch mehrere Zustände des Datensignals dargestellt. Diese werden als Zweiphasenkodierung bezeichnet und das gängige Manchester-Kodierungsschema ist eine Art der Zweiphasenkodierung.
Andere fortgeschrittene Kodierungsmethoden umfassen verschiedene Formen der Impulsbreitenkodierung. Das häufig verwendete Pulsweitenmodulationsschema (PWM) wandelt einen Analogwert direkt in die variierende Pulsbreite einer Impulsfolge mit konstanter Frequenz um. Andere Formen der Impulsbreitenkodierung verwenden zwei unterschiedliche Impulsbreiten, um ein "0"- und "1"-Bit in einer traditionellen Bitfolge darzustellen.
Nun, da wir eine grundlegende Nomenklatur zur Beschreibung gängiger Protokolle haben, können wir uns ansehen, wie Protokolle in LabVIEW FPGA implementiert werden. Um ein Protokoll in LabVIEW FPGA zu implementieren, gehen wir in der Regel zunächst durch das Timing-Diagramm und konvertieren die Zustandsänderungen der verschiedenen Signalleitungen und das Timing zwischen diesen Änderungen in die entsprechenden LabVIEW Funktionen und Strukturen. Jede Zustandsänderung einer digitalen Leitung wird mit dem FPGA-I/O-Knoten und das Timing mit den LabVIEW FPGA Timing-Funktionen (Schleifen-Timer und Warten) implementiert. Schritte im Timing-Diagramm, die mehrmals wiederholt werden, werden mit Hilfe der For- oder While-Schleife implementiert. Für umfangreichere Protokolle können Gruppen von Funktionen und Strukturen im SubVI gekapselt werden, um die Wiederverwendung von Programmcode zu ermöglichen und den Code modularer und überschaubarer zu gestalten.
Als erstes Beispiel implementieren wir das oben in Abbildung 1 dargestellte SPI-Timing-Diagramm. Die Kommunikation mit dem SPI-Protokoll besteht aus Datenpaketen, die zwischen zwei Geräten gesendet werden. Bei der SPI-Kommunikation gibt es ein Master-Gerät, das das ChipSelect-Signal und das Taktsignal steuert. Es können ein oder mehrere Slave-Geräte mit eigener ChipSelect-Signalleitung vom Master zu jedem Slave und einer gemeinsamen Datenleitung für alle Geräte vorhanden sein. Wenn die Anwendung eine Kommunikation in beide Richtungen zwischen Master und Slave(s) umfasst, werden üblicherweise zwei Datenleitungen verwendet, die mit Master Out Slave In (MOSI) und Master In Slave Out (MISO) bezeichnet werden. In unserem Beispiel konzentrieren wir uns nur auf eine Datenleitung.
Abbildung 5: Verbindungsdiagramm für die SPI-Kommunikation zwischen zwei Geräten
Pakettransfers werden immer vom Master-Gerät initiiert, indem die ChipSelect-Leitung des adressierten Slave-Geräts aktiviert wird. In der Regel ist die ChipSelect-Leitung aktiv Low, so dass sie im Ruhezustand des Systems in einem High-Zustand verbleibt und vom Master auf Low gezogen wird, um eine Übertragung zu starten. Nach Aktivierung des ChipSelect-Signals aktualisiert der Master die Datenleitung und schaltet dann die Taktleitung um, um jedes Datenbit an den Slave zu übertragen. Der Inhalt des Datenpakets ist anwendungsspezifisch und der Definition des Entwicklers und Gerätedesigners überlassen.
Im entsprechenden LabVIEW FPGA Diagramm (siehe Abbildung 6 unten) wird jede Datenübertragung durch Einstellen des booleschen Elements "Schreiben" initiiert. Dadurch wird der TRUE-Case ausgeführt. Zunächst wird die ChipSelect-Leitung (SPI CS*) aktiviert, indem der Digitalausgang auf Low gesetzt wird. Gleichzeitig wird der Datenwert "Daten (Ausgang)" in die entsprechende Bitfolge (boolesches Array) umgewandelt. Die 1-μs-Wartefunktion ermöglicht es dem Slave-Gerät, für die folgenden Datenbits bereit zu sein. Dann wird eine Sequenz aus Aktualisieren der Datenleitung und Umschalten der Taktleitung 16 Mal in der For-Schleife wiederholt. Jedes Bit des booleschen Arrays wird an die Datenleitung (SPI DOUT) ausgegeben, gefolgt von der Taktleitung (SPI SCLK), die zuerst auf High und dann auf Low gesetzt wird. Die Funktion "Schleifen-Timer" ermöglicht die Ausführung der Schleife in Intervallen von 2 μs, während die Funktion "Warten" die Länge der High-Phase des Taktsignals auf 1 μs regelt und ein 500 kHz 50% Tastverhältnis erzeugt. Nachdem alle 16 Bits erzeugt wurden, werden die Chipauswahl und die Datenleitungen in den Ruhezustand zurückversetzt und die Funktion "Warten (Minimum)" wird eingefügt. An diesem Punkt ist der FPGA bereit für den nächsten Schreibbefehl.
Abbildung 6: LabVIEW FPGA-Diagramm einer einfachen SPI-Ausgabeimplementierung
Je nach Spezifikation der verwendeten SPI-Geräte und der Anwendung können beliebige Kommunikationsparameter (z.B. Anzahl der zu übertragenden Datenbits, Frequenz des Taktsignals usw.) im Diagramm angepasst oder dynamisch über ein Bedienelement auf dem Frontpanel des LabVIEW FPGA VIs gesteuert werden.
Bei Bedarf kann die Richtung jeder der in der Anwendung verwendeten digitalen Leitungen programmatisch mit Hilfe des Methodenknotens "FPGA-I/O-Ausgabe aktivieren festlegen" festgelegt werden (siehe Abbildung 7).
Abbildung 7: LabVIEW FPGA Initialisierung digitaler Leitungen
Die Implementierung des Eingangsteils eines Protokolls kann einige Herausforderungen mit sich bringen, da der Programmcode flexibler bei der Erkennung und Verarbeitung des Protokolls sein muss. Anstatt die digitalen Ausgangsleitungen zu aktualisieren und die entsprechenden Verzögerungen einzufügen, überwacht der Programmcode den Zustand verschiedener digitaler Leitungen und misst bei Bedarf die Zeit zwischen bestimmten Übergängen auf den Signalleitungen.
Das folgende Beispiel zeigt eine einfache SPI-Eingangsimplementierung entsprechend dem vorherigen SPI-Ausgangsbeispiel. Im Ruhezustand überwacht der FPGA die ChipSelect-Leitung und erkennt fallende Flanken. Bei einer fallenden Flanke beginnt es, die Taktleitung zu überwachen. Für jede von 16 steigenden Flanken des Taktsignals liest der FPGA das Datensignal und speichert den Bitwert in einem vorbelegten booleschen Array. Am Ende des Datenpakets, nach 16 Taktperioden, wird das boolesche Array in einen Integer umgewandelt und auf dem Frontpanel des VIs zur Verfügung gestellt.
Abbildung 8: LabVIEW FPGA-Diagramm einer einfachen SPI-Eingangsimplementierung
Aufgrund der Natur des SPI-Protokolls benötigt dieses Beispiel keine Zeitmessungen, da das gesamte Timing direkt durch Flanken im Protokoll gesteuert wird.
In diesem Abschnitt behandeln wir eine Reihe weiterer Themen, die bei der Entwicklung eines digitalen Kommunikationsprotokolls mit LabVIEW FPGA zu beachten sind.
In den vorherigen SPI-Beispielen wird jede Signalleitung nur von einem Gerät angesteuert. In vielen Protokollen können Signalleitungen jedoch von mehreren Geräten angesteuert oder gesteuert werden, abhängig vom Zustand des Busses oder der Kommunikation. Dadurch können mehrere Geräte die Übertragung auf dem Bus initiieren oder Daten über dieselbe Datenleitung senden und empfangen. Typischerweise wird dies mit einem Open-Collector/Open-Drain-Kreislauf erreicht. In dieser Konfiguration kann ein Gerät nur eine Signalleitung auf "Low" setzen oder ziehen, lässt die Signalleitung aber erlöschen, wenn es die Leitung auf "High" setzen oder nicht. Zusätzlich zu jedem Gerät, das mit einer Signalleitung verbunden ist, hat die Signalleitung auch einen Pull-Up-Widerstand auf eine eingestellte Spannung, um die High-Spannung der Leitung festzulegen, wenn keines der angeschlossenen Geräte das Signal niedrig steuert. Mit dieser Einstellung kann jedes Gerät die Leitung niedrig schalten, ohne Spannungskonflikte zwischen verschiedenen Geräten zu erzeugen. Solche Signale sind in der Regel als Aktiv-Low definiert. Das bedeutet, dass sich die Leitung in einem High-Zustand befindet, wenn sich der Bus im Ruhezustand befindet, und ein Gerät das Signal durch Ziehen an der Leitung auf Low aktiviert. Aktiv-Low-Signale werden oft durch einen Balken über dem Signalnamen oder ein Sternchen nach dem Signalnamen angezeigt, wie im Fall des in den vorherigen Beispielen verwendeten Signals ChipSelect* (SPI CS*).
Um ein Open-Collector-Signal in LabVIEW FPGA zu implementieren, verwenden wir die Möglichkeit, die Richtung der digitalen Leitung zu steuern, um zwischen dem Ansteuern einer Low-Leitung und dem Fließenlassen zu wechseln. In LabVIEW FPGA wird der I/O-Methodenknoten zum Aktivieren oder Deaktivieren einer digitalen Ausgangsleitung verwendet. Wenn eine Leitung deaktiviert ist, steuert der FPGA die digitale Leitung nicht an und lässt sie hoch schweben. Um die Leitung bei Aktivierung auf Low zu setzen, setzen wir die Ausgangsdaten auf FALSE. Ausgangsdaten ist ein Softwareregister, das seinen Wert beibehält, unabhängig davon, ob die Leitung als Antrieb oder als Fließkomma verwendet wird.
Die folgenden Abbildungen zeigen ein Beispiel für eine Open-Collector-Konfiguration in LabVIEW FPGA für das Protokoll I2C (Inter-Integrated Circuit). I2C wird in ähnlichen Anwendungen wie SPI zur Kommunikation mit verschiedenen Arten von integrierten Circuits wie EEPROMs, A/D-Wandler, DAC usw. verwendet. Der I2C-Bus hat nur zwei Signalleitungen, Takt und Daten, und jede ist eine offene Kollektorleitung. Zur Auswahl des richtigen Empfängers für eine Kommunikation sendet der Sender zunächst eine eindeutige Geräteadresse, die das Empfangsgerät angibt.
Zur Initialisierung des VIs für die Kommunikation mit offenem Kollektor werden die beiden Signalleitungen (SCL und SDA) deaktiviert, um den Bus in den Ruhezustand zu versetzen. Die Ausgangsdaten für jedes Signal sind auf FALSE gesetzt. Ab diesem Zeitpunkt wird der Zustand jeder Leitung mit der Methode "Ausgabe aktivieren" gesteuert, um die Leitung zu aktivieren und auf Low zu fahren oder sie zu deaktivieren und auf High zu setzen.
Abbildung 9: Konfigurieren von zwei digitalen Leitungen für Open-Collector-Kommunikation
Um eine Übertragung auf dem I2C-Bus zu initiieren, sendet der Sender eine Startbedingung, indem er die Datenleitung (SDA) auf Low und die Taktleitung (SCL) auf Low schaltet.
Abbildung 10: Implementieren der I2C-Startbedingung auf dem Bus
Um ein Datenbit auf dem I22C-Bus zu übertragen (siehe Abbildung 11), aktualisiert der Sender die Datenleitung (1.st Rahmen) und schaltet dann die Taktleitung auf High (2.nd Rahmen) und Low (4.th Rahmen) um.
Beim I2C-Protokoll wird nach der Übertragung jedes Datenbytes (8 Bit) eine zusätzliche Taktperiode in die Kommunikation eingefügt, damit die Empfangseinrichtung den erfolgreichen Empfang des vorherigen Bytes bestätigen kann. Dazu zieht der Empfänger die Datenleitung während der 9. Taktperiode auf Low. Senderseitig wird dies in unserem Beispiel durch Senden eines High-Datenbits und Prüfen des Ist-Zustands der Datenleitung (3. Frame) während der Taktperiode realisiert. Obwohl der Sender die Datenleitung hoch schweben lässt, sollte der tatsächliche Datenwert niedrig sein, da der Empfänger die Datenleitung auf Low zieht, um das letzte Datenbyte zu bestätigen.
Abbildung 11: Übertragen eines Datenbits auf dem I2C-Bus
Das OSI-Referenzmodell (Open Systems Interconnection) ist eine Darstellung der verschiedenen logischen Schichten eines Kommunikationsprotokolls einschließlich der Anwendung, die das Kommunikationsprotokoll verwendet. Es wird verwendet, um die verschiedenen Aspekte eines Protokolls und Netzwerks besser zu definieren und zu verstehen.
Abbildung 12 OSI-Referenzmodell
Schicht 1 ist die physikalische Schicht, die elektrische und mechanische Details verarbeitet und Daten über einen Träger übertragen kann. Auf dieser Ebene arbeiten einfache asynchrone Pakete.
Schicht 2 bietet grundlegende Definitionen für Bit- und Byte-Level-Daten sowie Modulation über NRZ hinaus und Synchronisation.
Die nächsten Schichten befassen sich mit Adressierung, Definition von Datenpaketen, Fehlerprüfung usw.
Wie wir in unseren Beispielen sehen können, arbeitet der FPGA an der physikalischen Schicht L1, die direkt mit den digitalen Ein- und Ausgangsleitungen auf elektrischer Ebene verbunden ist. Das bedeutet, dass wir als Entwickler eines digitalen Kommunikationsprotokolls in LabVIEW FPGA für alle Ebenen des Referenzmodells in Bezug auf Protokoll und Anwendung verantwortlich sind. Bei vielen einfacheren Protokollen erfordert dies nur etwas mehr Programmierung als bisher, um eine Schnittstelle über der Protokollschicht hinzuzufügen, die es der Anwendung ermöglicht, mit dem FPGA zu interagieren und das Protokoll zu verwenden. Für fortgeschrittenere Protokolle benötigen wir jedoch möglicherweise deutlich mehr Programmierung, um diese Zwischenprotokollschichten bereitzustellen, wie z. B. Fehlererkennung und -behandlung auf Busebene, Paketerstellung und -analyse, Behandlung verschiedener Arten von Paketen usw.
Wie wir gesehen haben, spielt Timing eine sehr wichtige Rolle bei der Entwicklung einer Protokollimplementierung. Daten- und Taktleitungen müssen in genauen Abständen aktualisiert werden. Beim Dekodieren eines Protokolls ist es wichtig, die gleichen Intervalle genau zu messen. Es ist wichtig, das Timing-Verhalten des FPGAs im Auge zu behalten, wenn wir Kommunikationsprotokolle entwickeln, um sicherzustellen, dass unsere Implementierung die Anforderungen und Spezifikationen des Protokolls erfüllt.
Der FPGA arbeitet mit einer Grundtaktfrequenz und alle Timing-Funktionen basieren auf derselben Taktrate. Für LabVIEW FPGA ist die Standardtaktfrequenz 40 MHz, so dass jede Taktperiode und Zeiteinheit 25 Nanosekunden (ns) beträgt. In LabVIEW FPGA können Zeitintervalle für die Timing-Funktionen in Millisekunden, Mikrosekunden und Takten angegeben werden. Jeder Takt entspricht einer Taktperiode oder 25 ns. Dies bedeutet, dass die höchste Auflösung für die Angabe einer Verzögerung oder Schleifeniterationszeit 25 ns beträgt. Das klingt zwar sehr genau, aber wenn wir die Umkehrung nehmen und die möglichen Frequenzen bestimmen, die wir erzeugen können, sehen wir den Effekt, den sie bei höheren Raten hat.
Um eine Aktualisierungsrate von 1 MHz für eine digitale Leitung zu erzeugen, können wir eine Schleifen-Timer-Funktion für 40 Takte verwenden.
1 MHz => 1 μs = 1000 ns
1000 ns / 25 ns pro Takt = 40 Takte
Was ist, wenn wir eine Update-Rate von 1,25 MHz wünschen?
1,25 MHz => 0,8 μs = 800 ns
800 ns / 25 ns pro Takt = 32 Takte
Für 1,25 MHz verwenden wir eine Verzögerung von 32 Takten. Was ist, wenn wir eine Update-Rate von 1,1 MHz wünschen?
1,1 MHz => 0,9091 μs = 909,1 ns
909,1 ns / 25 ns pro Takt = 36,36 Takte
Da wir keine bestimmten Teiltaktperioden auswählen können, müssten wir 36 Taktperioden wählen, was einer Verzögerung von 900 ns entspricht und einer Frequenz von 1,11 MHz entspricht. Die nächsttiefere Frequenz ist 37 Takte oder 1,081 MHz. Wir sehen also, dass wir mit dem 40 MHz FPGA-Takt die digitalen Leitungen mit 1,081 MHz oder 1,111 MHz aktualisieren können, aber nicht zwischendurch.
Mit Hilfe der FPGA-Eigenschaften und Taktressourcen im LabVIEW Projekt können wir die Grundtaktfrequenz auf 80 oder 120 MHz ändern. Dadurch wird der FPGA mit einer höheren Frequenz betrieben und die Timing-Auflösung der Timing-Funktionen verbessert. Die höhere Taktfrequenz verringert jedoch auch die Komplexität, die im FPGA-VI-Diagramm verwendet und erfolgreich für den FPGA kompiliert werden kann.
Bei der Implementierung eines zeitgesteuerten Protokolls müssen Sie feststellen, ob die Timing-Auflösung des FPGAs den Anforderungen des Protokolls und der Anwendung entspricht. Dies ist besonders wichtig für das Timing, das erforderlich ist, um ein Protokoll zu erzeugen, wie die vorherigen Berechnungen gezeigt haben. Zum Lesen und Dekodieren von Protokollen ist es oft ausreichend, die Signalleitungen mit einer höheren Rate als der höchsten Aktualisierungsrate des Protokolls lesen zu können. Wir sollten die Signale mindestens doppelt so schnell abtasten können wie die Update-Rate.
Wenn wir Zeitmessungen an einem Eingangssignal durchführen müssen, um die im Protokoll enthaltenen Daten zu dekodieren, müssen wir zusätzliche Berechnungen durchführen, um die Timing-Auflösung zu bestimmen, die für die genaue Dekodierung des Protokolls erforderlich ist.
Zustandsautomaten können eine nützliche Technik sein, um die Kodierung oder Dekodierung eines digitalen Kommunikationsprotokolls zu implementieren. In LabVIEW können Zustandsautomaten einfach mit Hilfe der While-Schleife und einer Case-Struktur zur Darstellung der verschiedenen Zustände implementiert werden.
Der Zustandsautomat hilft bei der Entwicklung von Kommunikationsprotokollen, da er das Timing-Diagramm natürlich in separate Schritte aufteilt und wir jeden in einen separaten Zustand im LabVIEW FPGA-Diagramm umwandeln können. Dadurch wird jeder Programmschritt isoliert und der Programmieraufwand in jedem Teil der Implementierung reduziert. Darüber hinaus vereinfacht es allgemeine Operationen wie die Fehler- und Ausnahmebehandlung, da wir von einer beliebigen Stelle in der Protokollausführung zu speziellen Fehlerbehandlungszuständen wechseln können. Manchmal werden Protokollspezifikationen als Zustandsautomaten geschrieben, die direkt in ein LabVIEW Zustandsdiagramm übersetzt werden können.
Für das SPI-Timing-Diagramm in Abbildung 1 sind die folgenden Schritte eine Möglichkeit, das Timing-Diagramm in einen Zustandsautomaten zu unterteilen.
Wir bemerken, dass es fünf verschiedene Schritte gibt, obwohl einige davon für jedes Datenbit wiederholt werden. Ursprünglich haben wir diese sich wiederholenden Schritte in einer For-Schleife implementiert. Im Zustandsautomaten erstellen wir für jeden dieser fünf Schritte einen eindeutigen Zustand und durchlaufen ihn anschließend. Für die drei sich wiederholenden Schritte, die die Datenleitung aktualisieren und die Taktleitung umschalten, konfigurieren wir den Zustandsautomaten so, dass er diese Sequenz 16 Mal wiederholt, bevor wir mit dem letzten Schritt fortfahren. Im LabVIEW Zustandsautomaten wird dies durch einen Zähler in einem Schieberegister der While-Schleife realisiert.
Ein weiterer Vorteil der Zustandsautomaten-Architektur besteht darin, dass sie es uns ermöglicht, eine Protokollimplementierung innerhalb einer LabVIEW FPGA Single Cycle Timed Loop (SCTL) zu implementieren. Die SCTL ermöglicht eine schnellere Ausführung des LV-FPGA-Diagramms, wodurch jeder Schleifenzyklus in einer Taktperiode ausgeführt werden kann. Dadurch können wir eine Signalleitung mit der FPGA-Grundtaktfrequenz aktualisieren. Die SCTL optimiert auch die Codeerzeugung, so dass der Code auf dem FPGA effizienter ist und weniger FPGA-Real Estate verwendet. Der in einer SCTL implementierte Code unterliegt jedoch mehreren Einschränkungen. So können wir beispielsweise nur einmal pro SCTL-Iteration auf jede Signalleitung zugreifen. Daher müssen wir die Zustände unseres Zustandsautomaten so definieren, dass wir jede Signalleitung nur einmal pro Zustand lesen oder aktualisieren.
Die folgenden Diagramme (Abbildung 13) zeigen die Implementierung des SPI-Ausgabeprotokolls mit Hilfe eines Zustandsautomaten in einer SCTL. Der Zustand "Ruhezustand" wartet, bis der Schreibbefehl die Ausgabe des nächsten Datenpakets startet. Außerdem wird der Datenwert für die Ausgabeoperation in ein boolesches Array umgewandelt. Der nächste Schritt Set CS aktiviert die ChipSelect-Leitung. Dann beginnen wir mit der Ausgabe der Datenbits. In Takt zurücksetzen aktualisieren wir die Datenleitung mit dem nächsten Bitwert und setzen das Taktsignal zurück. In Takt festlegen legen wir das Taktsignal fest, das den Empfänger zum Lesen des Datensignals triggert. In diesem Zustandspaar inkrementieren wir einen Zähler in einem Schieberegister, der den richtigen Datenwert aus dem booleschen Array auswählt, der an die Datenleitung gesendet werden soll. Nachdem wir das 16. Bit ausgegeben haben, gehen wir in den Zustand CS zurücksetzen über, wodurch alle Signalleitungen in den Ruhezustand des Busses zurückgesetzt werden. Von dort aus kehren wir in den Ruhezustand zurück und warten auf den nächsten Schreibbefehl.
Abbildung 13: Implementierung der SPI-Ausgabe in einer SCTL
Biphasenkodierung oder -modulation ist eine sehr gängige Art der Datenkodierung, die in vielen verschiedenen Protokollen verwendet wird. Es kombiniert das Datensignal und das Taktsignal in einer Signalleitung, wodurch der Verkabelungsbedarf reduziert und die Datenintegrität über längere Verkabelungsstrecken erheblich verbessert wird.