Forum: FPGA, VHDL & Co. bit_Vektor VHDL


von Martin (Gast)


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

von Nephilim (Gast)


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.

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


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

von Martin (Gast)


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

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


Lesenswert?

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

From the Scratch:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity Par2Ser is
6
    Port ( clk : in  STD_LOGIC;     -- z.B. 10MHz
7
           serout : out  STD_LOGIC; 
8
           frame  : out  STD_LOGIC; -- '1' solange Daten übertragen werden
9
           load   : in  STD_LOGIC;  -- Bitvektor laden
10
           parin  : in  STD_LOGIC_VECTOR (549 downto 0));
11
end Par2Ser;
12
13
architecture Behavioral of Par2Ser is
14
signal delaycnt : integer range 0 to 9999; -- 1ms/Bit
15
signal bitcnt : integer range 0 to 550;
16
signal bits  : STD_LOGIC_VECTOR (549 downto 0);
17
begin
18
   process begin
19
     wait until rising_edge(clk);
20
     if (load='1') then
21
       delaycnt <= 0; -- Bitdelay zurücksetzen
22
       bitcnt <= 550; -- 550 Bits sind zu übertragen
23
       bits <= parin; -- Daten zur internen Verarbeitung übernehmen
24
     else
25
       if (delaycnt/=9999) then   -- 1 ms vorbei?
26
         delaycnt <= delaycnt+1; -- nein: weiterzählen 
27
       else
28
         if (bitcnt/=0) then     -- sind noch Bits übrig?
29
           delaycnt <= 0;        -- ja: Bitdelay zurücksetzen
30
           bits <= '0' & bits(550 downto 1); -- das Schieberegister eins weiterschieben
31
           bitcnt <= bitcnt-1;   
32
         end if;
33
       end if;
34
     end if;
35
   end process;
36
   serout <= bits(0);
37
   frame <= '1' when bitcnt/=0 else '0';  
38
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.

von D. I. (Gast)


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.

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


Angehängte Dateien:

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
1
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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity Par2Ser is
6
    Port ( clk : in  STD_LOGIC;     -- z.B. 10MHz
7
           serout : out  STD_LOGIC; 
8
           frame  : out  STD_LOGIC; -- '1' solange Daten übertragen werden
9
           sclk   : out  STD_LOGIC; -- steigende Flanke = serout gültig
10
           load   : in  STD_LOGIC;  -- Bitvektor laden
11
           parin  : in  STD_LOGIC_VECTOR (549 downto 0));
12
end Par2Ser;
13
14
architecture Behavioral of Par2Ser is
15
signal phase  : std_logic := '0';
16
signal bitcnt : integer range 0 to 550;
17
signal bits   : STD_LOGIC_VECTOR (549 downto 0);
18
begin
19
   process begin
20
     wait until rising_edge(clk);
21
     if (load='1') then
22
       phase  <= '0';
23
       bitcnt <= 550; -- 550 Bits sind zu übertragen
24
       bits   <= parin; -- Daten zur internen Verarbeitung übernehmen
25
     else
26
       if (bitcnt/=0) then     -- sind noch Bits übrig?
27
         if (phase='1') then   
28
           bits   <= '0' & bits(549 downto 1); -- das Schieberegister eins weiterschieben
29
           bitcnt <= bitcnt-1;   
30
         end if;
31
         phase <= not phase;
32
       end if;
33
     end if;
34
   end process;
35
   serout <= bits(0);
36
   frame  <= '1' when bitcnt/=0 else '0';  
37
   sclk   <= phase;
38
end Behavioral;

Hier die Stimuli der Testbench
1
  clk <= not clk after 50 ns;
2
3
  tb : PROCESS BEGIN
4
    wait for 270 ns;
5
    parin <= '1'&(548 downto 1=>'0')&'1';
6
    parin <= (others=>'0');
7
    parin(0) <= '1';
8
    parin(5) <= '1';
9
    parin(9) <= '1';
10
    parin(15) <= '1';
11
    load <= '1';
12
    wait for 320 ns;
13
    load <= '0';
14
    wait; -- will wait forever
15
  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...

von D. I. (Gast)


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
>
1
bits<='1'&(548 downto 1=>'0')&'1'; -- nur das erste und letzte Bit
2
> 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.

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


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.

von Anfänger (Gast)


Lesenswert?

Hi,
ich programmiere auch grade an einem ähnlichen Code.

Mich würde mal die Zeile interessieren:
1
process begin
2
     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

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


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
1
   process (clk) begin
2
      if rising_edge(clk) then
3
         if (reset='1') then  -- Reset synchron
4
            :
5
         else                 -- die eigentliche Arbeit
6
            :
7
         end if;
8
      end if;
9
   end process;
oder mit der Schreibweise, die keine Sensitivity-Liste braucht
1
   process begin
2
      wait until rising_edge(clk);
3
      if (reset='1') then  -- Reset synchron
4
         :
5
      else                 -- die eigentliche Arbeit
6
         :
7
      end if;
8
   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:
1
   if rising_edge(Taster) then ...
2
3
   if falling_edge(ChipSelect) then ...
4
5
   if rising_edge(PS2CLK) then ...
6
   
7
   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....

von Anfänger (Gast)


Angehängte Dateien:

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

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


Angehängte Dateien:

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:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
USE ieee.numeric_std.ALL;
4
5
ENTITY tb_MFW_vhd IS
6
END tb_MFW_vhd;
7
8
ARCHITECTURE behavior OF tb_MFW_vhd IS 
9
10
  -- Component Declaration for the Unit Under Test (UUT)
11
  COMPONENT Sender3
12
  PORT(
13
    clk : IN std_logic;
14
    clk2 : IN std_logic;
15
    x : IN std_logic_vector(3 downto 0);
16
    load : IN std_logic;          
17
    serout : OUT std_logic
18
    );
19
  END COMPONENT;
20
21
  --Inputs
22
  SIGNAL clk :  std_logic := '0';
23
  SIGNAL clk2 :  std_logic := '0';
24
  SIGNAL load :  std_logic := '0';
25
  SIGNAL x :  std_logic_vector(3 downto 0) := (others=>'0');
26
27
  --Outputs
28
  SIGNAL serout :  std_logic;
29
30
BEGIN
31
32
  -- Instantiate the Unit Under Test (UUT)
33
  uut: Sender3 PORT MAP(
34
    clk => clk,
35
    clk2 => clk2,
36
    x => x,
37
    serout => serout,
38
    load => load
39
  );
40
41
  clk <= not clk after 10 ns;
42
  clk2 <= clk; -- beide Takte gleich
43
  
44
  tb : PROCESS  BEGIN
45
      wait for 100 ns;
46
      load <= '1';
47
      wait for 100 ns;
48
      load <= '0';
49
      wait; -- will wait forever
50
   END PROCESS;
51
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.

von Anfänger (Gast)


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

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


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.

von Anfänger (Gast)


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

von D. I. (Gast)


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
1
clk <= not clk after 10 ns;

oder das

1
clk <= not clk after 20 ns;

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


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

von D. I. (Gast)


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

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.