Forum: FPGA, VHDL & Co. Drehgeber (rotary encoder) - VHDL


von Felix O. (felixanius)


Lesenswert?

Hallo alle,

ich bin gerade dabei für ein kleines Projekt mit meinem Spartan 3E 
Starter einen rotary encoder (Drehregler) mit VHDL zu programmieren. 
Hier auf der mikrocontroller-Seite gibt es einen guten Artikel darüber 
und auch schon fertigen Code. Ich wollte das jedoch alleine versuchen 
und es möglichst verständlich programmieren. Könnt ihr mir sagen, ob das 
so in Ordnung ist? Ich habe ein bischen bedenken, da ich von möglicher 
Glitches gelesen habe. Die sind bei mir nicht berücksichtigt, wie wirkt 
sich das aus? Wenn das ein Problem ist, wie kann ich das in meinen Code 
verbessern ohne zu viele Änderungen zu machen? Danke!
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee numeric_std.all;
4
5
entity rotary_encoder is
6
  port(clk : in std_logic;
7
    rotary_a : in std_logic;
8
    rotary_b : in std_logic;
9
    rotary_center : in std_logic;
10
    rotary_use : out std_logic;
11
    left_to_right : out std_logic;
12
    rotary_push : out std_logic;)
13
  end entity;
14
  
