Forum: FPGA, VHDL & Co. VHDL Timing Probleme - Takt synchron herunterteilen


von Stones (Gast)


Lesenswert?

Hallo,

ich habe einen parallelen FIR Filter in einem FPGA implementiert, der 
mit 1GSPS arbeitet, bzw. mit 500MHz Takt arbeitet. Die Koeffizienten 
sind in ROMs gespeichert. Um die Wärmeentwicklung gering zu halten und 
nicht die 500MHz durch den ganzen FPGA zu ziehen, möchte ich den Takt 
auf 125MHz herunterteilen und mit diesem die ROM, FSM etc takten.


Wie mache ich dies am geschicktesten ohne mir Probleme einzuhandeln. Ich 
habe aktuell eine Lösung die halbwegs funktioniert, jedoch vermute ich, 
dass die vereinzelten Störungen hierher kommen.

Viele Grüße

von Duke Scarring (Gast)


Lesenswert?

Das hängt vom FPGA ab. Welchen genau hast Du?

Duke

von Stones (Gast)


Lesenswert?

Sorry vergessen mitzuteilen. Zynq UltraScale+ ZU4CG

von ticktack=fickfack (Gast)


Lesenswert?

Was spricht gegen die CMT die ohnehin benutzt wird um die 500 MHz im 
Chip zu verteilen?

https://www.xilinx.com/support/documentation/user_guides/ug572-ultrascale-clocking.pdf

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Xilinx? Da würde ich den MMCM nehmen, wie im verlinkten UG572 
beschrieben.

Duke

von Christian U. (christian_u189)


Lesenswert?

Bei 1 GSPS brauchst du einen Takt im FPA von 1 GHz um ein Sample pro 
Takt zu verarbeiten. Meinst du mit 500 MHz die Nyquist-Frequenz oder 
verabeitest du zwei Samples pro Takt?

Wenn du jetzt manchmal Daten verlierst hast du vielleicht Probleme im 
Clock Domain Crossing? Um die Daten zuverlässig zwischen den Clock 
Domains zu übertragen kannst du eine Asynchrone FIFO verwenden. Auf der 
500-MHz-Seite packst du 4 Samples zusammen und schreibst jeden 4. Takt 
in die FIFO. Die FIFO hat folglich eine Breite von 4 Samples. Auf der 
125-MHz-Seite kannst du dann jeden Takt 4 Samples auslesen sobald die 
FIFO ca. halb voll ist.
Wenn die Takte langfristig synchron laufen -- sprich: von der selben PLL 
kommen -- läuft die FIFO nie voll oder leer.
Ansonsten brauchst du ein Übersetzungsverhältnis dass etwas "Schlupf" 
zulässt. In diesem Beispiel würde du dann in jedem 5. Takt 5 Samples in 
die FIFO schreiben und die FIFO entsprechend breiter.

Hier eine generische Asynchrone FIFO: 
https://github.com/unhold/hdl/blob/master/vhdl/fifo.vhd

von Stones (Gast)


Angehängte Dateien:

Lesenswert?

Es gibt eine externe PLL für den globalen Takt. Im FPGA selbst werden 
die Daten vom ADC (welcher mit 1GSPS arbeitet) mit dem eigenen 
synchronen Takt des ADC parallelisiert. Die DSP, DACs etc. arbeiten mit 
den 500MHz von der externen PLL.
Für diese beiden Clock Domains habe ich eine asynchronous group 
angelegt.

Mit den 125MHz wird die FSM der DSP und die Koeffizienten ROMs getaktet, 
die Signalverarbeitung selber erfolgt mit 500MHz. Mit dem Aufbau, wie im 
Anhang dargestellt, habe ich negative Setup Slack an 2200 Punkten.

Erzeuge ich den Takt ganz simple wie folgt, gibt es keine Fehler. 
Allerdings habe ich gerade auch festgestellt, dass da etwas mit den 
Constraints nicht zu stimmen scheint.
1
process(clk)
2
            begin
3
                if falling_edge(clk) then
4
                    clk_div <= clk_div +1;
