mikrocontroller.net

Forum: FPGA, VHDL & Co. bit_Vektor VHDL


Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich schreibe grade an einer VDHL für einen FPGA und bin auf folgendes 
Problem gestossen:

Ich habe einen längeren Vektor mit 1 und 0 und will diesen über einen 
Ausgang ausgeben. Die Ziffern müssen also mit einem bestimmten 
Zeitabstand hintereinander ausgegeben werden. Wie kann ich dies 
realisieren (wait-Anweisung?).


Danke schonmal für die Antworten.
Gruß Martin

Autor: Nephilim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich würd über nen zähler, der aufgrund des bekannten taktes eine 
definierte zeit zählt, ein enable erzeugen womit dann nach und nach 1 
bit aus deinem vektor dem ausgang übergeben wird.

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

Bewertung
0 lesenswert
nicht lesenswert
> Wie kann ich dies realisieren (wait-Anweisung?).
In der Simulation: Ja.
In einer realen Hardware: Nein.

> Ich habe einen längeren Vektor...
Wie lang? Welche Zielplattform hast du? Hersteller?

Was du brauchst, ist ein Zähler (für die Zeit zwischen zwei Bits) und 
ein Schieberegister.

Das lässt sich in 20 Zeilen VHDL-Code beschreiben  ;-)

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
Danke für die Antworten.
Der Vektor ist etwa 550 Ziffern lang.

Im Moment schreibe/simluiere ich die VHDl in ModelSim XE 3.


Danke Martin

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

Bewertung
0 lesenswert
nicht lesenswert
> Der Vektor ist etwa 550 Ziffern lang.
Was ist das für ein Monstervektor....  :-o

From the Scratch:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Par2Ser is
    Port ( clk : in  STD_LOGIC;     -- z.B. 10MHz
           serout : out  STD_LOGIC; 
           frame  : out  STD_LOGIC; -- '1' solange Daten übertragen werden
           load   : in  STD_LOGIC;  -- Bitvektor laden
           parin  : in  STD_LOGIC_VECTOR (549 downto 0));
end Par2Ser;

architecture Behavioral of Par2Ser is
signal delaycnt : integer range 0 to 9999; -- 1ms/Bit
signal bitcnt : integer range 0 to 550;
signal bits  : STD_LOGIC_VECTOR (549 downto 0);
begin
   process begin
     wait until rising_edge(clk);
     if (load='1') then
       delaycnt <= 0; -- Bitdelay zurücksetzen
       bitcnt <= 550; -- 550 Bits sind zu übertragen
       bits <= parin; -- Daten zur internen Verarbeitung übernehmen
     else
       if (delaycnt/=9999) then   -- 1 ms vorbei?
         delaycnt <= delaycnt+1; -- nein: weiterzählen 
       else
         if (bitcnt/=0) then     -- sind noch Bits übrig?
           delaycnt <= 0;        -- ja: Bitdelay zurücksetzen
           bits <= '0' & bits(550 downto 1); -- das Schieberegister eins weiterschieben
           bitcnt <= bitcnt-1;   
         end if;
       end if;
     end if;
   end process;
   serout <= bits(0);
   frame <= '1' when bitcnt/=0 else '0';  
end Behavioral;
Mangels besser definierter Rahmenbedingungen soll gelten:
- 10MHz FPGA Takt
- ein Lade-Signal zur Übernahme des Vektors (load)
- das load-Signal soll nur für 1 Taktzyklus aktiv sein
  (sonst müsste die Handhabung des frame-Signals überarbeitet werden)
- ein Frame-Signal, das die Übertragung umrahmt (frame)
- jede ms wird ein Bit ausgegeben
- die Daten werden mit dem LSB voran ausgegeben.

Und ja, ich gebs zu, wegen der unklaren Aufgabenstellung sinds etwas 
mehr geworden als 20 Zeilen  ;-)