15
16
architecture behave of rotary_encoder is
17
18
begin
19
20
turning:process (clk, rotary_a, rotary_b)
21
begin
22
  if (clk'event and clk = '1') then
23
  
24
    if (rotary_a'event and rotary_a = '1') then    -- steigende Taktflanke
25
    
26
      if (rotary_b = '0') then
27
        left_to_right = '1';          -- turning right
28
        rotary_use = '1';            -- in use
29
      elsif (rotary_b = '0') then
30
        left__to_right = '0';          -- turning left
31
        rotary_use = '1';
32
      end if;
33
      
34
     elsif (rotary_a'event and rotary_a = '0') then  -- fallende Taktflanke
35
     
36
      if (rotary_b = '0') then
37
        left_to_right = '1';          -- turning right
38
        rotary_use = '1';
39
      elsif (rotary_b = '1') then
40
        left_to_right = '0';          -- turning left
41
        rotary_use = '1';
42
      end if;
43
      
44
    else
45
        rotary_use = '0';
46
    end if;
47
  end if;
48
end process;
49
50
pushing:process (clk, rotary_center)
51
begin
52
  if (clk'event and clk = '1') then
53
54
    if (rotary_center'event and rotary_center = '1') then    -- steigende Taktflanke
55
    
56
      rotary_push = '1';                    -- push
57
      rotary_use = '1';                    -- in use
58
    else
59
      rotary_push = '0';
60
      rotary_use = '0';
61
    end if;
62
  end if;
63
end process;
64
65
end behave;

: Bearbeitet durch User
von Christian R. (supachris)


Lesenswert?

Was genau stört sich an dem Code aus dem Drehgeber-Artikel? Wir haben 
den in leicht modifizierter Form (2-fach und 1-fach Abtastung) weltweit 
in Industrieprojekten im Einsatz, ohne einen Ausfall.

von Felix O. (felixanius)


Lesenswert?

Nichts stört mich an dem Code, bin mir sicher, dass das der optimale 
ist.

Wollte das nur selbst versuchen und hätte es, wenn ich den anderen Code 
noch nie gesehen hätte, immernoch so gemacht wie ich es jetzt gemacht 
habe. Über den Sinn bitte nicht weiter nachdenken, habe das eher aus 
Interesse gemacht :)

von Klaus F. (kfalser)


Lesenswert?

Felix O. schrieb:
> Könnt ihr mir sagen, ob das
> so in Ordnung ist?

Nein, das ist nicht in Ordnung, weil 2 verschachtelte if (x'event and x 
= '1') nicht möglich sind.
Das ist einerseits nicht synthetisierbar, und andererseits wäre es ja 
ein großer Zufall wenn die Flanken für clk und rotary_center "genau" 
zusammenfallen würden, oder?

von Felix O. (felixanius)


Lesenswert?

Danke!

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


Lesenswert?

Mal von dem verschachtelten Takt abgesehen:
Felix O. schrieb:
1
 if (rotary_a'event and rotary_a = '1') then    -- steigende Taktflanke
2
     rotary_use = '1'; 
3
 elsif (rotary_a'event and rotary_a = '0') then  -- fallende Taktflanke
4
     rotary_use = '1'; 
5
 else
6
     rotary_use = '0';   
7
 end if;
Wie sieht denn deiner Meinung nach ein Bauteil aus, das einen Eingang 
für eine fallende und einen für eine steigende Taktflanke hat? Und wenn 
eine Taktflanke theoretisch Null ps dauert, wie lange wird in diesem 
Design der rotary_use auf '1' sein? Wie lange würde rotary_use im relaen 
FPGA '1' sein?

> Ich wollte das jedoch alleine versuchen und es möglichst verständlich
> programmieren. Könnt ihr mir sagen, ob das so in Ordnung ist?
rotary_use = '0'; <--- Das geht so sicher nicht. Das ist kein VHDL...
VHDL ist eine Hadrwarebeschreibungssprache. Du musst also ein Bild 
oder eine Vorstellung von der Hardware haben, die du beschreiben 
willst. Sonst kommt nichts Brauchbares dabei heraus...

> Ich habe ein bischen bedenken, da ich von möglicher Glitches gelesen
> habe. Die sind bei mir nicht berücksichtigt, wie wirkt sich das aus?
So, dass dein Design evtl. jede ms ein Problem hat, oder aber auch nur 
1x pro Woche...
> Wenn das ein Problem ist, wie kann ich das in meinen Code verbessern
> ohne zu viele Änderungen zu machen?
Gar nicht. Am einfachsten löschst du den Code und sorgst beim 
Neuschreiben dafür dafür, dass du nur 1 einzigen Takt, der auf nur 1 
Flanke aktiv ist, im Design hast. Such einfach mal hier im Forum nach 
meinen Postulaten. Die gelten für alle Anfänger... ;-)

BTW: warum verwendest du nicht die Funktionen rising_edge() oder 
falling_edge() für einen Takt?

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

So sieht meins aus:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use IEEE.numeric_std.all;
4
5
entity Debenc is
6
    Port ( clk    : in  STD_LOGIC;
7
           encin  : in  STD_LOGIC_VECTOR(1 downto 0);
8
           r    : out  STD_LOGIC;
9
     l    : out  STD_LOGIC);
10
end Debenc;
11
12
13
architecture Behavioral of Debenc is
14
signal level0, level1, en_fall0, en_fall1: std_logic := '0';
15
signal count0, count1: integer range 0 to 255 := 0;
16
17
begin
18
19
r <= '1' when en_fall1 = '1' and level0 = '1' else '0';
20
l <= '1' when en_fall0 = '1' and level1 = '1' else '0';
21
22
process
23
variable en_sr0, en_sr1 : std_logic_vector (3 downto 0) := "0000";
24
  begin
25
   wait until rising_edge(clk);
26
  
27
  en_fall0 <= not en_sr0(2) and en_sr0(3);
28
  en_sr0 := en_sr0(2 downto 0) & level0;
29
  
30
  en_fall1 <= not en_sr1(2) and en_sr1(3);
31
   en_sr1 := en_sr1(2 downto 0) & level1;
32
  
33
  
34
  if   count0 < 255 and encin(0) = '1' then
35
      count0 <= count0 +1;
36
  elsif count0 >   0 and encin(0) = '0' then
37
      count0 <= count0 -1;
38
  end if;
39
  if   count0 < 8 then
40
      level0 <= '0';
41
  elsif count0 > 247 then
42
      level0 <= '1';
43
  end if;
44
  
45
  if   count1 < 255 and encin(1) = '1' then
46
      count1 <= count1 +1;
47
  elsif count1 >   0 and encin(1) = '0' then
48
      count1 <= count1 -1;
49
  end if;
50
  if   count1 < 8 then
51
      level1 <= '0';
52
  elsif count1 > 247 then
53
      level1 <= '1';
54
  end if;
55
56
end process;
57
end Behavioral;

Es ist natürlich mit realer Hardware getestet.

von Felix O. (felixanius)


Lesenswert?

@Gustl: danke für das Beispiel!


Lothar Miller schrieb:
> Mal von dem verschachtelten Takt abgesehen:
> Felix O. schrieb:
>
1
>  if (rotary_a'event and rotary_a = '1') then    -- steigende Taktflanke
2
>      rotary_use = '1';
3
>  elsif (rotary_a'event and rotary_a = '0') then  -- fallende Taktflanke
4
>      rotary_use = '1';
5
>  else
6
>      rotary_use = '0';
7
>  end if;
8
>
> Wie sieht denn deiner Meinung nach ein Bauteil aus, das einen Eingang
> für eine fallende und einen für eine steigende Taktflanke hat? Und wenn
> eine Taktflanke theoretisch Null ps dauert, wie lange wird in diesem
> Design der rotary_use auf '1' sein? Wie lange würde rotary_use im relaen
> FPGA '1' sein?

Also würde rotary_use verdamt schnell hin und her wechseln und ich 
könnte das gar nicht sinnvoll benutzen.

>
>> Ich wollte das jedoch alleine versuchen und es möglichst verständlich
>> programmieren. Könnt ihr mir sagen, ob das so in Ordnung ist?
> rotary_use = '0'; <--- Das geht so sicher nicht. Das ist kein VHDL...

Äh, ja sollte natürlich "<=" sein.

>> Wenn das ein Problem ist, wie kann ich das in meinen Code verbessern
>> ohne zu viele Änderungen zu machen?
> Gar nicht. Am einfachsten löschst du den Code und sorgst beim
> Neuschreiben dafür dafür, dass du nur 1 einzigen Takt, der auf nur 1
> Flanke aktiv ist, im Design hast.
Ja, dumm von mir eigentlich klar..

> BTW: warum verwendest du nicht die Funktionen rising_edge() oder
> falling_edge() für einen Takt?
Wir hatten das in einem Einführungskurs zu VHDL in der UNI mit dem 
clk'event ... gemacht aber auch mit dem Hinweis, dass rising_edge() 
genauer ist, da mit der neunwertigen-Logik bei meiner Beschreibung ja 
auch eine Veränderung von z.B. u nach 1 als treffendes Ereignis gesehen 
wird..
Werde mich mal an das rising_edge() gewöhnen.

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


Lesenswert?

Gustl Buheitel schrieb:
> So sieht meins aus:
Was tut diese Beschreibung?
Besonders da (und ähliche Abfragen) würde ich Probleme erwarten:
1
  if   count0 < 255 and encin(0) = '1' then
2
     count0 <= count0 +1;
Denn wenn encin() tatsächlich ein asynchroner Eingang ist, dann hast du 
da garantiert eine amoklaufende Statemachine (=Zähler). Genau wie da 
beschreiben:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html

Ich hätte eine Variante, die einen Takt und die beiden Spuren als 
Eingang bekommt, und einen Zähler als Ausgang hat:
http://www.lothar-miller.de/s9y/categories/46-Encoder
Und dort: zuallererst werden die beiden Eingänge einsynchronisiert...

Felix O. schrieb:
>> Wie sieht denn deiner Meinung nach ein Bauteil aus, das einen Eingang
>> für eine fallende und einen für eine steigende Taktflanke hat? Und wenn
>> eine Taktflanke theoretisch Null ps dauert, wie lange wird in diesem
>> Design der rotary_use auf '1' sein? Wie lange würde rotary_use im relaen
>> FPGA '1' sein?
> Also würde rotary_use verdamt schnell hin und her wechseln und ich
> könnte das gar nicht sinnvoll benutzen.
Es wäre einfach immer '0', weil eine Flanke keine Zeitdauer hat...

> Werde mich mal an das rising_edge() gewöhnen.
Kann nicht schaden...

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

Warum?

Was ich will, ist auch debouncen.

Also ich "sample" da quasi den asynchronen Eingang. Daher funktioniert 
das auch nur wenn die Clock sehr viel schneller ist wie das Signal von 
Encoder.
Wenn jetzt der Encoder von 0 auf 1 wechselt geht der Zähler langsam nach 
oben und wenn er von 1 auf 0 wechselt geht der Zähler nach unten. Mit 
dem Zähler füge ich da nur etwas "Trägheit" ein, quasi wie einen 
Kondensator der geladen/entladen wird.

Wenn da Jitter bei ist geht da zähler nicht ganz so schnell nach 
oben/unten und erreicht die 255/0 nie.

Mit
1
  if   count0 < 8 then
2
      level0 <= '0';
3
  elsif count0 > 247 then
4
      level0 <= '1';
5
  end if;
 habe ich dann Schwellen gesetzt, also wenn der Zähler < 8 dann ist das 
für mich hinreichend Null und wenn > 247 ist es hinreichend Eins. Man 
könnte das jetzt auch sicher anders machen, aber so funktioniert es 
recht gut.

: Bearbeitet durch User
von Felix O. (felixanius)


Angehängte Dateien:

Lesenswert?

Lothar Miller schrieb:

>> Werde mich mal an das rising_edge() gewöhnen.
> Kann nicht schaden...

Obwohl ich gerade sehen, dass in Dokumenten von Xilinx auch clk'event 
and clk ='1' genutzt wird. Warum machen die das, wenn das andere 
offensichtlich besser ist? Oder nutzen die nicht std_logic? :D

Siehe angehängtes Dokument.

von Gustl B. (-gb-)


Lesenswert?

clk'event and clk ='1'
und
wait until rising_edge(clk);
ist genau das Gleiche.
Bei Ersterem hast du aber ein if das du irgendwann wieder schließen 
musst, daher finde ich das nicht so hübsch.

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


Lesenswert?

Gustl Buheitel schrieb:
> Also ich "sample" da quasi den asynchronen Eingang. Daher funktioniert
> das auch nur wenn die Clock sehr viel schneller ist wie das Signal von
> Encoder.
Nein, das geht sicher dann und wann schief, denn der Zähler verzählt 
sich einfach. Es ist nämlich nicht so, dass der Eingang nur auf ein 
einziges Flipflop des Zählers geht, sondern auf alle Zählerflipflops 
parallel. Wenn da nicht die unterschiedlichen Laufzeiten zu den acht 
Flipflops durch das Routing wären...

> clk'event and clk ='1'
> und
> wait until rising_edge(clk);
> ist genau das Gleiche.
Nein, da fehlt noch das clk'last. Aber es wird vom Synthesizer das 
gleiche draus gemacht, weil es in der realen Hardware nur '0' und '1' 
für einen Takteingang gibt...

Felix O. schrieb:
> Obwohl ich gerade sehen, dass in Dokumenten von Xilinx auch clk'event
> and clk ='1' genutzt wird.
Danke für die Steilvorlage.
Du darfst nicht alles glauben, was dir von irgendwoher irgendwie 
zukommt. Siehe den Klassiker 
Beitrag "Re: Variable vs Signal"

> Warum machen die das, wenn das andere offensichtlich besser ist?
Keine Ahnung. Vielleicht "Weil man das hier schon immer so gemacht hat!"

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

Wiebitte?! Ich habe:
1
  if   count0 < 255 and encin(0) = '1' then
2
      count0 <= count0 +1;
3
  elsif count0 >   0 and encin(0) = '0' then
4
      count0 <= count0 -1;
5
  end if;
und encin(0) ist mein Eingang.

Jetzt kommt da die Taktflanke, es wird geguckt ob count0 < 255 and 
encin(0) = '1' oder count0 >   0 and encin(0) = '0' zutrifft und wenn, 
dann wird count0 <= count0 +1 oder count0 <= count0 -1 gemacht.
Aber dabei get doch nie der Eingang direkt an den Zähler sondern immer 
nur die 1. Klar, Zähler und Takt müssen natürlich so gewählt sein, dass 
der Zähler die Addition durchgeführt hat bevor der nächste Takt kommt, 
aber das ist bei mir mit 8-Bit und 75MHz locker gegeben.

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


Lesenswert?

Gustl Buheitel schrieb:
> Aber dabei get doch nie der Eingang direkt an den Zähler
Richtig, es ist noch vertrackter...

> Ich habe:
1
   wait until rising_edge(clk);  
2
    :
3
   if   count0 < 255 and encin(0) = '1' then
4
       count0 <= count0 +1;
5
   elsif count0 >   0 and encin(0) = '0' then
6
       count0 <= count0 -1;
7
   end if;
> und encin(0) ist mein Eingang.
Und encin(0) geht (über die Carry-Chain) auf alle 8 Flipflops von count0 
(das ist ja ein synchroner Zähler). Und wenn jetzt der Wechsel von 
encin(0) kurz vor, nach oder mit der Flanke vom clk kommt, dann rennt 
die Carrychain schon mal los, kommt aber evtl. nicht ganz durch. Und 
dein Zähler zählt eben nicht +1 oder -1 sondern irgendeinen Käse.

> Klar, Zähler und Takt müssen natürlich so gewählt sein, dass der Zähler
> die Addition durchgeführt hat bevor der nächste Takt kommt
Drehst du dann synchron am Rad?

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

Nein, das "glaube" ich nicht.

> Und encin(0) geht (über die Carry-Chain) auf alle 8 Flipflops von count0

Nur im Moment der steigenden Flanke von der Clock wird entschieden ob +1 
oder -1. Und danach läuft die Addition durch wie zu diesem einen 
Zeitpunkt entschieden.

Ja wenn encin(0) kurz vor der steigenden Taktflanke von 0 auf 1 wechselt 
und danach wieder auf 0 zurück wird trotzdem +1 gezählt obwohl encin(0) 
die meiste Zeit auf 0 liegt und nicht auf 1. Aber die Addition läuft 
immer genau so durch wie zum Zeitpunkt der steigenden Flanke entschieden 
wurde.

Natürlich sehe ich damit nicht das reale Signal des Encoders, aber ich 
taste es sehr oft, also meine Sampleclock ist sehr viel Größere wie die 
Änderungsrate des Encoders. Meintest du das? Also dass ich 
Wertänderungen zwischen den steigenden Taktflanken (= meine 
Samplezeitpunkte) nicht beachte?

Also ich habe mir jetzt mal eine Testbench geschrieben mit einem leicht 
verschobenen Takt, also es fällt jetzt das Encodersignal 2ns nach der 
Taktflanke von 1 auf 0 und es wird trotzdem richtig die 1 addiert. Es 
ist alerdings der Webpack ISim, der das vielleicht nicht korrekt macht 
mit den Laufzeiten.

So ich habe jetzt mit noch anderen Zeiten in der Testbench den Fall, 
dass der Eingang 0.3ns nach der steigenden Taktflanke von 1 auf 0 fällt 
und trotzdem das mit der Addition zumindest laut Simulation richtig ist. 
und das Carry muss sogar was machen von 10111 nach 11000.

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


Lesenswert?

Gustl Buheitel schrieb:
> Nur im Moment der steigenden Flanke von der Clock wird entschieden ob +1
> oder -1. Und danach läuft die Addition durch wie zu diesem einen
> Zeitpunkt entschieden.
Nein, die Addition für einen synchronen Zähler ist (hoffentlich) vor der 
Taktfklanke schon lange fertig berechnet. Und die Flipflops übernehmen 
mit dem Takt nur das Ergebnis (den neuen Zählerstand), das aus der Logik 
bereitgestellt wird. Und wenn diese Logik jetzt wegen der Änderung des 
Eingangssignals noch irgendwie rumzappelt, dann übernehmen die FFs eben 
dieses Gezappel.

> 2ns nach der Taktflanke von 1 auf 0
> dass der Eingang 0.3ns nach der steigenden Taktflanke
Du musst den Eingang kurz vor der Taktflanke ansteigen lassen. Und 
zwar um die Laufzeiten vom Portpin zur Logik früher. Nur so kann sich 
das Signal am FF ändern, wenn es nicht sollte, und so die tsu/th 
verletzen...

: Bearbeitet durch Moderator
von Gustl B. (-gb-)


Lesenswert?

Also der zeitliche Ablauf wie ich das bisher glaubte verstanden zu 
haben:
1
wait until rising_edge(clk);

Es wird auf die steigende Taktflanke gewartet.
1
if   count0 < 255 and encin(0) = '1' then
2
3
elsif count0 >   0 and encin(0) = '0' then
4
5
end if;

Kommt jetzt diese Taktflanke, dann wird "geguckt" welche und ob 
überhaupt eine der Bedingungen wahr ist.

Wenn eine wahr ist, dann wird das gemacht was drinnen steht, also 1 
addiert oder subtrahiert.

Das muss dann bis zur nächsten steigenden Flanke geschehen sein weil 
dort der Wert des Zählers für die Bedingungen abgefragt wird.

Aber anscheinend sehe ich das falsch, was passiert denn da genau? Also 
wann wird da das Eingangssignal angeguckt wenn icht genau einmal je Takt 
und zwar genau bei der steigenden Flanke?

Also genauer:

Ändert sich der Wert der if Bedingung, das ist ja Bool, auch zu anderen 
Zeiten als zur steigenden Flanke? Obwohl ich ja
1
wait until rising_edge(clk);
geschrieben hatte?

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


Lesenswert?

Gustl Buheitel schrieb:
> wait until rising_edge(clk);
> Es wird auf die steigende Taktflanke gewartet.
> Kommt jetzt diese Taktflanke, dann wird "geguckt" welche und ob
> überhaupt eine der Bedingungen wahr ist.
Du hast ein zu "ereignisgesteuertes" Bild der Hardware. Es wird nicht 
"gewartet" und es wird auch nichts "nachgeschaut". Sondern es wird ganz 
einfach mit der Taktflanke vom clk ein Flipflop angesteuert, vor dem ein 
Logiknetz sitzt, das den nächsten Zählerstand ausrechnet. Und dieser 
nächste Zählerstand sollte tunlichst vor der Taktflanke stabil sein, 
weil sonst dein Logiknetz irgendwie herumglitcht und hinundher zappelt.

> Wert der if Bedingung, das ist ja Bool
Die Bedingung ist ein logisches Gatter, das (vermutlich zusammen mit 
anderen Funktionen) in einer LUT realisiert ist, die direkt vor dem FF 
D-Eingang sitzt.

> Ändert sich der Wert der if Bedingung, das ist ja Bool, auch zu anderen
> Zeiten als zur steigenden Flanke?
Er ändert sich nach jeder Taktflanke (oder besser: er kann sich 
ändern) und muss rechtzeitig vor der nächsten Taktflanke stabil sein. 
Das nennt sich dann synchrones Design: 
Takt-Gezappel-Ruhe-Takt-Gezappel-Ruhe-Takt-Gezappel-Ruhe-Takt-usw.

Und wenn sich encin(0) ändert, dann ändert sich kurz darauf (Laufzeiten 
vom Pin zur Logik und durch die Logik hindurch) der Eingang der 
betroffenen Flipflops.

: Bearbeitet durch Moderator
von Sigi (Gast)


Lesenswert?

Gustl Buheitel schrieb:
>Kommt jetzt diese Taktflanke, dann wird "geguckt" welche und ob
>überhaupt eine der Bedingungen wahr ist.

und da liegt vlt. dein Denkfehler: es wird nicht zum Flankenzeitpunkt 
geguckt/gesampelt und dann das Ergebnis an alle anderen FFs übermittelt,
sondern COUNT0 und ENCIN werden in einen LUT-Wald eingefüttert. Und
dieser spuckt nach einiger Zeit ein Ergebnis aus (Dauer lässt sich bei
synchronen Signalen vom Fitter etc. genau berechnen).
Aber dein ENCIN ist NICHT synchron.

Und jetzt hast du zwei Fälle:
1. Der Ausdruck "count0 < 255 and encin(0) = '1'" wird in einem
Baum/Wald synthetisiert. Dann muss aber das Ergebnis zu allen
COUNT0-FFs, was aber unterschiedlich lange dauern kann => FSM und
COUNT0-FFs können ins Chaos geraten.
2. Ausdruck wird für jedes COUNT0-FF zu einem LUT-Baum: hier hast
du dann das Problem, dass ENCIN unterschiedlich lange braucht, d.h.
die Ergebnisse werden nicht synchron berechnet => FSM und COUNT0-FFs
stürzen auch hier ins Chaos.

Schau dir einfach mal die Technology-Schematics nach der Synthese
an und mach dir klar, dass alle Signale unterschiedliche Laufzeiten
haben.

von Gustl B. (-gb-)


Lesenswert?

Ich habe es vermutlich verstanden und so sollte es ok sein wenn ich also 
ein FF dazwischenhänge:
1
signal buffer : std_logic_vector (1 downto 0) := "00";
2
3
wait until rising_edge(clk);
4
5
buffer <= encin;
6
7
en_fall0 <= not en_sr0(2) and en_sr0(3);
8
en_sr0 := en_sr0(2 downto 0) & level0;
9
  
10
if   count0 < 255 and buffer(0) = '1' then
11
   count0 <= count0 +1;
12
elsif count0 >   0 and buffer(0) = '0' then
13
   count0 <= count0 -1;
14
end if;
15
16
if   count0 < 8 then
17
   level0 <= '0';
18
elsif count0 > 247 then
19
   level0 <= '1';
20
end if;

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


Lesenswert?

Gustl Buheitel schrieb:
> und so sollte es ok sein wenn ich also ein FF dazwischenhänge:
Eines reicht, zwei sind sicherer...  ;-)

von Gustl B. (-gb-)


Lesenswert?

Ja die zwei weil encin ja auch 2 Drähte sind, hatte ich nur 
rauseditiert.

Vielen Dank übrigens :-) Im meinem alten Weltbild dachte ich irgendwie, 
dass da schon ein Speicherelement drinnen wäre automatisch das den Wert 
zum Zeitpunkt der steigenden Flanke festhalten und dann erst an die 
Kombinatorik weiterreichen würde.

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


Lesenswert?

Gustl Buheitel schrieb:
> Ja die zwei weil encin ja auch 2 Drähte sind, hatte ich nur
> rauseditiert.
Nein, dann wären es 4... ;-)
Oder andersrum: zum Einsynchronisieren verwendest du, wenn deine Latenz 
es zulässt am besten 2 Flipflops pro asynchronem Eingang.

> Vielen Dank übrigens :-)
Kein Ursache...

von Gustl B. (-gb-)


Lesenswert?

Ich hatte das mit den 2 FFs für einen Scherz gehalten da ich ja Buffer 2 
Bits breit gemacht, aber in dem Codeausschnitt nur eines verwendet hatte 
:-D

von Felix O. (felixanius)


Lesenswert?

So, hatte mir Lothars Beispiel angeschaut und danach selbst versucht auf 
die Zustände etc zu kommen, hat auch funktioniert. Allerdings habe ich 
das doch ein wenig anders:
1
architecture behave of rotary_encoder is
2
3
type positions is (P00, P01, P10, P11);
4
signal p : positions := P00;
5
signal rot_ab : std_logic_vector(1 downto 0);
6
7
begin
8
9
turning:process (clk, rotary_a, rotary_b)
10
begin
11
  wait untill rising_edge(clk);
12
  
13
  rot_ab <= rotary_a & rotary_b;
14
  
15
  case p is
16
    when P00 => if (rot_ab = "10") then 
17
        p <= P10;        
18
        rotary_use <= '1';
19
        left_to_right <= '1';              -- links_nach_rechts
20
        elsif (rot_ab = "01") then 
21
        p <= P01;
22
        rotary_use <= '1';
23
        left_to_right <= '0';              -- rechts_nach_links
24
        end if;
... usw.

1. Ich habe in der Sensitivitätsliste rotary_a und rotary_b noch drin. 
Brauche ich das, oder benutzen wir die Änderungen der beiden Signale eh 
erst, wenn wir einen neuen Taktzyklus haben? Und da der Prozess, der 
dann rotary_use usw benutzt, auch erst mit dem neuen Taktzyklus 
angesprochen wird, reicht ein clk in der Sensitivitätsliste? Aber warum 
gibt es dann Fälle, wo das clk nicht ausreicht?

2. Lothar du hast bei dir noch den Prozess:
1
 process begin -- Eintakten der asynchronen Signale
2
    wait until rising_edge(clk);
3
    i <= A & B;  -- Zusammenfassen der Eingänge A und B
4
    e <= i;
5
  end process;

Kannst du bitte nochmal erklären, warum das nötig ist und was passieren 
würde, wenn man das wie in meinem Code weglässt und direkt A und B 
benutzt?



Danke!

von Gustl B. (-gb-)


Lesenswert?

Mal ne komische Idee, aber kann man das nicht sogar ganz ohne Takt 
machen?
1
library ieee;
2
use ieee.std_logic_1164.all;
3
4
entity Debenc is
5
   Port (encin : in  STD_LOGIC_VECTOR(1 downto 0);
6
         r     : out STD_LOGIC;
7
         l     : out STD_LOGIC);
8
end Debenc;
9
10
architecture Behavioral of Debenc is
11
begin
12
13
process
14
begin
15
wait until falling_edge(encin(0));
16
17
   if encin(1) = '1' then
18
      r <= '1';
19
   else
20
      r <= '0';
21
   end if;
22
23
end process;
24
25
process
26
begin
27
wait until falling_edge(encin(1));
28
29
   if encin(0) = '1' then
30
      l <= '1';
31
   else
32
      l <= '0';
33
   end if;
34
35
end process;
36
37
end Behavioral;

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Mein Gott, die klassische Lösung mit Dekodertabelle und 4 FlipFlops kann 
man nicht vereinfachen oder verbessern, nur verschlimmbessern. Und es 
geht auch nicht rein kombinatorisch. Das Ganze System ist die asynchrone 
Abtastung eines Gray-Codes, die funktioniert nun mal so.

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> Mein Gott, die klassische Lösung mit Dekodertabelle und 4 FlipFlops kann
> man nicht vereinfachen oder verbessern, nur verschlimmbessern. Und es
> geht auch nicht rein kombinatorisch. Das Ganze System ist die asynchrone
> Abtastung eines Gray-Codes, die funktioniert nun mal so.

:o)

mehr muss man dazu auch nicht sagen...

von Felix O. (felixanius)


Lesenswert?

berndl schrieb:
> Falk Brunner schrieb:
>> Mein Gott, die klassische Lösung mit Dekodertabelle und 4 FlipFlops kann
>> man nicht vereinfachen oder verbessern, nur verschlimmbessern. Und es
>> geht auch nicht rein kombinatorisch. Das Ganze System ist die asynchrone
>> Abtastung eines Gray-Codes, die funktioniert nun mal so.
>
> :o)
>
> mehr muss man dazu auch nicht sagen...


Haha ja kann ich verstehen, dass sowas für Kenner der Materie in den 
Augen schmerzt, aber wenn man dabei ist soetwas zu lernen, kommen nunmal 
seltsame Ideen und Fragen auf :D

Mit dem Takt würde mich jetzt auch interessieren. Wenn man jetzt einen 
Prozess ohne Takt macht aber sonst alle anderen Prozesse mit Takt, dann 
dürfte es doch keine Synchronisationsschwierigkeiten geben oder? Also 
jedenfalls, wenn das Ergebnis des Prozesses ohne Takt von einem Prozess 
mit Takt benutzt wird. Oder doch?

von Falk B. (falk)


Lesenswert?

@Felix O. (felixanius)

>Augen schmerzt, aber wenn man dabei ist soetwas zu lernen, kommen nunmal
>seltsame Ideen und Fragen auf :D

Ja, was meist an mangelnden Grundlagen liegt.

>Mit dem Takt würde mich jetzt auch interessieren. Wenn man jetzt einen
>Prozess ohne Takt macht aber sonst alle anderen Prozesse mit Takt, dann
>dürfte es doch keine Synchronisationsschwierigkeiten geben oder?

Oder.

> Also
>jedenfalls, wenn das Ergebnis des Prozesses ohne Takt von einem Prozess
>mit Takt benutzt wird. Oder doch?

Oder doch.

Siehe oben. Du musst dich mal mit den Grundlagen der Digitaltechnik 
befassen. Was macht kombinatorische Logik? Was machen Speicherelemente? 
Wie muss das Timing sein? Und in den höheren Semestern lernt man dann 
was über asynchrone Taktdomänen und deren Probleme sowie Lösungen.

von Felix O. (felixanius)


Lesenswert?

Falk Brunner schrieb:
> @Felix O. (felixanius)
>
>>Augen schmerzt, aber wenn man dabei ist soetwas zu lernen, kommen nunmal
>>seltsame Ideen und Fragen auf :D
>
> Ja, was meist an mangelnden Grundlagen liegt.

Hm aber irgendwo muss man anfangen die Grundlagen zu lernen. Das man 
alles was man in Büchern liest sofort komplett versteht halte ich für 
unwahrscheinlich und da finde ich ist es viel effektiver, man setzt sich 
praktisch mit dem Thema auseinander und merkt dann, wo noch Lücken sind 
bzw. was man noch nicht ganz verstanden hat. Ich sehe das Forum hier als 
Hilfe um die Grundlagen zu verstehen/festigen. Die Fragen richten sich 
an User, die viel Ahnung in dem Gebiet haben und vielleicht auch wissen, 
wo die Verständnisprobleme von Anfängern liegen. Und die vorallem Lust 
darauf haben die Fragen zu beantworten und zu helfen. Wer nicht 
antworten will, antwortet halt nicht, hatte nur hier den Eindruck, dass 
es sehr viele hilfsbereite User gibt, deswegen all die Fragen.

Ich möchte später nicht als VHDL-Programmierer arbeiten, ich habe nur 
zur Zeit Interesse an der Sprache und an FPGAs bekommen. Dazu bearbeite 
ich gerade ein Projekt, welches eine Spielerei mit LEDs ist (Grundlagen 
;))
Ich bin mir ziemlich sicher, dass mir hier einer die Frage oben in drei 
Sätzen beantworten könnte und ich dann zumindest auf das Beispiel 
bezogen die Nutzung vom Takt besser verstehen würde.

