Forum: FPGA, VHDL & Co. timing constraints / Clocks etc.


von Björn R. (doerben)


Lesenswert?

Moin,
ich komme bei den timing constraints einfach nicht weiter. Ich habe das 
auch noch nicht so richtig verstanden und verstehe aber auch nicht die 
Xilinx Dokumentation.

Wenn man weiss worum es geht ist die Doku leicht - wenn man es nicht 
versteht finde ich es schon sehr schwierig zu verstehen.

Zum Problem:

Im Timing_Summary sind immer 600 Eintrge bei "Check Timing" 400 bei "No 
Clock" und 200 bei "unconstrained internal endpoint".

Ich besitze 2 Clocks die von ausserhalb kommen. Eine SPI_CLK (8MHz) und 
eine Clock (125MHz).

Die SPI_CLK geht über einen I/O zu einem IBUFG und ist von dort aus als 
Signal SCLK vorhanden. Wobei ich vor dem IBUFG -create_clock verwende 
und nach IBUFG create_generated_clock. Habe ich das soweit richtig 
verstanden ?

Die "System" Clock kommt als Differential Clock vom Generator und geht 
auf die IOs CLKIN_P und CLKIN_N. Die IOs sind an einem IBUFGDS 
"angeschlossen" welcher aus dem Diff Signal die Clock FPGA_CLK_125 
macht. Dieses Signal geht an einen MMCM und ich erstelle daraus die 
Clock FPGA_CLK_100 welche ich als CLocksignal für alle meine Entitys 
benutze.

create_clock -period 8.000 -name FPGA_CLK_125_DS -waveform {0.000 4.000} 
[get_ports CLKIN_P]

create_clock -period 125.000 -name SPI_CLK -waveform {0.000 62.500} 
[get_ports SPI_CLK]

create_generated_clock -name SCLK -source [get_ports SPI_CLK] 
-multiply_by 1 -add -master_clock SPI_CLK [get_pins CON_IBUFG/O]

create_generated_clock -name FPGA_CLK_125 -source [get_ports CLKIN_P]
-multiply_by 1 -add -master_clock FPGA_CLK_125_DS [get_pins 
CON_IBUFGDS/O]

create_generated_clock -name FPGA_CLK_100 -source [get_pins 
MMCME2_BASE_inst/CLKIN1] -multiply_by 1 -add -master_clock FPGA_CLK_125 
[get_pins MMCME2_BASE_inst/CLKOUT0]


Das sind derzeit alle Clocks in meiner Constraint File.

Lasse ich die gernerated Clocks weg sagt er "timing met" aber 600 "Check 
Timing" Einträge. mit den Einträgen sagt Vivado "timing not met" und 
weiterhin 600 Einträge.


Ich verzweifel.Ich habe sehr bald Abgabe meiner Arbeit und komme dort 
einfach nicht weiter. Daraus resultiert auch das die Post Synthese 
Simulation nicht die Werte wie die Behav Simulation bringt.

Hoffnungsvoll,
Björn

von Duke Scarring (Gast)


Lesenswert?

Björn R. schrieb:
> Wenn man weiss worum es geht ist die Doku leicht - wenn man es nicht
> versteht finde ich es schon sehr schwierig zu verstehen.
Damit bist Du nicht allein...

> Ich besitze 2 Clocks die von ausserhalb kommen. Eine SPI_CLK (8MHz) und
> eine Clock (125MHz).
Da geht es schon los. Sind die Takte unabhängig voneinander?
Sprich: kommen die letzendlich aus verschiedenen Taktquellen oder sind 
sie vom selben Quartz abgeleitet.

Wenn es verschiedene Taktquellen sind, mußt Du die Signale beachten, die 
von einer Taktdomäne gespeist werden und in der anderen genutzt werden.
Das nennt sich dann 'clock domain crossing' und braucht besondere 
Beachtung.

Duke

von Björn R. (doerben)


Lesenswert?

Duke Scarring schrieb:
>> Ich besitze 2 Clocks die von ausserhalb kommen. Eine SPI_CLK (8MHz) und
>> eine Clock (125MHz).
> Da geht es schon los. Sind die Takte unabhängig voneinander?
> Sprich: kommen die letzendlich aus verschiedenen Taktquellen oder sind
> sie vom selben Quartz abgeleitet.
>
> Wenn es verschiedene Taktquellen sind, mußt Du die Signale beachten, die
> von einer Taktdomäne gespeist werden und in der anderen genutzt werden.
> Das nennt sich dann 'clock domain crossing' und braucht besondere
> Beachtung.

Ich denke einen Anfang der Probleme haben wir schonmal gefunden.

Die SPI_CLK kommt von einem Raspberry , die Clock für den FPGA wird mit 
auf dem Board vom FPGA (ARTIX 7) erzeugt, also ja die Erzeugung 
geschieht nicht von derselben Taktquelle.

Ich habe einen Vektor SPI_DATA welcher mit jedem Takt von SPI_CLK den 
Wert von der MOSI-Leitung liest und diesen "speichert". Das passiert 
SPI-Üblich während Chip Select = 0 ist. Wenn CS nicht 0 ist werden 
Abschnitte von SPI_DATA anderen Vektoren zugewiesen welche folglich mit 
anderen Entitys welche die FPGA_CLK_100 nutzen verbunden sind.


Nur eine Clock Group zu erstellen hat leider keine Besserung gebracht. 
Was muss dort besonders beachtet werden ?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Björn R. schrieb:
> Ich denke einen Anfang der Probleme haben wir schonmal gefunden.
Du kannst 2 unabhängige Takte nicht zueinander constrainen. Für diesen 
Taktdomänenübergang kannst du nicht das FPGA verantwortlich machen, den 
muss du selber in die Hand nehmen. Du musst die Toolchain anweisen, alle 
Pfade zwischen diesen beiden Taktdomänen zu ignorieren, weil sie eh' 
nicht automatisiert umgesetzt werden können, sondern einen Fifo oder ein 
Handshakeverfahren brauchen...

