Forum: FPGA, VHDL & Co. Puls Clock Crossing Problem


von Matthias G. (mgottke)


Lesenswert?

Hallo Zusammen,

ich habe in einem Design an mehreren Stellen folgendes Problem:
Es müssen Daten (Register und andere) Signale von einer Clock-Domain in 
eine andere überführt werden. Beide Clocks sind zueinander frei laufend. 
Also keinerlei Abhängigkeiten zueinander. Auch die Frequenz des Clocks 
kann auf der Daten-Source-Seite (Eingangs-Seite) größer oder kleiner 
sein als auf der anderen Seite (Ausgagns-Seite) sein.

Da dieses Problemstellung etliche male im Design vorkommt, möchte ich 
gerne ein Modul schreiben, welches ein Übernahmesignal Eingangsseitig in 
einen 1-Takt langen Puls ausgangsseitig Transferiert. Der Puls 
ausgangsseitig soll die Übernahme der Daten steuern.

Das Eingangsseitige Übernahmesignal ist ebenfalls ein Puls mit einer 
Länge von einem oder aber auch mehreren Takten. Ausgewertet werden soll 
dabei die steigende Flanke eingangsseitig.

Damit sich die Daten eingangsseitig während der Übergabe nicht ändern 
können, soll ein Busy Signal eingangsseitig eine Datenaktualisierung 
verhindern bzw. verzögern. Das Busy soll erst wieder aufgelöst werden, 
wenn ausgangsseitig der Puls beendet ist.

Die Ein-, bzw. Ausgangssignale sollen natürlich Clocksynchron zum 
jeweiligen Takt sein.

Die Entity sieht also so aus:
1
entity clk_crossing_puls is port
2
(
3
   -- Eingangsseite
4
   clk_in     : in  std_logic;
5
   puls_in    : in  std_logic;
6
   busy       : out std_logic;
7
   -- Ausgangsseite
8
   clk_out    : in  std_logic;
9
   puls_out   : out std_logic
10
);
Wie könnte nun aber das passende Design dazu aussehen, das möglichst 
kleine Verzögerungszeiten realisiert aber dennoch resistent gegenüber 
metastabilen Zuständen ist.

Vielen Dank schon mal für möglichen Lösungsansätze.

von SuperWilly (Gast)


Lesenswert?

Wie groß darf / soll der Unterschied zwischen den beiden Takten denn 
sein ?

Gruß,
SuperWilly

von noone (Gast)


Lesenswert?

hoi...
wenn du xilinx verwendest kannste im coregenerator schauen ... unter 
independent clocks fifo ... sonst stehen glaube ich im "advanced FPGA 
design" von kilts auch sachen dazu drinne...

mfg

von Matthias G. (mgottke)


Lesenswert?

> Wie groß darf / soll der Unterschied zwischen den beiden Takten denn
> sein ?
Er sollte möglichst klein sein. Wie groß er sein darf, so stellt sich 
die Frage nicht. Die Frage ist, was ist möglich. Alles was an Zeit 
benötigt wird, fehlt anderen Prozessen wie u.a. einer CPU die in dem 
zyklischen Prozess eingebunden ist.

> wenn du xilinx verwendest kannste im coregenerator schauen ... unter
> independent clocks fifo
Xilinx verwende ich diesmal (leider) nicht, aber Fifos sind an dieser 
Stelle keine Lösung. Das Resultat brauche ich nämlich sofort. Insofern 
benötige ich trotzdem noch ein Signal das mitteilt, dass die Daten da 
sind. Ok, auf das Busy könnte man da verzichten, aber Blockrams sind 
Mangelware und bei über 400 Bits und einer benötigten Puffertiefe 1 eine 
Verschwendung. Im anderen Fall hänge Double-Buffer dran und dort ist 
eine zwingende Rückwärtige Verriegelung (Busy) notwendig.

von SuperWilly (Gast)


Lesenswert?

Mit Unterscbied zwischen den Takten meinte
ich Frequenz-Unterschied !

SuperWilly

von Gast (Gast)


Lesenswert?


von Matthias G. (mgottke)


Lesenswert?

Danke für die App_Note, die muss ich mir erst einmal näher zu Gemüte 
führen. Dazu werde ich morgen Berichten.

> Mit Unterscbied zwischen den Takten meinte
> ich Frequenz-Unterschied !
Steht noch nicht endgültig fest, kann aber durchaus größer Faktor 2 
sein. Von daher gesehen also beliebig.

von Matthias G. (mgottke)


Lesenswert?

So, nun habe ich den Flancter durchgearbeitet. Interressanter Ansatz. 
Die Anwendung mit dem Interrupt ist ja schön und gut. Wie aber im Text 
schon erwähnt ist der Ausgang teil-synchron bzw. teil-asynchron zu 
beiden Clocks. Damit keine Metatstabile Zustände auftreten, müssten dann 
am out noch zwei FF in Reihe geschaltet werden (mit dem out-clock 
(reset-clock)). Um ein Puls von einem Takt länge zu erzeugen, noch ein 
weiteres. Das Signal müsste dann nach den zwei FFs wieder zurück zur 
Eingangsseite mit weiteren zwei FF geleitet werden. Diese dann mit dem 
Eingangstakt (sysclk). Am Eingang kommt dann noch eine kleine 
Statemachine.

