Forum: FPGA, VHDL & Co. Signal um beliebige Takte verzögern Teil 2


von Christoph M. (joeder3th)


Lesenswert?

Hallo,

ich würde gerne ein Signal um eine beliebige Anzahl von Takten 
verzögern.
Die Forumsuche habe ich schon verwendet, jedoch bin ich nur auf den 
Lösungsansatz mit dem Schieberegister gekommen. Wenn ich diese Variante 
für mein Design verwende, verbrauche ich zuviele Ressourcen. Ich würde 
gerne ein 4KHz Signal um mindestens 2 Perioden permanent verzögern. Hab 
schon einwenig recherchiert, dass man es mit einem Counter realisieren 
kann. Nun meine Frage, ob jemand einen Beispiel-Code von so einer 
Verzögerung mittels Counter hat.


lg

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


Lesenswert?

Christoph M. schrieb:
> Hab schon einwenig recherchiert, dass man es mit einem Counter
> realisieren kann.
Das ist wie wenn ich schreibe:
Ich hab gehört, dass man ein Auto mit Stahl realisieren kann...

> Nun meine Frage, ob jemand einen Beispiel-Code von
> so einer Verzögerung mittels Counter hat.
Was du brauchst ist ein Ringpuffer, mit einer Speichertiefe von 
2*fadc/4kHz Worten. Wenn du also dien Signal z.B. mit 48kHz abtastest, 
dann brauchst du einen Speicher mit 2*48/4 = 24 Worten

> Ich würde gerne ein 4KHz Signal
WAS für ein signal? Analog/Digital?
> um mindestens 2 Perioden permanent verzögern.
Um 2 Perioden von was?
Ist die Frequenz des Signals konstant?
Welche Abtastrate hat dein ADC?

Und richtig: zur Realisierung eines Ringpuffers brauchst du (mindestens) 
einen Zähler. Aber viel wichtiger ist der Speicher...

von Christoph M. (joeder3th)


Lesenswert?

Danke für die schnelle Antwort.... :)


Lothar Miller schrieb:
> Christoph M. schrieb:
>> Hab schon einwenig recherchiert, dass man es mit einem Counter
>> realisieren kann.
> Das ist wie wenn ich schreibe:
> Ich hab gehört, dass man ein Auto mit Stahl realisieren kann...

Ja war ein bisschen blöd formuliert... :)



Lothar Miller schrieb:
>> Ich würde gerne ein 4KHz Signal
> WAS für ein signal? Analog/Digital?
>> um mindestens 2 Perioden permanent verzögern.
> Um 2 Perioden von was?
> Ist die Frequenz des Signals konstant?
> Welche Abtastrate hat dein ADC?


Es handelt sich um ein Rechtecksignal mit 4 KHz welches konstant bleibt.
Dieses Signal möchte ich mit dem FPGA um 2 Perioden von diesen 4 Khz 
verzögern und wieder ausgeben.


Das ganze hat nichts mit einem ADC zu tun ich möchte nur dieses 4 KHz 
Signal verzögern.

Mir ist schon klar, ich muss einen Counter verwenden, wenn ein 
vorgegebener Wert erreicht ist habe ich dann auch meine Verzögerung 
erreicht. Jedoch wie gebe ich dann das Signal aus. Ich denk mal es ist 
ganz einfach nur ich komm da im Moment nicht weiter. Ich weiss nicht wie 
ich es ausgeben soll (das verzögerte 4 KHz Signal)

lg

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


Lesenswert?

Welchen Jitter darf dieses verzögerte Signal maximal haben?
100ns? 1us? 10us?

von Christoph M. (joeder3th)


Lesenswert?

Ich hab mir mal 1us als Grenze gesetzt.

lg

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


Lesenswert?

Christoph M. schrieb:
> Ich hab mir mal 1us als Grenze gesetzt.
Dann wäre das gerade mal ein Schieberegister mit 250 Stellen. Das sind 
gerade mal 16 Luts, wenn die als Schieberegister geschaltet werden. 
Kleiner bekommst du das auch mit irgendwelchen Zählern und Speichern 
niemals hin...

Du brauchst also
1. einen Zähler, der die die 1us Sample-Zeit erzeugt, und dann
2. das Schieberegister.

Nehmen wir mal 50MHz FPGA-Takt. Dann sieht das so aus:
1
:
2
signal oneus_cnt : integer range 0 to 49 := 0;
3
signal sr = std_logic_vector(249 downto 0) := (others=>'0');
4
:
5
process begin
6
   wait until rising_edge(clk); -- 50MHz
7
   if (oneus_cnt=49) then