BTW:
Ich möchte ohne weitere Synchronisationsmaßnahmen keinen 550 Bit Vektor 
empfangen müssen. Wehe, die Quarzfrequenz weicht nur einen Hauch ab...

Normalerweise wird da (wie bei SPI) ein Takt pro Bit mitgegeben, oder 
ein Bit-Stuff-Mechanismus eingeführt (wie bei CAN), damit sich der 
Empfänger wieder aufsynchronisieren kann.

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder (jenachdem wie hoch die Datenrate sein muss und wer empfängt) 
einfach das Bit 3 Takte lang senden mit Start und Stoppbit dann sollte 
auch das syncen nicht mehr so tragisch sein.

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

Bewertung
0 lesenswert
nicht lesenswert
> Bit 3 Takte lang senden mit Start und Stoppbit dann sollte
> auch das syncen nicht mehr so tragisch sein.
Rechne das mal durch mit Start-Bit, dann 550 Datenbits mit
bits<='1'&(548 downto 1=>'0')&'1'; -- nur das erste und letzte Bit ist gesetzt 
und dann einem Stoppbit. Wann wird hier bei 100ppm-Quarzen bei Sender 
und Epmfänger die Synchronisation verloren sein? Wirst du das letzte Bit 
und das Stop-Bit immer korrekt zuordnen können? Wie machst du das mit 
dem Einsynchronisieren beim Empfänger?

Nein, da muss ganz einfach eine Art von Synchronisation her. Am 
einfachsten wäre es, das Ganze mit einem begleitenden Takt zu 
übertragen:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Par2Ser is
    Port ( clk : in  STD_LOGIC;     -- z.B. 10MHz
           serout : out  STD_LOGIC; 
           frame  : out  STD_LOGIC; -- '1' solange Daten übertragen werden
           sclk   : out  STD_LOGIC; -- steigende Flanke = serout gültig
           load   : in  STD_LOGIC;  -- Bitvektor laden
           parin  : in  STD_LOGIC_VECTOR (549 downto 0));
end Par2Ser;

architecture Behavioral of Par2Ser is
signal phase  : std_logic := '0';
signal bitcnt : integer range 0 to 550;
signal bits   : STD_LOGIC_VECTOR (549 downto 0);
begin
   process begin
     wait until rising_edge(clk);
     if (load='1') then
       phase  <= '0';
       bitcnt <= 550; -- 550 Bits sind zu übertragen
       bits   <= parin; -- Daten zur internen Verarbeitung übernehmen
     else
       if (bitcnt/=0) then     -- sind noch Bits übrig?
         if (phase='1') then   
           bits   <= '0' & bits(549 downto 1); -- das Schieberegister eins weiterschieben
           bitcnt <= bitcnt-1;   
         end if;
         phase <= not phase;
       end if;
     end if;
   end process;
   serout <= bits(0);
   frame  <= '1' when bitcnt/=0 else '0';  
   sclk   <= phase;
end Behavioral;

Hier die Stimuli der Testbench
  clk <= not clk after 50 ns;

  tb : PROCESS BEGIN
    wait for 270 ns;
    parin <= '1'&(548 downto 1=>'0')&'1';
    parin <= (others=>'0');
    parin(0) <= '1';
    parin(5) <= '1';
    parin(9) <= '1';
    parin(15) <= '1';
    load <= '1';
    wait for 320 ns;
    load <= '0';
    wait; -- will wait forever
  END PROCESS;
und im Anhang (Screenshot) die ersten paar Bits der Übertragung.
Wenn das Frame-Signal jetzt noch invertiert wird, haben wir ein 
lupenreines SPI-Protokoll...

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>> Bit 3 Takte lang senden mit Start und Stoppbit dann sollte
>> auch das syncen nicht mehr so tragisch sein.
> Rechne das mal durch mit Start-Bit, dann 550 Datenbits mit
>
bits<='1'&(548 downto 1=>'0')&'1'; -- nur das erste und letzte Bit
> ist gesetzt 
und dann einem Stoppbit. Wann wird hier bei
> 100ppm-Quarzen bei Sender und Epmfänger die Synchronisation verloren
> sein? Wirst du das letzte Bit und das Stop-Bit immer korrekt zuordnen
> können? Wie machst du das mit dem Einsynchronisieren beim Empfänger?
>

