Forum: FPGA, VHDL & Co. VHDL Impulszähler spinnt


von Maximilian L. (mex_1991)


Lesenswert?

Guten Vormittag,

ich habe versucht, einen Impulszähler zu realisieren, sprich:
Man drückt einen Taster, dann soll sich der Wert auf insg. zwei 
7-Segment-Anzeigen um 1 erhöhen.

Wow, das muss echt einfach sein -dachte ich.

Jetzt hab ich jedoch das Problem, dass beim Drücken des Tasters der 
Zähler immer woanders landet , d.h. mal wird "07". mal "23"  usw. 
angezeigt, obwohl von "00" gestartet wurde.

Ich will aber, dass der Wert sich immer nur um 1 erhöht. Wieso es nicht 
so passiert, weiß ich nicht genau aber ich habe eine Vermutung:

Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu 
oft aufgerufen. Der Taster bleibt ja paar Millisekunden oder so 
gedrückt, deswegen wird zu oft hochgezählt.

Ist das richtig so? Kann ich das Problem lösen, indem ich den Takt von 
50Mhz auf zb 2Hz reduziere?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu
> oft aufgerufen. Der Taster bleibt ja paar Millisekunden oder so
> gedrückt, deswegen wird zu oft hochgezählt.
Kommt drauf an, wie deine Beschreibung aussieht...

> Ist das richtig so? Kann ich das Problem lösen, indem ich den Takt von
> 50Mhz auf zb 2Hz reduziere?
Vermutlich ja, das ist aber völliger Murks.
Der richtige Weg ist es, den Taster zu entprellen und eine 
Flankenerkennung drauf zu setzen. Es gibt hier im Forum zig Diskussionen 
dazu.

> Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu
> oft aufgerufen.
In der Hardware wird da nirgends irgendein "Prozess aufgerufen". Sondern 
es wird deine Hardwarebeschreibung vom Synthesizer in Flipflops und LUTs 
übersetzt, dann vom Placer platziert, vom Router verdrahtet und vom 
BitGen in einen Bitstrom umgewandelt, der dann ins FPGA geladen wird. 
Sieh dir also mal den RTL-Schaltplan an, dann siehst du, was der 
Synthesizer gemacht hat und kannst kontrollieren, ob das dem entspricht, 
was du eigentlich beschreiben wollstest.

: Bearbeitet durch Moderator
von Thorsten S. (thosch)


Lesenswert?

Da fehlen wohl zwei Vorgänge in deinem unbekannten VHDL-Code:
1. Signal vom Taster entprellen
z.B. mit einem Zähler, der losläuft, sobald der Taster gedrückt ist und 
zurückgesetzt wird, sobald der Taster nicht gedrückt ist.
Bei einem bestimmten Zählerstand (höchstwertiges Bit nehmen!) stoppt der 
Zähler und dieses Stop-Signal ist das entprellte.

2. Entprelltes Signal differenzieren
mit Gatter über ein FlipFlop, so daß 1 geliefert wird, solange am FF 
Input das Signal 1 ist, am FF Output aber noch 0.

Dieses Signal als CE für deinen Zähler und das funktioniert.

von Maximilian L. (mex_1991)


Lesenswert?

Danke soweit.

Ich denke ich mache es folgendermaßen:

Ich werde einfach die vier möglichen Tasterzustände abfragen.
Diese Lösung scheint mir am einfachsten.

Orientiert habe ich mich hier 
https://www.mikrocontroller.net/articles/Entprellung ab 
"Flankenerkennung".

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> Ich werde einfach die vier möglichen Tasterzustände abfragen.
Du solltest dabei übrigens beachten, dass asynchrone Eingänge erst mal 
eingetaktet werden müssen:
http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html
Sonst passiert dir schnell mal das da:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html

> Ich denke ich mache es folgendermaßen:
> Ich werde einfach die vier möglichen Tasterzustände abfragen.
Ein Tipp aus der Praxis: verwende von Anderen nur solchen Code, den du 
auch selbst zu 100% verstanden hast. Im Zweifelfall suchst du nämlich 
auch selbst nach dem Problem.

> Diese Lösung scheint mir am einfachsten.
Die Sache mit Google ist dir schon mal zu Ohren gekommen?
https://www.google.com/search?q=taster+entprellen+vhdl
Und von dort aus dann z.B. das 
http://www.lothar-miller.de/s9y/categories/5-Entprellung