8
      sr <= sr(sr'left-1 downto 0) & input;
9
      oneus_cnt <= 0;
10
   else
11
      oneus_cnt <= oneus_cnt+1;
12
   end if;
13
end process;
14
15
output <= sr(sr'left);
16
:

von Christoph M. (joeder3th)


Lesenswert?

Hallo

danke für deine Code, hab mein Taktfrequenz angepasst und siehe da es 
funktioniert :)

Danke vielmals,

einmal muss ich noch lästig sein, ist es möglich die Einstellung der 
Verzögerung sprich den Wert der Verzögerung variable zu machen?

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


Lesenswert?

Christoph M. schrieb:
> siehe da es funktioniert :)
Klar.  ;-)
> Danke vielmals,
De nada.

> einmal muss ich noch lästig sein, ist es möglich die Einstellung der
> Verzögerung sprich den Wert der Verzögerung variable zu machen?
Ja.
1
   port (
2
      in clk     : std_logic;
3
      in input   : std_logic;
4
      in delayus : std_logic_vector(7 downto 0);
5
        :
6
      out output : std_logic;
7
        :
8
      );
9
:
10
signal oneus_cnt : integer range 0 to 49 := 0;
11
signal sr = std_logic_vector(249 downto 0) := (others=>'0');
12
:
13
process begin
14
   wait until rising_edge(clk); -- 50MHz
15
   if (oneus_cnt=49) then
16
      sr <= sr(sr'left-1 downto 0) & input;
17
      oneus_cnt <= 0;
18
   else
19
      oneus_cnt <= oneus_cnt+1;
20
   end if;
21
end process;
22
23
output <= sr(to_integer(unsigned(delay)));
24
:
Aber wenn du das zur Laufzeit machen willst, wird dich das Ressourcen 
kosten, weil dann keine LUTs mehr als Schieberegister verwendet werden 
können...

von berndl (Gast)


Lesenswert?

Lothar Miller schrieb:
> Aber wenn du das zur Laufzeit machen willst, wird dich das Ressourcen
> kosten, weil dann keine LUTs mehr als Schieberegister verwendet werden
> können...

dann kann man ein Block-RAM opfern und einen synchronen FIFO bauen. Ist 
zwar auch Verschwendung, aber das RAM ist eh' auf dem Chip vorhanden. 
Bei einem 2k*9 RAM koennte man sogar 2048*9 Werte fuer ein Signal 
speichern...

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


Lesenswert?

berndl schrieb:
> dann kann man ein Block-RAM opfern und einen synchronen FIFO bauen.
Das wäre auch elegant, dann könnte man auch den Jitter noch deutlich 
reduzieren und vor allem: dann brauchen wir wieder den bereits erwähnten 
Zähler.. ;-)

Hier mal die obige Lösung mit 255 Abgriffen:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity Delayline is
6
    Port ( clk : in  STD_LOGIC;
7
           input : in  STD_LOGIC;
8
           output : out  STD_LOGIC;
9
           delay : in  STD_LOGIC_VECTOR (7 downto 0));
10
end Delayline;
11
12
architecture Behavioral of Delayline is
13
signal oneus_cnt : integer range 0 to 49 := 0;
14
signal wrptr : unsigned (7 downto 0) := (others=>'0'); -- unsigned wegen des kostenlosen wrap-arounds... ;-)
15
signal rdptr : unsigned (7 downto 0) := (others=>'0'); -- unsigned wegen des kostenlosen wrap-arounds... ;-)
16
type speicher is array(0 to 255) of STD_LOGIC;
17
signal memory : speicher; 
18
begin
19
20
process begin
21
   wait until rising_edge(clk); -- 50MHz
22
   if (oneus_cnt=49) then
23
      memory(to_integer(wrptr)) <= input;
24
      wrptr       <= wrptr+1;
25
      rdptr       <= wrptr-unsigned(delay);
26
      oneus_cnt   <= 0;
27
   else
28
      oneus_cnt   <= oneus_cnt+1;
29
   end if;
30
end process;
31
32
output <= memory(to_integer(rdptr));

Und tatsächlich: es wird hier ein DP-RAM erkannt, das dann aber wegen 
des geringen Speicherbedarfs in LUTs abgebildet:
1
INFO:Xst:3231 - The small RAM <Mram_memory> will be implemented on LUTs in 
2
order to maximize performance and save block RAM resources. If you want to 
3
force its implementation on block, use option/constraint ram_style.
4
    -----------------------------------------------------------------------
5
    | ram_type           | Distributed                         |          |
6
    -----------------------------------------------------------------------
7
    | Port A                                                              |
8
    |     aspect ratio   | 256-word x 1-bit                    |          |
9
    |     clkA           | connected to signal <clk>           | rise     |
10
    |     weA            | connected to signal <_cmp_eq0000>   | high     |
11
    |     addrA          | connected to signal <wrptr>         |          |
12
    |     diA            | connected to signal <input>         |          |
13
    -----------------------------------------------------------------------
14
    | Port B                                                              |
15
    |     aspect ratio   | 256-word x 1-bit                    |          |
16
    |     addrB          | connected to signal <rdptr>         |          |
