www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Taktfrequenzerhöhung


Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bei folgendem Beispiel komme bei "Simulate Post-Fit Model" (ISE 10.1) 
auf maximalen Takt von ca. 12MHz, in Timing Report steht:

Max. Clock Frequency (fSYSTEM) 100.000 MHz
Clock to Setup (tCYC)    10.000 ns.
Setup to Clock at the Pad (tSU)   6.500 ns.
Clock Pad to Output Pad Delay (tCO)   14.500 ns.

Ich verwende XC95144XL, wie kann ich Takt erhöhen ?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity tap_ctl is
Port (          DATA : inout  STD_LOGIC_VECTOR (15 downto 0);
                BUSY : out  STD_LOGIC;
                WR : in  STD_LOGIC;
                CMD : in  STD_LOGIC;
                CS : in  STD_LOGIC;
                RESET : in  STD_LOGIC;
                -- Clocks GCLK0, faster clock - GCLK0 --
                GCLK0 : in  STD_LOGIC
);
end tap_ctl;


architecture Behavioral of tap_ctl is

signal tmp_data : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
type cmd_states is ( IDLE, DATA_CMD, DATA_WRITE, DATA_READ );
signal cmd_state : cmd_states := IDLE;

begin
        uc_iface: process(GCLK0, RESET)
        begin
                if RESET = '1' then
                        cmd_state <= IDLE;
                        tmp_data <= (others => '0');
                elsif rising_edge(GCLK0) then
                        case cmd_state is
                        when IDLE =>
                                cmd_state <= IDLE;
                                if CS='1' and CMD='1' and WR='0' then
                                        cmd_state <= DATA_CMD;
                                        tmp_data <= DATA;
                                elsif CS='1' and CMD='0' and WR='1' then
                                        cmd_state <= DATA_WRITE;
                                        tmp_data <= DATA;
                                elsif CS='1' and CMD='0' and WR='0' then
                                        cmd_state <= DATA_READ;
                                end if;

                        when DATA_CMD =>
                                cmd_state <= IDLE;

                        when DATA_WRITE =>
                                cmd_state <= IDLE;

                        when DATA_READ =>
                                cmd_state <= IDLE;
                        end case;
                end if;
        end process uc_iface;
        DATA <= tmp_data when cmd_state = DATA_READ else (others => 'Z');
        BUSY <= '0' when cmd_state = IDLE else '1';

end Behavioral;

Autor: Georg A. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie kommst du denn auf die 12MHz bzw. wer sagt das? Das wären ja ca. 
80ns Periodendauer. Das kann ich mir bei den dünnen kombinatorischen 
Pfaden gar nicht vorstellen...

