mikrocontroller.net

Forum: FPGA, VHDL & Co. Wie unterschiedliche Clock-Domains verwenden?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe einen I2S-Transmitter, den ich mit einem AXI-Stream Interface 
ausstatten möchte. Der Transmitter alleine lässt sich ohne Probleme 
synthetisieren und funktioniert im FPGA wunderbar. Mit dem AXI-Stream 
Interface kombiniert ergeben sich aber Timing Violations beim Worst 
Negative Slack und beim Total Negativ Slack. Jetzt habe ich gelesen, 
dass es u. U. daran liegen könnte, dass ich die Signale nicht ordentlich 
einsynchronisiert habe. Daher habe ich mir mal die Erklärung vom Lothar 
Miller angeschaut

http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

und versucht die Synchronisation für das Reset-Signal (für den Anfang) 
meines Transmitters umzusetzen:
entity AXIS_I2S is
    Generic (   WIDTH       : INTEGER := 16
                );
    Port (  aclk        : in STD_LOGIC;
            aresetn     : in STD_LOGIC;

            -- AXI-Stream interface
            TDATA_RXD   : in STD_LOGIC_VECTOR(31 downto 0);
            TREADY_RXD  : out STD_LOGIC;
            TVALID_RXD  : in STD_LOGIC;

            -- I2S interface
            MCLK        : in STD_LOGIC;
            LRCLK       : out STD_LOGIC;
            SCLK        : out STD_LOGIC;
            SD          : out STD_LOGIC        
            );
end AXIS_I2S;

architecture AXIS_I2S_Arch of AXIS_I2S is

    type AXIS_State_t is (State_Reset, State_WaitForTransmitterReady, WaitForValid, WaitForBusy);

    signal CurrentState : AXIS_State_t                                      := State_Reset;

    signal FIFO             : STD_LOGIC_VECTOR(((2 * WIDTH) - 1) downto 0)  := (others => '0');

    signal TransmitterValid : STD_LOGIC;
    signal TransmitterReady : STD_LOGIC;
    signal TransmitterResetN: STD_LOGIC_VECTOR(1 downto 0);

    component I2S_Transmitter is
        Generic (   WIDTH   : INTEGER := 16
                    );
        Port (  MCLK    : in STD_LOGIC;
                ResetN  : in STD_LOGIC;
                Ready   : out STD_LOGIC;
                Valid   : in STD_LOGIC;
                Data    : in STD_LOGIC_VECTOR(((2 * WIDTH) - 1) downto 0);
                LRCLK   : out STD_LOGIC;
                SCLK    : out STD_LOGIC;
                SD      : out STD_LOGIC
                );
    end component;

begin

    Transmitter : I2S_Transmitter generic map(  WIDTH => WIDTH
                                                )
                                  port map(     MCLK => MCLK,
                                                ResetN => TransmitterResetN(1),
                                                Valid => TransmitterValid,
                                                Ready => TransmitterReady,
                                                Data => x"FF00FF00",
                                                LRCLK => LRCLK,
                                                SCLK => SCLK,
                                                SD => SD
                                                );

    -- Synchronize reset
    process(MCLK)
    begin
        if(rising_edge(MCLK)) then
            TransmitterResetN(0) <= aresetn;
            TransmitterResetN(1) <= TransmitterResetN(0);
        end if;
    end process;

    process(aclk)
    begin
        if(rising_edge(aclk)) then
            if(aresetn = '0') then
                CurrentState <= State_Reset;
            else
                case CurrentState is
                    when State_Reset =>
                        FIFO <= (others => '0');
                        --TransmitterValid <= '0';

                        CurrentState <= State_WaitForTransmitterReady;

                    when State_WaitForTransmitterReady =>
                        --TransmitterValid <= '0';

                        --if(TransmitterReady = '1') then
                            CurrentState <= WaitForValid;
                        --else
                        --    CurrentState <= State_WaitForTransmitterReady;
                        --end if;

                    when WaitForValid =>
                        TREADY_RXD <= '1';
                        
                        if(TVALID_RXD = '1') then
                            FIFO <= TDATA_RXD;
                            CurrentState <= WaitForBusy;
                        else
                            CurrentState <= WaitForValid;
                        end if;

                    when WaitForBusy =>
                        --TransmitterValid <= '1';
                        TREADY_RXD <= '0';

                        --if(TransmitterReady = '0') then
                            CurrentState <= State_WaitForTransmitterReady;
                        --else
                        --    CurrentState <= WaitForBusy;
                        --end if;

                end case;
            end if;
        end if;
    end process;
end AXIS_I2S_Arch;

Das aktuelle Design ergibt einen WNS and TNS von -5,7 ns, sprich es wird 
auch nicht funktionieren. Wo habe ich da den Denkfehler drin, bzw. muss 
ich es ganz anders machen?