Ich verstehe, dass es für jemanden, der sich mit VHDL schon Jahre 
beschäftigt, schwer nachzuvollziehen ist, warum ein Anfänger dieses und 
jenes noch nicht weiß. Aber dieses "Ist doch ganz logisch" ist nunmal 
nicht von Anfang an da.
Der Hinweis, ich solle erstmal Grundlagen lernen, hilft mir nicht 
weiter.

Ich hoffe trotzdem weiterhin auf Hilfe von den ganzen "Pros" hier :)

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


Lesenswert?

Felix O. schrieb:
> turning:process (clk, rotary_a, rotary_b)
> begin
>    wait untill rising_edge(clk);
Ein WAIT zusammen mit einer Sensitivliste geht nicht...
>
>   rot_ab <= rotary_a & rotary_b;
Aus Versehen Glück gehabt: wenigstens 1 Flipflops zum 
Einsynchronisieren...


> 1. Ich habe in der Sensitivitätsliste rotary_a und rotary_b noch drin.
Unnötig.
> Brauche ich das, oder benutzen wir die Änderungen der beiden Signale eh
> erst, wenn wir einen neuen Taktzyklus haben? Und da der Prozess, der
> dann rotary_use usw benutzt, auch erst mit dem neuen Taktzyklus
> angesprochen wird, reicht ein clk in der Sensitivitätsliste? Aber warum
> gibt es dann Fälle, wo das clk nicht ausreicht?
Die Sensitivliste verwendet nur der Simulator. Mit der Liste sagst du 
ihm, wann ein Prozess neu berechnet werden muss.
Ein synchroner Prozess muss nur mit dem Takt neu berechnet werden. Ein 
kombinatorischer Prozess braucht da alle Signale, die eine Auswirkung 
auf andere Signale haben.
Die Synthese erweitert eine unvollständige Sensitivliste von allein und 
gibt dir bestenfalls eine Info, dass das Syntheseergebnis nicht zur 
Simulation passt... :-o

