Hallo zusammen,
ich bin auf der Suche nach einer eleganten Lösung für ein CDC eines
unidirektionalen Interfaces.
1
signaldata_rdy:std_logic;
2
signaladdr:std_logic_vector(11DOWNTO0);
Beide Clock-Domains sind nicht phasengleich und können im der Frequenz
variieren. Die Quell-Domain kann also größer der Ziel-Domain sein, oder
auch kleiner, maximal jedoch Faktor 2 kleiner/größer.
Ein Handshake kann ich leider nicht einsetzen, ich habe also nur diese
beiden Eingänge zur Verfügung. Der Vorteil ist, dass ich eine definierte
Startadresse habe und die Adressen auch in definierter Reihenfolge
eintrudeln.
Meine Idee:
Ich verwende in der Quell-Domain einen Counter, der die data_rdy Pulse
zählt, damit diese dann in korrekter Anzahl auf der Ziel-Domain
ausgegeben werden können. Den Counter muss ich ausreichend groß
dimensionieren, so dass er auch bei "2*Ziel = Quell" nicht überläuft.
Also z.B. 9 Bit.
Nun hatte ich die Idee, dass der Counter in der Zieldomain entsprechend
heruntergezählt wird, bis er wieder auf 0 ist und solange synchron zum
Zieltakt Pulse ausgegeben werden.
An welcher Stelle aber muss ich den Counter dann sauber synchronisieren?
Und wie kann ich ihn dann gleichzeitig auf der einen Seite hochzählen,
aber auf der anderen Seite quasi asynchron herunterzählen?
Vielen Dank!
Andi :)
Andreas B. schrieb:> Ein Handshake kann ich leider nicht einsetzen, ich habe also nur diese> beiden Eingänge zur Verfügung.
Und dann willst du irgendwie noch einen Zähler über die Grenze
schmuggeln?
> Meine Idee:> Ich verwende in der Quell-Domain einen Counter, der die data_rdy Pulse> zählt, damit diese dann in korrekter Anzahl auf der Ziel-Domain> ausgegeben werden können. Den Counter muss ich ausreichend groß> dimensionieren, so dass er auch bei "2*Ziel = Quell" nicht überläuft.> Also z.B. 9 Bit.> Nun hatte ich die Idee, dass der Counter in der Zieldomain entsprechend> heruntergezählt wird, bis er wieder auf 0 ist und solange synchron zum> Zieltakt Pulse ausgegeben werden.
Welchen Takt sollte denn dieser Zähler haben? Du kannst ihn ja nicht
einmal mit dem Takt der Domain A und dann mit dem anderen Takt der
Domain B zählen lassen.
> Die Quell-Domain kann also größer der Ziel-Domain sein, oder auch> kleiner, maximal jedoch Faktor 2 kleiner/größer.
Und wie lange sind die Daten stabil? Wieviele Takte darf eine
Übertragung dauern? Wie ist die Datenrate (bzw. deren Verhältnis zur
Taktfrequenz)?
Dein ganzes Problem ruft irgendwie laut "Dual Clock Fifo"...
EDIT: nur Zweiter... ;-)
Hallo,
Marius Wensing schrieb:> Schon einmal über einen Dual-Clock-FIFO nachgedacht?
Ja habe ich, aber irgendwie hatte ich gehofft, dass ich mir nur wegen
dieses dummen Interfaces nicht so ein Monster einbauen muss. Denn eine
Logik, die den FIFO in der Ziel-Domain wieder auslesen muss, gehört dann
auch noch dazu.
Zumal der FIFO ja nur ein Bit breit sein muss. Ich will ja nicht die
Adressen zwischenspeichern, die kenne ich ja, sondern nur das data_rdy.
Zumindest sollte das mit den Adressen so passen... hoffe ich...
Lothar Miller schrieb:> Welchen Takt sollte denn dieser Zähler haben? Du kannst ihn ja nicht> einmal mit dem Takt der Domain A und dann mit dem anderen Takt der> Domain B zählen lassen.
Der Zähler soll in der Quell-Domain hochgezählt werden.
Aber genau an diesem Punkt wird es dann eben unlösbar, wenn der Zähler
in der Ziel-Domain wieder heruntergezählt werden soll :D
Genau diesen Knoten in meinem Kopf gilt es zu lösen...
Vielen Dank!
Andi :)
Ich habe gerade noch eine neue Info bekommen, die alles über den Haufen
wirft. Muss ich nochmal neu anfangen zu denken... Mist... gut, dass ich
noch nicht allzu weit war.
Fuer ein unidirektionales IF? Der Klassiker:
http://www.fpga4fun.com/CrossClockDomain.html
In der Quelle setzt du deine 12-bit Adresse auf, einen Takt (der Quelle)
spaeter geht DATA_RDY von 0 auf 1.
Im Ziel taktest du mit dessen Takt DATA_RDY ein, beim Uebergang von 0->1
uebernimmst du die Adresse, die natuerlich solange stabil sein muss.
Abhaengig von den Quell- und Zieltakten nimmst du dann dein DATA_RDY
wieder auf 0 zurueck (evtl. Counter in der Quelle, mit derem Takt falls
Ziel langsamer laeuft als Quelle)
Du kannst auch Adresse und DATA_RDY gleichzeitig setzen in der Quelle,
dann musst du aber im Ziel nochmal eine Verzoegerung (n Takte) einbauen.
Andreas B. schrieb:> Der Zähler soll in der Quell-Domain hochgezählt werden.> Aber genau an diesem Punkt wird es dann eben unlösbar, wenn der Zähler> in der Ziel-Domain wieder heruntergezählt werden soll :D
Sowas macht man dadurch, dass in der Zieldomain, ein Differenzzähler
gebildet wird und die Differenz dynmamisch gebildet wird. Damit kann die
Zieldomain auch schneller abziehen, als die Quelldomain reinschreibt.
Das ist aber ein Konstrukt, den ich selber nur einmal benötigt habe und
ich bezweifle stark, dass Deine Applikation sowas braucht.
Ein Asynchroner Fifo (wie schon angeraten) mitsamt overflow und
underflow-Behandlung zur abstrakten Weiterschaltung der Information
"FF-State" löst das Problem einfacher und übersichtlicher.
Andreas B. schrieb:> signal data_rdy : std_logic;> signal addr : std_logic_vector(11 DOWNTO 0);
Ich verstehe nur Bahnhof..
Die Quelldomain soll also Adressen und data_rdy an die Zieldomain
übertragen?
Aber die Adressen sind vorhersehbar?
Und was ist mit den Daten?
Auf welche der Timings hast du einen Einfluss?
Quelle, Ziel, beide?
Am Besten, du zeichnest uns mal ein Timing hin, wie die Signal aus der
Quelle kommen und wie das Ziel sie erwartet. Und welche Paramteter im
Timing du beeinflussen kannst.
Duke Scarring schrieb:> Das wäre doch noch ein schöner Artikel für Lothars Homepage.
Ich hätte auch sonst noch ein paar Ideen, aber irgendwie gerade keine
Zeit... ;-)
Eine eigene Frage?
Dieser Thread ist über 11 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.