FPGA-Encoder-Zähler läuft zufällig weg

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?

schematisch

Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan

Der Block mit 4 Eingängen XORwird ausgeführt als:

(IN1 xor IN2) xor (IN3 xor IN4)

Die Signale Count enableund Count directiongehen 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.

AIch 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!

Verwenden Sie Schmitt-Trigger, um die Encoder-Eingänge vor dem FPGA zu bereinigen? Wenn nicht, benötigen Sie nach den Synchronisierregs (vor Reg 2/5 oben) eine digitale Entprellung auf A und B.
Hast du es mal mit "analoger" Entprellung versucht? Ein kleiner RC-Tiefpass reicht in den meisten Fällen aus. Verwenden Sie auch einen optischen Encoder? Was ist mit Umgebungslicht, das auf die Detektoren trifft? Dies kann zu einer unregelmäßigen Ausgabe des Encoders führen.
Der Encoder ist komplett gekapselt, und ich bin mir nicht sicher, ob er optisch ist. Ich glaube nicht, dass Interferenzen am Encoder das Problem sind, obwohl ich mich irren könnte. Ich werde mich mit Schmitt-Filtern und Entprellungen befassen. Danke schön.
Sie brauchen die Entprellschaltung nicht unbedingt außerhalb des FPGA - als ich das letzte Mal an einem Projekt gearbeitet habe, das einen Encoder benötigte, wurde der Entpreller vollständig in VHDL erstellt - ich erinnere mich, dass die vhdl-Komponente standardmäßig niedrig ausgegeben wurde, dann jedes Mal es Wenn er eine Eingangsspitze vom Hallsensor erhielt, gab er High (einmal) aus und ignorierte dann seinen Eingang vom Hallsensor vollständig , bis die Zeit X abgelaufen war, wobei X ein Wert war, der hoch genug war, um den Rückprall zu ignorieren, aber niedrig genug dafür ignorierte den nächsten Impuls nicht; etwa 1 ms.
@medivh danke. Es sieht so aus, als hätte ich ein paar Ideen zum Ausprobieren aus diesem Thread. Ich melde mich bei euch allen mit dem, was ich herausgefunden habe. Danke an alle!
@Engineero Normalerweise wird es als guter Stil angesehen, ein oder drei Tage zu warten, bevor Sie eine Antwort akzeptieren. Auf diese Weise haben mehrere Personen Zeit, Antworten zu geben, und Sie können die beste annehmen. Aber wenn Sie eine Antwort akzeptieren und später eine bessere Antwort kommt, können und sollten Sie die Antwort ändern, die Sie akzeptieren. Da es einen leichten Interessenkonflikt gibt, wenn ich das sage, möchte ich absolut klarstellen, dass die beste Antwort immer gewinnen sollte (auch wenn es nicht meine Antwort ist).
@DavidKessner Nun, ich habe die Antwort akzeptiert, weil ich sie auf meinem System implementiert habe und sie einwandfrei funktioniert hat. Ansonsten würde ich dir zustimmen, dass es am besten wäre, auf ein paar weitere Antworten zu warten.

Antworten (2)

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.

Das macht Sinn, und ich habe das auch schon versucht, aber nur mit einer Zählung von 2 und 4 Taktimpulsen. Ich habe es anders implementiert (mit einem Zähler, nicht mit einem Schieberegister), aber ich kann es auf Ihre Weise versuchen. Aus Neugier, warum setze ich es nach Reg1 und Reg4 und nicht davor (an den Roheingängen)?
Reg1, Reg4werden als Clock-Crossing-Synchronisierer verwendet, da die Eingänge Aund Bbezü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.
Welche Art von Register würde ich für das Ausgangsregister verwenden (zweiter Absatz Ihrer Antwort oben). Könnte ich dies mit einem DQ-Flip-Flop tun und die Daten- oder Taktanschlüsse einfach nicht verdrahten?
Es funktionierte! Meine Zählungen laufen nicht mehr weg und es scheint tatsächlich mit einem 4-Bit-Schieberegister gut zu funktionieren. Vielen Dank!
Eindrucksvoll! Die Ausgangsstufe wäre ein Standardregister, der D-Eingang wäre (Q & ~reset) | setwo set = & shift_reg_bits;und reset = ~ |shift_reg_bits;. Ich kenne LabVIEW nicht, das ist Verilog.
Oh, dieser Teil wird auf einem Altera-Board gemacht, also wird er in Quartus II programmiert. Ich könnte auch Verilog machen, wenn ich ehrgeizig wäre, aber es scheint jetzt zu funktionieren, und ich möchte es nicht stören. Nochmals vielen Dank!

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.

Habe ich das richtig verstanden, dass Sie die Zustände, die Ihr Quadratur-Encoder einnehmen kann, im Grunde fest codieren und dann den aktuellen Zustand des Encoders mit dieser Wahrheitstabelle vergleichen, um zu bestimmen, ob Sie die Zählung erhöhen, die Zählung verringern oder halten sollen stetig? Das macht für mich auch Sinn. Wenn ich Zeit habe, werde ich versuchen, dies zu implementieren und zu sehen, ob es noch besser läuft, aber die akzeptierte Antwort läuft einwandfrei und ich bin etwas in Zeitnot. Danke schön!
@Engineero Du verstehst richtig.
Bei einem mechanischen Encoder bezweifle ich, dass die erfassten Frequenzen außerhalb von 0-50 Hz liegen, mit vielleicht einem uS Sprung an jeder Flanke. Indem Sie durch Bounce gehen, verschieben Sie das Problem stromabwärts. Wenn Sie beispielsweise ein Schneidwerkzeug positionieren oder einen Selbstzerstörungs-Timer mit einem Jog-Dial einstellen, würden Sie wahrscheinlich kein Überschwingen des Sollwerts aufgrund von Prellen tolerieren. Ich würde zuerst die Eingangssignale bereinigen - vorzugsweise außerhalb des FPGA, bis ich wusste, dass ich logische Ressourcen übrig hatte, um die Stückliste zu trimmen.