: Bearbeitet durch Moderator
von Maximilian L. (mex_1991)


Lesenswert?

Alles klar,

haben Sie noch einen Tipp wie weit der Verzögerungszähler bei 50MHz 
zählen sollte?

Ich schätze einfach mal aus dem Bauch:  bis 25.000.000 -> dann sollte 
ein Drücken jede halbe Sekunde funktionieren, oder?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> Ich schätze einfach mal aus dem Bauch:  bis 25.000.000 -> dann sollte
> ein Drücken jede halbe Sekunde funktionieren, oder?
Ein Taster, der eine halbe Sekunde braucht, "fühlt" sich nicht gut an. 
Er lässt sich nur sehr holprig bedienen.
Und zudem prellt kein halbwegs funktionierender Taster für eine halbe 
Sekunde. Ich würde da bestenfalls 50ms ansetzen.

> wie weit der Verzögerungszähler bei 50MHz zählen sollte?
Also muss der Zähler 50ms/20ns = 2_500_000 Schritte zählen und somit von 
0 bis 2499999 laufen.

von Maximilian L. (mex_1991)


Angehängte Dateien:

Lesenswert?

Ich bin leider gescheitert das richtig umzusetzen. Vielleicht hat jemand 
Lust sich den Code mal anzusehen und den Fehler zu finden.
Der Impulszähler springt weiterhin um zu viele Schritte nach vorne...

von Duke Scarring (Gast)


Lesenswert?

Jetzt wäre der richtige Zeitpunkt eine Testbench aufzusetzen und sich 
das Verhalten des Codes mal im Simulator anzuschauen.

von Maximilian L. (mex_1991)


Lesenswert?

Ich hab sowas leider nicht

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Die beigefügte Beschreibung dürfte sich überhaupt nicht synthetisieren 
lassen, da das Signal V_BT überhaupt nicht existiert. Zudem wurde auch 
nicht Lothars Hinweis beachtet, dass Eingangssignale einsynchronisiert 
werden müssen; dies ist um so wichtiger, weil der Wert von BT(1) an 
mehreren Stellen verwendet wird.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Duke Scarring schrieb:
> Jetzt wäre der richtige Zeitpunkt eine Testbench aufzusetzen und sich
> das Verhalten des Codes mal im Simulator anzuschauen.

Wobei sich da natürlich sofort die Frage stellt: hat jemand mal paar 
schöne Modelle von prellenden Tastern zur Hand, mit der man die 
Testbench bestücken kann?

Ist das irgendwie sowas?
1
  process
2
  is begin
3
    taster(0) <= '0';
4
    wait for .5 ms;
5
    taster(1) <= '1';
6
    wait for .3 ms;
7
    taster(0) <= '0';
8
    wait for 3 ms;
9
    taster(0) <= '1';
10
    wait for .4 ms;
11
    taster(0) <= '0';
12
    wait for length_of_this_keypress;
13
    taster(0) <= '1';
14
    wait for .5 ms;
15
    taster(0) <= '0';
16
    wait for .3 ms;
17
    taster(0) <= '1';
18
    wait;
19
  end process;

: Bearbeitet durch Moderator
von Maximilian L. (mex_1991)


Lesenswert?

Andreas S. schrieb:
> Die beigefügte Beschreibung dürfte sich überhaupt nicht synthetisieren
> lassen, da das Signal V_BT überhaupt nicht existiert. Zudem wurde auch
> nicht Lothars Hinweis beachtet, dass Eingangssignale einsynchronisiert
> werden müssen; dies ist um so wichtiger, weil der Wert von BT(1) an
> mehreren Stellen verwendet wird.

Stimmt, dieses "V_" gehört da nicht hin. Beim Testlauf hatte ich das da 
noch nicht stehen. Mein Fehler

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> Ich hab sowas leider nicht

Deswegen musst Du Testbench ja auch selbst erstellen. Möglicherweise 
besitzt Dein FPGA-Entwicklungswerkzeug sogar die Möglichkeit, zu einem 
HDL-Quelltext auf Knopfdruck den Rumpf der zugehörigen Testbench zu 
erstellen.

von Maximilian L. (mex_1991)


Angehängte Dateien:

Lesenswert?

