У меня есть плата Xilinx FPGA с кристаллом 50 МГц. Мне нужно разделить это до 2 Гц в VHDL. Как мне это сделать?
У меня есть плата Xilinx FPGA с кристаллом 50 МГц. Мне нужно разделить это до 2 Гц в VHDL. Как мне это сделать?
Ответы:
В принципе, есть два способа сделать это. Во-первых, использовать ядро синтезатора часов Xilinx. Одним из преимуществ этого является то, что инструменты Xlinx распознают часы как таковые и направят их через необходимые пути. Инструменты также будут обрабатывать любые временные ограничения (в данном случае это не совсем применимо, поскольку это тактовая частота 2 Гц)
Второй способ - использовать счетчик для подсчета количества более быстрых тактовых импульсов, пока не пройдет половина вашего более медленного тактового периода. Например, для вашего случая число быстрых тактовых импульсов, составляющих один тактовый период медленного тактового цикла, составляет 50000000/2 = 25000000. Поскольку мы хотим половину тактового периода, это 25000000/2 = 12500000 для каждого полупериода. , (продолжительность каждого максимума или минимума).
Вот как это выглядит в 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;
Что следует отметить:
EDIT: clk_2Hz_i используется для буферизации выходного сигнала. VHDL не любит использовать сигнал справа от назначения, когда он также является выходом.
if prescaler = 50_000_000/4 then ...
и prescaler <= prescaler + 1;
будет немного проще.
clk_2Hz
это выход, но все же его значение читается в этой строке clk_2Hz <= not clk_2Hz;
. Я редактировал в исправлении.
prescaler <= (others => '0');
и prescaler <= '0';
?
others
использовалось, когда читал книгу VHDL, которую я имею. Это просто ярлык для объявления всех «других» битов общим значением вместо использования чего-то вроде «000000000000000000 ....» и т. Д.
Используйте предварительный пересчет часов.
Ваше предварительное значение будет вашим (clock_speed / требуемый_clock_speed) / 2 так (50 МГц (50 000 000) / 2 Гц (2)) / 2 = 12 500 000, что в двоичном виде будет 101111101011110000100000.
Проще говоря: (50 000 000) / 2) / 2 = 12 500 000 преобразовать в двоичный файл -> 101111101011110000100000
Вот некоторый код того, что нужно сделать: используйте newClock для того, что вам нужно 2 Гц для ...
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'
, сосчитать до prescaler / 2 и назначить newClk <= not newClk
?
Обычно вы не хотите синхронизировать что-либо медленное, просто создайте разрешение с правильной скоростью и используйте это в логике:
if rising_edge(50MHz_clk) and enable = '1' then
Вы можете создать включение таким образом:
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;
создайте пару констант с вашей тактовой частотой и желаемой частотой включения - и все готово, с самодокументированным кодом для загрузки.
Я бы предпочел использовать IP-менеджер менеджера цифровых часов Xilinx primitice .
Он имеет графический интерфейс настроек, где вы можете указать, какую частоту вы хотите. Он сгенерирует компонент с желаемым выходом в качестве частоты.
Его можно найти в мастере IP;
И тогда вы сможете указать, какую частоту вы хотите:
Фактор = входной сигнал-частота / выходной прескейлер-частота.
CE = часы включены. Это должен быть импульс длительностью один такт (clk) или высокий, если он не используется.
Q = Выходной сигнал импульса шириной один такт с требуемой частотой.
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;