Mit 550 Bit hab ichs nicht durchgerechnet aber beim PCI-Bus mit 33 MHz 
zur Uebertragung von 8 bit Woertern mit 2 Bitseriellenkarten von einem 
PC zum anderen klappt das. Muesste ich jetzt die Formel rauskramen evtl 
muss man dann halt 4 oder 5 Takte uebertragen.
Start-Bit = 1 und Stopp-Bit = 0 dann erkennt man zum Synchronisieren 
dass sobald eine positive Flanke auf der Leitung ist dass eine 
Uebertragung beginnt. Wenn nichts uebertragen wird liegt eben 0 an.

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

Bewertung
0 lesenswert
nicht lesenswert
Ich habe deine Antwort nicht ganz verstanden, aber
> ein PCI-Bus mit 33 MHz
ist absolut synchron, und bei der
> Uebertragung von 8 bit Woertern mit 2 Bitseriellenkarten
wird nach jedem Byte neu synchronisiert
(Startbit + 8 Datenbits + Stopbit).

Alle Protokolle, die ich kenne, die nur auf 1 Datenleitung aufgebaut 
sind, geben auf dieser Datenleitung implizit auch den Takt mit (CAN, 
Sercos, Ethernet...) damit sich der Empfänger an den Sender 
aufsynchronisieren kann.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich programmiere auch grade an einem ähnlichen Code.

Mich würde mal die Zeile interessieren:
process begin
     wait until rising_edge(clk)

Dies bedeutet ja, dass ich auf eine steigende Flanke von clk warte. Das 
clk ist doch intern in meinem FPGA mit einer festen Frequenz drin oder?
Also kann ich es dann dem entsprechnden Pin zuweisen. Es wäre aber somit 
kein in bit, weil ich es nicht von außen anlege.

Ist dies so oder hab ich da was flasch verstanden. Sorry für die Frage, 
bin aber noch Anfänger was das programiieren angeht.

Grüße

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

Bewertung
0 lesenswert
nicht lesenswert
> Das clk ist doch intern im FPGA mit einer festen Frequenz drin oder?
Der Takt ist genau mit der Frequenz drin, die du von Aussen am 
entsprechenden Clock-Pin eingibst. In der Regel ist das ein externer 
Takt von 30-100MHz, auf den (im Idealfall) alle Prozesse im FPGA 
sensitiv sind.

So ist es (besonders für Anfänger) am einfachsten, wirklich synchrone 
und damit definierte Designs zu machen. Später kommt dann schon mal der 
eine oder andere Takt dazu.

> bin aber noch Anfänger was das programiieren angeht.
Wie gesagt, sorg dafür, dass in jedem getakteten Prozess der gleiche 
Takt drin steht. Ob das jetzt mit der traditionellen 
Lehrbuch-Schreibweise
   process (clk) begin
      if rising_edge(clk) then
         if (reset='1') then  -- Reset synchron
            :
         else                 -- die eigentliche Arbeit
            :
         end if;
      end if;
   end process;
oder mit der Schreibweise, die keine Sensitivity-Liste braucht
   process begin
      wait until rising_edge(clk);
      if (reset='1') then  -- Reset synchron
         :
      else                 -- die eigentliche Arbeit
         :
      end if;
   end process;
das ist egal, aber so bekommst du auf jeden Fall definierte Laufzeiten 
und prüfbare Designs hin.

Schlimm wird es, wenn in deinem FPGA-Design z.B. sowas steht:
   if rising_edge(Taster) then ...

   if falling_edge(ChipSelect) then ...

   if rising_edge(PS2CLK) then ...
   
   if rising_edge(clk) then ...