Danke euch,

ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und 
zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum 
metastabilen Zustand kommen

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Jörg W. schrieb:
> Ist das irgendwie sowas?
Ich habe gerade kein Bild von 'echtem' Prellen da, das sieht i.d.R. noch 
viel  wilder aus, aber für die Simulation kann man das gelten lassen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und
> zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum
> metastabilen Zustand kommen

In Deinem Quellcode hast Du nach wie vor einen nicht einsynchronisierten 
Reset, den Du zudem noch als asynchronen Reset eines getakteten 
Prozesses verwendest. Schlimmer geht es kaum. Zwar werden in Deinem 
konkreten Projekt mögliche Probleme nur sehr, sehr selten auftreten, und 
wenn sie auftreten, dass nur so kurzzeitig, dass Du sie vermutlich nicht 
einmal bemerken könntest, aber trotzdem ist das ganze nicht sauber.

von Maximilian L. (mex_1991)


Angehängte Dateien:

Lesenswert?

Vielen Dank, das habe ich außer Acht gelassen. Da der Reset hier nicht 
wirklich notwendig ist, werde ich ihn ganz weglassen.

Im Anhang der verbesserte Code ohne den Reset

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Duke Scarring schrieb:
> Jörg W. schrieb:
>> Ist das irgendwie sowas?
> Ich habe gerade kein Bild von 'echtem' Prellen da, das sieht i.d.R. noch
> viel  wilder aus, aber für die Simulation kann man das gelten lassen.

Da fällt mir doch gerade ein: habe vor längerer Zeit mal ein paar 
Dreh-Encoder am Logic Analyzer aufgezeichnet. Habe mal von zweien die 
Daten in eine VHDL-Testbench umgewandelt. Falls jemand also real 
prellende Kontakte haben oder seine Encoder-Entprellung mit realen Daten 
simulieren möchte: hier sind sie. ;-)

(Für einen einfachen Kontakt nimmt man einfach eine Spur eines der 
Encoder, oder schneidet sich nur ein paar Teile aus dem Code aus.)

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und
> zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum
> metastabilen Zustand kommen
Bei einer Taktfrequenz von 50MHz gibt es absolut keine relevanten 
metastabilen Zustände. Heutige Flipflops schaffen es locker, sich 
innerhalb von 2..3ns zu "beruhigen". Deshalb muss das Thema 
"Metastabilität" bei Taktfrequenzen bis zu 300MHz überhaupt nicht in 
Betracht gezogen werden.

Warum man trotzdem einsynchronisieren muss? Das steht in aller 
Ausführlichkeit im Link, den ich zum Thema "FSM mit asynchronem Eingang" 
weiter oben schon gepostet habe. Das, was dort besprochen wird, hat 
wiederum überhaupt nichts mit Metastabilität zu tun. Und solche Fehler 
können und werden auch schon bei niedrigsten Taktfrequenzen passieren.

Maximilian L. schrieb:
> Im Anhang der verbesserte Code ohne den Reset
In einem getakteten Prozess kommt nach dem getakteten Block nicht noch 
irgendwelcher kombinatorischer Klimbim, von dem ohnehin keines der 
Signale in der Sensitivliste auftaucht. Eine derart unvollständige 
Sensitivliste sorgt zuverlässig dafür, dass die Simulation nicht zur 
Hardware passt. Der Synthesizer sagt dir das auch, wenn du die Infos und 
Warnungen mal genau anschaust.

> if ... and taster_old='0' then
taster_old ist immer '0'...

: Bearbeitet durch Moderator
von Maximilian L. (mex_1991)


Lesenswert?

Danke für die Info, dass der kombinatorische Kram vor/nach den Prozess 
gehört.
Ich werde den kombinatorischen Kram wahrscheinlich dann einfach in ein 
Untermodul packen.

Ist das Vorhandensein des kombinatorischen Klimbims denn auch wirklich 
ein Problem, dass für die Fehlfunktion sorgt? Also ist das der Grund 
wieso der
Zähler beim Drücken des Tasters zu weit hochzählt? Das könnte ich mir 
nämlich nicht vorstellen.

Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."?

Sorry für die ganzen Nachfragen, der Einstieg in VHDL fällt mir wegen 
der ganzen anderen Programmiersprachen etwas schwierig.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maximilian L. schrieb:
> Ich werde den kombinatorischen Kram wahrscheinlich dann einfach in ein
> Untermodul packen.
Sieh dir an, wie man das nebenläufig (concurrent) beschreibt. Und wenn 
du einem 7 bit breiten Vektor ein 7 Bit breiten Wert zuweist, dann 
brauchst du keinen Range angeben:
1
    if (einer=0) then segmentoutput3(6 downto 0) <= "1000000";  
