mikrocontroller.net

Forum: FPGA, VHDL & Co. FiFo-Datenübernahme und -Datenausgabe mittels eigener Takte


Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Miteinander.

Ich habe folgendes Problem und bitte nun um ein paar Denkanstöße.

Es soll synthetisierbar sein.

Ich habe mir ein FiFo gebastelt mit den folgenden Eingängen:
DataIn (std_logic_vector)
DataOut (std_logic_vector)
WriteClk (std_logic)
ReadClk (std_logic)
SysClk (std_logic)

Aufgabe des FiFo's ist es 2 Teile mit verschiedenen Clocks zu verbinden.

Ich habe mir die Übernahme der Daten in das FiFo mit der steigenden 
Flanke von WriteClk vorgestellt und das Auslesen mit ner steigenden 
Flanke von ReadClk.

Mit dem Takt SysClk habe ich das FiFo intern synchronisiert (Also so, 
dass mit dem SysClk in das FiFo geschrieben und aus dem FiFo gelesen 
wird).

Allerdings habe ich die Signale ReadClk und WriteClk bisher nur auf = 
'1' abgefragt.

Somit habe ich ein Problem wenn die Signale ReadClk oder WriteClk länger 
als ein Takt (SysClk) anstehen.

Mein Lösungsvorschlag wäre einfach auf SysClk und ReadClk bzw. WriteClk 
abzufragen. Aber da gibt mir das ISE eine Fehlermeldung bezüglich 
mehrerer Clocks aus (...appears to be controlled by multiple clocks.) 
(Was ja auch stimmt)

Hätte vielleicht jemand einen Vorschlag wie ich das ganze lösen könnte?

Vielen Dank schon mal im voraus

VG

Martin R.

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit drei Takten ist das nirgends synthetisierbar. Fuer zwei Takte 
benutzt du am besten den core generator von ISE - da kannst du sicher 
sein, dass es funktioniert. Eigene Codes mit zwei getrennten Clocks sind 
machbar, aber im Aufwand nicht zu unterschaetzen. Es gibt auch eine 
Application Note von Xilinx mit passenden vhdl-Quellen: xapp258.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Merk dir den alten Zustand der beiden Takte und reagiere auf
> if WriteClkOld='0' and WriteClk='1' then --- steigende Flanke
Ich hoffe, du hast die Schreib- und Lesetakte schon einsynchronisiert?

Oder setze mit der steigenden Flanke von WriteClk ein Merker-FF und 
setze das mit dem eigentlichen Lesevorgang zurück.

Aber ich würde an deiner Stelle mal ganz tief in mich gehen, und 
kontrollieren, ob da wirklich 3 Takte nötig sind. Alles ungleich 1 Takt 
ist ein potenzieller Kündigungsgrund ;-)

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Miteinander

Danke für die schnellen Antworten.

Das mit dem Core-Generator...
Hätte es lieber selbst geschrieben, dann weiß ich genau wie das Ding 
funktioniert. Außerdem 100 Seiten Beschreibung für nen FiFo ist schon 
ein bisschen viel.
Ich nehm das mal als letzte Möglichkeit.

Ich denke, dass ich zuerst das mit dem MerkerFF nochmal ausprobiere.


Aber ich würde an deiner Stelle mal ganz tief in mich gehen, und
kontrollieren, ob da wirklich 3 Takte nötig sind. Alles ungleich 1 Takt
ist ein potenzieller Kündigungsgrund ;-)

Naja. 2 Takte habe ich ja schon..... Da dachte ich mir: Einer mehr oder 
weniger...


Wegen dem:
Oder setze mit der steigenden Flanke von WriteClk ein Merker-FF und
setze das mit dem eigentlichen Lesevorgang zurück.

Was für einen Lesevorgang meinst Du?






VG

