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


von Michael (Gast)


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?

von Jochen F. (jamesy)


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?

von Summy L. (mightyright)


Lesenswert?

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

von Stefan Salewski (Gast)


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.

von Stefan Salewski (Gast)


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.

von Commtel @. (commtel)


Angehängte Dateien:

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

von Phil (Gast)


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:
1
 if divider = 0 then
2
  divider <= 50000000;
3
  LD4 <= led;
4
  led <= not led;
5
 else
6
  divider <= divider -1;
7
 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

von Martin (Gast)


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 :-)

von D. I. (Gast)


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.

von Summy L. (mightyright)


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...

von D. I. (Gast)


Lesenswert?

C und VHDL haben weder syntaktisch geschweige denn semantisch was 
gemeinsam

von Christian R. (supachris)


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.

von Summy L. (mightyright)


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.

von D. I. (Gast)


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

von Stefan Salewski (Gast)


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.

von D. I. (Gast)


Lesenswert?

Probier das Beispiel mal aus:

http://www.lothar-miller.de/s9y/archives/70-Asynchroner-Reset.html

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

von Stefan Salewski (Gast)


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.

von D. I. (Gast)


Lesenswert?

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

von Stefan Salewski (Gast)


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...

von D. I. (Gast)


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

von Stefan Salewski (Gast)


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...

von D. I. (Gast)


Lesenswert?

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

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


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_papers/wp272.pdf

von Stefan Salewski (Gast)


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!

von danny w. (weisti)


Lesenswert?

Ich habe ein ähnliches Problem.

das signal "drehzahl" soll hochgezählt werden.
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
use ieee.std_logic_arith.all;
4
use IEEE.NUMERIC_STD.ALL;
5
6
7
entity anlauf_str is
8
  port(
9
    clk: IN STD_LOGIC; 
10
    drehzahl_max: in STD_LOGIC_VECTOR(7 downto 0);
11
    drehzahl: out STD_LOGIC_VECTOR(7 downto 0)
12
  );
13
end anlauf_str;
14
15
architecture behavioral of anlauf_str is
16
17
18
begin
19
20
process(clk)      
21
variable anlauf : std_logic :='1';
22
variable dz_buff: STD_LOGIC_VECTOR(7 downto 0); -- buffer für signal-drehzahl
23
24
begin
25
  
26
  if dz_buff="11111111" then
27
    anlauf:='0';
28
  end if;
29
  
30
  if dz_buff="00000000" then
31
    anlauf:='1';
32
  end if;
33
  
34
  if anlauf='1' then
35
  
36
  dz_buff:=dz_buff+1;
37
  
38
  elsif anlauf='0' then
39
  
40
  dz_buff:=dz_buff-1;
41
  end if;
42
  
43
  drehzahl<=dz_buff;  -- dieses signal soll hochgezählt werden
44
end process;
45
46
47
end behavioral;

Fehlermeldung:
1
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?

von Tobias (Gast)


Lesenswert?

Da sind mehrere Sachen schwierig. Für
1
 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
1
 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
1
 if rising_edge(clk)

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

Viele Grüße

Tobias

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


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_logic_arith+obsolete

> 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-Kombinatorische-Schleife

von xilinx gefrusteter (Gast)


Lesenswert?

Lothar Miller schrieb:
> Mit Vektoren rechnet man nicht.

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

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


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...   :-/

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.