2
    elsif (einer=1) then segmentoutput3(6 downto 0) <= "1111001";
3
    elsif (einer=2) then segmentoutput3(6 downto 0) <= "0100100";
kann so abgekürzt werden:
1
    if    (einer=0) then segmentoutput3 <= "1000000";  
2
    elsif (einer=1) then segmentoutput3 <= "1111001";
3
    elsif (einer=2) then segmentoutput3 <= "0100100";
Und wenn du nicht jedem Signal noch den Namen "out" oder "output" gibst, 
obwohl es kein FPGA-Ausgang ist und unnötige Zwischensignale weglässt, 
dann wird das Ganze noch lesbarer.
1
  seg4 <= "1000000" when einer=0 else
2
          "1111001" when einer=1 else
3
           :
4
          "0000000" when digit=8 else
5
          "0010000";
6
7
  seg5 <= "1000000" when zehner=0 else
8
          "1111001" when zehner=1 else
9
           :
10
          "0000000" when zehner=8 else
11
          "0010000";


> Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."?
Mit einer Simulation findest du das in kurzer Zeit heraus.

> Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."?
So hast du es geschrieben:
1
   if rising_edge(clk) then                                           
2
        if taster_deb='1' and taster_old='0' then
3
        impulscounter <= impulscounter + 1;
Weil hier aber taster_old mit '0' initialisiert ist und niemals geändert 
wird, zählt der Zähler alle 20ns hoch, so lange der Taster gedrückt ist.
Du kannst es z.B. so machen:
1
  process
2
  begin
3
  wait until rising_edge(clk);
4
  ff1_out <= BT(1);
5
  ff2_out <= ff1_out;      --ff2_out ist nun zu verwenden
6
  taster_old <= taster_deb;
7
  end process;
Allerdings könnte man den ganzen Zirkus ohne Prozesse auch wesentlich 
kompakter schreiben:
1
  signal btsr: std_logic_vector[1 downto 0] := "00"; -- Schieberegister für BT(1)
2
:
3
:    
4
  stsr <= btsr(0) & BT(1) when rising_edge(clk);  -- Einsynchronisierung
5
  taster_old <= taster_deb when rising_edge(clk); -- für Flankenerkennung
6
:
7
:
8
  --Entprellen
9
  process begin
10
    wait until rising_edge(clk);
11
    if btsr(1)= taster_deb then debcnt <= 0;
12
    else debcnt <= debcnt + 1;
13
    end if;
14
15
    if (debcnt=2499999) then taster_deb <= btsr(1);
16
    end if;
17
  end process;


> Ist das Vorhandensein des kombinatorischen Klimbims denn auch wirklich
> ein Problem, dass für die Fehlfunktion sorgt? Also ist das der Grund
> wieso der Zähler beim Drücken des Tasters zu weit hochzählt?
Nein. Allerdings ist deine Simulation falsch und passt nicht zur 
Hardware. Sowas bringt dich jetzt schon (zeig mal deine Simulation) und 
später bei größeren Designs erst recht in ernstliche Schwierigkeiten.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Lothar M. schrieb:
1
  stsr <= btsr(0) & BT(1) when rising_edge(clk);  -- Einsynchronisierung

Korrekt wäre eher:
1
  btsr <= btsr(0) & BT(1) when rising_edge(clk);  -- Einsynchronisierung

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ja, tatsächlich.
Sehen wir es als kleinen Aufmerksamkeitstest für die 
Überallherkopierer...  ;-)

von Maximilian L. (mex_1991)


Lesenswert?

> Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."?
Mit einer Simulation findest du das in kurzer Zeit heraus.


--> Genau darin lag das Problem. Danke für die ganzen Tipps, ich werde 
mal meinen Code schöner gestalten.

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Maximilian L. schrieb:
> Danke für die ganzen Tipps, ich werde
> mal meinen Code schöner gestalten.
Das ist auch wichtig, aber vorher kommt die Testbench.
Im Anhang mal ein Gerüst, wie das auschauen könnte.

Duke

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
Noch kein Account? Hier anmelden.