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
Sorry vergessen mitzuteilen. Zynq UltraScale+ ZU4CG
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
Xilinx? Da würde ich den MMCM nehmen, wie im verlinkten UG572 beschrieben. Duke
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
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
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.
Nur aus Interesse: Welchen ADC verwendest du?
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.
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.
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
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
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.
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.
Wow wie cool. Ich kann 1 GSample im Spartan7 XC7S50 mit 32 FIR Koeffizienten in Echtzeit filtern. Mehr Platz ist aber nicht.
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).
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.