Hallo,
kann mir bitte jemand erklären wie man asynchrone Signale richtig
einsynchronisiert? (z.B. ein I/O Signal)
Ich kenne bisher diese 2 Varianten :
Beispiel:
FPGA
|
sig_async --> | -> sig_sync
|
Variante (1) - meine bisherige Taktik:
sig_sync übernimmt nur einen neuen Wert (bei steigender Taktflanke),
wenn sig_async für 2 Takte gleich ist.
Variante (2)
Oft habe ich folgendes gelesen (ich glaube u.a. hier im Forum):
sig_async --> FF_1 --> FF_2 -> sig_sync
Was genau bewirken die beiden in Serie geschalteten FFs?
Geht es darum, dass sich FF_1 theoretisch in einem metastabilen Zustand
befinden kann (Spike auf sig_async zur Taktflanke). Damit würde zwar
FF_2 u.U. kurzzeitig eine Signaländerung erkennen. Aber da die
Setup&Hold Zeiten nicht eingehalten werden, liegt an sig_sync ein
sauberes taktsynchrones Signal (ohne Spike) an.
Ist das richtig oder bin ich total auf dem Holzweg?
Danke für alle Kommentare,
Nik
> Geht es darum, dass sich FF_1 theoretisch in einem metastabilen> Zustand befinden kann (Spike auf sig_async zur Taktflanke).
Das muß keineswegs ein Spike sein, sowas passiert dir theoretisch (und
praktisch) sogar, wenn das Signal ein einziges Mal den Zustand wechselt.
Es reicht einfach aus, wenn die Setup oder die Hold-Zeit verletzt wird.
Offenbar verwendest du das externe Signal im 1. Fall als Reset oder
Enable für einen Zähler. Allerdings ist es dadurch trotzdem ein
asynchrones Signal!! (Lass doch mal VHDL-Code zur Variante 1 sehen ;-)
Der eigentliche Witz ist der, dass das asynchrone externe Signal in
einer umfangreichen State-Machine auf viele FFs geht. Und durch
unterschiedliche Laufzeiten im FPGA sehen diese FFs teils eine 0 und
teils eine 1. So kann es passieren, dass die SM falsch
weiterschaltet/reagiert.
Absolut kampferprobt und z.B. weitverbreitet in Mikrocontrollern
eigesetzt ist die Variante 2.
@Lothar:
Diese Variante ist auf Xilinx-FPGAs aber in gewisser Weise gefährlich:
Die Synthese implementiert ein Schieberegister in einer LUT, dadurch
wird das FF im IO-Buffer nicht benutzt, und man hat keine festen
setup-to-clock Zeiten, das kann schnell schief gehen, wenn man z.B. zwei
Signale parallel einlesen will, die dann unterschiedliche Laufzeiten
haben.
Deswegen sollte man entweder per Constraints inputsr(0) in ein IO-FF
zwingen oder - häufig die einfachere Lösung - durch zuweisen eines
Reset-Werts an inputsr erzwingen, dass es in FF umgesetzt wird.
Für das Entprellen von Tasten stellt das natürlich kein Problem dar.
> keine festen setup-to-clock Zeiten, das kann schnell schief gehen,> wenn man z.B. zwei Signale parallel einlesen will, die dann> unterschiedliche Laufzeiten haben.
Hmmm, wenn ich parallele Signale einlesen will, brauche ich sowieso eine
andere Validierungsart. Ich werde mich auch wenn das FF im IO-Treiber
liegt, nicht darauf verlassen können, das jede Flanke gleichzeitig
einsynchronisiert wird. I.A. werden also die Daten stabil anliegen,
anschliessend das Write-Signal deaktiviert werden.
> wird das FF im IO-Buffer nicht benutzt, und man hat> keine festen setup-to-clock Zeiten,
Richtig, man muß sich nicht unnötig Probleme machen.. ;-)
> oder - häufig die einfachere Lösung - durch zuweisen eines> Reset-Werts an inputsr erzwingen, dass es in FF umgesetzt wird.
Oder mehrere Bits des SR abfragen. Ich mache für (langsame) asynchrone
Signale zur Spikeunterdrückung gerne den Vergleich über das ganze
Schieberegister:
@ Nik N.
Die erste Variante solltest du schnell wieder vergessen.
>durch zuweisen eines>Reset-Werts an inputsr erzwingen, dass es in FF umgesetzt wird.
Das ist nicht notwendig. Sobald auf die Zwischenwerte zugegriffen wird,
werden automatisch FF's verwendet.
Hallo,
danke für die ganzen Antworten, aber das muss ich jetzt erstmal
sortieren.
@L. Miller:
Variante (1) hätte ich bisher immer so implementiert.
1
process(clk)
2
ifrising_edge(clk)then
3
sig_tmp<=sig_async;
4
ifsig_tmp=sig_asyncthen
5
sig_sync<=sig_async;
6
else
7
sig_sync<=sig_sync;
8
endif;
9
endif;
Variante (3):
Die eine deiner Variante, macht im Prinzip das gleiche, nur ohne
Latches, oder?
1
processbegin
2
waituntilrising_edge(clk);
3
inputsr<=inputsr(1downto0)&input;
4
if(inputsr="000")thensyncinput<='0';endif;
5
if(inputsr="111")thensyncinput<='1';endif;
6
endprocess;
Variante (4):
Wenn ich Jan M. richtig verstehe werden hier gar keine seriell
verschalteten FFs generiert, oder?
1
processbegin
2
waituntilrising_edge(clk);
3
inputsr<=inputsr(1downto0)&input;
4
endprocess;
5
syncinput<=inputsr(2);
Dann meine Fragen:
a) Wie schaut denn dann eine richtige Implementierung von Variante 2
aus? (sig_async -> FF -> FF ->sig_sync)
2) Was bewirken die beiden FFs dann im Detail?
Mir scheint, es gibt einige verschiedene Varianten dieses Problem zu
lösen. Die Varianten unterscheiden sich in Details bei der
Implementierung die ja scheinbar durchaus wichtig sind.
Grüße,
Nik
lkmiller:
>> Hmmm, wenn ich parallele Signale einlesen will, brauche ich sowieso eine
andere Validierungsart.
ich hätte einfach dieses über einen vector gelöst, sprich diese
"single-line-sync"-Lösung parallelisiert. Wie würdest Du es machen?
Grüße
Olaf
>Dann meine Fragen:>a) Wie schaut denn dann eine richtige Implementierung von Variante 2>aus? (sig_async -> FF -> FF ->sig_sync)>2) Was bewirken die beiden FFs dann im Detail?
Sie testen das Signal auf einen stabilen (gültigen) Pegel. Mit einem FF
würdest du das nur theoretisch hinbekommen. Dazu testet man die
FF-Ausgänge auf gleiche Pegel.
@Nik
Der ganze Grund für die Geschichte ist, man das Eingangsignal eines FF
nicht ändern darf, kurz bevor (Setup-Zeit) und kurz nach (Hold Zeit) der
Taktflanke.
Bei einem Signal von außen, das nichts mit dem Takt im CPLD/FPGA zu tun
hat, kann man das aber nie garantieren, man muß also damit rechnen dass
es passiert.
Das Problem ist nun, dass in einer komplexen Schaltung das externe
Eingangssignal nun auf mehrere FFs gleichzeitig geht (z.B. bei einer
State Machine). Wenn nun das Signal sich während der Taktflanke ändert,
kommt es vor, dass einige FF das Signal übernehmen, und andere nicht.
Das ergibt eine Fehlfunktion der Schaltung.
Weiters kann es passieren, dass ein FF metastabil wird, d.h. der Ausgang
ist nicht nach der spezifizierten Durchlaufzeit stabil, sondern braucht
länger, oszilliert usw. Dieser metastabile Zustand wird nach einer
bestimmten Zeit zur Ruhe, die Dauer des Zustands ist zufallig, der
Ausgang am FF auch.
Die Abhilfe ist das Synchronisieren : Das externe Signal kommt in das
FPGA nur über eine einziges FF, dieses kann dann kippen oder nicht. Wenn
dieses FF metastabil wird, dann betrifft es den Eingang des nächsten FF,
dieses schaltet aber erst wieder nach der Taktperiode. Das erste FF hat
also eine ganze Taktperiode Zeit, um den metastabilen Zustand zu
verlassen. Bei den heutigen FPGAs ist die Wahrscheinlichkeit, dass das
erste FF dann noch instabil ist, extrem gering. Nach der klassischen
Variante schaltet man noch ein FF nach und wiederholt das Spiel. Dann
werden die Wahrscheinlichkeiten noch kleiner.
Deshalb zu deinen Varianten :
- Die Variante (1) ist unsinnig kompliziert, obwohl sie nicht
wirkungslos ist.
Das hängt damit zusammen dass das asynchrone Signal über ein gemeinsames
FF läuft, die Synchronisierung ist einstufig.
- Die Variante (3) ist OK, zusätzlich hast Du ein Tiefpassfilter. Die
Schaltung hat eine Verzögerung von 3-4 Takten, und setzt voraus das das
Eingangssignal lansam gegenüber der Taktfrequenz ist.
- Variante (4) erzeugt natürlich seriell verschaltete FFs, wieso auch
nicht.
Diese Variante geht schief, es wird nur eine FF-Stufe implementiert :-o
Nur das 2. FF ist wirklich zur Synchronisation da (Bild).
Das andere FF und der MUX davor ist nur großes Brimborium.
> Wenn ich Jan M. richtig verstehe werden hier gar keine seriell> verschalteten FFs generiert, oder?
Doch, aber diese FFs werden (platzsparend) als Schieberegister in eine
LUT gepackt. Wenn du nur asynchrone Signale (Taster, RS232, ...)
verarbeitest, ist das keine Einscharänkung. Wenn du aber schnelle
asynchrone Signale verarbeiten willst, die zueinander in zeitlichem
Bezug stehen, dann ist es besser, das FF im IOB mitzubenutzen.
> über einen vector gelöst, sprich diese "single-line-sync"-Lösung> parallelisiert. Wie würdest Du es machen?
Wenn du z.B. 8 Asynchrone Eingänge hast, dann brauchst du (mindestens)
16 FFs, dass alles hübsch einsynchronisiert ist. Ob du dann schreibst:
1
Input:instd_logic_vector(7downto0);
2
:
3
signalffA:std_logic_vector(7downto0);
4
signalffB:std_logic_vector(7downto0);
5
:
6
processbegin
7
waituntilrising_edge(clk);
8
ffA<=Input;
9
ffB<=ffA;
10
endprocess;
oder
1
InputZ:instd_logic;
2
InputY:instd_logic;
3
InputX:instd_logic;
4
InputW:instd_logic;
5
:
6
signalsrZ:std_logic_vector(1downto0);
7
signalsrY:std_logic_vector(1downto0);
8
:
9
processbegin
10
waituntilrising_edge(clk);
11
srZ<=srZ(0)&Input0;
12
srY<=srY(1)&Input0;
13
srX<=srX(2)&Input0;
14
:
15
endprocess;
das ist "nur" eine Frage, was schöner aussieht. Wenn alle Signale
voneinander unabhängig sind, ist Variante 2 schöner. Wenn es ein Bus
ist, eher Variante 1.
Aber bei einem parallelen Bus ist es wie gesagt oft sinnvoll, eine
andere Validierungs-Art zum einsynchronisieren zu verwenden.
Einen Bus asynchron zu einem FPGA zu führen ist eh meistens eine
schlechte Idee, kommt aber leider vor, habe ich auch schon gemacht.
Es geht dabei nur darum, die Daten zu einem Zeitpunkt abzutakten an dem
diese stabil sind.
Dazu hat jeder Bus ein einzelnes Signal (RD, WR oder eine anderes
Strobe), welches dies signalisiert.
Dieses eine Signal wird synchronisert und auf den bestimmten Pegel
gewartet. Da die Synchronisierung vielleicht eine Zeitverzögerung
erzeugt, können die Daten am Bus schon vorbei sein. In diesem Fall muß
man diese durch zusätzliche FF Ketten der Datensignale ausgleichen.
Jan M. wrote:
> @Lothar:> Diese Variante ist auf Xilinx-FPGAs aber in gewisser Weise gefährlich:> Die Synthese implementiert ein Schieberegister in einer LUT, dadurch> wird das FF im IO-Buffer nicht benutzt,
So allgemein kann man das nicht sagen. Ein SRL16 hat nur zwei Ausgänge,
darum ist es für eine seriell-parallel-Wandlung mit mehr als zwei
parallen Ausgängen nicht geeignet. Hier wird es wohl verwendet werden.
Tom
@Thomas:
Ja, alles was von der einfachen Beschreibung "vorne rein, hinten raus"
abweicht kann nicht in Schieberegister gepackt werden - Deswegen auch
mein Vorschlag mit den Resets; jeder andere parallele Zugriff auf
mehrere Bits funktioniert natuerlich auch oder man zwingt die Synthese
durch Attribute oder Constraints dazu, die FF zu behalten oder IO-FF zu
benutzen - es gibt viele Moeglichkeiten, aber die einfachste und
direkteste beinhaltet diese Falle, deswegen meine "Warnung".
>> Aber bei einem parallelen Bus ist es wie gesagt oft sinnvoll, eine>> andere Validierungs-Art zum einsynchronisieren zu verwenden.> jetzt aber: und welche? hast Du dazu auch ein Bsp.?
Klaus Falser hat es schon geschreiben: es gibt für parallele Busse
üblicherweise ein zusätzliches Steuersignal, das anzeigt, wenn die Daten
gültig (und stabil) sind. Nur dieses eine Signal muß synchronisiert
werden, dann sind die Setup-Zeiten für die entsprechenden FFs erfüllt.
Ich würde sogar noch weitergehen, und z.B. ein Write-Signal als lokalen
Takt die Daten einlesen lassen, und anschliessend mit den gespeicherten
Daten weiterarbeiten.
>Diese Variante ist auf Xilinx-FPGAs aber in gewisser Weise gefährlich:>Die Synthese implementiert ein Schieberegister in einer LUT, dadurch>wird das FF im IO-Buffer nicht benutzt, und man hat keine festen>setup-to-clock Zeiten, das kann schnell schief gehen, wenn man z.B. zwei>Signale parallel einlesen will, die dann unterschiedliche Laufzeiten>haben.
Ist das nicht bei asynchronen Signalen egal? Das FF ist zwar zum
Nulltarif, aber es stört das einsynchronisieren nicht. "Parallele"
Signale bekommst du mit Synchronisierstufen eh nicht sauber eingetaktet,
braucht es schon eine Fifo.
Hallo,
jetzt sind ja noch einige Beiträge zusammen gekommen.
Alles zum Thema Bussynchronisieren würde ich später gerne in einem
anderen Thread diskutieren damit dieser hier nicht zu unübersichtlich
wird
@Klaus Falser: Danke für das Wie und Warum. Das ist jetzt klar!
Im Prinzip gibt es dann verschiedene Wege um eine 2- oder mehrstufige FF
Stufe zu beschreiben. Man muss nur überprüfen ob die Synthese auch
tatsächlich 2 FFs generiert und nicht nur eine wie bei meiner Variante 1
Richtig?
>> Wenn ich Jan M. richtig verstehe werden hier gar keine seriell>> verschalteten FFs generiert, oder?>Doch, aber diese FFs werden (platzsparend) als Schieberegister in eine>LUT gepackt.
Die genauen Unterschiede oder Hintergründe zwischen der Variante mit 2
FFs oder einem Schieberegister (LUT) ist aber immer noch nicht ganz
klar.
1
signalsig_tmp1:STD_LOGIC;
2
signalsig_tmp2:STD_LOGIC_VECTOR(1downto0);
3
4
----------------------------------------
5
-- 2 FFs
6
----------------------------------------
7
process(CLK)
8
begin
9
ifrising_edge(CLK)then
10
sig_tmp1<=sig_async1;
11
sig_sync1<=sig_tmp1;
12
endif;
13
endprocess;
14
15
16
----------------------------------------
17
-- Schieberegister
18
----------------------------------------
19
process(CLK)
20
begin
21
ifrising_edge(CLK)then
22
sig_tmp2<=sig_tmp2(0)&sig_async2;
23
endif;
24
endprocess;
25
sig_sync2<=sig_tmp2(1);
Die synthetisierte FF Stufe ist klar. Aber was bei der LUT Version
passiert, verstehe ich nicht ganz. Das LUT arbeitet doch genauso
clocksynchron, richtig? (Siehe Anhang)
Danke für eure Antworten,
Nik
>Die synthetisierte FF Stufe ist klar. Aber was bei der LUT Version>passiert, verstehe ich nicht ganz. Das LUT arbeitet doch genauso>clocksynchron, richtig?
Der Unterschied ist die Lage im FPGA: Direkt am Input befindet sich ein
spezielles FF fuer genau den Zweck, hereinkommende Signale zu
synchronisieren. Die LUT muss aber irgendwo in der restlichen Logik des
FPGAs untergebracht werden, so dass die Signallaufzeiten vom Pin zu
dieser LUT stark schwanken koennen je nach Design.
(Bei Tastern ist das natuerlich voellig unerheblich, bei schnellen
Signalen die synchron zu irgendeinem Takt von aussen sind, kann das aber
grosse Probleme verursachen)
> Das LUT arbeitet doch genauso clocksynchron, richtig? (Siehe Anhang)
In diesem Bild siehst du nicht, wie die FFs tatsächlich realisiert
werden. Was dur in diesem Plan siehst, ist nur, was die Synthese aus
deiner Beschreibung gemacht hat.
Abhängig von den Einstellungen in Translate und P&R können daraus
einzelne FFs werden oder das Ganze könnte in eine LUT gepackt werden und
zudem das FF im IOB verwendet werden oder nicht.
> bei schnellen Signalen die synchron zu irgendeinem Takt von aussen sind,> kann das aber grosse Probleme verursachen
Und dann sind Timing-Constraints unabdingbar...
BTW:
> Das LUTdie Look-Up-Tabelle --> die LUT
Die Diskussion über LUT, SRL und FF ist unsinnig und verwirrt nur.
Wichtig ist, dass eine Kette von 2 oder mehrern FFs erzeugt wird.
Das 1. FF in ein IOB zu legen, könnte höchstens den Vorteil haben, dass
diese vielleicht in Bezug auf Metastabilität optimiert sind, aber das
ist eine Hypothese.
Es geht bei dieser Diskussion ja über asynchrone Signale von außen.
Irgendwelche Timing-Constraints sind deshalb komplett unsinnig. Damit
will man je erreichen, dass 2 oder mehrere verschieden Pfade in den
Laufzeiten übereinstimmen.
Aufgrund der Metastabilität kann man aber 2 Signale NIEMALS parallel
eintakten, weil es ganau die Eigenschaft der Metastabiliät ist, dass der
Ausgang des FFs kippen kann oder nicht. Es kann deshalb immer vorkommen,
dass ein Port das jeweilige Eingangsignal einen Takt früher sieht als
der andere.
Ok,
bei der direkten FF Beschreibung werden also defintiv 2 FF erzeugt.
1
process(CLK)
2
begin
3
ifrising_edge(CLK)then
4
sig_tmp1<=sig_async1;
5
sig_sync1<=sig_tmp1;
6
endif;
7
endprocess;
bei der Beschreibung mittels Schieberegister können entweder FF oder
LUTs Verwendung finden.
1
process(CLK)
2
begin
3
ifrising_edge(CLK)then
4
sig_tmp2<=sig_tmp2(0)&sig_async2;
5
endif;
6
endprocess;
7
sig_sync2<=sig_tmp2(1);
Kann man dann folgendes Fazit unter das Thema ziehen:
1) Die Problematik (Warum und Weshalb) hat Klaus Falser sehr schön
erklärt (24.02.2009 09:42)
2) Meine Variante 1 erzeugt nur eine 1-stufige Synchronisierung, was
nicht ausreichend ist
3) Zur Synchronisierung werden mindestens 2 FF benötigt. Beide
Beschreibungen (siehe dieser Beitrag) mit 2FF oder Schieberegister sind
in Ordnung
Zum synchronisieren eines std_logic sind beide Wege richtig...
Aber wie willst du es machen wenn du ein std_logic_vector
synchronisieren willst? Dann bräuchtest du für die Version mit dem
Schieberegister ein Zweidimensionales;) => Für die Synchronisation eines
std_logic_vectors nehme ich deine erste Version (natürlich entsprechend
angepasst).
Hier mal schnell skizziert (will keine neue Diskussion anfangen - nur
falls das jemand liest der einen Vector synchronisieren will):
Port signal : std_logic_vector
signal signal_1 : std_logic_vector
signal signal_2 : std_logic_vector
process(CLK)
begin
if rising_edge(CLK) then
signal_1 <=sigal;
signal_2<=signal_1;
end if;
end process;
> bei der direkten FF Beschreibung werden also defintiv 2 FF erzeugt.
Nein, wenn keine der Zwischenstufen (sig_tmp1) verwendet wird, kommt das
in eine LUT. So schlau sind die Tools ;-)
Boris wrote:
> Port signal : std_logic_vector> signal signal_1 : std_logic_vector> signal signal_2 : std_logic_vector>> process(CLK)> begin> if rising_edge(CLK) then> signal_1 <=sigal;> signal_2<=signal_1;> end if;> end process;
Gefährlich, weil ja wegen unterschiedlicher Signallaufzeiten, die
Signale teilweise um einen Takt verzögert ausgegeben werden. Besser:
Handshake...
Andere Ideen??
> Gefährlich, weil ja wegen unterschiedlicher Signallaufzeiten, die> Signale teilweise um einen Takt verzögert ausgegeben werden.
Ich wollte damit nicht einen parallelen Bus synchron in das FPGA
bekommen. Das klappt so niemals!
Ich wollte nur z.B. 8 paralell angeschlossene Taster einsynchronisieren.
Und muß durch die Vektor-Schreibweise nicht jede Strippe einzeln in die
Hand nehmen. Jedes dieser Eingangssignale ist also asynchron sowohl zum
Takt wie auch zu den anderen Signalen.
Hallo,
damit dieser Thread nicht zu unübersichtilch wird, habe ich die
Beitraege die das Synchronisieren von STD_LOGIC_VECTORen bzw. parallelen
Bussignalen betreffen in einen neuen Thread gepackt:
Beitrag "Einsynchronisieren von STD_LOGIC_VECTORen"
Weitere Kommentare zu diesem Thread hier, sind natürlich noch weiterhin
sehr willkommen.
gruß,
Nik
>Das 1. FF in ein IOB zu legen, könnte höchstens den Vorteil haben, dass>diese vielleicht in Bezug auf Metastabilität optimiert sind, aber das>ist eine Hypothese.
Hab ich doch mal für einen V5-3 die Setup/Holdzeiten am IIO-FF und am
SRL nachgeschaut:
SRL 1.03/0.26 ns
IO-FF 0.39/-0.12 ns
Damit ist für das SRL der "böse Teil" der Taktperiode länger.
MfG
> Für was steht denn eigentlich SRL ?
Wenn man die LookUpTable (LUT) in Xilinx-FPGA's in dem Modus
Schieberegister (Shift Register) verwendet, nennt Xilinx das SRL16 Macro
(vor Virtex5). wofür das L steht ist unbekannt (vielleicht length 16
(um, verwechslungen mit SR als Set/Reset FlipFlop zu vermeiden?)). Beim
V6 mit breiteren LUT wird das Schieberegister dann auch tiefer als 16.
MfG, AH