mikrocontroller.net

Forum: FPGA, VHDL & Co. LED-Zähler mit Xilinx CPLD


Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

für ein größeres Projekt möchte ich erstmal etwas kleiner Anfangen:

Also in ein Xilinx CPLD 9536 oder 9572 soll ein 8-Bit Binärzähler rein.
Die 8 Bits sollen direkt eine Low-Current-LED antreiben.

Eingangssignale:
-Clock
-Reset

Ausgang:
-8*LED

Dieser Zähler soll dann später auf 16 oder sogar 32 Bit erweitert
werden.


Wie läßt sich das mit VHDL realisieren? Welche Bücher/Tutorials sind
empfehelendswert?


Gruß
Holger

Autor: Xenu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wie läßt sich das mit VHDL realisieren?

Na so:


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity counter is

  port
  (
    clk : in std_logic;
    rst : in std_logic;
    q   : out std_logic_vector(7 downto 0)
  );

end counter;
------------------------------------------------
architecture counter_arch of counter is

  signal count : std_logic_vector(7 downto 0);

begin
------------------------------------------------
process (clk,rst)
begin

  if(rst = '0') then
     count <= (others => '0');
  elsif(rising_edge(clk)) then
     count <= count + 1;
  end if;

end process;
------------------------------------------------
  q <= count;
------------------------------------------------
end counter_arch;

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, danke. Wie lege ich denn nun noch die Pins fest?

Gruß
Holger

Autor: Xenu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der UCF-Datei, die Du Deinem Projekt hinzufügen musst.

Am besten Du liest Dir mal das hier durch, da steht alles drin, was Du
für den Anfang wissen musst:

http://www.xilinx.com/publications/products/cpld/l...

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So werden alle LEDs immer an sein...Du brauchst noch einen
Clockvorteiler(außer Du taktest den CPLD direkt mit 10Hz oder so ;)).

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, danke für die Tipps. Bisher habe ich alles verstanden. Nun kann
ich doch auch einfach das ganze um 8 LEDs auf 16 erweitern -oder?

"q   : out std_logic_vector(15 downto 0)"


Nun möchte ich aber nicht 16 LEDs sondern 8 und mittels Schalter
zwischen den oberen und unteren 8 Bits schalten. Geht das auch?

Gruß
Holger

Autor: Xenu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>um 8 LEDs auf 16 erweitern -oder?

Richtig.

>mittels Schalter zwischen den oberen und unteren 8 Bits schalten.
>Geht das auch?

Klaro:

  q <= count(15 downto 8) when (Schalter = '1') else count(7 downto
0);


Wobei "Schalter" ein std_logic-Eingang ist.

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mmm, sieht ja einfacher aus als erwartet. Wie MHz kann denn so ein CPLD
bei diesem Zähler verarbeiten?

Gruß
Holger

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenne mich mit CPLDs nicht aus...Irgendwie ist das bei denen anders
als bei FPGAs, aber ich denke 50 MHz sollten auf jeden Fall drin sein.


Daniel

Autor: Xenu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wie MHz kann denn so ein CPLD bei diesem Zähler verarbeiten?

Kommt natürlich auf CPLD und Geschwindigkeitsgrad an.
Am einfachsten wäre es du synthetisierst das Ganze mal und
schaust nach was Dir die ISE sagt.

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe jetzt den Zähler auf 32-Bit aufgebaut (CPLD 9572). Dazu
insgesamt 4 Schalter für die vier Bytes sowie ein enable-Schalter.

Könnt Ihr Euch das mal anschauen. Macht das so Sinn?


mfg
Holger


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 zaehler is
    Port ( rst : in  STD_LOGIC;
           clk : in  STD_LOGIC;
           sw1 : in  STD_LOGIC;
           sw2 : in  STD_LOGIC;
           sw3 : in  STD_LOGIC;
           sw4 : in  STD_LOGIC;
           enable : in  STD_LOGIC;
           q : out  STD_LOGIC_VECTOR (7 downto 0));
end zaehler;