17
    |     doB            | connected to signal <output>        |          |
18
    -----------------------------------------------------------------------

Wir die Länge dann z.B. auf 8192 Bits aufgeblasen, dann kommt 
tsatsächlich das gewünschte BlockRAM heraus... ;-)

von Christoph M. (joeder3th)


Lesenswert?

Hallo,

ich hab mir die Realisierung mittels des Speichers nochmal angeschaut.
Kann es sein, dass die Läösung mit den 255 Abgriffen aber nur eine 
Periode verzögter oder?

Ich hab es mal angepasst für 2 Perioden bzw. ich denke es sollte so 
funktionieren.
1
entity main is
2
    Port ( reset : in  STD_LOGIC;
3
           clk : in  STD_LOGIC;
4
        referenz : in STD_LOGIC;
5
        output : out STD_LOGIC);
6
end main;
7
8
architecture Behavioral of main is
9
10
----------------------------------------------------------------------------------------------------
11
12
signal oneus_cnt : integer range 0 to 100 := 0;
13
signal wrptr : unsigned (9 downto 0) := (others=>'0'); -- unsigned wegen des kostenlosen wrap-arounds... ;-)
14
signal rdptr : unsigned (9 downto 0) := (others=>'0'); -- unsigned wegen des kostenlosen wrap-arounds... ;-)
15
type speicher is array(0 to 512) of STD_LOGIC;
16
signal memory : speicher; 
17
18
Signal delay : unsigned (9 downto 0) := "0111110100";   
19
20
----------------------------------------------------------------------------------------------------
21
22
begin
23
24
----------------------------------------------------------------------------------------------------
25
26
delay_process : process (reset,clk)
27
begin
28
if reset = '0' then
29
  oneus_cnt <= 0;
30
elsif rising_edge(clk) then -- 100MHz
31
  if (oneus_cnt=100) then
32
    memory(to_integer(wrptr)) <= referenz;
33
      wrptr       <= wrptr+1;
34
      rdptr       <= wrptr-unsigned(delay);
35
      oneus_cnt   <= 0;
36
   else
37
      oneus_cnt   <= oneus_cnt+1;
38
   end if;
39
end if;
40
end process;
41
42
----------------------------------------------------------------------------------------------------
43
44
output <= memory(to_integer(rdptr));
45
46
----------------------------------------------------------------------------------------------------
47
48
end Behavioral;

Bin ich hier richtig von meiner Denkweise? Wenn ich das die Delay auf 
den Wert 500 einstelle, dann sollte das Signal um 2 Perioden verzögert 
sein oda?

lg

von icke (Gast)


Lesenswert?

Leuchtet mir alles ein, nur wieso passt denn Lothars Lösung rein? Ich 
dachte ein Schieberegister passt NICHT?
Sonst wär mir nur ein entsprechend langsamer Takt eingefallen. Phase von 
dem Rechtecksignal ist vermutlich konstant?

von Christoph M. (joeder3th)


Lesenswert?

Hallo,

ja ist konstant!

Sagen wir es mal so....
Er kann VHDL ich noch nicht so gut.. :)

Theoretisch müsste ich aber die 1us auch noch reduzieren können oder??
Könnte es mit 100ns noch klappen?

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


Angehängte Dateien:

Lesenswert?

Christoph M. schrieb:
> Bin ich hier richtig von meiner Denkweise? Wenn ich das die Delay auf
> den Wert 500 einstelle, dann sollte das Signal um 2 Perioden verzögert
> sein oda?
Was sagt denn deine Simulation?
Meine sagt (für meinen Code) auf jeden Fall: Ja, stimmt.

von Christoph M. (joeder3th)


Angehängte Dateien:

Lesenswert?

Hallo,

ok die Größe vom Array war falsch
jetzt sagt die meine Simulation auch, dass es passt.. :)
danke!

und noch zur Frage der Genauigkeit. Dazu müsste ich den oneus_cnt 
counter und das Array anpassen oder?

lg

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


Lesenswert?

Christoph M. schrieb:
> und noch zur Frage der Genauigkeit.
Fachwort: Jitter
> Dazu müsste ich den oneus_cnt counter und das Array anpassen oder?
Ja, du müsstest öfter abtasten: Wenn du alle 500ns abtastest, dann 
brauchst du doppelt soviel Speicher und bekommst den halben Jitter.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Wenn man Dein Bild so anschaut, dann sieht das aus wie ein Taktsignal. 
Wenn man einen Takt um das Vielfache einer Periodendauer verzögert, dann 
hat man wieder das selbe Taktsignal, lediglich mit einer einzigen 
Verzögerung am Anfang. Wenn die 4kHz fest sind, dann kannst Du diese 
Einschaltverzögerung mit einem x-beliebigen Zähler und einem clock gate 
bauen.

Ansonsten natürlich ein Schieberegister...

Gruß
Marcus

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.