www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Einfacher Zähler in VHDL mit Spartan 3 Starter Board


Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo! Ich bin ein absoluter Neuling, was VHDL angeht. Ich versuche 
einen Zähler zu schreiben, damit ich eine LED zum blinken bringen kann. 
Hier mein Versuch:

entity BlinkerSchaltung is
    Port ( CLK  : in std_logic;
           LD4 : out std_logic);
end BlinkerSchaltung;

architecture Behavioral of BlinkerSchaltung is
signal divider : std_logic;
signal led : std_logic;
 begin
   process(CLK)
     begin
        if (CLK'event and CLK = '1') then
           if divider = 0 then
              divider <= 50000000;
            LD4 <= led;
           else
                  divider <= divider -1;
           end if;
        end if;
    end process;

end Behavioral;

Das Starter Board hat ja an der Unterseite einen Quarz, der einen Takt 
von 50MHz erzeugt, deswegen der Zähler, von 50000000 abwärts. Dann würde 
die LED pro Sekunde einmal aufblinken. Also immer wenn der Zähler bei 
Null ankommt. Ich entdecke meinen Denkfehler einfach nicht. Kann mir da 
jemand weiterhelfen?

Autor: Jochen Fe. (jamesy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist die LED dann nur einen Clockzyklus an - also etwa 20 Nanosekunden? 
Die LED müßte nach Ablauf des Zählers getoggelt werden, oder übersehe 
ich was?

Autor: Summy Long (mightyright)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, ja da ist was dran. Ich dachte eher 1 sek leuchten und 1 sek nicht 
leuchten.

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hallo! Ich bin ein absoluter Neuling,

Wenn ich mich nicht täusche bekommt dein signal led doch nirgends einen 
Wert zugewiesen. Und stets nur "LD4 <= led;" macht doch auch keinen 
Sinn. Nebenbei, statt Divider würde ich die Bezeichnung Counter 
verwenden.

Ninn doch für den Anfang eines der zahlreichen Blinker-Beispiele aus den 
Tutorials, hatte ich auch gemacht als ich mein erstes Board bekam.

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>signal divider : std_logic;

OK, das ist natürlich auch Quatsch. Mit einem Bit kann man ja schlecht 
einen Zähler bauen, also std_logic_vector, integer, signed oder unsigned 
als sinnvollere Datentypen nehmen.

Autor: Commtel @msn (commtel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Morgen

hab hier ne pdf für Anfänger in der sowas beschrieben wird

oder hier ne gute Info Quelle

http://www.lothar-miller.de/s9y/

c.u
Commtel

Autor: Phil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du die LED Toggeln willst solltest du wie schon erwähnt zumindest 
dein Signal led am Anfang einen Wert zuweisen und dann würde ich das im 
Code noch so abändern:
 if divider = 0 then
  divider <= 50000000;
  LD4 <= led;
  led <= not led;
 else
  divider <= divider -1;
 end if;

Da ja immer erst nach dem Ende des Prozesses die Werte übergeben werden 
übergibst du hier wenn der Zähler auf 0 ist den "alten" Wert von led und 
speicherst dann den neuen Wert in led, der einfach nur invertiert ist. 
Somit toggelt deine Led.

Gruß Phil

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

hier der Code - so müsste es funktionieren...

entity BlinkerSchaltung is
    Port ( CLK  : in std_logic;
           LD4 : out std_logic);
end BlinkerSchaltung;

architecture Behavioral of BlinkerSchaltung is
signal divider : integer range 0 to 50000000;
signal led : std_logic;
 begin
   process(CLK)
     begin
        if (CLK'event and CLK = '1') then
           if divider = 0 then
              divider <= 50000000;
              led <= not led;
           else
              divider <= divider -1;
           end if;
        end if;
    end process;

  ld4 <= led;

end Behavioral;


damit es "sauber" wäre, wäre es noch sinvoll als 1. if bedingung einen 
reset einzubauen. Und if clk'event and clk='1' als elsif danach 
abzufragen... aber funktionieren tuts so auch..

so würde die led jetzt immer wenn die 50 mio abgelaufen wären ihren 
zustand ändern...

Viel Glück damit :-)

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin schrieb:

> damit es "sauber" wäre, wäre es noch sinvoll als 1. if bedingung einen
> reset einzubauen. Und if clk'event and clk='1' als elsif danach
> abzufragen... aber funktionieren tuts so auch..
>
> so würde die led jetzt immer wenn die 50 mio abgelaufen wären ihren
> zustand ändern...
>
> Viel Glück damit :-)

Genau das ist nicht sauber weil das ein asynchroner Reset ist. Wenn 
Reset dann synchron.
Außerdem wird 50.000.001 gezählt, also die Led toggelt 1s+20ns.

Autor: Summy Long (mightyright)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für eure tollen Antworten. Ich denke so werde ich das 
hinbekommen. Ich tue mich etwas schwer mit VHDL. Ich dachte eigentlich, 
dass es mir mit meinen C Kenntnissen wesentlich einfacher fallen wird. 
Aber nur Übung macht den Meister :-) . Danke nochmal...

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C und VHDL haben weder syntaktisch geschweige denn semantisch was 
gemeinsam

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde sogar soweit gehen, zu sagen, dass C-Kenntnisse eher ein 
Hindernis beim Erlernen von VHDL sind. Viel besser ist, sich hinter dem 
Quellcode immer FlipFlops und Gatter vorzustellen.

Autor: Summy Long (mightyright)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal! Also hier habe ich dann jetzt den Zähler mit RST.

entity BlinkerSchaltung is
        Port ( CLK  : in std_logic;
             RST  : in std_logic;
               LD4  : out std_logic);
end BlinkerSchaltung;

architecture Behavioral of BlinkerSchaltung is
   signal divider : integer range 0 to 50000000;
   signal led : std_logic;
begin
   process(CLK, RST)
     begin
      if RST = '1' then
       divider   <= 50000000;
             led <= '0';         -- mit '1' funktioniert es nicht.
          else
         if (CLK'event and CLK = '1') then
           if divider = 0 then
              divider <= 50000000;
              led <= not led;
                else
                     divider <= divider -1;
           end if;
         end if;
      end if;
    end process;

  LD4 <= led;

end Behavioral;

So funktioniert die Schaltung einwandfrei, bei ISE bekommt man nur bei 
dem Vorgang "synthesize xst" ein Ausrufezeichen. UNten im Reiter steht 
aber nix. Hat das dann was zu bedeuten? Und oben bei led <= '0' ,ich 
kann für den Reset keine 1 eingeben. Wisst ihr da vll eine Lösung?
Dass C und VHDL nichts gemeinsam haben, dachte ich mir. Ich ging einfach 
nur davon aus, wenn man schon eine Programmiersprache relativ gut 
beherrscht, sollte es wohl leichter fallen eine andere zu erlenen, als 
wenn man noch nie etwas mit Progsprachen zu tun gehabt hätte.

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest den Reset synchron machen, sieh dir dazu die Seite von 
Lothar Miller an warum.

Zum Unterschied: Mag wohl daran liegen das C eine Programmiersprache ist 
und VHDL eine Hardwarebeschreibungssprache

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du solltest den Reset synchron machen,

Ich wüsste jetzt so spontan nicht warum...

>signal divider : integer range 0 to 50000000;

Mal so am Rande, das sind 50000000+1 Zustände, wenn man bei 50MHz Takt 
eine Periode von exakt 1 Sekunde will benötigt man einen weniger.

@Michael Kremer

>beherrscht, sollte es wohl leichter fallen eine andere zu erlenen,

Ich würde an Deiner Stelle schon mal einen kurzen Blick in ein Buch 
werfen, sonst bleibt es lange Stümperei. Wenn man die ersten 200 Seiten 
vom Reichardt/Schwarz durch hat, so kennt man die Grundbegriffe. Viel 
weiter bin ich leider auch noch nicht gekommen...

Daher verstehe ich auch nicht, warum es mit '1' nicht funkionieren 
sollte.

>led <= '0';         -- mit '1' funktioniert es nicht.

Übrigens, deine Einrückungen sind sehr seltsam, könnte an Tabulatoren 
liegen, die unterschiedlich behandelt werden, je nach Editor.

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probier das Beispiel mal aus:

http://www.lothar-miller.de/s9y/archives/70-Asynch...

Dann sollte sich dies erklären warum man asynchrone resets vermeiden 
sollte

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wobei ich mich auch frage, wozu Reset, wenn es nur blinken soll, der 
Anfangszustand also egal ist. Und warum überhaupt ein internes Signal 
led?
Ich hätte es womöglich so probiert:

Ah halt, led wird gelesen und geschrieben, und wir wollen den Datentyp 
buffer vermeiden, also doch ein internes Signal.

entity BlinkerSchaltung is
  Port ( CLK  : in std_logic;
         LD4  : out std_logic);
end BlinkerSchaltung;

architecture Behavioral of BlinkerSchaltung is
  signal divider : integer range 0 to (50000000-1);
  signal led : std_logic;
begin
  if (divider<0) or (divider>=50000000) then --ensure safe start 
condition
    divider <= '0';
  end if;
  process(CLK)
  begin
    if (CLK'event and CLK = '1') then -- if rising_edge(CLK)
      if divider = 0 -- should take minimal resources
        divider <= (50000000-1);
        led <= not led;
      else
        divider <= divider - 1;
      end if;
    end if;
  end process;
  LD4 <= led;
end Behavioral;

Ohne Gewähr, wer mag mag es testen oder kommentieren.

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine sequentielle if-anweisung außerhalb eines prozesses scheint mir 
fragwürdig und '0' kann man nicht an integer zuweisen

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Eine sequentielle if-anweisung außerhalb eines prozesses scheint mir
>fragwürdig und '0' kann man nicht an integer zuweisen

Ja klar, es muss
divider <= 0;
heißen.

Wobei ich mich momentan frage, wie man sonst für ein Signal bzw. einen 
Zähler einen "sicheren" Anfangszustand gewährleisten kann, wenn man kein 
RESET-Signal verwenden möchte.

Sollte

signal divider : integer range 0 to (50000000-1);

bereits gewährleisten, dass der Anfangswert in diesem Bereich liegt?

Ich meine mich zu errinnern, mal eine direkte Zuweisung eines 
Anfangswertes gesehen zu haben, irgendwie signal x:integer <= 0; oder 
so, aber das mag nur für die Simulation möglich sein. Ich finde es im 
Buch gerade nicht, muss ich mal nachlesen...

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Salewski schrieb:

> Wobei ich mich momentan frage, wie man sonst für ein Signal bzw. einen
> Zähler einen "sicheren" Anfangszustand gewährleisten kann, wenn man kein
> RESET-Signal verwenden möchte.

Du kannst einen Reset verwenden, jedoch sollte der synchron sein und 
nicht asynchron. Also erst Clock abfragen und darin dann den reset als 
erstes.
Alternativ kannst du auch eine FSM mit INIT state verwenden, so mache 
ich das immer, wenn ich keinen reset von außen brauche

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Autor: D. I. (grotesque)
Datum: 02.04.2010 19:45

>Eine sequentielle if-anweisung außerhalb eines prozesses scheint mir
>fragwürdig

Richtig, Reichardt/Schwarz schreiben (3.6.1):

4. Signalen oder Variablen, denen innerhalb einer getakteten 
if-Anweisung ein Wert so zugewiesen wird, dass sie zu D-Flipflops bzw. 
Registern synthetisiert werden, darf außerhalb dieser getakteten 
Anweisung kein Wert zugewiesen werden. Einzige Ausnahme ist die 
Zuweisung eines asynchronen RESET- oder PRESET-Signals, welches vor der 
getakteten if-Anweisung zugewiesen werden muss.

Wobei, irgendwie entspricht meine Initialisierung ja einem RESET?

>Du kannst einen Reset verwenden, jedoch sollte der synchron sein und
>nicht asynchron. Also erst Clock abfragen und darin dann den reset als
>erstes.

Also Reichardt/Schwarz machen gerne asynchrone RESETs, beispielsweise 
bei ihrem 4-Bit-Binärzählers SN74xx161 (code 5-3, Seite 97, 4. Auflage) 
und auch anderswo. Wobei, du machst ja durchaus recht haben...

>Alternativ kannst du auch eine FSM mit INIT state verwenden, so mache
>ich das immer, wenn ich keinen reset von außen brauche

Ah ja, muss ich wohl auch noch mal nachlesen...

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das mit dem asynchronen Reset ist noch überall vorhanden, was aber 
nicht heißt dass man sich das noch angewöhnen sollte.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Salewski schrieb:
> Also Reichardt/Schwarz machen gerne asynchrone RESETs
Diese asynchrone Resetterei machte bei ASICs noch Sinn. Und es ist ja 
auch durchaus eine gültige, sehr gängige, weit verbreitete und überall 
unterrichtete VHDL-Schreibweise....

Aber bei der Synthese für FPGAs muß man eben auch und gerade die 
Technologie mitbeschreiben, um ein gutes Design zu bekommen. Deshalb muß 
den Synthesizer ein wenig "nach dem Maul" beschrieben werden. Gerade für 
FFs gibt es bei Xilinx 2 Betreibearten: asynchron oder synchron. Wenn 
du asynchron zurücksetzt, dann wird ein synchrones Laden automatisch in 
erhöhtem Ressourcenbedarf resultieren. Dazu liest sich schön das öfters 
erwähnte WhitePaper 272 von Xilinx:
http://www.xilinx.com/support/documentation/white_...

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dazu liest sich schön das öfters
>erwähnte WhitePaper 272 von Xilinx:
>http://www.xilinx.com/support/documentation/white_...

Ah, danke Lothar, kannte ich noch nicht!

Autor: danny w. (weisti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe ein ähnliches Problem.

das signal "drehzahl" soll hochgezählt werden.

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_arith.all;
use IEEE.NUMERIC_STD.ALL;


entity anlauf_str is
  port(
    clk: IN STD_LOGIC; 
    drehzahl_max: in STD_LOGIC_VECTOR(7 downto 0);
    drehzahl: out STD_LOGIC_VECTOR(7 downto 0)
  );
end anlauf_str;

architecture behavioral of anlauf_str is


begin

process(clk)      
variable anlauf : std_logic :='1';
variable dz_buff: STD_LOGIC_VECTOR(7 downto 0); -- buffer für signal-drehzahl

begin
  
  if dz_buff="11111111" then
    anlauf:='0';
  end if;
  
  if dz_buff="00000000" then
    anlauf:='1';
  end if;
  
  if anlauf='1' then
  
  dz_buff:=dz_buff+1;
  
  elsif anlauf='0' then
  
  dz_buff:=dz_buff-1;
  end if;
  
  drehzahl<=dz_buff;  -- dieses signal soll hochgezählt werden
end process;


end behavioral;

Fehlermeldung:
found 0 definitions for operator "+".

ich habe jetz eine weile im Forum und über google nach lösungen gesucht 
und bin nur auf die erklärung gestoßen, dass es an unterschiedlichen 
datentypen der operanden liegen kann. Aber das ist doch nicht der fall.

Weeiß wer rat?

Autor: Tobias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da sind mehrere Sachen schwierig. Für
 use IEEE.NUMERIC_STD.ALL; 

in Verbindung mit Rechenoperationen als Signaltyp "unsigned" benutzen. 
Rechnen mit std_logic_vector geht mit anderen Bibliotheken, ist aber 
nicht sauber. Mit
 variable dz_buff: unsigned(7 downto 0); 

sollte die Fehlermeldung erstmal behoben sein. Dein Prozess reagiert 
aber auf positive und negative Flanken - solche FFs gibt es aber (mit 
wenigen ausnahmen nicht). Du müsstest also in den Prozess noch ein
 if rising_edge(clk) 

einbauen und deinen Code simulieren um zu gucken, was da eigentlich so 
passiert.

Viele Grüße

Tobias

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danny w. schrieb:
> Ich habe ein ähnliches Problem.
Besten Dank auch. Da habe ich einen ganzen Thread gelesen, um zum 
Schluss zu sehen, dass eine NEUE FRAGE angehängt wurde...
> Ich habe ein ähnliches Problem.
Du hast dir den vorgehenden Thread aber nicht durchgelesen!

> das signal "drehzahl" soll hochgezählt werden.
Alle Zähler brauchen einen Takt und Speicherelemente.

Entweder die hier:
> use IEEE.std_logic_1164.all;
> use ieee.std_logic_arith.all;
Oder besser die:
> use IEEE.NUMERIC_STD.ALL;
Aber niemals beide zusammen!
Zu den Gründen such mal hier im Forum nach "std_logic_arith obsolete":
http://www.mikrocontroller.net/search?query=std_lo...

> variable dz_buff: STD_LOGIC_VECTOR(7 downto 0);
>   dz_buff:=dz_buff+1;
Mit Vektoren rechnet man nicht.
Dafür gibt es die Datentypen signed/unsigned und integer.

Zur ausdauernden und unnötigen Verwendung von Variablen lies mal den 
Beitrag "Variable vs Signal"

Ich rate dir DRINGEND:
Lies das Buch VHDL-Synthese von Reichardt&Schwarz.
Du machst im Laufe deiner Beiträge tatsächlich JEDEN Fehler, der denkbar 
ist...  :-o
Das z.B., was du da oben beschrieben hast, nennt sich "kombinatorische 
Schleife": 
http://www.lothar-miller.de/s9y/categories/36-Komb...

Autor: xilinx gefrusteter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Mit Vektoren rechnet man nicht.

Hast du schon mal VHDL gesehen, dass Xilinx SysGen produziert?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
xilinx gefrusteter schrieb:
> Hast du schon mal VHDL gesehen, dass Xilinx SysGen produziert?
Die Welt ist nicht perfekt:
für den Microblaze werden sogar Vektoren mit (0 to 31) erzeugt...   :-/

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.