architecture Behavioral of zaehler is
   signal count : std_logic_vector(31 downto 0);
begin
process (clk,rst)
begin
  if(rst = '0') then count <= (others => '0');
  elsif(rising_edge(clk)) and (enable = '0') then count <= count +
1;
  end if;
end process;

process (sw1,sw2,sw3,sw4)
begin
  if(sw4 = '1') then q <= count(31 downto 24);
  elsif(sw3 = '1') then q <= count(23 downto 16);
  elsif(sw2 = '1') then q <= count(15 downto 8);
  elsif(sw1 = '1') then q <= count(7 downto 0);
  end if;
end process;

end Behavioral;

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach am besten alles in einem Prozess. Den Reset machste am besten
synchron(nach rising_edge...).

Man taktet einen Prozess niemals direkt mit Schaltern oder sonstigem
Zeug. Immer den Clock nehmen und die Signale dann synchron abfragen.

Ich schreib Dir noch schnell ein Beispiel...
Moment bitte.

Autor: Daniel R. (daniel_r)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Das Design ist nicht getestet... Dürfte so aber gehen.
Es befindet sich auch noch im Anhang, falls die Gliederung durch das
Forum-Format draufgeht.


entity counter is
port(
    clk        : in std_logic;
    reset        : in std_logic;
    switches      : in std_logic_vector(3 downto 0);
    q          : out std_logic_vector(7 downto 0)
   );
end counter;

architecture Behavioral of counter is
signal count    : std_logic_vector(31 downto 0);

begin

process(clk)
begin
  if rising_edge(clk) then
    if reset = '1' then
      q <= (others => '0');
      count <= (others => '0');
    else
      if count = x"FFFFFFFF" then
        count <= (others => '0');
      else
        count <= count +1;
      end if;

      case switches is
        when "0001" =>
          q <= count(7 downto 0);
        when "0010" =>
          q <= count(15 downto 8);
        when "0100" =>
          q <= count(23 downto 16);
        when "1000" =>
          q <= count(31 downto 24);
        when others =>
          q <= (others => '0');
      end case;
    end if;
  end if;
end process;

end Behavioral;

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super. Das habe ich mal durchlaufen lassen. 40 Makrozellen werden
benötigt und das ganze läuft bis 66MHz und passt in einen 9572. Das ist
ja schon was!!! Also Daniel erst einmal vielen Dank!!!

Nur eines noch: Gezählt soll nur wenn der Enable-Pin = 0. Also das muss
da noch mit rein. Reset und das Ausgeben soll jedoch jederzeit möglich
sein. Also unabhängig von Enable.

Gruß
Holger

Autor: Rainer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Daniel!

Ist denn die explizite Zuweisung der 0 notwendig, wenn der Zähler
überläuft? std_logic_vector sollte doch brav durchzählen! Aber ISE
sollte das eh optimieren!

Grüße
Rainer

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, und noch eine Frage und zwar zu den Zeilen:

case switches is
        when "0001" =>
          q <= count(7 downto 0);
        when "0010" =>
          q <= count(15 downto 8);
        when "0100" =>
          q <= count(23 downto 16);
        when "1000" =>
          q <= count(31 downto 24);
        when others =>
          q <= (others => '0');
      end case;

Könnte man, den Ausgang im Falle "when others" auch als Tristate
hochohmig schalten?


Gruß
Holger

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Holger

>Nur eines noch: Gezählt soll nur wenn der Enable-Pin = 0. Also das
muss
>da noch mit rein. Reset und das Ausgeben soll jedoch jederzeit
möglich
>sein. Also unabhängig von Enable.

Code folgt...

>Könnte man, den Ausgang im Falle "when others" auch als Tristate
>hochohmig schalten?

Selbstverständlich. Ich packs gleich in den Code mit rein.

@Rainer

>Ist denn die explizite Zuweisung der 0 notwendig, wenn der Zähler
>überläuft? std_logic_vector sollte doch brav durchzählen! Aber ISE
>sollte das eh optimieren!

