Forum: FPGA, VHDL & Co. Clock-Enable synchronisieren


von Marius W. (mw1987)


Lesenswert?

Hallo,

ich habe hier ein kleines Problem, welches ich aktuell noch nicht so 
recht lösen kann. Und zwar geht es um einen Transmitter im FPGA, der 
serielle Daten mit bis zu 160 MHz auf eine optische Schnittstelle geben 
kann. Die 160 MHz werden aus einer externen 40 MHz-Systemclock mit Hilfe 
einer PLL erzeugt.

Da der Transmitter-Pfad auch 40 und 80 MHz Datenrate unterstützen soll, 
gibt es ein globales Clock-Enable-Signal. Das erzeuge ich mit einem 
Zähler:
1
-- clock enable generation
2
process begin
3
  wait until rising_edge(clk160);
4
  
5
  if reset = '1' then
6
    ce_cnt <= 0;
7
    ce40 <= '0';
8
    ce80 <= '0';
9
  else
10
    if ce_cnt = 0 then
11
      ce40 <= '1';
12
      ce80 <= '1';
13
    else
14
      ce40 <= '0';
15
      if ce_cnt = 2 then
16
        ce80 <= '1';
17
      else
18
        ce80 <= '0';
19
      end if;
20
    end if;
21
22
    if ce_cnt = 3 then
23
      ce_cnt <= 0;
24
    else
25
      ce_cnt <= ce_cnt + 1;
26
    end if;
27
  end if;
28
end process;

Jetzt habe ich jedoch das Problem, dass die 40 MHz Daten möglichst 
phasensynchron zur 40 MHz-Clock sein sollen. Wie kann ich es erreichen, 
dass die externe 40 MHz-Clock und eine über Enable generierte 40 
MHz-Clock diesselbe Phasenlage haben?

Bisher ist mir nicht so viel eingefallen. Eventuell eine Phasendetektion 
mittels XOR?

Gruß
Marius

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


Lesenswert?

Marius Wensing schrieb:
> Wie kann ich es erreichen, dass die externe 40 MHz-Clock und eine über
> Enable generierte 40 MHz-Clock diesselbe Phasenlage haben?
Der 160MHz ist ja schon "synchron" zum Eingangstakt. Du musst also nur 
noch erkennen, wenn der 40MHz-Takt einen Flankenwechesel macht, und dann 
passend daraus dein Enable erzeugen...

> Eventuell eine Phasendetektion mittels XOR?
Ja, so werden Flanken im FPGA erkannt:
wenn (Signal im vorigen Takt) /= (Signal im jetzigen Takt), dann war 
das eine Flanke. Drei 160MHz-Takte später wird also wieder eine 
steigende/fallende 40MHz-Flanke kommen.


Oder du synchronisierst dein Signal aus der 160MHz-Domäne einfach auf 
den 40MHz-Takt um...

von Marius W. (mw1987)


Lesenswert?

Grundsätzlich habe ich das schon verstanden. Was jedoch mein "Problem" 
in der ganzen Überlegung ist:

Es gibt doch in den 160 MHz immer eine Flanke, die genau mit der Flanke 
der 40 MHz übereinstimmt. Damit handele ich mir doch Metastabilitäten 
ein, weil möglicherweise Setup/Hold-Zeiten verletzt werden.

MfG
Marius

von Klakx (Gast)


Lesenswert?

für process mit wait until (der eigentlich nur in einer testbench so 
auftauchen sollten) habe ich mir

wait until rising_edge(clk160); wait for 1 ps;

angewöhnt.

Ansonsten stimmen idR simulation mit synthese nicht überein.


Da du jetzt mit Clock-Enables arbeitest, ist erstmal alles synchron zu 
160 MHz. Nimm jetzt einfach das korrekte CE, um im Folgetakt die Daten 
in den 40/80 Rhythmus zu laden.

Verwende für übliche Prozesse:

process ..
if reset = '0' then
 -- setze register auf 0
elsif rising_edge(clk) then
 --setze register
end if;

Es sei denn, du wolltest wirklich keinen asynchronen Reset.

von Marius W. (mw1987)


Lesenswert?

Klakx schrieb:
> Da du jetzt mit Clock-Enables arbeitest, ist erstmal alles synchron zu
> 160 MHz. Nimm jetzt einfach das korrekte CE, um im Folgetakt die Daten
> in den 40/80 Rhythmus zu laden.

