mikrocontroller.net

Forum: FPGA, VHDL & Co. Bitfolge getriggert ausgeben


Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich moechte mit einem FPGA eine 64-stellige Bitfolgen ausgeben.
Die Bitlaenge soll 100ns betragen. Sonst ist das Signal high.
Die Ausgabe soll getriggert erfolgen.
Also benoetige ich ein Modul, mit zwei Eingaengen und einem Ausgang.
Die Bitfolge soll im VHDL code als Konstante hinterlegt werden.

Jetzt weis ich nicht so recht wie ich anfangen soll.
Ich habe zwei Ansaetze um die ich mich erstal kuemmern werde:
1. Einen Parallel-Reihen Umsetzer, wo die Eingaenge mit konstanten 
Signalen belegt sind. Wie ich diesen allerdings triggerbar mache, weis 
ich noch nicht.
2. Einen Zaehler nehmen und eine LUT. Bei der LUT trage ich dann meine 
gewuenschte Bitfolge ein und ich benoetige einen Zaehler, der beim 
Triggersignal einmal durchlaeuft und dann wieder auf den naechsten 
Triggerimpuls warted.

Geht das vielleicht auch einfacher, wie wurdet Ihr das machen?

Autor: Blubb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nicht einen UART oder SPI core nehmen und gescheit verschalten & 
parametretisieren?

Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Blubb schrieb:
> Warum nicht einen UART oder SPI core nehmen und gescheit verschalten &
> parametretisieren?
Darueber bin ich auch schon gestolpert. Im Prinzip suche ich sowas.
Ich bin aber Anfaenger, was VHDL betrifft und aus den Beispielen kann 
ich mir die Funktion nicht immer komplett herleiten.
Deswegen suche ich was Einfaches und Nachvollziebares.

Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eines koennte man noch erwaehnen. Im folgenden Schritt moechte ich die 
Ausgangssignale auch 32 aufbohren.

Autor: C. A. Rotwang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
qnd-snippets und ohne Garantie auf Tippfehler die wesentlichen 
Teilfunktionalitäten.
--Deklaration counter und ROM

constant ROM is std_logic_vector(63 downto 0) := x"FFFFFFFFFFFFFFFF";
subype T_count_idx is natural range 63 downto 0;
signal count_q:T_count_idx := T_count_idx'low;

--Steigende Flanke Trigger erkennen und einmal (run once) durchzählen:

--innerhalb getakteten process
trig_in_del_q <= trig_in;

if (trig_in_del_q = '0') and (trig_in = '1') then  --start count ny Loading index of MSb
 count_q <= T_count_idx'high;