Martin R.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Naja. 2 Takte habe ich ja schon.....
> Da dachte ich mir: Einer mehr oder weniger...
So hast du aus 2 möglichen Domänenübergängen (hin- und zurück) gleich 6 
gemacht. Aber wie heißt es so schön:
"Ist der Ruf erst ruiniert, lebt sichs völlig ungeniert" ;-)

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller wrote:
> So hast du aus 2 möglichen Domänenübergängen (hin- und zurück) gleich 6
> gemacht. Aber wie heißt es so schön:
> "Ist der Ruf erst ruiniert, lebt sichs völlig ungeniert" ;-)

Ich bin noch jung und unerfahren...

Das mit dem MerkerFF sieht dann so aus?

pEdgeDetect : process (sSysClk, spoWriteClk, sTemp) is
begin
if rising_edge (sSysClk) and spoWriteClk = '1' and sTemp = '0' then
   sTemp <= '1';
   sWriteClk <= '1';
else
   sTemp <= '0';
   sWriteClk <= '0';
end if;
end process;

Jetzt habe ich schon wieder ein :
Signal sWriteClk cannot be synthesized, bad synchronous description. The 
description style you are using to describe a synchronous element 
(register, memory, etc.) is not supported in the current software 
release.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> if rising_edge (sSysClk) and spoWriteClk = '1' and sTemp = '0' then
Nein, sowas findest du sicher in keinem Buch gängiger Lehrmeinung.
Obwohl das u.U. als Clock-Enable synthetisierbar wäre, wie die Meldung
> is not supported in the current software release
schon vermuten lässt ;-)

Zäumen wir das Pferd mal von vorne auf:
Welches FPGA?
Wie sind deine (3) Takt-Frequenzen?
Ist der Sys-Clock der sonst überall verwendetete FPGA-Clock?
Ist der Read-Clock synchron zum Sys-Clock?

Autor: xTMx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ich habe das jetzt mit einer händisch beschriebenen Flanke (mittels 
zweier Signale) gemacht. Ich hab halt jetzt den Nachteil, dass das 
Signal mindestens 2 Takte stail anliegen muss.

Auf der Seite B habe ich ein einen MicroBlaze. Dieser läuft mit 100MHz. 
Dieser Takt (SysClk) habe ich auch wieder phasensynchron herausgeführt 
und wird überall verwendet.
Der MB soll die Daten aus dem FiFo lesen sobald Daten darin stehen.
--> Somit kommt der ReadClk synchron zum SysClk. Aber nicht jedes mal.

Auf der Seite A ist ein Teil, dass die Daten in das FiFo reinschreibt.
Das Schreiben erfolgt auch  synchron zum SysClk. Aber nicht bei jedem 
SysClk.

Im Moment läuft das auf einem Virtex5. Soll aber auf allen möglichen 
Xilinx-Fpga's funktionieren.

Ich hoffe ich konnte nun alle Fragen beantworten und bedanke mich für 
die Hilfe.

VG

Martin R.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dieser Takt (SysClk) habe ich auch wieder phasensynchron herausgeführt
> und wird überall verwendet.
> Der MB soll die Daten aus dem FiFo lesen sobald Daten darin stehen.
> --> Somit kommt der ReadClk synchron zum SysClk. Aber nicht jedes mal.
Zusammenfassung: Wenn er kommt, dann synchron.

> Auf der Seite A ist ein Teil, dass die Daten in das FiFo reinschreibt.
> Das Schreiben erfolgt auch  synchron zum SysClk.
> Aber nicht bei jedem SysClk.
Zusammenfassung: Wenn er kommt, dann synchron.

Über alles: du hast offenbar ein Synchrones Design. Gut.

Dann solltest du den ReadClk und den WriteClk einfach nicht als Clock, 
sondern als Enable nehmen (ReadEnable und WriteEnable).
Fertig: keine Latency, alles synchron.