Richtig, der Counter resetted normalerweise selbstständig. De
Vollständigkeit halber habe ich den reset dazugeschrieben.



Daniel

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, Tristate geht mit 'Z' -oder? Nach Möglichkeit sollte der Reset
aber von Clock unabhängig sein.



Gruß
Holger

Autor: Daniel R. (daniel_r)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier der Code:
Bei "when others" wird der Ausgang jetzt auf Tristate geschaltet.
Außerdem habe ich den manuellen Reset des Counters nun
auskommentiert(unwirksam gemacht). Wie Rainer sagte, resettet der
Counter ja von selbst. Das spart Resourcen(von denen ein CPLD ja
sowieso nicht viel hat) und ist schneller(auf meinem Spartan3 würde es
jetzt mit 170MHz laufen).

Viel Spaß!!



entity counter is
port(
    clk        : in std_logic;
    reset      : in std_logic;
    switches   : in std_logic_vector(3 downto 0);
   enable    : in std_logic;
    q          : out std_logic_vector(7 downto 0)
   );
end counter;

architecture Behavioral of counter is
signal count    : std_logic_vector(31 downto 0);

begin

process(clk)
begin
  if rising_edge(clk) then
    if reset = '1' then
      q <= (others => '0');
      count <= (others => '0');
    else
     if enable = '0' then
      --  if count = x"FFFFFFFF" then      --Counter manuell resetten...
        --    count <= (others => '0');
        --else
           count <= count +1;
         --end if;
    end if;

      case switches is
        when "0001" =>
          q <= count(7 downto 0);
        when "0010" =>
          q <= count(15 downto 8);
        when "0100" =>
          q <= count(23 downto 16);
        when "1000" =>
          q <= count(31 downto 24);
        when others =>
          q <= (others => 'Z');   --Schaltet den Ausgang auf Tristate
      end case;
    end if;
  end if;
end process;

end Behavioral;

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hallo, Tristate geht mit 'Z' -oder?
Richtig.

>Nach Möglichkeit sollte der Reset aber von Clock unabhängig sein.

Genau das vermeidet man.
Der Clock ist ja immer da(sonst würde ja nichts laufen).

Außerdem macht ein synchroner Reset das Design schneller und braucht
meistens weniger Resourcen.

Falls Du trotzdem einen asynchronen Reset wünschst, dann schrein
einfach "if reset = '1'" vor "if rising_edge(clk)"...und vergiss
das "end if" nicht.


Gruß Daniel

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Daniel,

da war ich mit dem vorherigen Posting zu langsam ;-)

Kannst Du noch den Reset Clockunabhängig machen?



Gruß und schönes W'ende

Holger

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich muss noch mal neu anfangen. Alles hängt doch jetzt vom Clock-Signal
ab -oder?

Ich möchte meine Wunschkonfiguration noch mal darlegen und hoffe auf
Nachsicht:

1. wenn Enable-Signal anliegt, dann soll der Zähler die Ereignisse am
Clock-Eingang zählen (32-Bit)
2. Clock liegt nicht immer an, sondern wird extern dazugeschaltet
3. wenn kein Enable-Signal anliegt, dann
   -soll unabhängig ob ein Clock-Signal anliegt oder nicht ein Reset
möglich sein!
   -soll noch durch die vier Switch-Leitungen die jeweiligen Bytes
ausgegeben werden
   -sollen die Ausgänge hochohmig geschaltet werden, wenn keine
Switch-Leitung geschaltet wird

Also, ich brauche keinen Synchronzähler sondern einen Zähler der bei
Enable um sein Leben rennt. Für Reset und Auslesen ist genug Zeit
vorhanden!

Zählen und Reset/Ausgabe sind getrennt voneinander und während des
Zählens erfolgt kein Reset und kein Auslesen der Bytes!

So, nochmal viele Grüße
Holger

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mein letzter Versuch fürs Wochenende ...


entity counter is
port(
    clk        : in std_logic;
    reset      : in std_logic;
    switches   : in std_logic_vector(3 downto 0);
    enable    : in std_logic;
    q          : out std_logic_vector(7 downto 0)
    );