http://www.xilinx.com/support/documentation/sw_manuals/xilinx11/pce_p_exceptions_ignore_paths.htm

von Gerald M. (gerald_m17)


Lesenswert?

Macht es nicht auch bei solch einer lahmen Clock wie der 8Mhz SPI Clock 
Sinn dieses als Signal einzusynconisieren?

Also etwa:
1
 
2
SPIsync : process (125MhzClock)
3
Begin
4
If risingedge(125MhzClock) then
5
  SPIclock_old = SPiClock
6
  If ( (SPIclock_old = '0') and (SPIClock = '1')) then
7
    SPIclock_en =' 1'
8
     else SPIclock_en = '0'
9
     End if
10
End if
11
End process

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gerald M. schrieb:
> Also etwa
Das ist noch nicht einsynchronisiert, der Eingang wird ohne 
Zwischenspeicher direkt abgefragt! Da fehlt noch unbedingt 1 Flipflop.

Aber ich würde es so machen und damit jedem Gelecke mit 2 Takten aus 
dem Weg gehen. Denn schließlich ist letztlich der SS auch asynchron und 
muss für die Datenübernahme einsynchronisiert werden.

: Bearbeitet durch Moderator
von Duke Scarring (Gast)


Lesenswert?

Lothar M. schrieb:
> Aber ich würde es so machen und damit jedem Gelecke mit 2 Takten aus
> dem Weg gehen. Denn schließlich ist letztlich der SS auch asynchron und
> muss für die Datenübernahme einsynchronisiert werden.
Ich würde es auch (fast) so machen.

Im Prinzip kann man ein normales Shift-Register mit dem SPI-Clock 
beschreiben:
1
  process
2
  begin
3
    wait until rising_edge( SPI_CLK);
4
    shift_reg <= shift_reg( 6 downto 0) & SPI_DI;
5
  end process;

Für das Einlesen der Daten nimmt man die Flanke vom /SS. Und genau nur 
diese muss einsynchronisiert werden (2 FF).
1
  signal ss_reg : std_ulogic_vector( 2 downto 0); -- = 3 FF
2
  -- das dritte ist für die Flankenabfrage
3
  ..
4
  process
5
  begin
6
    wait until rising_edge( CLK);
7
    ss_reg <= ss_reg( 1 downto 0) & SPI_SS;
8
  end process;

Die anderen Signale (und der Inhalt vom Schieberegister) sind zu diesem 
Zeitpunkt stabil und damit unkritisch.
1
  process
2
  begin
3
    wait until rising_edge( CLK);
4
    -- Flankenabfrage
5
    if ss_reg( 2 dowtnto 1) = "01" then
6
      spi_data <= shift_reg;
7
    end if;
8
  end process;

Duke

von Björn R. (doerben)


Lesenswert?

Okey ich glaube so langsam kommt die Idee. Statt zwei Taktdomänen zu 
verwenden soll ich versuchen nur eine / die FPGA_CLK_100 als Clock zu 
verwenden und damit alles zu beschreiben.

shift_reg <= shift_reg( 6 downto 0) & SPI_DI;

Ist hierbei nicht immer die 8te Stelle SPI_DI ?



    wait until rising_edge( CLK);
    -- Flankenabfrage
    if ss_reg( 2 dowtnto 1) = "01" then
      spi_data <= shift_reg;

Passier hierbei nicht das gleiche wie bei meiner aktuellen 
Implementierung ? Weil shift_reg ist doch abhängig von der SPI_CLK oder 
irre ich mich da ?


Danke schonmal für eure Hilfe =)


LG
Björn

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

In

Björn R. schrieb:
> Passier hierbei nicht das gleiche wie bei meiner aktuellen
> Implementierung ?
Naja, die Namen in deinem Beispiel sind nicht ganz konsistent. Wenn du 
nur 1 Taktdomäne haben willst,  dann musst du die externen Signale über 
2  Flipflops einsynchronisieren. Und dann für den Takt eine 
Flankenerkennung implementieren. Und abhängig von der jeweiligen Flanke 
dann die Daten einlesen oder den Ausgang aktualisieren.

Oder du machst es wie von Duke vorgeschlagen: das eigentliche SPI 
Schieberegister mit dem Schwerpunkt Takten und die Datenübernahme dann 
über den einsynchronisierten Slaveselect.

von Duke Scarring (Gast)


Lesenswert?

Björn R. schrieb:
> shift_reg <= shift_reg( 6 downto 0) & SPI_DI;
>
> Ist hierbei nicht immer die 8te Stelle SPI_DI ?
Nein, weil mit 'wait until rising_edge( CLK);' ein Register (=DAS 
Schieberegister) draus gemacht wurde.

Ohne Prozess und ohne 'wait' hättest Du eine kombinatorische Schleife.

Duke

von Björn R. (doerben)


Lesenswert?

So,
habe noch viel gelesen und ich muss mich recht herzlich bei Euch Allen 
bedanken. Ihr habt mir echt geholfen =), vor allem in manchen Dingen 
"synchron" zu denken. Die SPI funktioniert nun und ich habe viele Teile 
meines Codes nochmal überarbeitet.

Ich verstehe zwar immernoch nicht die timing Constraints aber Vivado 
gibt schon sehr viel weniger Warnmeldungen aus.

Weil die Erzeugung des Bitstreams klappt werde ich das einfach mal auf 
den FPGA laden und mit einem Logic Analyzer schauen was passiert.

LG
Björn

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.