Ich habe mir da mal so ein Template gebastelt, das funkt ganz gut:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity FIFO is
    Generic (
           Addrbreite  : natural := 8;  -- Speicherlänge = 2^Addrbreite
           Wortbreite  : natural := 8
           );
    Port ( Din   : in  STD_LOGIC_VECTOR (Wortbreite-1 downto 0);
           Write : in  STD_LOGIC;
           Dout  : out STD_LOGIC_VECTOR (Wortbreite-1 downto 0);
           Read  : in  STD_LOGIC;
           Empty : out STD_LOGIC;
           Full  : out STD_LOGIC;
           CLK   : in  STD_LOGIC
           );
end FIFO;

architecture Behavioral of FIFO is

signal wrcnt : integer range 0 to (2**Addrbreite)-1 := 0;
signal rdcnt : integer range 0 to (2**Addrbreite)-1 := 0;
type speicher is array(0 to (2**Addrbreite)-1) of unsigned(Wortbreite-1 downto 0);
signal memory : speicher;   
signal full_loc  : std_logic;
signal empty_loc : std_logic;

begin
  process begin
     wait until rising_edge(CLK);
     if (Write='1' and full_loc='0') then
        memory(wrcnt) <= unsigned(Din);
        wrcnt <= wrcnt+1;
     end if;
     if (Read='1') then
        Dout <= std_logic_vector(memory(rdcnt)); -- Adresse getaktet --> BRAM
        rdcnt <= rdcnt+1;
     end if;
  end process;

  full_loc  <= '1' when rdcnt = wrcnt+1 else '0';
  empty_loc <= '1' when rdcnt = wrcnt   else '0';
  Full  <= full_loc;
  Empty <= empty_loc;

end Behavioral;

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar

Tut mir leid, dass ich mich erst jetzt wieder melde.

Ich habe Dein Code simuliert.
Dieser übernimmt jedesmal die Daten am DIN wenn ein Clk kommt und 
WriteEnable = 1 ist. Das hat mein Code am Anfang auch.
Dachte, dass wäre ein Fehler und deswegen hab ich mit der 
Flankenerkennung rumgespielt. Das hat dann nicht so richtig geklappt 
weil ich das Timing der anliegenden Daten nicht so recht beeinflussen 
konnte.

Ich habe dann den Block auf der Seite A mal genau simuliert und da kam 
heraus, dass das Data-Ready-Signal erst kommt wenn die Daten schon 
fertig sind und nicht erst mit der fallenden Flanke ready sind. Außerdem 
kommt es genau einen Takt. usw usw.

Auf jedenfall kann ich nun das Data-Ready-Signal so nehmen wie es ist 
ohne mir einen Kopf machen zu müssen.
Dein FiFo würde übrigends auch bei mir gehen.

Manchmal muss man wohl einfach mal probieren und dann nachbessern als 
vorher denken und alles unnötig aufblähen...

Nochmals VIELEN DANK

Martin

Autor: SuperWilly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wie ich sehe, zählt "rdcnt" (als Integer definiert) ohne 
Max-Wert-Abfrage o.Ä.
Was passiert, wenn (im gezeigten Fall für "Adressbreite=8") der Zähler
auf 9 springen möchte ?

Gruß
SuperWilly

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was passiert, wenn (im gezeigten Fall für "Adressbreite=8") der Zähler
>auf 9 springen möchte ?


Dann kann er das tun. Der Speicher ist ja erst bei 2**Addrbreite zuende. 
Da das eine Zweierpotenz ist, laeuft der Zaehler automatisch nach 0 
ueber (wenn er die richtige Breite hat, was die Synthese so erzeugen 
sollte).

Vielleicht sollte man sich aber trotzdem nicht darauf verlassen, dass 
die Synthese genau die richtige Vektorbreite verwendet, schliesslich 
gibt man mit range nur eine Mindestgroesse an.

Autor: SuperWilly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja sorry, meinte eigentlich:

Was passiert, wenn der Zähler auf (2**Addrbreite) springen möchte ...

Gruß,
SuperWilly

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.