> 2. Lothar du hast bei dir noch den Prozess:
>   -- Eintakten der asynchronen Signale
>
> Kannst du bitte nochmal erklären, warum das nötig ist und was passieren
> würde, wenn man das wie in meinem Code weglässt und direkt A und B
> benutzt?
Da passiert dann genau das, was ich in diesem Thread bis zum Umfallen 
erklärt habe: du hast eine FSM mit asynchronen Eingängen. Sieh dir 
einfach meine HP zum Thema Eintakten, Metastabilität, usw an.

> Danke!
Bitte!

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


Lesenswert?

Gustl Buheitel schrieb:
> Mal ne komische Idee, aber kann man das nicht sogar ganz ohne Takt
> machen?
Naja, du hast da sogar 2 Takte drin:
> wait until falling_edge(encin(0));
> wait until falling_edge(encin(1));
Und dann kommt die Geschichte mit dem Einsynchronisieren eben gleich 
danach, wenn die Ergebnisse (r und  l) dieses Prozesses im restlichen 
Design weiterverarbeitet werden sollen.

Am Rande:
deine Lösung hat einen fetten Haken: es können beide Signale 
gleichzeitig aktiv sein...

von Falk B. (falk)


Lesenswert?

@ Felix O. (felixanius)

>Hm aber irgendwo muss man anfangen die Grundlagen zu lernen.