Ja, mir ist prinzipiell klar, wie das geht. Allerdings habe ich 
beispielsweise für das ce40-Signal vier verschiedene Möglichkeiten, es 
bezüglich der externen 40 MHz zu positionieren. Nach dem Laden der 
FPGA-Firmware kann ich nicht direkt vorhersagen, wann der Zähler 
wirklich losläuft. Daher kann ich auch nicht sofort sagen, welche 
Phasenlage ich habe.

MfG
Marius

von D. I. (Gast)


Lesenswert?

Klakx schrieb:
> für process mit wait until (der eigentlich nur in einer testbench so
> auftauchen sollten) habe ich mir
>
> wait until rising_edge(clk160); wait for 1 ps;
>
> Verwende für übliche Prozesse:
>
> process ..
> if reset = '0' then
>  -- setze register auf 0
> elsif rising_edge(clk) then
>  --setze register
> end if;

Mr. Miller, übernehmen sie. ;)

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


Lesenswert?

D. I. schrieb:
> Mr. Miller, übernehmen sie. ;)
Sänk iu...  ;-)

Marius Wensing schrieb:
> Damit handele ich mir doch Metastabilitäten ein,
> weil möglicherweise Setup/Hold-Zeiten verletzt werden.
Vergiss bei diesen langsamen Geschwindigkeiten das Thema Metastabilität. 
Das wird mit halbwegs aktuellen FPGAs frühestens bei 300MHz aufwärts 
interessant. Sicher. Such mal nach Peter Alfke und "A spectre is hauting 
this newsgroup" oder lies das da:
http://www.lothar-miller.de/s9y/archives/62-Testaufbau-Metastabilitaet.html

Klakx schrieb:
> Es sei denn, du wolltest wirklich keinen asynchronen Reset.
Kann sein. Bei Xilinx-FPGAs ist ein asynchroner Reset Gift. Steht aber 
im Handbuch zum jeweiligen FPGA... ;-)

von Micha (Gast)


Lesenswert?

Marius Wensing schrieb:
> Ja, mir ist prinzipiell klar, wie das geht. Allerdings habe ich
> beispielsweise für das ce40-Signal vier verschiedene Möglichkeiten, es
> bezüglich der externen 40 MHz zu positionieren. Nach dem Laden der
> FPGA-Firmware kann ich nicht direkt vorhersagen, wann der Zähler
> wirklich losläuft. Daher kann ich auch nicht sofort sagen, welche
> Phasenlage ich habe.

jetzt habe ichs kapiert :)

Vorschlag 1:
Schick den Systemtakt in die Pll und nutze die synchronliegenden 40, 80 
und 160 MHz. (wechsel der Geschwindigkeiten mit Clock-Multiplexer)

Vorschlag 2:
Erzeuge ein Toggle-Signal und lass deine Transmitter-Logik sich an der 
steigenden Flanke ausrichten.

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


Lesenswert?

Klakx schrieb:
> für process mit wait until (der eigentlich nur in einer testbench so
> auftauchen sollten)
Warum?
Ein "wait until rising_edge(clk)" ist ein Garant für einen synchronen 
Prozess:
http://www.lothar-miller.de/s9y/archives/16-Takt-im-Prozess.html

Einen simplen durchlaufenden Zähler beschreibe ich so:
1
  cnt <= cnt+1 when rising_edge(clk);

> habe ich mir
> wait until rising_edge(clk160); wait for 1 ps;
> angewöhnt.
Angewöhnt? Warum solche Automatismen?
Klar gilt: nach dem Takt ist vor dem Takt. Und mit dem kleinen delta-t 
schaffst du vermeintlich klare Verhältnisse, allerdings ohne zu 
beachten, dass ein delta-t von 1ps in der Realität ohne jede Relevanz 
ist.

> Ansonsten stimmen idR simulation mit synthese nicht überein.
Warum?
Ich vermute, du hast dir aus irgendeinem Grund mal die Finger verbrannt.

Zum asynchronen Reset noch den Link:
http://www.lothar-miller.de/s9y/archives/70-Asynchroner-Reset.html
Bei Altera ist das offenbar anders, hier muss aber trotzdem wenigstens 
der Reset einsynchroniert deaktiviert werden. Und ein absolutes No-Go 
ist ein kombinatorischer asynchroner Reset, wo mit ein paar kleinen 
Spikes dann ein paar FF der FSM zurückgesetzt werden, die anderen aber 
nicht...

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.