Lauter verschiedene Takte in einem (1) Design, das kann nur schiefgehen. 
Und das Blöde daran ist, dass die daraus resultierenden Fehler nur 
manchmal auftreten, mal ganz selten, dann wieder öfter....

Autor: Anfänger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok Vielen Dank für die Antwort

Ich schreibe an einem Programm,an einem Test-Sender für die digitale 
Übertragung des Mehrfrequenzwahlverfahren.

Ich habe dieses mal angehängt.
x: 4bit Eingangsvector um die Taste zu wählen
y: 260bit Vector in dem die einzelnen Bits (0,1) drin stehen, welche 
nacheinander ausgegben werden sollen.

Sie sollen mit einem Abstand von 0.125 ms hintereiander ausgeben werden, 
die Frequenz des FPGAs beträgt 50 Mhz.


In dem Programm hab ich den Teil von oben einfach übernommen. Ich habe 
es dann mit dem FPGA in einem Digilabor getestet und wollte das Ergebins 
auf einem Oszi ausgeben, leider hat dies nicht funtioniert.

Wo liegt den der Fehler? Kann es an dem zweiten clk liegen?

Grüße

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

Bewertung
0 lesenswert
nicht lesenswert
> Kann es an dem zweiten clk liegen?
In diesem Fall eher nicht, aber der clk ist unnötig. du braichst nicht 
erst den Vektor x eintakten, sondern du könntest den select gleich auf 
dem x machen.

> die Frequenz des FPGAs beträgt 50 Mhz.
Welche Frequenz? clk oder clk2?

> Sie sollen mit einem Abstand von 0.125 ms hintereiander ausgeben werden,
> die Frequenz des FPGAs beträgt 50 Mhz.
Dann solltest du mit dem Zähler 0.125ms/20ns = 6250 Takte zählen (und 
den Kommentar mit der 1ms/Bit löschen). Wie kommst du eigentlich auf 
6144 (das sind 122,8us)?

> leider hat dies nicht funtioniert.
Bei mir gehts (in der Simulation mit der angehängten Source)   ;-)
Stimmt bei dir alles mit den Takten, Pinzuordnung....

Die Testbench ist eigentlich nur eine Stimuli mit dem Takt:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb_MFW_vhd IS
END tb_MFW_vhd;

ARCHITECTURE behavior OF tb_MFW_vhd IS 

  -- Component Declaration for the Unit Under Test (UUT)
  COMPONENT Sender3
  PORT(
    clk : IN std_logic;
    clk2 : IN std_logic;
    x : IN std_logic_vector(3 downto 0);
    load : IN std_logic;          
    serout : OUT std_logic
    );
  END COMPONENT;

  --Inputs
  SIGNAL clk :  std_logic := '0';
  SIGNAL clk2 :  std_logic := '0';
  SIGNAL load :  std_logic := '0';
  SIGNAL x :  std_logic_vector(3 downto 0) := (others=>'0');

  --Outputs
  SIGNAL serout :  std_logic;

BEGIN

  -- Instantiate the Unit Under Test (UUT)
  uut: Sender3 PORT MAP(
    clk => clk,
    clk2 => clk2,
    x => x,
    serout => serout,
    load => load
  );

  clk <= not clk after 10 ns;
  clk2 <= clk; -- beide Takte gleich
  
  tb : PROCESS  BEGIN
      wait for 100 ns;
      load <= '1';
      wait for 100 ns;
      load <= '0';
      wait; -- will wait forever
   END PROCESS;
END;

BTW:
>>>    x: in bit_vector(1 to 4);
Diese Schreibweise ist unüblich und bringt früher oder später Probleme. 
Mach daraus einen "normalen" 4-Bit Vektor vom Typ std_logic mit dem MSB 
links. Sowas also std_logic_vector(3 downto 0);