PS: Ja, ich weiß das man verschiedene Clock-Domainen meiden sollte, bzw. 
es nicht ganz trivial ist (siehe mein Beispiel). Das Problem hier ist 
allerdings, dass der AXI Bus des Systems leider auf einer komplett 
anderen Frequenz läuft und das sich das mit dem I2S beißt (100 MHz AXI, 
12,288 MHz I2S). Daher bleibt mir leider nichts anderes übrig.

Danke für ein paar Denkanstöße :)

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
AXI reset ist doch normalerweise asynchron?

Beitrag "Re: Altera Reset Synchronizer richtig machen"

P.S.: und wenn etwas asynchron ist, braucht der Timing Analyzer ein 
set_false_path statement

: Bearbeitet durch User
Beitrag #6180951 wurde vom Autor gelöscht.
von Christoph Z. (christophz)


Bewertung
0 lesenswert
nicht lesenswert
Ich arbeite nicht mit Altera, darum nehme ich mal an, dass es für den 
Reset so ist, wie Markus F. schreibt.

Für die I2S Komponente musst du das "Valid" Signal einsynchronisieren. 
Dabei musst du aufpassen, dass es in der AXI Domäne genug lange aktiv 
bleibt, bis es deine I2S Domäne sicher gelesen hat (die ist ja ca. 8 mal 
langsamer). Also entweder einen Puls-stretcher einfügen oder auf 
Vier-Phasen-Handshake umbauen.

Das Synchronisierte "Valid" und das "Data" Signal brauchen dann beide 
noch eine False-path Constraint.

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Christoph Z. schrieb:
> Ich arbeite nicht mit Altera, darum nehme ich mal an, dass es für den
> Reset so ist, wie Markus F. schreibt.
>
> Für die I2S Komponente musst du das "Valid" Signal einsynchronisieren.
> Dabei musst du aufpassen, dass es in der AXI Domäne genug lange aktiv
> bleibt, bis es deine I2S Domäne sicher gelesen hat (die ist ja ca. 8 mal
> langsamer). Also entweder einen Puls-stretcher einfügen oder auf
> Vier-Phasen-Handshake umbauen.
>
> Das Synchronisierte "Valid" und das "Data" Signal brauchen dann beide
> noch eine False-path Constraint.

Das Valid-Signal habe ich erst einmal ausgeklammert. Mit den I2S 
Signalen hatte ich einen TNS von -1000 ns und daher wollte ich erst 
einmal schauen welche Signale da mit rein spielen. Aktuell habe ich nur 
den Reset in beiden Clock-Domainen aktiv und da bekomme ich es schon 
nicht hin den TNS auf 0 zu reduzieren...
Hab es auch schon mit dem ASYNC_REG Attribut probiert
    attribute ASYNC_REG : string;
    attribute ASYNC_REG of TransmitterResetN        : signal is "TRUE";

Aber auch das hat leider nicht geholfen (mit Vivado von Xilinx).

Edit: Hab nun was (anscheinend) passendes gefunden:
set_false_path -from [get_clocks clk_fpga_0] -to [get_clocks -of_objects [get_pins System_i/ClockingWizard/inst/mmcm_adv_inst/CLKOUT0]]

Weiß noch nicht ob es das richtige ist, aber der Fehler ist weg...

: Bearbeitet durch User
von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Weiß noch nicht ob es das richtige ist, aber der Fehler ist weg...

Genau. Jetzt prüft es der Timing Analyzer einfach nicht mehr. Du musst 
dann allerdings selbst dafür sorgen, dass das Signal entweder an einen 
asynchronen Eingang geht oder passend eingetaktet wird.

von Christoph Z. (christophz)


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Weiß noch nicht ob es das richtige ist, aber der Fehler ist weg...

Nochmals etwas klarer Übersetzt: Die Fehlermeldung ist jetzt weg, dein 
Design behandelt den Übergang zwischen den Taktdomänen aber noch nicht 
richtig, wird also in Realität hin und wieder komische Sachen machen 
(Verhext, haunted design...).

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Ich glaube ich habe jetzt eine Antwort gefunden. Das Problem mit dem 
Reset habe ich durch einen zweiten Reset gelöst, der für das Interface 
da ist und mittels "Processor System Reset" auf den entsprechenden Takt 
synchronisiert wird. Für die Signale nehme ich dann einen entsprechenden 
xpm_cdc Block:

https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_2/ug953-vivado-7series-libraries.pdf

Damit scheint es (zumindest) laut der Implementierung zu klappen. Ich 
bin gespannt...

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Kurzes Update:
Die Synchronisation und die Implementierung scheint nun zu funktionieren 
und auch das AXI-Stream Interface funktioniert zu 95% so wie es soll. 
Aktuell habe ich noch ein paar µs keine vernünftigen Daten, aber das 
scheint noch ein Problem in der Software oder in der Hardware zu sein 
(siehe Screenshot). Das ist aber definitiv ein anderes Problem...

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.

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