Hi!
Habe einen Zustandsautomaten programmiert und bleibe nun in einem
Zustand hängen. Ist folgende Abfrage gültig?
1
whenZ_3S=>ifQINT>30then
2
FOLGE_Z<=Z0;
3
elseFOLGE_Z<=Z_3S;
4
endif;
Hier wird im Zustand Z_3S abgefragt, ob der Zähler QINT (integer) größer
als 30 ist. Ist dem so, dann wird auf den Grundzustand Z0 gewechselt,
ansonsten im Zustand Z_3S geblieben. Eine Simulation mit Modelsim zeigt
nun aber, dass der Zustand Z_3S nie verlassen wird, obwohl der Zähler
bereits weit über 30 hinausläuft.
Woran kann das liegen?
Vielen Dank für Tipps,
bg, Ole
Zur weiteren Information hier noch der gesamte Code:
du hast in der Sensivity-Liste den Zähler vergessen
UE_SN: process (TASTER, ZUSTAND, QINT)
Tipp: du kannst auch Modelsim zur Ausgabe eines solchen Fehlers
veranlassen
Trage in der modelsim.ini folgendes ein:
CheckSynthesis = 1
Ole schrieb:> Nun scheint alles bestens zu funktionieren :)
In der Simulation: Ja.
Ind der Praxis: Nie und nimmer.
Warum bin ich mir da so sicher?
Weil du hier asynchrone Eingänge einfach ohne Einsynchronisieren auf
eine FSM loslässt:
1
TASTER:inBIT_VECTOR(4downto0);-- Taster up, enter, down, left, right
Hallo Lothar!
Vielen Dank für deine Kritik.
Erreicht werden soll folgendes: Wenn der Vierfachswitch SW7 komplett
geschlossen ist, sollen die fünf Taster Up, Enter, Down, Left und Right
ausgelesen werden. Jedem Taster ist ein LED-Code zugeordnet, welcher
nach dem Drücken 3 Sekunden lang anliegen soll.
Bspw. sollen bei der Taste Up die LEDs 0110 anzeigen, also die mittleren
beiden sollen 3 Sekunden leuchten.
Du hast im Übrigen Recht, ich habe diesen Code noch nicht auf einem
Board ausprobiert. Ob es zu Laufzeitproblemen kommt, kann ich demnach
nicht sagen.
Die prellenden Taster halte ich für vernachlässigbar, da ja ganze drei
Sekunden gewartet werden soll. Ich glaube nicht, dass dem menschlichen
Nutzer dann auffällt, ob der so eben losgelassene Taster noch ein paar
mal in den nächsten µs den Zähler resettet. Für zeitlich kritische
Anwendungen hast du natürlich Recht.
OT: Mein Lob an deine sehr gut verständliche Homepage! Habe darin eben
gelesen und bin über den synchronen Reset gestolpert. Ich habe gelernt,
dass der Reset aus Sicherheitgründen assynchron auszuführen ist. Falls
mal der Takt ausfällt, ist es dann immer noch möglich, die zu steuernde
Maschine (oder andere Dinge) auf einen Grundzustand zurück zu bringen.
Vielen Dank noch mal für deine Hilfe,
bg, Ole
Ole schrieb:> Ich habe gelernt, dass der Reset aus Sicherheitgründen assynchron> auszuführen ist. Falls mal der Takt ausfällt, ist es dann immer noch> möglich, die zu steuernde Maschine (oder andere Dinge) auf einen> Grundzustand zurück zu bringen.
Das eine hat mit dem Anderen nichts zu tun. Es gibt in der
Sicherheitstechnik andere Methoden, Ausgänge sicher zu schalten. Denn
um die geht es da ja ausschließlich. Du müsstest also nur den
Ausgangstreiber mit dem Reset in einen sicheren Zustand bringen.
Sicherheitstechnisch reicht es nämlich gar nicht aus, ein so tief
vergrabenes Bauteil wie das FPGA "sicher" zu machen, und sich dann drauf
zu verlassen, dass die nachfolgenden Bauteile sicher abschalten.
> Falls mal der Takt ausfällt
Dann ist der Reset sicher eines der kleineren Probleme!
Ich hatte im Feld noch nie einen ausgefallenen Quarzoszillator.
Dass ein asynchroner Reset imFPGA Ressourcen frisst, das zeigt der
Beitrag "Xilinx und die Resets"
Für andere Hersteller lont es sich, das Handbuch zu lesen. Und wenn
schon, dann sollte der Reset zwar asynchron kommen (können), aber nur
synchron weggehen dürfen! Denn sonst läuft dir dein Sytem mal an und mal
nicht. Ich konnte das seinerzeit auch nicht glauben, ist aber so... ;-)
> Die prellenden Taster halte ich für vernachlässigbar
Wenn du es nur nicht vergisst, dass die Dinger potentiell unsauber sind,
dann kannst du das schon machen.
> OT: Mein Lob an deine sehr gut verständliche Homepage!
Danke.
Hallo!
Lothar hatte Recht, auf einem Board ging mit dem Code schon mal gar
nichts. Lag wahrscheinlich an Latches.
Demnach wurde nun noch mal ein neuer Code entwickelt, indem vor allem
die Signale "LAUFEN" und "FERTIG" eingeführt wurden. Wenn "LAUFEN" 1
ist, zählt der Zähler hoch und stellt nach 3 Sekunden "FERTIG" auf 1.
Solange "FERTIG" nicht 1 ist, kann nicht in einen anderen Zustand
gewechselt werden.
Daraus ergibt sich die Logik, dass FERTIG und LAUFEN nicht gleichzeitig
1 bzw. 0 sein können.
Genau das tritt jedoch leider ein, wie bei der angehängten
Timing-Simulation ersichtlich.
Was genau funktioniert da nicht?
Ich verrate dir nicht, wo der Fehler liegt, aber ich kann dir sagen,
dass es von der Mischung synchroner und asychroner Prozesse kommt und
sich "Latency" nennt.
Nur so viel: du kommst beim Zurücksetzten von LAUFEN 1 Takt "zu spät"
(= to late) , weil du den Umweg über ein weiteres Signal machst. Dieser
Umweg kostet dich 1 Takt.
BTW:
Hi!
Danke für deine Hilfe! Dieses doppelte Signal war tatsächlich ein Dorn
im Auge, jedoch fand ich es einfach schön, vom Timer ein Signal
zurückgeben zu können.
Nun wird im Übergangsschaltnetz einfach wieder auf den Zählerstatus
abgefragt. Herausgekommen ist Folgendes:
ifRESET='0'thenZUSTAND<=Z0;--bei reset in Z0 gehen
52
elsifCLK='1'andCLK'eventthen
53
ifDIPSW="1111"then
54
ZUSTAND<=FOLGE_Z;
55
endif;
56
endif;
57
endprocessZ_Speicher;
58
59
----UEBERGANGSSCHALTNETZ----
60
UE_SN:process(TASTER,ZUSTAND,QINT)
61
begin
62
ifZUSTAND=Z0then
63
caseTASTERis
64
when"11110"=>FOLGE_Z<=Z_ENTER;
65
when"11101"=>FOLGE_Z<=Z_UP;
66
when"11011"=>FOLGE_Z<=Z_DOWN;
67
when"10111"=>FOLGE_Z<=Z_LEFT;
68
when"01111"=>FOLGE_Z<=Z_RIGHT;
69
whenothers=>FOLGE_Z<=Z0;
70
endcase;
71
else
72
ifQINT>300000000then
73
FOLGE_Z<=Z0;
74
else
75
FOLGE_Z<=ZUSTAND;
76
endif;
77
endif;
78
endprocessUE_SN;
79
80
----AUSGANGSSCHALTNETZ----
81
A_SN:process(ZUSTAND)
82
begin
83
caseZUSTANDis
84
whenZ0=>LED<="1111";
85
LAUFEN<='0';
86
whenZ_UP=>LED<="1001";
87
LAUFEN<='1';
88
whenZ_ENTER=>LED<="0000";
89
LAUFEN<='1';
90
whenZ_DOWN=>LED<="0110";
91
LAUFEN<='1';
92
whenZ_LEFT=>LED<="0101";
93
LAUFEN<='1';
94
whenZ_RIGHT=>LED<="1010";
95
LAUFEN<='1';
96
endcase;
97
endprocessA_SN;
98
99
----TIMER----
100
ZAEHLER:process(CLK)
101
begin
102
ifCLK='1'andCLK'eventthen
103
ifLAUFEN='1'then
104
QINT<=QINT+1;
105
else
106
QINT<=0;
107
endif;
108
endif;
109
endprocessZAEHLER;
110
111
endVerhalten;
Blöderweise kann das leider wieder noch nicht auf einem Board
ausprobiert werden, in der Simulation läuft es aber zu mindest schon
mal.
Ich frage mich, was du gegen die asynchronen Prozesse hast. Im
Übergangsschaltnetz wird der Folgezustand berechnet und später dann der
Zustand in SPEICHER aktualisiert. Letzteres passiert Taktsynchron. Das
Ausgangsschaltnetz habe ich bis jetzt noch nicht synchron gesehen.
Zusätzlich vertraue ich auf den jetzigen Code, da laut Synthetisierer
keine Latches erzeugt werden.
Danke nochmals, lg,
Ole
Ole schrieb:> Ich frage mich, was du gegen die asynchronen Prozesse hast. Im> Übergangsschaltnetz wird der Folgezustand berechnet und später dann der> Zustand in SPEICHER aktualisiert. Letzteres passiert Taktsynchron.
Und wie hast du dir die Latency eingefangen? Weil du die verschlungenen
Wege vom einen zum anderen Signal nicht mehr nachvollziehen konntest.
Und noch immer machst du einen unnötigen Umweg über den State, um deinen
Zähler zurückzusetzen. Dein Zähler wird einen Takt zu spät
zurückgesetzt. Auch das ist ein Takt Latency.
Lies einfach mal das durch:
http://www.lothar-miller.de/s9y/archives/43-Ein-oder-Zwei-Prozess-Schreibweise-fuer-FSM.html> Das Ausgangsschaltnetz habe ich bis jetzt noch nicht synchron gesehen.
Gegenfrage: Wofür braucht man ein Ausgangsschaltnetz, wenn man jeden
Ausgang registrieren kann, weil im IO-Pin vom FPGA sowieso ein Flipflop
ist?
> Zusätzlich vertraue ich auf den jetzigen Code,> da laut Synthetisierer keine Latches erzeugt werden.
Gut, wenn du deinen Beschreibungsstil gefunden hast und damit glücklich
bist...
> Danke nochmals
Keine Ursache.
Ole schrieb:> Ich frage mich, was du gegen die asynchronen Prozesse hast.
Als ich mit VHDL angefangen hab, hab ich mal einen einfachen
Zustandsautomat geschrieben, der ohne Takt auskommen sollte.
Auf einem CPLD ausprobiert: geht!
Auf einem FPGA ausprobiert: geht nicht!
Tatsächlich nahm der Automat im FPGA Zustände ein, die es in meinem Code
überhaupt nicht gab.
Wie kann das sein?
Der Zustand (in Deinem Fall "ZUSTAENDE") wird als Bitwort kodiert, d.h.
der tatsächliche Zustand des Automaten ergibt sich aus der Kombination
der einzelnen Bits im Wort.
Im FPGA werden nun die Bits unterschiedliche Laufzeiten haben, d.h. beim
Übergang von einem Zustand in einen anderen, wird es vorkommen, daß es
zwischenzeitlich auch ein ganz anderer Zustand im Bitwort steht.
Mit Takt ist das kein Problem, weil das Bitwort zu einem ganz bestimmten
Zeitpunkt "geschrieben" und "gelesen" wird und dazwischen der Zustand
egal ist.
Ohne Takt reagiert der Automat sofort auf jede Änderung, dann verrennt
er sich und Du kommst in Teufels Küche.