www.mikrocontroller.net

Forum: FPGA, VHDL & Co. FSM Problem(Ein zustand als Taktverzögerung)


Autor: VHDL_Bginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen!
Ich habe wieder ein Problem mit einem Zustandsautomat.Ein zustand will 
ich als eine 30 ns Taktverzögerung verwenden.Das heisst ich muss die 
zahl 3 da definieren und mit jedem clock(100 MHz)wird der zahl 
dekrementiert(!=0=>im aktuellen zustand bleiben) wenn ich die Null 
erreiche, dann kann ich zum nächsten zustand springen.Aber das programm 
macht total was anders sogar kann es die zahl auch nicht 
dekrementieren.Ich haoffe dass jemand mir bei diesem Problem helfen 
könnte.)ISE webpack(9.2i & 10.1).
MFG

Autor: Mark (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@VHDL_Bginner

es wäre hilfreich, wenn Du den VHDL-Code mal posten würdest, oder willst 
Du gleich die fertige Lösung von jemand anders haben?

Autor: Neuling_1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MARK!Es ist nett von Dir,dass du schnell darauf antwortest.Ich denke 
mein problem habe ich richtig beschrieben und wenn man sorgar keine 
Ahnung in VHDL kann er es verstehen denke ich mal.Das Problem haengt 
nicht davon ab wie man es in VHDL schreiben kann,Aber meine frage ist 
sowas in Hardware realisierbar.
Und hier ein code stück extra für Dich für 2 zustände aber die frage für 
Alle selbsverständlich:
begin
:
signal counter:std_logic_vector(2 downto 0):="000";
Eins:process(clk)  --Aktualisierung
begin
:
if rising_edge(clk) then
State_nxt<=S0;
end if;
end process(Eins);
zweitens;process(zustand)
begin
case zustand is
when s0 => state_nxt<=s1;      --counter ist schon initialisiert
when s1  => counter<=counter+1;-- hier ist eine Inkrementierung)
            if counter<4 then  --wieso counter zaehlt nicht hoch?
            state_nxt<=s1;--wenn ich ein extra zustand definiere wird
            end if;      --inkrementiert aber wenn ich so definiere
                         --macht er gar nichts
             else
            state_nxt<=s0;
end case;
end process zweitens;
:
Für jede Hilfe bin ich sehr Dankbar.
MFG

Autor: Neuling_1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry!ich habe mich vertippt.im ersten prozess statt state_nxt<=s0 muss 
state_current<=state_nxt sein.

Autor: Rick Dangerus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bau Dir eine Testbench dazu und teste das im Simulator!
Außerdem mußt Du dafür sorgen, das Dein counter auch mal wieder 
zurückgesetzt wird.

Rick

Autor: Joachim Schäfer (joachims)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Eine Möglichkeit währe z.B.:
es wird nun jeder State um 3 Takte verzögert, ich habe allerdings die 
Statemachine hier in if else ausgeführt, das geht auch mir switch
und mit Signalen.
Ich bin selbst allerdings Anfänger (VHDL) und würde mich über
kommentare der VHDL Cracks freuen !

Gruß Joachim



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity FSM is
 Port (  RESET   : IN std_logic;
      CLK      : IN std_logic;
      OUTPUT   : OUT std_logic_vector(3 downto 0)
    );
end FSM;
architecture Behavioral of FSM is
begin

process (RESET,CLK)
variable count   : integer range 0 to 2;
variable zustand  : integer range 0 to 3;
begin

  if RESET = '1' then
    count := 0;
  elsif rising_edge(CLK) then
  count := count +1;
    if count > 2 then
      count := 0;
      if zustand = 0 then
        OUTPUT <= "0001";
        zustand :=  zustand + 1;
      elsif zustand = 1 then
        OUTPUT <= "0010";
        zustand :=  zustand + 1;
      elsif zustand = 2 then
        OUTPUT <= "0100";
        zustand :=  zustand + 1;
      elsif zustand = 3 then
        OUTPUT <= "1000";
        zustand := 0;
      end if;
    end if;
  end if;
end process;
end Behavioral;

Autor: Neuling_1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Joachim.Aber was Du da geschrieben hast ist ein 3 takt verzögerung 
für jeden zustand aber das will ich nicht.Mein problem liegt darin,dass 
Du 3 states hast nehmen wir an!und in einem  einzelnen State willst du 
eine verzögerung von 40 ns Z.B(clock 100MHz).Also in einem zustand musst 
Du ein defaultwert definieren fuer dein Counter und je nachdem wie Du 
den zähler zählen(ink. oder dekr.) willst .Counter hat den max oder min 
wert nicht erreicht bleibt in demselben zustand(UND HIER IST MEIN 
PROBLEM)sonst naechsten zustand wird erreicht.