Sicher, aber nicht dirch maiximal wildes Drauflosrennen mit ein 
Bruchteil eines Bruchteils von Wissen.

> Das man
>alles was man in Büchern liest sofort komplett versteht halte ich für
>unwahrscheinlich

Logisch, aber . . .

>und da finde ich ist es viel effektiver, man setzt sich
>praktisch mit dem Thema auseinander und merkt dann, wo noch Lücken sind
>bzw. was man noch nicht ganz verstanden hat.

Jain. Wie überall muss man erstmal das kleine 1x1 lernen. Und das tut 
man am besten, indem man es im Lehrbuch liest, durchdenkt und genau so 
nach macht. Auf Digitalechnik bezogen heißt das, was sind Logikgatter, 
was ist ein FlipFlop, Wie funktionieren sequentielle und kombinatorische 
Schaltungen. Das alles muss man erstmal durchkauen, mit kleinen Übungen, 
die aber noch recht eingeschränkt sind. Bei VHDL ist es ähnlich. 
Kombinatorische und sequentielle Prozesse, sinnvolle, synthetisierbare 
Beschreibungen von Standard funktionaliät, State machine.

Was du machst ist, mit deinem Funken Halbwissen alles neu erfinden 
wollen. Aber das geht schief. Zuerst musst du mal alles so nachmachen 
und versthen, wie es im Buch steht. DANACH kannst du kreativ werden.

