Ich habe ein Xilinx-FPGA-Board mit einem 50-MHz-Quarz. Ich muss das in VHDL auf 2 Hz herunterteilen. Wie mache ich das?
Grundsätzlich gibt es zwei Möglichkeiten, dies zu tun. Die erste besteht darin, den nativen Clock-Synthesizer-Kern von Xilinx zu verwenden. Einer der Vorteile davon ist, dass die Xlinx-Tools die Uhr als solche erkennen und sie durch die erforderlichen Pfade leiten. Die Tools behandeln auch alle Zeitbeschränkungen (in diesem Fall nicht wirklich anwendbar, da es sich um einen 2-Hz-Takt handelt).
Die zweite Möglichkeit besteht darin, einen Zähler zu verwenden, um die Anzahl der schnelleren Taktimpulse zu zählen, bis die Hälfte Ihrer langsameren Taktperiode vergangen ist. In Ihrem Fall beträgt die Anzahl schneller Taktimpulse, die eine Taktperiode eines langsamen Taktzyklus ausmachen, beispielsweise 50000000/2 = 25000000. Da wir eine halbe Taktperiode wollen, sind das 25000000/2 = 12500000 für jede Halbperiode . (die Dauer jedes Hochs oder Tiefs).
So sieht es in VHDL aus:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.all;
entity scale_clock is
port (
clk_50Mhz : in std_logic;
rst : in std_logic;
clk_2Hz : out std_logic);
end scale_clock;
architecture Behavioral of scale_clock is
signal prescaler : unsigned(23 downto 0);
signal clk_2Hz_i : std_logic;
begin
gen_clk : process (clk_50Mhz, rst)
begin -- process gen_clk
if rst = '1' then
clk_2Hz_i <= '0';
prescaler <= (others => '0');
elsif rising_edge(clk_50Mhz) then -- rising clock edge
if prescaler = X"BEBC20" then -- 12 500 000 in hex
prescaler <= (others => '0');
clk_2Hz_i <= not clk_2Hz_i;
else
prescaler <= prescaler + "1";
end if;
end if;
end process gen_clk;
clk_2Hz <= clk_2Hz_i;
end Behavioral;
Dinge zu beachten:
EDIT: clk_2Hz_i wird verwendet, um das Ausgangssignal zu puffern. VHDL mag es nicht, ein Signal rechts von einer Zuweisung zu verwenden, wenn es auch ein Ausgang ist.
if prescaler = 50_000_000/4 then ...
und prescaler <= prescaler + 1;
wäre etwas einfacher.clk_2Hz
es sich um eine Ausgabe handelt, aber dennoch wird ihr Wert in dieser Zeile gelesen clk_2Hz <= not clk_2Hz;
. Ich habe im Fix bearbeitet.prescaler <= (others => '0');
und prescaler <= '0';
?others
beim Lesen eines VHDL-Buches verwendet wurde, das ich habe. Es ist nur eine Abkürzung, um alle "anderen" Bits zu einem gemeinsamen Wert zu deklarieren, anstatt etwas wie "000000000000000000 ..." usw. zu verwenden.Verwenden Sie einen Clock-Prescaler.
Ihr Prescaler-Wert ist Ihr (clock_speed/desired_clock_speed)/2, also (50 MHz (50.000.000)/2 hz (2))/2 = 12.500.000, was binär 101111101011110000100000 wäre.
Einfacher : (50.000.000)/2)/2 = 12.500.000 in binär umwandeln -> 101111101011110000100000
Hier ist ein Code, was zu tun ist: Verwenden Sie newClock für alles, wofür Sie 2 Hz benötigen ...
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ClockPrescaler is
port(
clock : in STD_LOGIC; -- 50 Mhz
Led : out STD_LOGIC
);
end ClockPrescaler;
architecture Behavioral of ClockPrescaler is
-- prescaler should be (clock_speed/desired_clock_speed)/2 because you want a rising edge every period
signal prescaler: STD_LOGIC_VECTOR(23 downto 0) := "101111101011110000100000"; -- 12,500,000 in binary
signal prescaler_counter: STD_LOGIC_VECTOR(23 downto 0) := (others => '0');
signal newClock : std_logic := '0';
begin
Led <= newClock;
countClock: process(clock, newClock)
begin
if rising_edge(clock) then
prescaler_counter <= prescaler_counter + 1;
if(prescaler_counter > prescaler) then
-- Iterate
newClock <= not newClock;
prescaler_counter <= (others => '0');
end if;
end if;
end process;
end Behavioral;
newClock : std_logic := '0'
, bis prescaler/2 hochzählen und zuweisen newClk <= not newClk
?Normalerweise möchten Sie eigentlich nichts so langsames takten, erstellen Sie einfach eine Aktivierung mit der richtigen Rate und verwenden Sie diese in der Logik:
if rising_edge(50MHz_clk) and enable = '1' then
Sie können die Freigabe so erstellen:
process
variable count : natural;
begin
if rising_edge(50MHz_clk) then
enable <= '0';
count := count + 1;
if count = clock_freq/desired_freq then
enable <= '1';
count := 0;
end if;
end if;
end process;
Erstellen Sie ein paar Konstanten mit Ihrer Taktfrequenz und der gewünschten Aktivierungsfrequenz und los geht's, mit selbstdokumentierendem Code zum Booten.
Ich würde eher vorschlagen, Xilinx Primitice Digital Clock Manager IP zu verwenden .
Es verfügt über eine grafische Einstellungsschnittstelle, auf der Sie die gewünschte Frequenz angeben können. Es erzeugt eine Komponente mit Ihrer gewünschten Ausgabe als Frequenz.
Es kann im IP Wizard gefunden werden;
Und dann können Sie angeben, welche Frequenz Sie möchten:
Faktor = Eingangssignal-Frequenz/Ausgangs-Prescaler-Frequenz.
CE = Taktfreigabe. Es sollte ein eintaktiger (clk) breiter Impuls oder hoch sein, wenn er nicht verwendet wird.
Q = Ausgangssignal eines einen Takt breiten Impulses mit der gewünschten Frequenz.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
entity prescaler is
generic (
FACTOR : integer);
port (
clk : in std_logic;
rst : in std_logic;
CE : in std_logic;
Q : out std_logic);
end prescaler;
architecture for_prescaler of prescaler is
signal counter_reg, counter_next : integer range 0 to FACTOR-1;
signal Q_next: std_logic;
begin -- for_prescaler
process (clk, rst)
begin -- process
if rst = '1' then -- asynchronous reset (active low)
counter_reg <= 0;
elsif clk'event and clk = '1' then -- rising clock edge
counter_reg <= counter_next;
end if;
end process;
process (counter_reg, CE)
begin -- process
Q_next <= '0';
counter_next <= counter_reg;
if CE = '1' then
if counter_reg = FACTOR-1 then
counter_next <= 0;
Q_next <= '1';
else
counter_next <= counter_reg + 1;
end if;
end if;
end process;
process (clk, rst)
begin -- process
if rst = '1' then -- asynchronous reset (active low)
Q <= '0';
elsif clk'event and clk = '1' then -- rising clock edge
Q <= Q_next;
end if;
end process;
end for_prescaler;
Matt Jung
Artur Vancans