Autor: Neuling_1 (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo again!Hier ist ein source code Beispiel mit einem Testbench der 
mein problem zeigt.Cout ist als counter Pin für die Visualisierung.Aber 
bei der simulation kriege ich kein counter inkrementierung.

Autor: Start-ING (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@neuling1
da das offensichtlich nicht Dein richtiger Code ist, denn er ist absolut 
nicht synthesefähig, können wir Dir bei Deinem Problem auch nur schlecht 
weiterhelfen. Der Fehler kann nahezu überall liegen. es geht los mit 
syntaxfehlern, fehlenden Signalen in der sensitivity list oder 
ähnlichem. Prinzipiell ist es recht leicht möglich, sowas zu 
realisieren...

Autor: Neuling_1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast recht:-)sorry aber hier ist der richtige Code:Diese Problem hat 
mich richtig geärgert.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity TEST is
port(clk:in std_logic;
     sort:out std_logic;
    Cout:out std_logic_vector(2 downto 0)
    );
end TEST;

architecture Behavioral of TEST is
type zustaende is (s0,s1);
signal zustand:zustaende:=s0;
signal folge:zustaende:=s0;
signal counter:std_logic_vector(2 downto 0):="000";

begin
erstens:process(clk)
begin
if rising_edge(clk) then
zustand<=folge;
end if;
end process erstens;
zweitens:process(zustand)
begin
case zustand is
when s0 => folge<= s1;
when s1 => counter<=counter+1;
           if counter<3 then
            folge<=s1;
     Cout<=counter;
           else
             folge<=s0;
      counter<=(others=>'0');
   end if;
end case;
end process zweitens;
Drittens:process(zustand)
begin
case zustand is
when s0 => sort<='0';
when others => sort<='1';
end case;
end process Drittens;


end Behavioral;

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Neuling_1

Was für ein Code und welche Testbench gehört zu der Waveform?

Autor: Neuling_1 (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier ist die Code + Testbench

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity TEST is
port(clk:in std_logic;
     sort:out std_logic;
    Cout:out std_logic_vector(2 downto 0)
    );
end TEST;

architecture Behavioral of TEST is
type zustaende is (s0,s1);
signal zustand:zustaende:=s0;
signal folge:zustaende:=s0;
signal counter:std_logic_vector(2 downto 0):="000";

begin
erstens:process(clk)
begin
if rising_edge(clk) then
zustand<=folge;
end if;
end process erstens;
zweitens:process(zustand)
begin
case zustand is
when s0 => folge<= s1;
when s1 => counter<=counter+1;
           if counter<3 then
            folge<=s1;
     Cout<=counter;
           else
             folge<=s0;
      counter<=(others=>'0');
   end if;
end case;
end process zweitens;
Drittens:process(zustand)
begin
case zustand is
when s0 => sort<='0';
when others => sort<='1';
end case;
end process Drittens;


end Behavioral;

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas:
:
counter<=counter+1;
:
darf nur in einem getakteten Prozess stehen.
Sonst gibt das eine kombinatorische Schleife.


In deinem Fall hat der Simulator Glück und reagiert nicht mehr auf eine
Änderung von counter, weil der nämlich in der sensitivity-list fehlt.

Wenn du den korrekterweise einfügst
:
zweitens:process(zustand,counter)
:
dann hängt der Simulator sich genauso auf wie deine Hardware.

Also:
Zähler immer taktabhängig.

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bevorzuge die Ein-Prozess-Statemachine.
Deine Aufgabe sieht dann so aus:
if rising_edge(clk) then
  case zustand is
     when s0 => zustand <= s1;
                sort    <= '0';
     when s1 => counter <= counter+1;
                if (counter<3) then
                   zustand <= s1;
                   Cout    <= counter;   -- Fehler? Cout wird nur hier aktualisiert!!
                else
                   zustand <= s0;
                   counter <= (others=>'0');
                end if;
                sort <= '1';
     when others ; -- könnte hier stehen
  end case;
end process;

Hier steht nur der Clock in der Sensitivity-List.
Ist irgendwie lesbarer als die Zwei- oder gar
Drei-Prozess-Schreibweise.
Man muß sich nur daran gewöhnen, dass sich hier
irgendwo ein Takt Latency einschleichen könnte,
aber Denken hält jung.

Alternativ könnte ich Schreiben:
if rising_edge(clk) then
  case zustand is
     when s0 => zustand <= s1;
     when s1 => counter <= counter+1;
                if (counter=3) then
                   zustand <= s0;
                   counter <= (others=>'0');
                end if;
  end case;
end process;

-- concurrent Zuweisungen
Cout <= counter;   
sort <= '0' when zustand=s0 else '1';

Autor: Neuling_1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke schön für Deine Antwort.Du hast die ein prozessdarstellung 
verwendet.meine Frage:ist es nicht realisierbar wenn ich die 3 prozess 
darstellung benutze.IN dieser darstellung hab ich ein prozess für 
zustandsregister und zweiter für zustandübergänge und dritter für die 
Augänge.Bis jetzt ich weiss nicht woran liegt mein Fehler.In meinem Code 
werd ich mein state S1 natürlich mit einem positiven flanke erreichen 
und wenn ich drin bin muss counter inkrementiert werden. Also brauche 
ich keine zusätzliche takte für die Anweisungen was ich drin im meinem 
zustand definiert habe.(Device ist cpld coolrunnerII).

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Neuling_1
Du hast ein Verständnisproblem.

Zur Vereinfachung: ein Counter hat mehrere stabile Zustände und ist 
daher eine State-Machine (und umgekehrt).

Wenn du aber für eine State-Machine einen getakteten Prozess für die 
Übernahme des Folgezustands brauchst, dann brauchst du auch für das 
Weiterschalten des Counters einen getakteten Prozess.

Ins Unreine geschrieben könnte das evtl. so aussehen:
erstens:process(clk) begin
  if rising_edge(clk) then
    zustand <= folge;
    if(zustand=S1)  counter <= counter+1; 
    else            counter <= (others=>'0');
    end if;
  end if;
end process erstens;

zweitens:process(zustand, COUNTER) begin -- ALLE Signale in die Sensitivity-List!!!!!!!
  case zustand is
    when s0 => folge   <= s1;
    when s1 => if (counter<3) then
                  folge   <= s1;
                  Cout    <= counter; -- soll das so sein??
               else
                  folge   <= s0;
               end if;
  end case;
end process zweitens;

Drittens:process(zustand) begin
  case zustand is
     when s0 =>     sort<='0';
     when others => sort<='1';
  end case;
end process Drittens;

Aber ehrlich gesagt: ein halbes Jahr später würde (selbst) ich (selbst) 
das nicht mehr kapieren!!!!

Autor: Joachim Schäfer (joachims)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Weshalb möchtest Du denn 3 Prozesse ?
Kannst Du das Problem Beschreiben ohne deine eigenen
Lösungsansätze in Spiel zu bringen?

So ganz Verstanden hab ich ja nicht was Du vorhast, aber eine 
Statemachine
in der ein Zustand um n Takt Counts verzögert wird, das ist auch so 
machbar:




library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;


entity stateTest2 is
 Port (  RESET   : IN std_logic;
      CLK      : IN std_logic;
      OUTPUT2   : OUT std_logic_vector(3 downto 0)
    );
end stateTest2;
architecture Behavioral of stateTest2 is
type zustaende is (s0,s1);
signal zustand:zustaende:=s0;

begin

process (RESET,CLK)
variable count   : integer range 0 to 2;

begin

  if RESET = '1' then
    count := 0;
    zustand <= s0;
  elsif rising_edge(CLK) then
    case zustand is
          when s0 =>   OUTPUT2 <= conv_std_logic_vector(count,4);
                  count := count +1;
                  if count > 2 then
                    count := 0;
                    zustand <= s1;
                  else
                    -- mach irgend etwas
                  end if;

          when s1 =>   OUTPUT2 <=conv_std_logic_vector(count,4);
                  zustand <=s0;
    end case;
  end if;
end process;
end Behavioral;

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Joachim Schäfer

Ja, jetzt aber auch, wo kommt denn jetzt auf einmal der Reset her?

Als kleine Gedankenstütze:
ein FPGA braucht keinen Reset, das ist nach dem Laden schon definiert.
Z.B. so wie's Neuling_1 gemacht hat:
type zustaende is (s0,s1);
signal zustand:zustaende:=s0;
signal folge:zustaende:=s0;
signal counter:std_logic_vector(2 downto 0):="000";
Einen Reset-Eingang braucht nur der Entwickler für seinen Reset-Knopf.



Aber wenn schon ein Reset, dann bitte synchron.
Was haben wir schon für Dinge mit asynchronen Signalen erlebt...
Und ein Reset ist das Asynchronste überhaupt.
Dieser globale Reset mit seinem globalen Reset-Netzwerk kann
dir z.B. mit einem kleinen Spike das halbe FPGA zurücksetzen,
aber die andere Hälfte nicht.
Und das gibt lustige Fehler: jedesmal einen anderen.

Warum nicht so (wir alle lieben synchrone Designs):
process (RESET,CLK)
variable count   : integer range 0 to 2;
begin
  if rising_edge(CLK) then
    if RESET = '1' then
      count := 0;
      zustand <= s0;
    else
      case zustand is
          when s0 =>   OUTPUT2 <= conv_std_logic_vector(count,4);
                  count := count +1;
                  if count > 2 then
                    count := 0;
                    zustand <= s1;
                  else
                    -- mach irgend etwas
                  end if;

          when s1 =>   OUTPUT2 <=conv_std_logic_vector(count,4);
                  zustand <=s0;
      end case;
    end if;
  end if;
end process;
Vorher aber den Reset-Eingang wie üblich über zwei FFs auf den CLK 
synchronisieren.

Autor: Joachim Schäfer (joachims)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@lkmiller
Danke, ich hab ja in nem Beitrag weiter oben schon geschrieben, das ich 
noch nicht viel Erfahrung mit VHDL habe.
Ja den Reset braucht man hier sicher nicht, aber in der Simulation habe 
ich es schon benötigt um definierte Ausgangszustäbde zu bekommen.
Warscheinlich hätte ich das damals dort auch anders machen können aber
na ja wie gesagt ich lerne noch!
Auch der Tipp mit dem Syncronen Reset und den Folgefehlern
die entstehen könne , ist sehr interresannt.
Ja als Softwareentwickler muss mann mit dem parallelen Ablauf im FPGA
schon umdenken !

Gruß joachim

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.