Ich programmiere ein Altera FPGA mit Quartus II v9.0, um Encoder-Impulse zu zählen und diese Zählung an ein externes LabVIEW-Programm auszugeben (siehe Diagramm unten). Ich konnte dank der StackExchange-Community ein Problem mit meinem Code debuggen , aber jetzt bekomme ich zeitweise einen Runaway in meiner Encoder-Zählung.
Wenn ich meinen Encoder bewege, zeigt mein LabVIEW-Code den aktuellen Zählerstand korrekt an. Wenn ich aufhöre, den Encoder zu bewegen, stoppt die Zählung etwa die Hälfte der Zeit, und die andere Hälfte der Zählung läuft einfach weg. Ich vermute, dass der Encoder in einem Zwischenzustand hängen bleibt und eine meiner Phasen flattert. Gibt es einen Trick, mit dem ich dies herausfiltern kann, oder eine bessere Methode zum Zählen von Encoderimpulsen, die ich in mein Altera-FPGA programmieren kann?
Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan
Der Block mit 4 Eingängen XOR
wird ausgeführt als:
(IN1 xor IN2) xor (IN3 xor IN4)
Die Signale Count enable
und Count direction
gehen in eine eingebaute 32-Bit-Zählerfunktion ( LPM_COUNTER
) auf meinem Altera FPGA ein, das mit Quartus II v9.0 programmiert wurde. Die Ausgabe dieses Zählers wird in einem Puffer ( LPM_BUSTRI
) gespeichert und mit einem LabVIEW-Programm gelesen, wann immer der LabVIEW-Code dies benötigt. Ich habe einen ähnlichen LabVIEW-Code, der andere Puffer aus dem FPGA liest, der gut funktioniert, daher bin ich mir ziemlich sicher, dass das Problem irgendwo in meinem FPGA liegt.
A
Ich habe versucht, den Signalen und eine Triggerverzögerung hinzuzufügen B
, die nur dann eine Änderung des Signals registriert, wenn dieses Signal für eine bestimmte Anzahl von Taktzyklen hoch oder niedrig geblieben ist (ich habe bisher 2 und 4 versucht). Dies schien das Problem zu verschlimmern. Ich habe auch versucht, einen vierten Satz DQ-Flip-Flops hinzuzufügen, was keinen offensichtlichen Effekt hatte.
Ich danke Ihnen für Ihre Hilfe!
Erfassen Sie die Eingabe und nicht den Zähler, um zu sehen, ob Bounce Ihr Problem ist. Wenn Sie über einen Speicherbereich verfügen, verwenden Sie den Flankentrigger, um die Erfassung zu erhalten. Versuchen Sie andernfalls, eine Entprellung zwischen Reg1/Reg2 und zwischen Reg4/5 hinzuzufügen.
Um dies zu implementieren, verwenden Sie ein 8- oder 16-Element-Schieberegister, das von synchronisiertem A gespeist wird. Nehmen Sie das UND und das ~ ODER zwischen allen Schieberegisterbits, diese geben Ihnen die Signale "alles gesetzt" und "alles gelöscht". Verwenden Sie dies als Set und Reset eines Ausgangsregisters, das REG2 speisen würde. Gleiches gilt für B -> REG 5.
Wenn Sie immer noch Störungen feststellen, können Sie entweder einen niedrigeren Takt versuchen oder das Schieberegister erweitern. Oberhalb von 16 Stufen ist es wahrscheinlich besser, als Binärzähler und Last-State-Bit umzugestalten. Bei jedem Zyklus, wenn sich der Zustand vom letzten unterscheidet, Rücksetzen des Zählers und Aktualisieren des letzten Zustands. Wenn der Zähler überläuft, ohne gelöscht zu werden, ist dies Ihr Auslöser, um den Ausgang zu setzen/zurückzusetzen.
Reg1
, Reg4
werden als Clock-Crossing-Synchronisierer verwendet, da die Eingänge A
und B
bezüglich asynchron sind CLK1
. Das erkennt man daran, dass sie nichts anderes tun, als die Signale um einen Zyklus zu verzögern. Da Sie möchten, dass sich die maximal verfügbare Einrichtungszeit für die Metastabilität zwischen den Synchronisiererstufen einpendelt, möchten Sie keine Zwischenlogik, die eine Routing-Verzögerung hinzufügt. Wenn der Synchronisierer irgendetwas erreicht, möchten Sie außerdem, dass diese Logik das saubere Signal nach dem Synchronisierer verwendet.(Q & ~reset) | set
wo set = & shift_reg_bits;
und reset = ~ |shift_reg_bits;
. Ich kenne LabVIEW nicht, das ist Verilog.Tut mir leid, ich hätte früher darauf geantwortet, aber ich war nicht in der Stadt und hatte nur begrenzten Internetzugang. Ich sehe, dass Shuckc dies bereits beantwortet hat, aber ich habe das Gefühl, dass ich eine Lösung habe, die überlegen wäre.
Das Problem beim Entprellen und/oder Filtern von A und B besteht darin, dass es Ihren Decoder daran hindern kann, mit maximaler Geschwindigkeit zu arbeiten (und somit Zählwerte zu verpassen), es komplizierter macht, die Logikgröße erhöht und vor allem nicht erforderlich ist.
Beginnen Sie damit, die sechs Register, die Sie bereits in Ihrem Schaltplan haben, beizubehalten. Nennen wir die Ausgabe von Reg2 und Reg5 als A und B. Die Ausgabe von Reg3 und Reg6 heißt A_prev und B_prev – was im Grunde der Wert von A und B für die vorherige Uhr ist.
Als Nächstes erstellen Sie eine Wahrheitstabelle in etwa so:
A_prev, B_prev, A, B, Count_En, Count_Dir
0 0 0 0 0 0
0 0 0 1 1 0
...etc...
Sie müssen die gesamte Wahrheitstabelle selbst ausfüllen, aber Sie bekommen die Idee. Grundsätzlich sehen Sie sich den aktuellen Zustand von A und B zusammen mit den vorherigen Werten für A und B an und entscheiden, ob Sie Ihren Zähler erhöhen oder verringern möchten. Jetzt erstellen Sie eine Logik, um diese Wahrheitstabelle zu implementieren. Ich empfehle, dass Sie auch die Ausgabe dieser Wahrheitstabelle registrieren, bevor Sie die Signale an den Zähler senden.
Diese Wahrheitstabelle passt in ein Paar LUTs mit 4 Eingängen (der Grundbaustein der meisten FPGAs). Im Wesentlichen ist dies super klein. Das Registrieren der Ausgabe dieser Wahrheitstabelle erfordert auch im Wesentlichen keine Logik, da jede LUT im FPGA ein Flip-Flop an den Ausgängen der LUTS hat. Vergleichen Sie dies mit einer Filterung/Entprellung, die 16 oder 32 Flip-Flops benötigen könnte und die Nützlichkeit der nicht verwendeten LUTs einschränkt. Diese Logik ist also 1/16 oder 1/32 der Größe der gefilterten/entprellten Version.
Wenn Sie ein neueres FPGA verwenden, das über eine LUT mit 6 Eingängen verfügt, die in zwei kleinere LUTs aufgeteilt werden kann, verbraucht dieses Design noch weniger Logikressourcen.
Die Registrierung des Ausgangs ermöglicht es Ihrer Logik, auf den meisten halbwegs modernen FPGAs mit mehr als 100 MHz zu laufen, oder macht es viel einfacher, Ihre Timing-Einschränkungen zu erfüllen, wenn Sie mit langsameren Taktraten arbeiten. Dies klingt zwar nicht wichtig, kostet aber nichts und verbessert die Robustheit dieses Designs erheblich und ermöglicht eine einfachere Wiederverwendung in zukünftigen Projekten, in denen Ihre Hauptuhr schneller ist.
Das Schöne an diesem Design ist, dass sich A_in oder B_in buchstäblich bei jeder Flanke Ihres 25-MHz-Takts ändern können. Wenn Sie ein wenig Rauschen oder Prellen an Ihren Eingängen haben, kann dies dazu führen, dass Ihr Zähler zwischen zwei benachbarten Signalen hin und her "vibriert", aber dies würde / könnte auch mit einer gefilterten / entprellten Version passieren.
Der Grund, warum dieses Design A und B nicht filtern/entprellen muss, liegt darin, dass es so schnell arbeiten kann, wie es Ihr 25-MHz-Takt zulässt. Es kann nicht durch eine sich schnell ändernde oder laute Eingabe verwirrt werden, wie es Ihr vorheriges Design könnte.
Ein Lieblingsärgernis von mir ist die schlecht implementierte Quadraturdekodierung. Normalerweise ist es eine schlechte Software-Implementierung, die dazu führt, dass der Decoder Impulse verpasst oder überspringt, aber gelegentlich tut dies auch eine Hardware-Implementierung. Ich sage nicht, dass das Filtern / Entprellen der Quadratureingänge Impulse überspringen wird, aber ich sage, dass dieser Ansatz in jeder Hinsicht besser ist, einschließlich der maximalen Geschwindigkeit, mit der er Impulse akzeptieren kann.
shuckc
JimmyB
Ingenieur
Schildfoss
Ingenieur
Benutzer3624
Ingenieur