Vergiss die ganzen bit und bit_vector Definitionen und arbeite nur 
mit std_logic (oder std_ulogic). Sonst klemmt es jedesmal an der 
Schnittstelle, weil die ganze restliche Welt kein bit verwendet.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Hilfe


Sorry muss mich korrigieren, es sind genau 49,152 Mhz, daher die 6144 
Takte :-)

Der Ozillator im FPGA hat die Frequenz von 49,152 Mhz, dass giilt dann 
laut Datneblatt für GCLK0 von dem FPGA.
Hirt könnte es sein, dass ich ihn damals flasch angeschlossen hatte.

Mit der Testbench kenn ich mich nicht aus.
Hab das ganze mit Modelsim simuliert, da hatte es funtioniert. Dann im 
Labor mit dem FPGA aber nicht mehr.

Arbeite für die Aufgabe das erste mal mit vdhl-Code und mit einem FPGA, 
fällt nicht leicht, da gleich den Überblick zu haben.

Grüße

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

Bewertung
0 lesenswert
nicht lesenswert
> Arbeite für die Aufgabe das erste mal mit vdhl-Code und mit einem FPGA,
> fällt nicht leicht, da gleich den Überblick zu haben.
Ja, das ist, wie wenn du das Autofahren gleich mit dem "Rückwärts 
Einparken" beginnen würdest. So ein bisschen "Lauflicht mit 
Tastenabfrage" usw. usf. ist anschaulicher und sollte vorher schon mal 
gemacht werden...

> 49,152 Mhz, daher die 6144 Takte :-)
Rechne das mal mit /allen Nachkommastellen nochmal durch:
Ich komme auf 6140,625   :-o

Du darfst trotzdem nicht von 0 bis 6144 zählen, denn das sind 6145 
Takte, also einer zuviel. Denn die 0 ist ja auch einen ganzen Takt lang 
aktiv. Also müsstest du mit deiner Formel von 0 bis 6143, nach meiner 
Berechnung eher von 0 bis 6139 (oder doch 6140 wegen der 0,625) zählen.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am Ende hab ich im Labor auch noch mal was leichteres ausprobiert um den 
FPGA zu testen.

Wenn ich es dirket in den Taschenrechner eingebe, kommt 6144 raus. Hab 
es jetzt nochmal genauer gerechnet, kommt dann auch auf 6140,625.
Werde dann mal bis 6139 zählen. Falss es funtioniert, kann ich ja dann 
im Oszi schauen, ob die 0.125 ms hinkommen.

Grüße

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Anfänger schrieb:
> Wenn ich es dirket in den Taschenrechner eingebe, kommt 6144 raus. Hab
> es jetzt nochmal genauer gerechnet, kommt dann auch auf 6140,625.

Diesen Taschenrechner würde ich wegwerfen.

Ähm grad eine Frage für verwirrte Dumme:

Sind das 50 MHz
clk <= not clk after 10 ns;

oder das

clk <= not clk after 20 ns;

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

Bewertung
0 lesenswert
nicht lesenswert
> clk <= not clk after 10 ns;
Das sind 50 MHz, denn der Takt ist für 10ns low, dann für 10ns high.
In der Summe 20ns = 50MHz  ;-)

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>> clk <= not clk after 10 ns;
> Das sind 50 MHz, denn der Takt ist für 10ns low, dann für 10ns high.
> In der Summe 20ns = 50MHz  ;-)

Ich danke dir, mich hat das Quick Start Tutorial von Xilinx immer 
verwirrt warum die Low und High 20ns Sekunden haben obwohl das Startan3 
Eval Board nen 50MHz Oszi hat bis ich gerade gesehen habe dass deren 
Design (bzw. Simulation) im QST auf 25MHz ausgelegt ist fuer das 
Spartan-3 Demo Board mit 50MHz .,,. so ein Kack

Mein Gott manchmal dieses Brett vorm Kopf...

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.