Autor: Johann (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Durch Timing Einstellungen in testbench.tbw (ist für mich als Anfänger 
einfacher). Ab ca. 12 MHz funktioniert die Simulation nicht mehr.

Sim Console meldet auch:
at 176.800 ns(3), Instance /testbench/UUT/tmp_data_11_REG/ : Warning: 
/X_FF SETUP High VIOLATION ON I WITH RESPECT TO CLK;
  Expected := 3 ns; Observed := 1.5 ns; At : 176.8 ns

und so weiter.

Autor: Oliver N. (neufranke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wo kommen denn die timings her, die da verletzt sein wollen?

Autor: Georg A. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, die Ursache ist Pad-In to Setup, weil wohl du die Daten (und 
auch WR etc.) in der Testbench zu kurz vor der steigenden Taktflanke 
draufgibst. Das sieht aus, als wäre das Timing fest kodiert, mit dem 
Takt scheint das nicht viel zu tun zu haben. Wenn es in der Realität 
auch so asynchron ist, hast du ein ganz anderes Problem, was sich auch 
mit nur 100kHz Takt nicht löst...

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

Bewertung
0 lesenswert
nicht lesenswert
@  Johann
Georg hat es schon gesagt, du wirst das Problem mit der Warning 
niemals lösen können. Das ist eine Verletzung der Setup-Zeit 
(alternativ könntest du auch die Hold-Zeit verletzen), die in einem 
metastabilen Verhalten der betroffenen FFs resultieren wird. Bei deinem 
Design sind das die FFs der State-Machine, die kann dann beligib hin und 
her hüpfen.... :-o

Dein Problem lässt sich nicht sicher lösen, weil du 3 Steuersignale 
gleichzeitig hast: CS, WR und CMD.
     when IDLE =>
        cmd_state <= IDLE;
        if    CS='1' and CMD='1' and WR='0' then
           cmd_state <= DATA_CMD;
        elsif CS='1' and CMD='0' and WR='1' then
           cmd_state <= DATA_WRITE;
        elsif CS='1' and CMD='0' and WR='0' then
           cmd_state <= DATA_READ;
       end if;
Was passiert hier, wenn du ausgehend von CS='0', CMD='0' und WR='0' auf
CS='1', CMD='0' und WR='1' umschaltest und dabei das WR='1' nur eine 
Nanosekunde später (und dazwischen der Takt) kommt?
Richtig: du bekommst über CS='1', CMD='0' und WR='0' zwischendurch den 
Zustand DATA_READ. Und das dauert...., bis der beendet ist.
Zudem hast du in diesem Augenblick eine Buskollision, weil gleichzeitig 
der uC und dein CPLD Daten auf den Bus legen.


Üblicherweise ist CS low-aktiv und pegelgesteuert, und WR low-aktiv und 
flankengesteuert (steigende Flanke übernimmt Daten). Dann könntest du 
das Design anders aufsetzen und die Daten synchron zum WR-Impuls 
übernehmen und erst danach verarbeiten.
Die Richtung des Bustreibers wird direkt vom externen Steuersignal 
umgeschaltet, denn der hat die Kontrolle über den Bus.

Du solltest auch die Daten innerhalb deines Designs in zwei Richtungen 
auftrennen: data_in und data_out, dann wird das mit dem Mux einfacher.

Du wechselst von einer Taktdomäne (deine externe Signale) in eine andere 
Taktdomäne (der CPLD-Takt). Dazwischen müssen 2 FF-Stufen zur 
Synchronisation eingefügt werden.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity tap_ctl is
Port (          DATA : inout  STD_LOGIC_VECTOR (15 downto 0);
                BUSY : out  STD_LOGIC;
                WR : in  STD_LOGIC;
                CMD : in  STD_LOGIC;
                CS : in  STD_LOGIC;
                RESET : in  STD_LOGIC;
                -- Clocks GCLK0, faster clock - GCLK0 --
                GCLK0 : in  STD_LOGIC
);
end tap_ctl;


architecture Behavioral of tap_ctl is

signal CSsr : STD_LOGIC_VECTOR (1 downto 0) := (others => '0'); -- Synchronisations-Schieberegister für CS
signal data_in : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
signal data_out : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
type cmd_states is ( IDLE, DATA_CMD, DATA_WRITE, DATA_READ );
signal cmd_state : cmd_states := IDLE;

begin
        process(GCLK0) begin
           if rising_edge(GCLK0) then
              CSsr <= CSsr(0) & CS;
           end if;
        end process;

        uc_iface: process(GCLK0, RESET)
        begin
                if RESET = '1' then
                        cmd_state <= IDLE;
                        tmp_data <= (others => '0');
                elsif rising_edge(GCLK0) then
                        case cmd_state is
                        when IDLE =>
                                cmd_state <= IDLE;
                                if    CSsr(1)='1' and CMD='1' and WR='0' then
                                        cmd_state <= DATA_CMD;
                                elsif CSsr(1)='1' and CMD='0' and WR='1' then
                                        cmd_state <= DATA_WRITE;
                                elsif CSsr(1)='1' and CMD='0' and WR='0' then
                                        cmd_state <= DATA_READ;
                                end if;

                        when DATA_CMD =>
                                data_out <= irgendwas;
                                cmd_state <= IDLE;

                        when DATA_WRITE =>
                                cmd_state <= IDLE;

                        when DATA_READ =>
                                data_out <= irgendwasanderes;
                                cmd_state <= IDLE;
                        end case;
                end if;
        end process uc_iface;

        process (WRn) begin
           if rising_edge(WRn) then
              data_in <= DATA;
           end if;
        end process;

        DATA <= data_out when WRn='1' else (others => 'Z');  -- Der Datenbus wird direkt vom externen signal kontrolliert
        BUSY <= '0' when cmd_state = IDLE else '1';

end Behavioral;

BTW:
Am einfachsten wäre es allerdings, wenn du den Takt vom uC auf das CPLD 
geben würdest, denn dann ist dein Design synchron zur Taktdomäne des uC.

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Lothar für deine Hilfe.

Es ist nur ein Auszug aus meinem Design. Eigentlich habe ich 2 Takte. 
Ersten zur Kommunikation mit uC(AVR32) und zweiten - variablen Takt(frei 
einstellbar) - für so was wie serielle Schnittstelle. Wenn die erste FSM 
in z.B. Zustand DATA_CMD geht dann übernimmt die zweite FSM(GCLK2) die 
Daten und verarbeitet die. Ich hatte die Idee auch den CS als GCLK0 zu 
benutzen, also so was wie:
elsif rising_edge(CS) then
Kann es funktionieren ? Vorausgesetzt WR und CMD sind stabil zu dem 
Moment.

Ich werde deine Änderungen heute Abend ausprobieren.
Johann.

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

Bewertung
0 lesenswert
nicht lesenswert
>  Vorausgesetzt WR und CMD sind stabil zu dem Moment.
Ja, das ist gut so.

Aber du mußt jetzt noch einen ähnlichen sicheren Übergang ind die zweite 
Taktdomäne machen: erst die Daten stabilisieren, und dann das 
Übergabesignal aktivieren und vor der Übernahme einsynchronisieren.

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach langem durchprobieren, eine Variante:
begin

        uc_iface: process(CS, RESET)
        begin
                if RESET = '1' then
                        data_out <= (others => '0');
                elsif rising_edge(CS) then
                        if CMD='0' and WR='1' then
                                data_out <= data_in; -- nur als Beispiel
                        end if;
                end if;
        end process uc_iface;

        DATA <= data_out when WR = '0' else (others => 'Z');
        data_in <= DATA;
        BUSY <= '0' when WR = '0' else '1';


Performance Summary
Min. Clock Period   14.000 ns.
Max. Clock Frequency (fSYSTEM)   71.429 MHz.
Limited by Clock Pulse Width for CS
Pad to Pad Delay (tPD)   11.000 ns.
Setup to Clock at the Pad (tSU)   2.100 ns.
Clock Pad to Output Pad Delay (tCO)   10.200 ns.

Hier muss ich nach WR = '1' Setup Time von 11 ns einhalten. Bekomme ich 
bei dem CPLD überhaupt bessere Zeiten? (Speed 10ns)

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.