5
                    clk_target_pre <= clk_div(clk_div'high);
6
                end if;
7
    end process;
8
9
bufg_inst_clk_target : BUFG
10
        port map (
11
            I => clk_target_pre,
12
            O => clk_targetx
13
        );

: Bearbeitet durch Moderator
von Christian U. (christian_u189)


Lesenswert?

Mit den Änderungen an der Taktquelle beeinflusst du die Phase der Clocks 
zueinander. Das kann die unterschiedlichen Ergebnisse erklären.

Wie machst du die Clock Domain Crossings? Verlässt du dich darauf dass 
die Clocks synchron laufen? Dann darfst du keine unterschiedlichen 
Groups in "set_clock_groups -asynchronous" verwenden, weil das einem 
False Path auf alle Pfade zwischen den Clock Domains gleich kommt.

Kannst du den Clock vom ADC_PHY runter teilen? Dann hast du nur mehr 
einen Clock-Pfad zum FPGA und brauchst dich nicht um die Phasenlage der 
Clock-Eingänge zueinander kümmern.

von Gustl B. (-gb-)


Lesenswert?

Nur aus Interesse: Welchen ADC verwendest du?

von Stones (Gast)


Lesenswert?

Hallo Christian,

bisher hatte ich für die beiden Domains "set_clock_groups -asynchronous" 
gewählt und die Phasenlage dann über die externe PLL korrigiert.

Ich habe jetzt mal den Takt von der externen PLL genommen um den 
gesamten FPGA zu takten incl. ADC. Die Phasen bekäme ich auch in dem 
Fall extern in den Griff. Bin jetzt jedoch bei über 11000 failing 
Endpoints und gerade am versuchen dies in den Griff zu bekommen. Die 
Implementierung läuft jetzt gefühlt auch noch ein gutes Stück länger als 
zuvor bereits bei über einer Stunde :(

Verwendet werden mehrere ADS5400, denn die Latenz ist auch noch wichtig.

von Markus F. (mfro)


Lesenswert?

Deine schnelle Clock ist doch eine ganzzahlige Vielfache deiner 
langsamen.

Wenn Du durch geeigneten Hardwareeinsatz dafür sorgen kannst, dass die 
synchron sind und bleiben, musst Du der Synthese (über multicycles) doch 
bloss noch erklären, dass das so ist.

"set_clock_groups -asynchronous" macht genau das Gegenteil.

von Christian U. (christian_u189)


Lesenswert?

Hallo Stones,

So wie ich dein Design verstanden habe schlummert ein Timing-Problem, 
dass du mit "set_clock_groups -asynchronous" in der STA überdeckst.
Lass uns das gerne weiter diskutieren falls dir Bits kippen oder das 
Design sehr zuverlässig werden muss.

Viel Erfolg mit Vivado!

Freundliche Grüße

von daniel__m (Gast)


Lesenswert?

Hi,

Stones schrieb:
> Zynq UltraScale+

statt MMCM oder FF, nimm doch BUFGCE_DIV.

Bei den hohen Frequenzen mit Logik einen Takt erzeugen, wäre mir zu 
unsicher (Jitter) und bei mehreren Takten, welche zueinander Bezug haben 
(sollen), kommt noch Routingdelay hinzu. Die o.g. Primitives sind aus 
meiner Sicht ideal für diese Anwendung.

grüße

von Gustl B. (-gb-)


Lesenswert?

Nun, 1 GHz braucht er nicht im FPGA, die braucht nur der ADC. Der ADC 
gibt seine Daten über einen oder zwei Bus(se) aus und zwar mit Takt.

Sampletakt am ADC ist immer 1 GHz.

Mit einem Datenbus:
Der ADC gibt einen Takt F_sample/2 aus und die Daten dazu als DDR, also 
bei steigender und fallender Flanke.

Mit zwei Datenbussen:
Der ADC gibt zwei Takte F_sample/2 aus und die Daten dazu als SDR. Und 
da kann man jetzt einstellen ob die beiden Takte synchron sein sollen, 
oder ob die um 180° phasenverschoben sein sollen. (Die Daten dann auch).

Er bekommt also immer einen F_sample/2 Takt in sein FPGA. Das sollte 
auch einigermaßen jitterfrei sein weil das unsprünglich aus der 
Sampleclock stammt.

Wenn er jetzt intern seine Daten mit geringerem Takt verarbeiten möchte, 
dann kann er problemlos diesen Takt in eine PLL/MMCM füttern und daraus 
weitere Takte erzeugen. Er kann aber auch einen weiteren externen 
Taktgeber verwenden und mit dem Takte erzeugen die dann zu dem ADC Takt 
asynchron laufen. Dafür gibt es dual independent Clock FIFOs um die 
Übergänge zwischen Taktdomänen zu erledigen.

Ich würde für die Logik im FPGA die unabhängig vom ADC laufen soll nicht 
den Takt vom ADC verwenden. Denn der Takt vom ADC leigt nicht an wenn du 
den ADC in den Standby versetzt.

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Nachtrag:

Ich bastel selber gerade mit ADCs und hätte natürlich auch gerne einen 
FIR. Aber bei den hohen Datenraten muss das ja parallel gehen und das 
traue ich mir nicht zu, ich wollte das also an den PC auslagern.

Aber siehe da, der Xilinx FIR compiler kann das schon eingebaut. Man 
kann da sagen alle wie viele Takte ein neuer ADC Wert reinkommt. Und 
diesen Wert kann man auch deutlich < 1 einstellen. Wenn man also mit 
jeder Clock z. B. 4 ADC Werte bekommt, dann kann man das da einstellen 
und bekommt schlicht einen breiteren AXI Stream Bus. Im Anhang ein 
Bildchen wie das bei 4 ADC Werten ja FIR Clock aussieht.

Ausserdem bin ich freudig überrascht wie gut das optimiert. Ich habe 
jetzt nur aus Spaß einen FIR mit 128 Koeffizienten (symmetrisch) in 
einem kleinen Spartan7 und da ist noch Platz. Bei 200 MHz FIR Takt und 
10 MSample/s ADC braucht das nur 5 DSP Einheiten. Finde ich sehr gut und 
werde ich in Zukunft häufiger verwenden.

von Gustl B. (-gb-)


Lesenswert?

Wow wie cool. Ich kann 1 GSample im Spartan7 XC7S50 mit 32 FIR 
Koeffizienten in Echtzeit filtern. Mehr Platz ist aber nicht.

von Blechbieger (Gast)


Lesenswert?

Stones schrieb:
> Verwendet werden mehrere ADS5400, denn die Latenz ist auch noch wichtig.

Mehrere ADC ist ein wesentlicher Punkt. Damit hast du bei n ADC n+1 
Takte mit zwar exakt identischer Frequenz da aus derselben PLL aber mit 
unterschiedlicher Phasenlage abhängig vom Boardlayout. Je höher n desto 
unwahrscheinlicher wird es dass es überhaupt ein gültiges Timing gibt. 
Wesentlich einfacher wird das Timing wenn du pro ADC ein dual-clock FIFO 
verwendest. Die Eingangsseite mit 2*16 Bit wird mit der lokalen Clock 
(500 MHz) des ADC-PHY betrieben, die Ausgangsseite mit 4*2*16 Bit mit 
der globalen Clock (125 MHz).

von Stones (Gast)


Lesenswert?

So, wollte nochmal kurz Rückmeldung geben. Das ganze läuft jetzt 
wunderbar ohne Störungen, danke für die hilfreichen Tipps.
Die komplette Logik wird jetzt nur noch von dem einen Takt der externen 
PLL gepeist. Die Constraints sehen jetzt wie folgt aus:
1
set_multicycle_path -setup -end -from [get_clocks clk_target] -to [get_clocks clk] 4
2
set_multicycle_path -hold -end -from [get_clocks clk_target] -to [get_clocks clk] 3
3
set_clock_groups -asynchronous -group [get_clocks clk_pl_0] -group [get_clocks clk_target]

Die Asynchrone Gruppe wird zwischen Zynq AXI Clock und meiner DSP Clock 
wird noch aufgrund der AXI Stream FIFOs benötigt.

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Stones schrieb:
> Die Koeffizienten
> sind in ROMs gespeichert.

Das ROM möchte ich mal sehen, dass 500MHz macht.

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.