>darauf haben die Fragen zu beantworten und zu helfen. Wer nicht
>antworten will, antwortet halt nicht, hatte nur hier den Eindruck, dass
>es sehr viele hilfsbereite User gibt, deswegen all die Fragen.

Klar, aber machmal ist einfach der Hinweis notwenig, dass wir hier nicht 
in der Grundschule sind, wo alles haarklein immer wieder vorgekaut wird.
Es ist Eigeninitiative vonnöten.

>Ich möchte später nicht als VHDL-Programmierer arbeiten, ich habe nur
>zur Zeit Interesse an der Sprache und an FPGAs bekommen. Dazu bearbeite
>ich gerade ein Projekt, welches eine Spielerei mit LEDs ist (Grundlagen
>;))

Naja, die echten Grundlagen wären sinnvoller. Z.B. mal ein VHDL-Tutorial 
durcharbeiten, davon gibt es einige.

>Ich verstehe, dass es für jemanden, der sich mit VHDL schon Jahre
>beschäftigt, schwer nachzuvollziehen ist, warum ein Anfänger dieses und
>jenes noch nicht weiß.

Jain.

> Aber dieses "Ist doch ganz logisch" ist nunmal
>nicht von Anfang an da.

Sicher.

>Der Hinweis, ich solle erstmal Grundlagen lernen, hilft mir nicht
>weiter.

Vielleicht doch. Zuerst musst du bestehende, vollständige Beispiele 
nachvollziehen und mehr oder weniger 1:1 nachbauen.

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.