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
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.
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.
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.
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: