Hallo,
ich stehe da irgendwie auf dem Schlauch. Folgender VHDL Code
entity ResetGenerator is
Port ( RESET_IN : in STD_LOGIC;
CLK_IN : in STD_LOGIC;
STATE_OUT: out std_logic_vector(1 downto 0);
RESET_OUT : out STD_LOGIC);
end ResetGenerator;
architecture Behavioral of ResetGenerator is
signal state: bit_vector(1 downto 0);
begin
process(state, RESET_IN, CLK_IN)
begin
if rising_edge(CLK_IN) then
case state is
when "00" =>
state <= "00";
RESET_OUT <= '0';
if RESET_IN = '1' then
state <= "01";
RESET_OUT <= '1';
end if;
when "01" =>
state <= "11";
RESET_OUT <= '1';
when "11" =>
state <= "10";
RESET_OUT <= '0';
when "10" =>
state <= "10";
RESET_OUT <= '0';
if RESET_IN = '0' then
state <= "00";
RESET_OUT <= '0';
end if;
when others =>
state <= "00";
end case;
end if;
end process;
STATE_OUT <= to_stdlogicvector(state);
end Behavioral;
Soll ein RESET_IN Signal entgegennehmen, für zwei CLK_IN Zyklen eine
'1' auf das Ausgangssignal RESET_OUT legen und danach warten, bis das
Eingangssignal wieder auf Null geht, damit das ganze wieder von vorn
beginnen kann.
Board ist ein Spartan 3AN Prototypenboard von DIGILENT, ich benutze ISE
13.2.
CLK_IN ist der 50MHz Quarz, RESET_IN einer der Taster.
RESET_OUT, STATE_OUT und auch der Taster sind auf LEDs gelegt,
das RESET_OUT-Signal wird zusätzlich noch mit einem Oszi überprüft.
Wenn ich jetzt das ganze ausprobiere:
Taste gedrückt: LED für Taste an, STATE_OUT ist "10"
Taste losgelassen: LED für Taste aus, STATE_OUT ist "00"
Es wird beim Drücken der Taste ein 40ns Impuls erzeugt.
So weit so gut...
Tippe ich jetzt mehrfach auf den Taster hängt das ganze nach kurzer
Zeit.
Wenn es hängt:
Taste gedrückt: LED für Taste an, STATE_OUT ist _"00"_
Taste losgelassen: LED für Taste aus, STATE_OUT ist "00"
Es wird beim Drücken der Taste KEIN 40ns Impuls erzeugt.
Wie kann das sein? Was habe ich da nicht begriffen?
Gruß, Patric
keine fundierten Tipps, aber:
1. hast du das ganze mal simuliert?
2. die Fehlerbeschreibung klingt, als ob du irgendwo Probleme mit einem
prellenden Taster hättest
Ok, wie geht das mit der Lesbarkeit?
Und Danke erstmal für die Antwort.
zu 1. nein ich habe es nicht simuliert (kenne mich da mit den Tools
(noch)
nicht so ganz aus.
zu 2. Müsste es nicht egal sein, ob der Taster prellt? Das Ding hängt
komplett. Selbst wenn der Taster irgendwo prellt müsste sich das ganze
doch
wieder fangen, da es keinen Zustand gibt, der als Sackgasse in Frage
kommt?
Der Taster funktioniert laut LED und die 50MHz sind auch weiterhin da
(Oszi geprüft).
Warnungen:
Ja, jede Menge, die aber nichts mit dem entsprechenden Fetzen Hardware
zu tun haben. Nur für den ResetGenerator beschwert sich das Tool über
den
default case (zu recht) und schmeisst ihn weg.
Ich habe das Ganze noch eben mal mit einem globalen asynchronen Reset
versehen (weiterer Taster). Es dauert gefühlt 5* so lang bis das Ganze
hängt.
Aber es lässt sich wieder zum Leben erwecken indem man state auf "00"
zwingt
und RESET_OUT auf '0'.
Kann ein bit_vector noch andere Zustände annehmen als "00" "01" "11"
"10"?
Derzeitiger Code:
1
entityResetGeneratoris
2
Port(RESET_IN:inSTD_LOGIC;
3
RESET:inSTD_LOGIC;
4
CLK_IN:inSTD_LOGIC;
5
STATE_OUT:outstd_logic_vector(1downto0);
6
RESET_OUT:outSTD_LOGIC);
7
endResetGenerator;
8
9
architectureBehavioralofResetGeneratoris
10
11
signalstate:bit_vector(1downto0);
12
13
begin
14
process(RESET,state,RESET_IN,CLK_IN)
15
begin
16
ifRESET='1'then
17
state<="00";
18
RESET_OUT<='0';
19
else
20
ifrising_edge(CLK_IN)then
21
casestateis
22
when"00"=>
23
state<="00";
24
RESET_OUT<='0';
25
ifRESET_IN='1'then
26
state<="01";
27
RESET_OUT<='1';
28
endif;
29
when"01"=>
30
state<="11";
31
RESET_OUT<='1';
32
when"11"=>
33
state<="10";
34
RESET_OUT<='0';
35
when"10"=>
36
state<="10";
37
RESET_OUT<='0';
38
ifRESET_IN='0'then
39
state<="00";
40
RESET_OUT<='0';
41
endif;
42
whenothers=>
43
state<="00";
44
endcase;
45
endif;
46
endif;
47
endprocess;
48
STATE_OUT<=to_stdlogicvector(state);
49
endBehavioral;
Toll die Formatierung funktioniert ziemlich gut :)
Hallo Patric,
> Kann ein bit_vector noch andere Zustände annehmen als "00" "01" "11"> "10"?
Nein, der bit_vector(1 downto 0) kennt keine anderen Werte.
Aber dein Synthesetool erkennt, dass du eine Statemachine baust, und es
kann die interne Codierung der States anders wählen, als du im VHDL-Code
angibst. Die Ausgänge müssen mit den Werten im Code übereinstimmen, aber
die internen Zustände können eine andere Codierung aufweisen. Du kannst
in der ISE die Codierung der SM vorgeben. Evtl ist dort eine Codierung
wie "one hot" eingestellt, dann werden deine vier Zustände mit 4
Flipflops codiert, und dann kann es verbotene Zustände geben, in denen
sich die SM aufhängt.
Reset_in ein ansynchrones Signal von außen, das du zunächst
einsynchronisieren musst. Andernfalls kann es passieren, dass Reset_in
genau bei einer Taktflanke schaltet. Ein Teil der Logik wertet noch den
alten Wert von Reset_in aus, ein anderer Teil sieht schon den neuen
Wert, und insgesamt erhältst du ein verbotenes Ergebnis (SM hängt sich
auf).
viele Grüße
Achim S.
Danke Achim!
Also die Antwort auf meine Frage mit den Zuständen des bit_vectors wäre
dann ein nein, aber das Synthesetool weiss es besser?
Ich dachte ich hätte das RESET_IN Signal über die Statemachine
einsynchronisiert. Nun gut dann werde ich mir morgen mal ISE genauer
ansehen, oder kannst Du mir sagen wo ich Einfluss auf die SM-Generation
nehmen kann?
Ach Quartus war irgendwie einfacher :)
Aber das werde ich mir mal genauer zu Gemüte führen, ich habe schon an
meinem Verstand gezweifelt. Immerhin ist es ja schon ein Gray-Code.
> Nun gut dann werde ich mir morgen mal ISE genauer> ansehen, oder kannst Du mir sagen wo ich Einfluss auf die SM-Generation> nehmen kann?
auf dem Rechner hier habe ich nur die 10.1 installiert. Dort kannst du
die Einstellung über einen Rechtsklick auf Synthesize XST -> Properties
-> HDL Options einstellen. In anderen Versionen muss es nicht genau so
heißen, aber ähnlich.
> Ich dachte ich hätte das RESET_IN Signal über die Statemachine> einsynchronisiert.
Nö: du wertest das Signal zwar nur bei der steigenden Taktflanke aus,
aber das Signals kann sich genau zu diesem Zeitpunkt ändern. Um es
einzusynchronisieren musst du es mit der steigenden Taktflanke einem
internen Signal zuweisen. Und dieses interne Signal nutzt du dann (mit
einem Takt Verzögerung) zur Steuerung der SM.
Wenn sich dann das externe Signal genau bei der Taktflanke ändert,
erhält das interne Signal den neuen Wert entweder gleich oder erst einen
Takt später, aber es hat auf jeden Fall kurz nach der Taktflanke einen
eindeutigen Wert. Und alle Teile der Logik der SM sehen den identischen,
eindeutigen Wert und schalten mit dem nächsten Takt "in die selbe
Richtung".
viele Grüße
Achim S.
Achim S. schrieb:> Nö: du wertest das Signal zwar nur bei der steigenden Taktflanke aus,> aber das Signals kann sich genau zu diesem Zeitpunkt ändern.
Und noch nicht mal das ist das Problem. Das kommt nämlich gleich danach:
nicht alle Flipflops der FSM sehen den selben Pegel. Das ist der
eigentliche Knackpunkt.
1
process(RESET,state,RESET_IN,CLK_IN)
2
begin
3
ifRESET='1'then
4
state<="00";
5
RESET_OUT<='0';
6
else
7
ifrising_edge(CLK_IN)then
Diese Sensitivliste ist überbestimmt. Da muss der Simulator zu viel tun,
denn er wird unnötigerweise bei einer Änderung von state und RESET_IN zu
einer Neuberechnung genötigt!
Patric vL schrieb:> Ach Quartus war irgendwie einfacher :)
Das hat nichts mit Quartus zu tun. Auch Altera kocht da mit dem selben
Wasser: unterschiedliche Laufzeiten von asynchronen Signalen, die direkt
in eine FSM gehen, führen per Definition zu Fehlern.
> Nun gut dann werde ich mir morgen mal ISE genauer ansehen, oder kannst> Du mir sagen wo ich Einfluss auf die SM-Generation nehmen kann?
Als Faustformel: wenn du durch eine geänderte FSM-Implementierung ein
anderes Verhalten der FSM bekommst, dann hast du mit an Sicherheit
grenzender Wahrscheinlichkeit einen Designfehler, der irgendwas mit
Laufzeiten und/oder der Verdrahtung zu tun hat.
Patric vL schrieb:> Ich habe das Ganze noch eben mal mit einem globalen asynchronen Reset> versehen (weiterer Taster). Es dauert gefühlt 5* so lang bis das Ganze> hängt.
Wie gesagt: andere Verdrahtung, anderes Verhalten.
Ursache: nicht einsynchronisierter Eingang, der direkt in die FSM geht.
Ein asynchroner Reset, wieder mal...
Hallo Achim S.,
hallo Lothar M.,
zu dem Punkt Synthesetool erkennt Statemachine:
Beim Schematic sind tatsächlich 4 FlipFlops zu erkennen. Ich durchschaue
das Schematic nicht ganz, aber es sieht nach einer OneHot-Codierung aus.
Beim Menuepunkt "FSM Encoding Algorithm" war "Auto" eingetragen.
Ich habe das RESET-Signal erstmal wieder rausgenommen (war eh nur um zu
prüfen, ob man einen augenscheinlichen "00" state auf "00" resetten
kann)
und ich habe "FSM Encoding Algorithm" auf "None" gesetzt damit
funktioniert
der folgende Code:
1
process(CLK_IN)
2
begin
3
ifrising_edge(CLK_IN)then
4
casestateis
5
when"00"=>
6
state<="00";
7
RESET_OUT<='0';
8
ifRESET_IN='1'then
9
state<="01";
10
RESET_OUT<='1';
11
endif;
12
when"01"=>
13
state<="11";
14
RESET_OUT<='1';
15
when"11"=>
16
state<="10";
17
RESET_OUT<='0';
18
when"10"=>
19
state<="10";
20
RESET_OUT<='0';
21
ifRESET_IN='0'then
22
state<="00";
23
RESET_OUT<='0';
24
endif;
25
whenothers=>
26
state<="00";
27
endcase;
28
endif;
29
endprocess;
zumindest habe ich nach 5min Finger wundtippen keinen Hänger gehabt (ich
weiss, dass dies kein Beweis ist).
zum Punkt einsynchronisieren des RESET_IN Signales:
Ich habe in einem zweiten process das RESET_IN Signal mit CLK_IN
synchronisiert und dabei das Signal synced_reset generiert und dieses
statt RESET_IN verwendet. Code:
1
process(CLK_IN)
2
begin
3
ifrising_edge(CLK_IN)then
4
synced_reset<=RESET_IN;
5
endif;
6
endprocess;
7
8
process(CLK_IN)
9
begin
10
ifrising_edge(CLK_IN)then
11
casestateis
12
when"00"=>
13
state<="00";
14
RESET_OUT<='0';
15
ifsynced_reset='1'then
16
state<="01";
17
RESET_OUT<='1';
18
endif;
19
when"01"=>
20
state<="11";
21
RESET_OUT<='1';
22
when"11"=>
23
state<="10";
24
RESET_OUT<='0';
25
when"10"=>
26
state<="10";
27
RESET_OUT<='0';
28
ifsynced_reset='0'then
29
state<="00";
30
RESET_OUT<='0';
31
endif;
32
whenothers=>
33
state<="00";
34
endcase;
35
endif;
36
endprocess;
"FSM Encoding Algorithm" wurde wieder auf "Auto" gesetzt. Im Schematic
konnte ich jetzt keine OneHot-Codierung finden. Daher habe ich
"FSM Encoding Algorithm" auf "OneHot" gesetzt ich konnte aber immer noch
keine OneHot-Codierung im Schematic finden. Die "Auto" und "OneHot"
Versionen habe ich getestet (diesmal mit Funktionsgenerator) und auch
diesmal hängt nichts.
Fazit:
An sich war die Gray-Codierung nicht falsch, aber das Synthesetool
hat eine OneHot-Codierung daraus gemacht und die knirscht, weil das
RESET_IN-Signal dadurch nicht (mehr?) synchronisiert war.
Ich danke Euch, ich war nämlich kurz davor meinen Verstand zu verlieren,
abgesehen davon fallen mir spontan drei Stellen ein, bei denen diese
Art Fehler auch noch dazwischen funkt.
Gruß, Patric
bitteschön, und schön dass es jetzt klappt.
> An sich war die Gray-Codierung nicht falsch, aber das Synthesetool> hat eine OneHot-Codierung daraus gemacht und die knirscht, weil das> RESET_IN-Signal dadurch nicht (mehr?) synchronisiert war.
Ich würde eher formulieren: das Reset_in ist seiner Natur nach ein
asynchrones Signal, und du musst erst ein synchrones Signal daraus
machen.
In der One-hot SM führt das asynchrone Eingangssignal zu Fehlern bis hin
zum Aufhängen. In deiner Gray-codierten SM, bei der alle Zustände
genutzt werden, führt das asynchrone Eingangssignal "nur" zu einem
falschen Durchlaufen der States (der Ausgangspuls kann z.B. mal zu kurz
oder zu lang werden), aber nicht zum Aufhängen der SM. Das ist zwar
schon mal eine Verbesserung, und bei flüchtigem Darübersehen fallen
verbleibende Fehler vielleicht nicht mal auf. Aber die richtige Lösung
besteht allein darin, das Signal einzusynchronisieren.
viele Grüße
Achim S.
und ich würde Dir dringend dazu raten deine FSM wie oben beschrieben zu
definieren und dem Synthesetool die Entscheidung der Codierung zu
überlassen
>type state_type is (idle, zustand1, zustand2, zustand3);>signal state : state_type;
da kann man dem state nämlich gleich noch einwenig Info mit geben, wie
"idle", "reset_active", "wait_for_reset_low" oder ähnlich ;-)
Gruß
Kann es ein dass alle INterpretationen falsch waren und
der Code
state <= "00";
RESET_OUT <= '0';
if RESET_IN = '1' then
state <= "01";
RESET_OUT <= '1';
end if;
einfach Mist ist?
Könnte das Problem des Hängens nicht besser mit
if RESET_IN = '1' then
state <= "01";
RESET_OUT <= '1';
else
state <= "00";
RESET_OUT <= '0';
end if;
gefixt werden?
Zwei verschiedene Zuweisungen auf 'state' , welche soll
denn bitteschön gelten? MIt 'else' eindeutig
@Martin
Soweit ich das verstanden habe wird bei der Synthese
1
RESET_OUT<='0';
2
ifRESET_IN='1'then
3
state<="01";
4
RESET_OUT<='1';
5
endif;
Der Anweisungsblock von oben nach unten interpretiert und der letzte
Zustand "gilt". Das macht den Code lesbarer, weil man oben quasi
erstmal den Default-Zustand definieren kann und unten auf die
Einzelfälle eingehen kann.
In einem meiner Bücher wurde das als guter Stil propagiert.
martin schrieb:> Zwei verschiedene Zuweisungen auf 'state' , welche soll> denn bitteschön gelten?
Solange wie die bei VHDL im Prozess stehen, gewinnt die letzte
Zuweisung.
> MIt 'else' eindeutig
Ja, aber: Es wird gern vergessen alle Signale, die ein Prozess treibt,
in jedem möglichen Zweig zu setzten (zumindest bei komplexeren Sachen).
Daher ist es nicht verkehrt erstmal allen Signalen einen default-Wert
zuzuweisen und den dann ggf. zu "überschreiben".
Duke
@Achim S.
Spontan hätte ich ja gesagt, dass, da beim Gray-Code ja immer nur ein
Bit kippt alles in Ordnung sein sollte, aber nach längerem Meditieren
kommen mir Zweifel.
Ich habe dass jetzt noch mal mit Funktionsgenerator, "None",
Gray-Codierung und ohne Synchronisierung durchlaufen lassen, mit Oszi
auf Nachleuchten unendlich und siehe da: manche Impulse sind nur 20ns
lang. Also es scheint ein "Durchrutschen" von "00" auf "11" zu geben.
Ich ziehe mein Fazit zurück :( War zugegebenermassen nur ein Versuch
wenigstens ein wenig Recht zu haben ;)
ABER meine Gray-Version würde wenigstens nicht hängenbleiben (jaja
ich weiss unsauber ist unsauber).
@martin (Gast)
Lesbarkeit ist immer gut. Würde denn eine solche Codierung auch
hängenbleiben können? Die bit_vector[2]-Gray-Version hat ja durch
die Synthese als OneHot zusätzliche "illegale" States erzeugt, die sich
mit when others nicht abfangen liessen, weil es semantisch vollständig
auscodiert war.
martin schrieb:> Zwei verschiedene Zuweisungen auf 'state' , welche soll> denn bitteschön gelten?
Wie üblich beim Prozess: die letzte Zuweisung an ein Signal gewinnt...
Der "Zwischenzustand" existiert in diesm Fall gar nicht. Nehmen wir mal
diese (etwas unsinnige und umständliche) Beschreibung:
1
process(clk)begin
2
ifrising_edge(clk)then
3
Ausgang<='0';
4
ifEingang='1'then
5
Ausgang<='1';
6
endif;
7
endif;
8
endprocess;
Frage:
Was macht bei einer Taktflanke der Ausgang, wenn der Eingang '1' ist?
Antwort:
Der Ausgang ist fest auf '1'. Da gibt es keine auch noch so kurzen
Spikes nach '0', obwohl da eine Defaultzuweisung (Ausgang <= '0') steht.
Patric vL schrieb:> ABER meine Gray-Version würde wenigstens nicht hängenbleiben (jaja> ich weiss unsauber ist unsauber).
Glück gehabt, denn du hast alle Zustände verwendet.
Wenn das jetzt aber nicht sowas simples wäre, sondern eine FSM, die z.B.
einen Getränkeautomaten steuert, dann käme z.B. der Kaffee und dann wäre
Ende. Oder es käme nur ein Becher, oder kein Pulver...
EDIT:
Zweiter! Duke hatte das mit dem "gewinnen" schon erwähnt... ;-)