Ho una scheda FPGA Xilinx, con un cristallo da 50 MHz. Devo dividerlo fino a 2Hz in VHDL. Come faccio a fare questo?
Ho una scheda FPGA Xilinx, con un cristallo da 50 MHz. Devo dividerlo fino a 2Hz in VHDL. Come faccio a fare questo?
Risposte:
Fondamentalmente, ci sono due modi per farlo. Il primo è usare il core del sintetizzatore di clock nativo Xilinx. Uno dei vantaggi di questo è che gli strumenti Xlinx riconosceranno l'orologio in quanto tale e lo instraderanno attraverso i percorsi richiesti. Gli strumenti gestiranno anche tutti i vincoli di temporizzazione (non realmente applicabili in questo caso, poiché è un clock a 2Hz)
Il secondo metodo consiste nell'utilizzare un contatore per contare il numero di impulsi di clock più veloci fino a quando non è trascorsa metà del periodo di clock più lento. Ad esempio, nel tuo caso, il numero di impulsi di clock veloce che compongono un periodo di clock di un ciclo di clock lento è 50000000/2 = 25000000. Dato che vogliamo un periodo di mezzo clock, è 25000000/2 = 12500000 per ogni semiciclo . (la durata di ogni massimo o minimo).
Ecco come appare in VHDL:
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;
Cose da notare:
EDIT: clk_2Hz_i viene utilizzato per bufferizzare il segnale di uscita. A VHDL non piace usare un segnale a destra di un compito quando è anche un'uscita.
if prescaler = 50_000_000/4 then ...
e prescaler <= prescaler + 1;
sarebbe un po 'più semplice.
clk_2Hz
sia un output, ma il suo valore viene letto in questa riga clk_2Hz <= not clk_2Hz;
. Ho modificato la correzione.
prescaler <= (others => '0');
e prescaler <= '0';
?
others
stato usato quando ho letto un libro VHDL. È solo una scorciatoia per dichiarare tutti gli "altri" bit su un valore comune invece di usare qualcosa come "000000000000000000 ....", ecc.
Usa un orologio prescaler.
Il tuo valore prescaler sarà il tuo (clock_speed / desiderata_clock_speed) / 2 so (50Mhz (50.000.000) / 2hz (2)) / 2 = 12.500.000 che in binario sarebbe 101111101011110000100000.
Più semplicemente: (50.000.000) / 2) / 2 = 12.500.000 convertiti in binari -> 101111101011110000100000
Ecco un codice su cosa fare: usa newClock per qualsiasi cosa tu abbia bisogno di 2hz per ...
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'
, contare fino a prescaler / 2 e assegnare newClk <= not newClk
?
Di solito non vuoi davvero sincronizzare nulla di così lento, devi solo creare un'abilitazione alla velocità corretta e usarla nella logica:
if rising_edge(50MHz_clk) and enable = '1' then
puoi creare l'abilitazione così:
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;
crea un paio di costanti con la frequenza di clock e la frequenza di abilitazione desiderata e parti, con il codice di auto-documentazione per l'avvio.
Preferirei suggerire di utilizzare IP Xilinx primitice digital clock manager .
Ha un'interfaccia grafica delle impostazioni in cui è possibile specificare la frequenza desiderata. Genererà un componente con l'uscita desiderata come frequenza.
Può essere trovato nella procedura guidata IP;
E poi sarai in grado di specificare quale frequenza vuoi:
Fattore = input-segnale-fragranza / output-prescaler-fragranza.
CE = Clock Enable. Dovrebbe essere un impulso di un clock (clk) ampio o alto se non utilizzato.
Q = Segnale di uscita di un impulso ampio di un clock con la frequenza desiderata.
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;