Hallo Zusammen, Wir haben hier jetzt mal ein erstes Projekt auf einem FPGA zum laufen bekommen. Nun würden wir uns freuen, wenn die Profis mal drüber schauen würden und die ganz groben Schnitzer aufzeigen könnten. Rahmenbedingungen: In dem Projekt handelt es sich um eine Winkelerfassung mit Quadratur-Ausgabesignal. Da das ganze recht zügig mit etwa ~40Hz rotiert und eine Auflösung von min. 0,1° haben soll sind wir auf einen FPGA (Dev-board mit Cyclon IV, später MAX10) gegangen. Aus dem Analogteil kommen drei Rechtecksignale mit 4MHz, einmal "Referenz", einmal "Winkel" und einmal "Winkel_90"(mit konstant 90° Phasenversatz zum Winkelsignal). Der Phasenversatz zwischen Referenz und Winkelsignal entspricht einem Winkel von maximal 10°. Insgesamt gibt es für eine volle Umdrehung also 36 mal diesen 10° Bereich. Im ersten Schritt werden die Signale einsynchronisiert und daraus über einen NCO ein etwas geglättetes Signal im FPGA erzeugt. Dann wird aus dem Referenz- und dem Winkelsignal ein XOR gebildet und dieses mit 200MHz gezählt. Anschließend wird daraus ein Zählwert von 0-3600 generiert und das Quadratursignal entsprechend erzeugt (Schritt vor, Schritt zurück). Es gibt ja doch ein paar Fallstricke beim ersten FPGA-Projekt, Latches, Timing, .... soweit bekannt und verstanden wurde das berücksichtigt. Es gibt aber sicher trotzdem Verbesserungspotential. Grundsätzlich läuft die Sache inzwischen und jetzt geht es an den Feinschliff. Besonders interessant wäre für uns: - Fehler/unsaubere Programierung beseitigen - Höhere Auflösung, d.h. schnellerer Zähler - Glättung des Signals durch mehr Mittelung Vielen Dank für eure Mühe und frohe Festtage! Fabian P.S. Um die ganze Sache mit nur einer Clock-Domain (200MHz) zum laufen zu kriegen, wurden diverse Zwischenregister eingefügt und das ganze manchmal "sequentiell" (signal "step") programmiert (ja ich weiß... beschrieben). Nur als Vorwarnung, dass die ganzen FPGA Experten hier nicht gleich vom Stuhl fallen;-)
Fabian N. schrieb: > Im ersten Schritt werden die Signale einsynchronisiert Das ist ein netter Schuss ins Knie:
1 | if rising_edge(clk) then |
2 | input_1 <= input_async_1; -- einsynchronisieren durch FlipFlop |
3 | input_1_inv <= not input_async_1; |
Nimm mal an, dass die beiden Flipflops input_1 und input_1_inv so verdrahtet werden, dass die Laufzeiten t1 und t2 vom asynchronen Eingang zu den beiden Flipflops unterschiedlich lang sind:
1 | |
2 | t1->kurz |
3 | input_async_1 -------o---------------------------------|D FF1 input_1 |
4 | | _____ _____ clk|> |
5 | | | | | | |
6 | | | | | | |
7 | | | | | | |
8 | | | | | | |
9 | | | | | | |
10 | |______| |_____| '-------O|D FF2 input_1_inv |
11 | t2->lang clk|> |
Was passiert dann einmal pro Minute, Stunde, Tag, Woche, wenn sich der Pegel am input_async_2 etwa mit der Taktflanke ändert?
1 | ____ ____ ____ ____ ____ |
2 | clk ____| |____| |____| |____| |____| |___ |
3 | _______________ : _____________ |
4 | input_async_1 _______| : |________________| : |
5 | :t1 : : : : |
6 | v_______________ : : ____________ |
7 | D von FF1 ________| : |________________| : |
8 | :t2 : : : : |
9 | __________v : : ________________ : |
10 | D inv von FF2 |_______________| : |__________ |
11 | :_________: : :________ |
12 | Q von FF1 _______________| |___________________| =input_1 |
13 | _______________: :________: |
14 | Q von FF2 |____________________| |_____=input_1_inv |
15 | ????????? |
16 | beide gleich |
Richtig: beide Flipflops haben für 1 Taktzyklus den gleichen Pegel. Und dann kommt es drauf an, wie der Rest der Schaltung auf so einen Fehler reagiert. Hintergrund: http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html Also: zuallererst ganz am Anfang das Signal einsynchronisieren. Und dann synchron weiterverarbeiten und ggfs. duplizieren/negieren. Und damit nicht die Toolchain dieses Einsynchronisierflipflop "automatisch" verdoppelt, würde ich da 2 Sync-Flipflops hintereinander schalten. Aber warum machst du eigentlich aus 1 Eingang 2 Signale? Du kannst beim Portmapping ja auch invertierte Signale verdrahten. Das hier sieht mir auch nach einen Fehler aus: integer range -1023 to 1023; Ich hätte da erwartet: integer range -1024 to 1023; Und wofür ist der Automat in qdec_output_counter? Brauchst du da die Verzögerung von 4 Takten vom Start bis zum Ergebnis vom o_qdec_counter? Das input_xor wäre mir kein eigenes Modul wert. Da werden doch nur 2 Bits miteeinander verXORt, das geht doch mit 1 Zeile auch einfach dort, wo man es braucht.
:
Bearbeitet durch Moderator
Zur Form: - Registrierte Signale (d.h. FFs) evtl. schon beim Definieren Wert zuordnen, nicht erst beim Reset im Prozess. - Wertezuweisungen an Signale (z.B. im Reset-Teil) besser per vordefinierter Konstante, statt per "0000...0000". Z.B. hat eine Typänderung mehrere Editierschritte zur folge und ist somit fehleranfälliger. - Reset-Signale in der Abhängigkeitsliste beim Prozess-Start ist bei dir überflüssig: du resettest immer synchron (gut!). - In einigen Prozessen hast du den Reset-Teil am Anfang, in anderen am Ende: mach alle Reset-Teile am Anfang. - Einige Prozesse verwenden Variablen: darauf kann man idR verzichten, macht auch das Debuggen im Simulator einfacher. - Instantiierungen der Unterkomponenten bitte nur per Names-Parameter, und jeweils ein Port je Zeile: a => upper_a, b => upper_b, etc. - etc. Zum Design: - Ich habe nicht die Zeit, alles zu überschauen, aber grob von der Funktionalität würde ich sagen, dass einiges zu kompliziert ausgedrückt wurde, evtl. auch die Zuordnung in die einzelnen Komponenten. Aber es geht auch viel schlechter. - Nichtverwendete Pins (insbes. Outputs) bitte mitdefinieren und geeignet zuordnen (z.B. SRAM-#WE per <= "1").
Vielen Dank euch beiden und sorry für die späte Rückmeldung! @Lothar Ja, das mit der Eintaktung war natürlich ne grandiose Leistung... In dem Moment wo ich deinen Satz angefangen habe zu lesen, ist es mir dann auch schon gedämmert... ist beseitigt. Die Integer-Range passt natürlich auch nicht und ob die 4 Takte im qdec_output_counter nötig sind, prüfe ich nochmal. Möglicherweise sind die auch nur ein Überbleibsel von anderen/vorhergehenden Versionen, wo ich diese benötigt habe. @Sigi Du hast recht, da sind einige Code-technische Unsauberkeiten (Reset an Anfang/Ende gemischt, ...)die werden alle noch beseitigt. Primär ging es mir um die FPGA-typischen Fallstricke wenn man von der µC-Schiene kommt. Die Sache mit der "Instantiierungen der Unterkomponenten..." hab ich noch nicht ganz verstanden. Was meinst du hiermit? @all Gibt es noch Ideen/Vorschläge wie ich mehr Auflösung generieren könnte? Also im Prinzip wie ich mehr Zählwerte zwischen den beiden Flanken des eingetakteten Rechtecksignals bzw. dem NCO bekomme? Ich denke mit der allgemeinen Taktfrequenz hochgehen wird nur noch geringfügig gehen, der Max10 kann glaub auch gar nicht mehr viel schneller. Gibt es da irgendwelche schnelleren FPGA-Peripherals die man für sowas verwenden kann? Oder eben weitere Ideen? Vielen Dank schonmal und beste Grüße, Fabian
Fabian N. schrieb: > Also im Prinzip wie ich mehr Zählwerte zwischen den beiden Flanken des > eingetakteten Rechtecksignals bzw. dem NCO bekomme? Das klingt nach dem klassischen Problem: Wie erhöhe ich die Samplerate? a) Wenn sich der System-Takt nicht mehr erhöhen lässt, dann kann man mit mehreren Phasen des Taktes abtasten. Z.B. Diese 4 Takte per DCM/PLL erzeugen: 200 MHz +0°, +90°, +180°,+270°. Das erhöht die Abtastrate um den Faktor 4. Die Auswertelogik wird natürlich etwas komplizierter. Etwas einfacher: Mit einem IDDR-FF tastest du beide Flanken ab und bekommst immerhin schon den Faktor 2. b) ISERDES (Xilinx, Intel hat sicher etwas ähnliches). Diese lassen sich wesentlich höher Takten und geben dir die Werte parallel. c) externes-Samplemodul oder GTX-Serdes (CDR wird arretiert)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.