Eu tenho uma placa FPGA Xilinx, com um cristal de 50 MHz. Eu preciso dividir isso em 2Hz em VHDL. Como eu faço isso?
Eu tenho uma placa FPGA Xilinx, com um cristal de 50 MHz. Eu preciso dividir isso em 2Hz em VHDL. Como eu faço isso?
Respostas:
Basicamente, existem duas maneiras de fazer isso. O primeiro é usar o núcleo do sintetizador de relógio nativo Xilinx. Uma das vantagens disso é que as ferramentas do Xlinx reconhecem o relógio como tal e o direcionam pelos caminhos necessários. As ferramentas também lidam com qualquer restrição de tempo (não é realmente aplicável neste caso, pois é um relógio de 2 Hz)
A segunda maneira é usar um contador para contar o número de pulsos de clock mais rápidos até que metade do seu período de relógio mais lento tenha passado. Por exemplo, no seu caso, o número de pulsos de clock rápidos que compõem um período de relógio de um ciclo lento é 50000000/2 = 25000000. Como queremos um período de meio relógio, isso é 25000000/2 = 12500000 para cada meio ciclo . (a duração de cada alta ou baixa).
Aqui está o que parece em 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;
Coisas a serem observadas:
EDIT: clk_2Hz_i é usado para armazenar em buffer o sinal de saída. O VHDL não gosta de usar um sinal à direita de uma atribuição quando também é uma saída.
if prescaler = 50_000_000/4 then ...
e prescaler <= prescaler + 1;
seria um pouco mais simples.
clk_2Hz
ser uma saída, mas seu valor está sendo lido nesta linha clk_2Hz <= not clk_2Hz;
. Eu editei na correção.
prescaler <= (others => '0');
e prescaler <= '0';
?
others
era usado ao ler um livro de VHDL que tenho. É apenas um atalho para declarar todos os "outros" bits para um valor comum em vez de usar algo como "000000000000000000 ....", etc.
Use um prescaler de relógio.
Seu valor de pré-calibrador será seu (velocidade do relógio / velocidade do relógio desejada) / 2, para (50Mhz (50.000.000) / 2hz (2)) / 2 = 12.500.000, que em binário seria 101111101011110000100000.
Mais simplesmente: (50.000.000) / 2) / 2 = 12.500.000 converter em binário -> 101111101011110000100000
Aqui está um código do que fazer: Use newClock para o que você precisar de 2 hz para ...
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'
, contar até prescaler / 2 e atribuir newClk <= not newClk
?
Na verdade, você normalmente não quer marcar nada tão lento, basta criar uma habilitação na taxa correta e usá-la na lógica:
if rising_edge(50MHz_clk) and enable = '1' then
você pode criar o enable assim:
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;
crie algumas constantes com a sua frequência de clock e a freqüência de ativação desejada e pronto, com código de auto-documentação para inicializar.
Prefiro sugerir o uso do IP do gerenciador de relógio digital Xilinx primitice .
Possui interface de configurações gráficas onde você pode especificar qual frequência deseja. Ele irá gerar um componente com a saída desejada como frequência.
Pode ser encontrado no Assistente de IP;
E então você poderá especificar qual frequência deseja:
Fator = frequência de sinal de entrada / frequência de pré-calibrador de saída.
CE = Ativar relógio. Deve ser um pulso amplo de um relógio (clk) ou alto, se não for usado.
Q = Sinal de saída de um pulso amplo com a freqüência desejada.
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;