end if;
if (count_q /= T_count_idx'low) then  --decrement as long lower boundary reached
 count_q <= count_q - 1;
end if;



--64x1 ROM auslesen

data_out <= ROM(count_q);  --bit-counter is also address of ROM


Da fehlt noch jede menge drumherum (entity, architectur  Rahmen) aber 
das sollte mensch der guten Willens ist, einer VHDL-Syntax Beschreibung 
oder Beispielen entnehmen können.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
> Die Ausgabe soll getriggert erfolgen.
Woher kommt der Trigger? Wie lange ist der aktiv? Wenn der auch nur für 
1 Taktzyklus aktiv ist, dann ist es einfacher, sonst muss eine 
Flankenerkennung eingebaut werden. Und was soll passieren, wenn während 
der Übertragung erneut ein Trigger kommt: ignorieren, sofortiger 
Neustart der Übertragung oder Neustart nach Ende der Übertragung?

> 1. Einen Parallel-Reihen Umsetzer, wo die Eingaenge mit konstanten
> Signalen belegt sind. Wie ich diesen allerdings triggerbar mache, weis
> ich noch nicht.
Mal angenommen, der Trigger käme von extern, dann muss er 
einsynchronisiert und dann die Flanke erkannt werden. Mit der steigenden 
Flanke wird dann das Schieberegister geladen, sonst wird dauernd von 
rechts eine '1' eingeschoben:
:
constant PATTERN : std_logic_vector(63 downto 0) := x"1234567890abcdef";
signal sr_pattern : std_logic_vector(63 downto 0) : (others => '1');
signal sr_trigger : std_logic_vector(2 downto 0) : (others => '0');
:
   -- Trigger für Flankenerkennung einsynchronisieren 
   sr_trigger <= sr_trigger(1 downto 0) & in_trigger when rising_edge(clk);

   process begin
      wait until rising_edge(clk);
      -- ständig von rechts eine '1' einschieben
      sr_pattern <= sr_pattern(62 downto 0) & '1';
      if sr_trigger(2 downto 1)="01" then  -- aber bei steigender Flanke: Schieberegister laden
         sr_pattern <= PATTERN;
      end if;
   end process;
   
   serial_out <= sr_pattern(63);
:

: Bearbeitet durch Moderator
Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Euch Beiden fuer die Beispiele. Ich sehe mir das mal an und 
versuche es umzusetzen.

Lothar M. schrieb:
> Mark W. schrieb:
>> Die Ausgabe soll getriggert erfolgen.
> Woher kommt der Trigger? Wie lange ist der aktiv? Wenn der auch nur für
> 1 Taktzyklus aktiv ist, dann ist es einfacher, sonst muss eine
> Flankenerkennung eingebaut werden.

Ich denke CLK wird 10MHz sein. Dann wollte ich mir mit einem Taktteiler 
den Trigger generieren, also syncron mit CLK. Benoetigen tue ich bis 
10kHz. Der Triggerpuls ist also laenger als die Bitfolge selbst.

> Und was soll passieren, wenn während
> der Übertragung erneut ein Trigger kommt: ignorieren, sofortiger
> Neustart der Übertragung oder Neustart nach Ende der Übertragung?
>
Kann ich erstmal ignorieren, weil ich das ausschliesse.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
> Ich denke CLK wird 10MHz sein. Dann wollte ich mir mit einem Taktteiler
> den Trigger generieren, also syncron mit CLK. Benoetigen tue ich bis
> 10kHz. Der Triggerpuls ist also laenger als die Bitfolge selbst.
Wenn du es schlau anstellst, dann nicht. Denn dann generierst du dir den 
Triggerimpuls so, dass er genau einen Taktzyklus lang aktiv ist. So 
funktioniert synchrones Design am einfachsten...
:
constant PATTERN : std_logic_vector(63 downto 0) := x"1234567890abcdef";
signal sr_pattern : std_logic_vector(63 downto 0) : (others => '1');
signal trigger : std_logic : '0';
signal trigger_cnt : integer range 0 to 1000000 := 0;
:
   -- Triggerimpuls erzeugen
   process begin
      wait until rising_edge(clk);
      trigger_cnt <= trigger_cnt+1;
      trigger     <= '0';
      if trigger_cnt=999999 then  -- Zeit abgelaufen
         trigger_cnt <= 0;
         trigger     <= '1';      -- trigger für 1 Taktzyklus aktiv
      end if;
   end process;

   -- Trigger für Flankenerkennung einsynchronisieren 
   sr_trigger <= sr_trigger(1 downto 0) & in_trigger when rising_edge(clk);

   process begin
      wait until rising_edge(clk);
      -- ständig von rechts eine '1' einschieben
      sr_pattern <= sr_pattern(62 downto 0) & '1';
      if trigger='1' then  -- mit Trigger: Schieberegister laden
         sr_pattern <= PATTERN;
      end if;
   end process;
   
   serial_out <= sr_pattern(63);
:

: Bearbeitet durch Moderator
Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe jetzt mal den Code von Lothar versucht, aber es geht nicht.
Ich bekomme immer Fehlermeldungen bezueglich der Deklaration der 
Signale.
Hier ist mein VHDL Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity PULSER is

  port(
    clk  : in  std_logic;
    serial_out : out std_logic);

end PULSER;

architecture BEHAVIOR of PULSER is

  constant PATTERN : std_logic_vector(63 downto 0) := x"aaaaaaaaaaaaaaaa";
  signal sr_pattern : std_logic_vector(63 downto 0) : (others => '1');
  signal trigger : std_logic : '0';
  signal trigger_cnt : integer range 0 to 1000000 := 0;
begin
  
process begin
    wait until rising_edge(clk);
    trigger_cnt <= trigger_cnt+1;
    trigger <= '0';
    if trigger_cnt=999999 then
       trigger_cnt <= 0;
       trigger <= '1';
    end if;
end process;
  
  sr_trigger <= sr_trigger(1 downto 0) & in_trigger when rising_edge(clk);
  
process begin
    wait until rising_edge(clk);
    sr_pattern <= sr_pattern(62 downto 0) & '1';
    if trigger = '1' then
       sr_pattern <= PATTERN;
    end if;
end process;
  
serial_out <= sr_pattern(63);
  
end BEHAVIOR;
Und hier die Fehlermeldungen:

ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(16,52-16,53) 
(VHDL-1261) syntax error near :
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(23,3-23,14) 
(VHDL-1241) trigger_cnt is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(24,3-24,10) 
(VHDL-1241) trigger is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(26,6-26,17) 
(VHDL-1241) trigger_cnt is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(27,6-27,13) 
(VHDL-1241) trigger is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(25,6-25,17) 
(VHDL-1241) trigger_cnt is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(31,2-31,12) 
(VHDL-1241) sr_trigger is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(35,3-35,13) 
(VHDL-1241) sr_pattern is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(37,6-37,16) 
(VHDL-1241) sr_pattern is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(36,6-36,13) 
(VHDL-1241) trigger is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(41,15-41,25) 
(VHDL-1241) sr_pattern is not declared
ERROR - 
C:/AllMyFiles/LatticeDiamondProjects/Pulser01/pulser.vhd(13,1-43,14) 
(VHDL-1284) unit behavior ignored due to previous errors

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
> signal sr_pattern : std_logic_vector(63 downto 0) : (others => '1');
> signal trigger : std_logic : '0';
Ja, da fehlen wohl noch 2 '=' Zeichen. Aber keine Sorge, du findest den 
richtigen Platz. Einfach mal die Zeile drüber oder drunter anschauen... 
;-)