end counter;

--------------------------------------------------

architecture Behavioral of counter is
signal count    : std_logic_vector(31 downto 0);

begin

process(clock)
begin
  if enable = '0' then           --aktive low

    if rising_edge(clk) then
       q <= (others => 'Z');
       count <= count +1;
    ebd if;

  else

  if reset = '1' then            --aktive high
     q <= (others => '0');
     count <= (others => '0');

  else

     case switches is            --aktive high
        when "0001" =>
          q <= count(7 downto 0);
        when "0010" =>
          q <= count(15 downto 8);
        when "0100" =>
          q <= count(23 downto 16);
        when "1000" =>
          q <= count(31 downto 24);
        when others =>
          q <= (others => 'Z');   --Tristate
      end case;

  end if;
  end if;
end process;

end Behavioral;

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt schaltest Du aber bei jeder Flanke des Clocks die Ausgänge auf
Tristate. Außerdem werden die Bytes nur ausgegeben, wenn kein enable
anliegt(also enable = '1'). Das entspricht nicht Deinen Vorgaben.

Wenn ich nacher noch Lust habe schreibe ich Dir das Zeug schnell...


Daniel

Autor: Daniel R. (daniel_r)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
entity counter is
port(
    clk        : in std_logic;
    reset      : in std_logic;
    switches   : in std_logic_vector(3 downto 0);
   enable    : in std_logic;
    q          : out std_logic_vector(7 downto 0)
   );
end counter;

architecture Behavioral of counter is
signal count    : std_logic_vector(31 downto 0);

begin

process(clk,enable,reset,switches,count)
begin

  case switches is
        when "0001" =>
          q <= count(7 downto 0);
        when "0010" =>
          q <= count(15 downto 8);
        when "0100" =>
          q <= count(23 downto 16);
        when "1000" =>
          q <= count(31 downto 24);
        when others =>
          q <= (others => 'Z');     --Tristate
   end case;


  if reset = '1' then      --Asynchroner Reset
      q <= (others => '0');
      count <= (others => '0');
  elsif  rising_edge(clk) then
       if enable = '0' then    --Synchroner Zähler mit enable
        count <= count +1;
      end if;

  end if;
end process;

end Behavioral;


Daniel

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für die Hilfe. Montag komm ich erst wieder an meinem PC ran.

Ich brauch unbedingt einen VHDL-Buch. Welches kann man mir empfehlen?
(amazon?)


Gruß
Holger

Autor: high_speed (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
VHDL-Synthese
Entwurf digitaler Schaltungen und Systeme
von Jürgen Reichardt, Bernd Schwarz

ISBN 3-486-27384-1

http://users.etech.haw-hamburg.de/users/Schwarz/En......
http://users.etech.haw-hamburg.de/users/Reichardt/buch.html

Kapietel 8 (Synthesefähiger Entwurf eines Mikroprozessors)
http://users.etech.haw-hamburg.de/users/Schwarz/En......

VHDL-Quellcodes und Musterlösungen
http://users.etech.haw-hamburg.de/users/Reichardt/buch.html

MfG
Holger

Autor: high_speed (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, es geht um obiges Beispiel:

  if reset = '1' then      --Asynchroner Reset
      q <= (others => '0');
      count <= (others => '0');
  elsif  rising_edge(clk) then
       if enable = '0' then    --Synchroner Zähler mit enable
        count <= count +1;
      end if;


Da wird doch bei einem Reset 0 an q ausgegeben -oder?


Gruß
Holger

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, stimmt.

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK,

dann kann ich die Zeile ja löschen. Übrigens funzt der Zähler ansonsten
1a!


Gruß
Holger

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mahlzeit,

also mit einem 100MHz Quarzoszillator läuft das Teil auch noch! Laut
ISE sollte die Hälfte drin sein ;-)


Gruß
Holger

Autor: Daniel R. (daniel_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf meinem FPGA liefe es laut ISE mit 200MHz ;)

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.