Hallo Leute! Es ist bekanntlich nötig, externe asynchrone Signale erstmal über 2 FFs im FPGA einzusynchronisieren. Dieses Einsynchronisieren führt allerdings dazu, dass man dann eine Verzögerung von 2 Takten hat. Nehmen wir nun an, dass ein internes Modul, welches ein externes Triggersignal empfängt, mit einem Clock von nur 8 MHz getaktet wird. Das würde bedeuten, dass das Signal erst nach 2 * 125 ns synchronisiert dort ankommen würde. Nun frage ich mich, ob es nicht sinnvoll ist, dass man das Einsynchronisieren mit Hilfe von 2 FFs durchführt, die allerdings mit einer höheren Frequenz arbeiten. Das hätte auch den Vorteil, dass man kürzere externe Triggerpulse erkennen kann. Da ich im FPGA über DCMs an anderer Stelle mit 100 MHz arbeite, könnte ich dann diese 100 MHz dazu nutzen, um mein Signal in nur 2 * 10 ns einzusynchronisieren. Dieses auf den 100 MHz Clock einsynchronisierte Signal muss dann zwar "langgezogen" werden, um in die 8 MHz Domäne ordnungsgemäß transferiert zu werden, aber das würde IMHO höchstens zu einen weiteren Taktverzögerung von bis zu 125 ns führen. Das Domain-Crossing an sich von 100 MHz nach 8 MHz sollten Tools wie Xilinx ISE eigentlich automatisch machen, da das ganze ja intern über DCMs geht, deren Clock-Beziehungen die Tools kennen. Und falls dort das Timing nicht hinkommen sollte, wird ja eh gesagt, dass Metastabilität sowieso nur bei höheren Frequenzen auftreten kann. Ist sowas sinnvoll, oder mache ich da einen Denkfehler? Grüße, Anguel
Anguel S. schrieb: > Das Domain-Crossing an sich von 100 MHz nach 8 MHz sollten Tools wie > Xilinx ISE eigentlich automatisch machen, Ja, das machen sie. Allerdings wirst du beim Umweg über die 100 MHz-Domäne dann auf ein mal mit einer virtuellen Taktfrequenz von 200 MHz (und damit einer Zeit von 5ns) am Übergang zwischen den 100 MHz und den 8 MHz konfrontiert werden. Denn 100/8 = 12,5. Und diese 0,5 halbieren dir die Setupzeit für den Übergang des Triggersignals. Denn es könnte ja ein 100MHz-Takt genau zum Zeitpunkt t=120ns und der nächste zum Zeitpunkt t=130ns kommen. Der 8 MHz-Takt kommt aber zum Zeitpunkt t=125ns... :-o > Es ist bekanntlich nötig, externe asynchrone Signale erstmal über 2 FFs > im FPGA einzusynchronisieren. Mit diesen Faustformeln ist das so eine Sache... Man sollte wissen, warum diese 2 FFs da sind. Wenn dieses externe Signal in einen Zähler oder eine FSM geht (was ja meist der Fall sein dürfte), dann muß das entsprechende signal rechtzeitig vor der nächsten steigenden Taktflanke stabil am FF-eingang anliegen. Die 2 FFs wurden/werden verwendet, wenn sich möglicherweise der metastabile Zustand des 1. FFs solange halten kann, dass bei der nächsten Taktflanke noch kein stabiler Zustand an den beteiligten FFs angekommen wäre. Dann sorgt das 2. FF für klare Verhältnisse. Allerdings sind solche Betrachtungen zur Metastabilität bei aktuellen FPGAs eigentlich erst bei Taktfrequenzen >200MHz nötig. Deren FFs sind so schnell, dass sich bei kleineren Taktfrequenzen ein metastabiler Zustand gar nicht so lange halten kann, dass bei einer Taktfrequenz von 8MHz beim nächsten Takt nicht schon alles klar wäre. Fazit: bei dieser Taktfrequenz wird dir zum Einsynchronisieren 1 FF ausreichen. > Ist sowas sinnvoll, oder mache ich da einen Denkfehler? Dieser Umweg über die 100MHz Taktdomäne ist unnötig. Aber er könnte dir (wenn du die Sache mit den 5 ns in den Griff bekommst) die Latenz zum Erkennen des Triggersignals reduzieren. Denn wenn ein Triggersignal zum Zeitpunkt t=10ns kommt, dann bekommst du es auch mit nur 1 Sync-FF erst zum Zeitpunkt t=250ns in deiner FSM mit (also fast 2 Takte später). Wenn du es in der 100MHz-Domäne eintaktest und den 5 ns Pfad nach dem Sync-FF im Griff hast, dann könntest du schon bei t=125 darauf reagieren.
Vielen Dank an Lothar für die sehr ausführliche Antwort! Lothar Miller schrieb: > Allerdings wirst du beim Umweg über die 100 > MHz-Domäne dann auf ein mal mit einer virtuellen Taktfrequenz von 200 > MHz (und damit einer Zeit von 5ns) am Übergang zwischen den 100 MHz und > den 8 MHz konfrontiert werden. Ja, das ist mir bekannt. Falls ich übrigens mit dem Timing an der Grenze zw. 100 MHz und 8 MHz nicht hinkommen sollte, würde (wenn ich das richtig verstehe) schlimmstenfalls folgendes passieren: Das einsynchronisierte Signal aus der 100 MHz Domäne wechselt von '0' auf '1' so, dass die Setup-Zeit des 8 MHz FFs missachtet wird. Somit wird dieses 8 MHz FF kurz metastabil, was aber keine schlimmen Konsequenzen für den Rest der Schaltung hätte da < 200 MHz. Schlimmstenfalls würde ich dann "nur" das Triggersignal zu diesem Zeitpunkt verpassen, da sich das FF aufgrund der Metastabilität auf '0' statt auf '1' einpendelt. In diesem Fall würde ich das Triggersignal aber beim nächsten 8 MHz clk rising edge mitbekommen, ich würde es also nicht ganz verpassen, da ich das Signal in der 100 MHz Domäne sowieso auf 13 * 10 ns = 130 ns stretche. Richtig? > Fazit: bei dieser Taktfrequenz wird dir zum Einsynchronisieren 1 FF > ausreichen. 2 FFs werden also nur empfohlen, falls man 100% sicher sein möchte, dass auch bei hohen Frequenzen nix schief geht. > Dieser Umweg über die 100MHz Taktdomäne ist unnötig. Aber er könnte dir > (wenn du die Sache mit den 5 ns in den Griff bekommst) die Latenz zum > Erkennen des Triggersignals reduzieren. Genau diese Latenz möchte ich reduzieren. Außerdem möchte ich in der Lage sein, Triggersignale, die kürzer als 125 ns sind, zu erkennen. Deshalb wollte ich über 100 MHz eintakten.
Anguel S. schrieb: > Ja, das ist mir bekannt. Falls ich übrigens mit dem Timing an der Grenze > zw. 100 MHz und 8 MHz nicht hinkommen sollte, würde (wenn ich das > richtig verstehe) schlimmstenfalls folgendes passieren: ... Richtig? Insgesamt richtig, aber weil du damit ja auch 1 FF zusätzlich hast, ist nichts gewonnen. Das könntest du mit 8 MHz Takt direkt auf dem Eingangssignal auch machen... > Deshalb wollte ich über 100 MHz eintakten. Du gewinnst wie gesagt nur was, wenn du dann das 100 MHz FF direkt weiterverwenden kannst, ohne nochmal auf 8 MHz "umzusynchronisieren"... > 2 FFs werden also nur empfohlen, falls man 100% sicher sein möchte, dass > auch bei hohen Frequenzen nix schief geht. Es ist eine Frage von Wahrscheinlichkeiten. Dazu gibt es entsprechende Whitepaper und Dokumentationen von den FPGA-Herstellern... Siehe auch im Beitrag "Re: Signal per Taktflanken setten/resetten"
Lothar Miller schrieb: > Insgesamt richtig, aber weil du damit ja auch 1 FF zusätzlich hast, ist > nichts gewonnen. Das könntest du mit 8 MHz Takt direkt auf dem > Eingangssignal auch machen... Jetzt bin ich wieder etwas verwirrt und poste deshalb mal, was ich jetzt habe (clk_slow = 8 MHz, clk_fast = 100 MHz):
1 | entity hw_trig_in_synchronizer is |
2 | Port ( clk_slow : in STD_LOGIC; |
3 | clk_fast : in STD_LOGIC; |
4 | hw_trig_in_asynch : in STD_LOGIC; |
5 | hw_trig_in_synch : out STD_LOGIC); |
6 | end hw_trig_in_synchronizer; |
7 | |
8 | architecture Behavioral of hw_trig_in_synchronizer is |
9 | |
10 | signal hw_trig_in_clk_fast : std_logic := '0'; |
11 | signal hw_trig_in_stretched : std_logic := '0'; |
12 | |
13 | signal hw_trig_in_stretch_count : unsigned(3 downto 0) := to_unsigned(0, 4); |
14 | |
15 | begin
|
16 | |
17 | synch_hw_trig_in_to_clk_fast: process (clk_fast) |
18 | begin
|
19 | if (rising_edge(clk_fast)) then |
20 | -- da wir unter 200 MHz arbeiten, müsste ein FF zum einsynchronisieren ausreichen
|
21 | hw_trig_in_clk_fast <= hw_trig_in_asynch; |
22 | -- priority used:
|
23 | if (hw_trig_in_clk_fast = '1') then |
24 | hw_trig_in_stretch_count <= to_unsigned(1, 4); |
25 | elsif (hw_trig_in_stretch_count < 12 AND hw_trig_in_stretch_count /= 0) then |
26 | hw_trig_in_stretch_count <= hw_trig_in_stretch_count + 1; -- increment |
27 | elsif (hw_trig_in_stretch_count = 12) then -- and no hw_trig_in_clk_fast |
28 | hw_trig_in_stretch_count <= to_unsigned(0, 4); |
29 | end if; |
30 | --- independent if:
|
31 | if (hw_trig_in_stretch_count > 0 OR hw_trig_in_clk_fast = '1') then |
32 | hw_trig_in_stretched <= '1'; |
33 | else
|
34 | hw_trig_in_stretched <= '0'; |
35 | end if; |
36 | end if; |
37 | end process; |
38 | |
39 | |
40 | synch_hw_trig_in_to_clk_slow : process (clk_slow) |
41 | begin
|
42 | if (rising_edge(clk_slow)) then |
43 | if (hw_trig_in_stretched = '1') then |
44 | hw_trig_in_synch <= '1'; |
45 | else
|
46 | hw_trig_in_synch <= '0'; |
47 | end if; |
48 | end if; |
49 | end process; |
50 | |
51 | end Behavioral; |
Ich denke so müsste ich nun innerhalb von ca. 125 ns (etwas mehr wenn das Triggersignal ungünstig ankommt) immer in der clk_slow (8 MHz) Domäne angekommen sein, oder?
Anguel S. schrieb:
Nein, du streust dir sehr viel VHDLcode-Sand in die Augen. Das Problem
liegt ja hier:
1 | if (rising_edge(clk_fast)) then |
2 | :
|
3 | if (hw_trig_in_stretch_count > 0 OR hw_trig_in_clk_fast = '1') then |
4 | hw_trig_in_stretched <= '1'; |
5 | else
|
6 | hw_trig_in_stretched <= '0'; |
7 | end if; |
8 | end if; |
9 | :
|
10 | if (rising_edge(clk_slow)) then |
11 | if (hw_trig_in_stretched = '1') then |
12 | :
|
13 | end if; |
14 | end if; |
Zwischen irgendeinem Zeitpunkt, zu dem hw_trig_in_stretched gesetzt wird und einem anderen Zeitpunkt, zu dem es abgefragt wird, vergehen u.U. nur 5ns. Das ist das Problem, das auf diese Art nicht lösen kannst...
Jetzt habe ich folgendes gefunden: http://www.lothar-miller.de/s9y/categories/19-SpikePuls Das würde wahrscheinlich mein Problem am besten lösen. Ich würde dann aber nur 1 Synchro-FF (statt 2 FFs) verwenden und den synchronen Teil mit den 8 MHz betreiben. Das einzige wo ich mir nicht ganz sicher bin, wie ich das abändere, damit nicht nur ein einzelnes Spikeout Signal ausgegeben wird, sondern dass Spikeout oben bleibt, während Spikein oben bleibt.
Anguel S. schrieb: > Jetzt habe ich folgendes gefunden: Das war auch nicht sonderlich gut versteckt... ;-) > Das würde wahrscheinlich mein Problem am besten lösen. Das glaube ich nicht, denn deine Aufgabe ist ein andere... Es ist auch nicht schneller als das einfache Einsynchronisieren über 1 FF. Denn wenn du das wegdiskutierst, bekommst du wieder ein asynchrones Signal mit den hinlänglich bekannten Effekten... > ich würde dann aber nur 1 Synchro-FF (statt 2 FFs) verwenden und den > synchronen Teil mit den 8 MHz betreiben. Dann bist du wieder beim einfachen FF zum Eintakten. Fertig. Das letzte FF ist nur dafür da, das erste zurückzusetzen...
Also jetzt bin ich komplett verwirrt :-) Meine Idee ist, dass ich möglichst kurze Signale erkennen kann und diese so schnell wie möglich in die 8 MHz Domäne einsynchronisiere. Durch ext. Signal --> Marker-FF --> Einzelnes Synchro-FF @ 8 MHz hätte ich das doch erreicht, wenn ich nicht etwas komplett falsche verstehe. Da ich vorher nicht wusste, dass man solche asynchronen Marker-FFs verwenden kann, wollte ich das ext. Signal ursprünglich mit einer höheren Taktrate (100 MHz) abtasten. Außerdem bin ich ganz am Anfang davon ausgegangen, dass ich 2 Synchro-FFs @ 8 MHz zum einsynchronisieren bräuchte, was sich nachher als überflüssig herausstellte, da nur 1 Synchro-FF bei dieser Frequenz reicht.
Anguel S. schrieb: > Meine Idee ist, dass ich möglichst kurze Signale erkennen kann und diese > so schnell wie möglich in die 8 MHz Domäne einsynchronisiere. Ah, ok. Wenn ein externes signal kürzer sein kann als das Abtastintervall, dann ist der Spike-Detektor das richtige... Nur darfst du dann das Zurücksetzen eben nicht direkt vom externen Signal abhängig machen. Es könnten ja auch 2 (oder mehr) externe Impulse gekommen sein... BTW: Der Spike-Detector ist übrigens während des Rücksetzens für 1 Takt "blind"!
Ok, vielen Dank nochmal für die Hilfe, ich werde etwas am Simulator herumprobieren, ob ich das mit dem Zurücksetzen hinbekomme ;)
Was spricht denn dagegen, einfach eine Flankendetektion zu machen?
Peter schrieb: > Was spricht denn dagegen, einfach eine Flankendetektion zu machen? Mit welchem Takt?
Chris schrieb: > Geht das überhaupt intern, mit nur 8 MHz? Was geht? Immerhin lief der erste IBM-PC auf X86 Basis mit 4,77MHz, und auch das hat die Entwicklung der Menschheit nicht aufgehalten... ;-)
Ich habe den "Spike zu Puls" Code von Lothar Miller (http://www.lothar-miller.de/s9y/categories/19-SpikePuls) nun etwas umgewandelt. Wie bei Lothar werden auch hier sehr kurze Spikes mit Hilfe eines asynchr. FFs, das auf deren rising_edge() reagiert, erkannt. Erkannte Spikes erscheinen dann beim nächsten rising_edge(clk) am synchronen Ausgang des Moduls. Ich nutze zum einsynchronisieren ein einziges synchr. FF, da ich davon ausgehe, dass mein Takt weit unter 200 MHz liegt. Bei mir bleibt dann der synchrone Ausgang solange auf '1', bis an einem darauf folgenen rising_edge(clk) eine '0' als ext. Signal anliegt. Angehängt habe ich die Simulation und die RTL-Ansicht.
1 | entity hw_trig_in_synchronizer is |
2 | Port ( clk : in STD_LOGIC; |
3 | hw_trig_in_asynch : in STD_LOGIC; |
4 | hw_trig_in_synch : out STD_LOGIC); |
5 | end hw_trig_in_synchronizer; |
6 | |
7 | architecture Behavioral of hw_trig_in_synchronizer is |
8 | |
9 | signal hw_trig_in_synch_int : std_logic := '0'; |
10 | signal spike_mark : std_logic := '0'; |
11 | |
12 | begin
|
13 | |
14 | -- Spike-Marking-FF
|
15 | process (hw_trig_in_synch_int, hw_trig_in_asynch) |
16 | begin
|
17 | if (hw_trig_in_synch_int = '1' AND hw_trig_in_asynch = '0') then |
18 | spike_mark <= '0'; |
19 | elsif rising_edge(hw_trig_in_asynch) then |
20 | spike_mark <= '1'; |
21 | end if; |
22 | end process; |
23 | |
24 | -- Synch asynchronous Spike-Mark-FF
|
25 | process (clk) |
26 | begin
|
27 | if (rising_edge(clk)) then |
28 | -- da wir unter 200 MHz arbeiten, müsste ein FF zum einsynchronisieren ausreichen
|
29 | hw_trig_in_synch_int <= spike_mark; |
30 | end if; |
31 | end process; |
32 | |
33 | hw_trig_in_synch <= hw_trig_in_synch_int; |
34 | |
35 | end Behavioral; |
Weiß jemand, wie kurz eigentlich ein Spike beim Spartan3 sein darf??? Grüße, Anguel
Das UND-Gatter sieht irgendwie zwielichtig aus... :-/ 1. Das verletzt mein Postulat zum nicht-kombinatorischen Reset. 2. Ich bin mir nicht sicher, was passiert, wenn hw_trig_in_synch_int='1' ist und eine steigende Flanke am hw_trig_in_asynch kommt. Ich würde fast behaupten, dass der Reset langsamer weggeht, als der Takt ans FF kommt. Damit wäre die Taktflanke verpasst...
Überzeugt :) Dann muss wohl eine HW-Lösung zum Abfangen kurzer Pulse her. Und einsynchronisiert wird dann über ein einziges synchrones FF. Ich hoffe trotzdem, dass diese Gedankenspielerei auch anderen hilft. Nochmals vielen Dank an Lothar!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.