Geht man mal davon aus, dass das CE des Eingangs-FF durch die 
Statemachine mit Kombinatorischer Logig angesteuert wird, so gibt es da 
keine Verzögerung. Das Ausgangssignal steht also nach der 
Ausgangssynchronisation nach 2-3 Ausgangstakte zur Verfügung. Dann 
dauert es wieder 2-3 Eingangstakte bis das Ausgangssignal rückwärtig zur 
Statemachine einsynchronisiert ist. Nun dauert es auch noch 1 
Eingangstakt bis das Busy, gesteuert durch die Statemachine, weggeht.
Im worst case dauert das ganze dann 4 Eingangs-Clocks + 3 
Ausgangs-Clocks. Na ja, nicht gerade sehr schnell.

Vielleicht gehts ja doch auch schneller?

von Falk B. (falk)


Lesenswert?

@  Matthias G. (mgottke)

>Vielleicht gehts ja doch auch schneller?

Ja, mach dein Design sauber synchron zu EINEM Takt. Alles andere geht 
gegen den Baum ist ist den Zoff keine Nanosekunde wert.

Was glaubst denn, wofür du diese vielen asynchronen Takte brauchst?

MFG
Falk

von Matthias G. (mgottke)


Lesenswert?

> Ja, mach dein Design sauber synchron zu EINEM Takt. Alles andere geht
> gegen den Baum ist ist den Zoff keine Nanosekunde wert.

Schön wärs, geht aber leider nicht. Es gibt im Design nun mal komplexe 
Berechnungen die in Hardare ausgelagert sind. Durch die Komplexität und 
der Bitbreite von 32 Bit ist nun mal keine Taktrate oberhalb einer 
gewissen Frequenz möglich. In der Kette befindet sich aber auch eine CPU 
die viel schneller ist. Wenn ich der nicht einen höheren Takt verpasse, 
dann reicht das zur Verfügung stehende Zeitfenster nicht mehr aus um die 
erforderlichen Berechnungen durchzuführen.

Also bitte nicht so verpauschalieren. Die Zeitlichen Anforderungen habe 
ich mir schließlich nicht ausgedacht. Ein durchgängig synchrones Design 
wäre mir auch lieber.

Viele Grüße Matthias

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


Lesenswert?

Es geht "nur" um das Valid-Signal?
Die Daten sind (über Busy) zum gleichen Zeitpunkt stabil?

Also langsam zum Mitschreiben.
Weil clk_in < clk_out sein kann, wird auch puls_in < t(clk_out) werden 
können.
Dann würde ich das mit der üblichen Wischertechnik machen:
Zieldomäne ist clk_out. Mit dem puls_in setzt du setzt asynchron ein FF 
(ffpi). Damit hast du auch kürzere Pulse als 1 clk_in gespeichert. Jetzt 
muß dieses Flag synchronisiert werden (dieser saure Apfel bleibt dir). 
Wenn der puls_out aktiv wird, wird die ganze Registerkette (aus 
srpi(1,0) & ffpulsin) zurückgesetzt. Dann wird das Busy-Flag nach 
Rücksynchronisierung wieder gelöscht. Hier könntest du evtl. noch ein FF 
einsparen.
1
:
2
:
3
signal ffpi : std_logic;
4
signal srpi0,srpi1 : std_logic;
5
signal srpo0,srpo1 : std_logic;
6
begin
7
8
  -- synchron zu clk_in
9
  process begin
10
     wait until rising_edge(clk_in);
11
     srpi0 <= ffpi;
12
     srpi1 <= srpi0;
13
  end process;
14
15
  process (puls_in, srpo1) begin
16
     if (srpo1='1') then            -- synchron zu clk_out
17
        ffpi <= '0';
18
     elsif rising_edge(puls_in) then -- synchron zu clk_in
19
        ffpi <= '1';
20
     end if;
21
  end process;
22
23
  process begin
24
     wait until rising_edge(clk_out);
25
     if (srpo1='1') then
26
        srpo0 <= '0';
27
        srpo1 <= '0';
28
     else
29
        srpo0 <= ffpi;
30
        srpo1 <= srpo0;
31
     end if;
32
  end process;
33
34
  puls_out <= srpo1;
35
  busy  <= '1' when (ffpi='1' or srpi0='1' or srpi1='1') else '0';
36
:
37
:

Die andere Möglichkeit wäre, mit dem puls_in synchron zum clk_in alle 
Daten in ein Synchronisations-Schieberegister zu laden und über zwei 
Stufen in die clk_out Domäne zu takten. Dann wäre auch das busy-Signal 
unnötig.

von Matthias G. (mgottke)


Lesenswert?

Danke Lothar,

Die beschriebene Variante habe ich in ähnlicher Weise mal umgesetzt. Die 
Funktioniert auch.