Und den sr_trigger gibt es wie den in_trigger in der zweiten Variante 
nicht mehr, weil er nicht mehr nötig ist. Fazit: einfach die unnötige 
Eintakterei rauslöschen. Und dann sieht das nicht mehr so schlecht aus 
(zur Beschleunigung der Simulation zähle ich nur 1000 Pulse und starte 
neu).

: Bearbeitet durch Moderator
Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hoert sich ja beruhigend an. Schau ich mir gleich morgen nochmal an. 
Ich dachte schon, dass es etwas Grundlegendes ist, im Aufbau oder so.

Autor: Mark W. (kram) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe es jetzt bis zur Simulation hinbekommen.
Danke schon mal bis hierher. Jetzt kann ich mit den Parametern spielen 
und mir die Funktionen klar machen.
Hier ist dann der Code fuer die angehaengte simulation:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity PULSER is

  port(
    clk  : in  std_logic;
    serial_out : out std_logic);

end PULSER;

architecture BEHAVIOR of PULSER is

  constant PATTERN : std_logic_vector(63 downto 0) := x"0123456789abcdef";
  signal sr_pattern : std_logic_vector(63 downto 0) := (others => '1');
  signal trigger : std_logic := '0';
  signal trigger_cnt : integer range 0 to 1000000 := 0;
begin
  
process begin
    wait until rising_edge(clk);
    trigger_cnt <= trigger_cnt+1;
    trigger <= '0';
    if trigger_cnt = 1000 then
       trigger_cnt <= 0;
       trigger <= '1';
    end if;
end process;
  
  --sr_trigger <= sr_trigger(1 downto 0) & in_trigger when rising_edge(clk);
  
process begin
    wait until rising_edge(clk);
    sr_pattern <= sr_pattern(62 downto 0) & '1';
    if trigger = '1' then
       sr_pattern <= PATTERN;
    end if;
end process;
  
serial_out <= sr_pattern(63);
  
end BEHAVIOR;

Und Testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity TEST is
end TEST;

architecture BEHAVIOR of TEST is
signal CLK: std_logic;
signal serial_out: std_logic;

component PULSER
  port(  CLK:     in   std_logic;
      serial_out: out std_logic);
end component;

for all: PULSER use entity work.PULSER(BEHAVIOR);
begin

Clock: process begin
  CLK <=   '0';
  wait for 100 ns;
  CLK <= '1';
  wait for 100 ns;
end process Clock;

C1: PULSER port map(CLK, serial_out);
end BEHAVIOR;

Allerdings ist mir eine Sache nicht ganz klar, und zwar was C1 in der 
vorletzten Zeile vom Testbench bedeutet.
Ist das die Verbindung vom Testbench, wo das DUT quasi angedockt wird?

Autor: Achim S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
> Ist das die Verbindung vom Testbench, wo das DUT quasi angedockt wird?

Ja: du erzeugst damit in der Testbench eine Instanz deiner Komponente 
Pulser.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
> was C1 in der vorletzten Zeile vom Testbench bedeutet.
Dort wird eine Instanz namens C1 der zuvor bekannt gegebenen Komponente 
PULSER angelegt.
Das ist exakt das selbe, wie auch andere Untermodule in einem darüber 
liegenden VHDL
Modul eingebunden werden.

Eine Testbench ist verglichen mit anderen VHDL Modulen aber einfach zu 
erkennen: die Entity hat keine Ports, also keine Verbindung "nach 
außen".

Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Euch Beiden, ich glaube, ich habe es verstanden mit der Instanz. 
Ich kann den Namen offenbar frei waehlen, deswegen hatte ich mich 
Anfangs gewundert, weil das nirgends auftaucht.
Und in meinem Buch steht nur, dass deklarierte Signale als aktuelle 
Signale an die als Komponente C1 platzierte Entity uebergeben werden.

: Bearbeitet durch User
Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zur Unterscheidung bekommen bei mir (fast) alle Signale in der Testbench 
den Präfix 'tb_':
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity TEST is
end TEST;

architecture BEHAVIOR of TEST is
signal tb_CLK: std_logic;
signal tb_serial_out: std_logic;

component PULSER
  port(  CLK:     in   std_logic;
      serial_out: out std_logic);
end component;

for all: PULSER use entity work.PULSER(BEHAVIOR);
begin

Clock: process begin
  tb_CLK <=   '0';
  wait for 100 ns;
  tb_CLK <= '1';
  wait for 100 ns;
end process Clock;

C1: PULSER port map(tb_CLK, tb_serial_out);
end BEHAVIOR;

Duke

Autor: Mark W. (kram) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, gute Idee.
Mir ist auch schon aufgefallen, dass es viele verschiedene 
"Schreibstile" und Hervorhebungsmerkmale gibt.
Auch mit dem Einruecken muss man erstmal klarkommen.
Ich achte darauf, was mir am Besten entgegen kommt.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark W. schrieb:
C1: PULSER port map(CLK, serial_out);
Ich empfehle hier, nicht die implizite Zuordnung per Position zu nehmen, 
sondern explizit den Port dem Signal zuzuordnen:
C1: PULSER port map(CLK=>CLK, serial_out=>serial_out);

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.

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