> Die andere Möglichkeit wäre, mit dem puls_in synchron zum clk_in alle
> Daten in ein Synchronisations-Schieberegister zu laden und über zwei
> Stufen in die clk_out Domäne zu takten. Dann wäre auch das busy-Signal
> unnötig.

Jetzt habe ich auch die variante 2 umgesetzt. Die ist im zeitlich 
verlauf ehr schneller und es wird kein asynchrones Reset benötigt. Das 
einsychronisieren übe zwei FFs in beide Richtungen bleibt in allen 
Varianten erhalten. Allerdings brauche ich das Busy trotzdem.

Hier meine Lösung:
1
architecture behavior of clk_crossing_puls is
2
   signal puls_in_r        : std_logic;                      -- zur Flankendetektion
3
   signal in_ff            : std_logic := '0';               -- Speicherung des Eingangspulses in einem FF
4
   signal in_to_out_r      : std_logic_vector(2 downto 0);   -- Sieberegister zur Synchronisation zum Ausgang hin
5
   signal out_to_in_r      : std_logic_vector(1 downto 0);   -- Sieberegister zur Synchronisation zum Eingang zurück
6
begin
7
8
   -- Eingangs FF zur Speichrung des Eingangssingals
9
   in_ff_proc: process(clk_in)
10
   begin
11
      if rising_edge(clk_in) then
12
         puls_in_r <= puls_in;                         -- zur Detektion der steigenden Flanke
13
         if (puls_in_r = '0') and (puls_in = '1') then -- bei steigender Flanke
14
            in_ff <= '1';
15
         elsif out_to_in_r(1) = '1' then
16
            in_ff <= '0';
17
         end if;
18
      end if;
19
   end process;
20
21
   busy <= '1' when (in_ff = '1') or ((puls_in_r = '0') and (puls_in = '1')) else '0'; -- Eingangs-FF verodert mit steigender Eingangs-Flanke
22
23
   -- Eingang zum Ausgang hin synchronisieren
24
   in_to_out_r_proc: process(clk_out)
25
   begin
26
      if rising_edge(clk_out) then
27
         in_to_out_r(0)          <= in_ff;
28
         in_to_out_r(2 downto 1) <= in_to_out_r(1 downto 0);
29
      end if;
30
   end process;
31
32
   -- Ausgangspuls aus dem in_to_out_r erzeugen
33
   puls_out <= '1' when in_to_out_r(2 downto 1) = "01" else '0';
34
35
   -- Ausgang zum Eingang hin zurück synchronisieren
36
   out_to_in_r_proc: process(clk_in)
37
   begin
38
      if rising_edge(clk_in) then
39
         out_to_in_r(0) <= in_to_out_r(2);
40
         out_to_in_r(1) <= out_to_in_r(0);
41
      end if;
42
   end process;
43
44
end behavior;
wahrscheinlich lässt sich da nicht mehr viel rausholen. Höchstens man 
arbeitet bei den Schieberegistern abwechselnd mit steigenden und 
fallenden Flanke. Das ist aber bei Frequenzen über 120 MHz ein heißes 
Eisen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Hm... also wieso machst du die "langsamen" Berechnungen nicht in 
mehreren schritten in einer Art Pipeline? Hätte zudem den vorteil das du 
nach einer initalen latenz in jedem Takt einen Wert lesen kannst...

von Matthias G. (mgottke)


Lesenswert?

Hallo Läubi:

> Hm... also wieso machst du die "langsamen" Berechnungen nicht in
> mehreren schritten in einer Art Pipeline? Hätte zudem den vorteil das du
> nach einer initalen latenz in jedem Takt einen Wert lesen kannst...

Das ist an der Stelle zu komplex um das zu erklären. Da spielen noch 
viele andere Faktoren im Design eine Rolle. Es sind dort mehrere CPUs im 
Design vorhanden und auch die Speicheranbindung (DDR2-RAM) spielt mit 
seinem Takt eine Rolle. Ich bin schon froh, dass sich die Taktraten auf 
zwei Takte reduzieren lassen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Was ich dir sonst noch empfehlen könnte wäre nen FSL Bus, Xilinx bietet 
da nen IP Core an, der kommt auch beim MicroBlaze in Multicore 
anwendungen zum Einsatz und unterstütz Asyncrone Ein/Ausgänge... 
Pufertiefe ist einstellbar und recht leicht im interface, basiert mein 
ich auf einem IBM Standar der auch offen ist.

von Matthias G. (mgottke)


Lesenswert?

Ich denke mit der Übernahme, dass das in meinem Fall schon die richtige 
Lösung ist. Die Daten, die ich Übernehmen muss kommen von mehreren 
Schnittstellen aktiv zur Übernahme, so dass dort eine riesen Palette an 
Daten anliegt. Diese werden auch ständig von verschiedenen Quellen, 
teilweise auch parallel, geändert. Es muss aber bei der Übernahme die 
Synchronität eines Datensatzes gewährt bleiben. Das sind aber 
Projektspezifische Probleme.

Aber danke für die Tips.

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.