时钟分频器有多种形式。如果您正在查看高速时钟,例如在使用双数据速率 (DDR) 存储器时,您实际上想要使用 FPGA 的时钟管理器。例如Xilinx 数字时钟管理器 (DCM)。这些提供了非常稳定的边沿同步时钟输出。
对于较低速度的时钟,您可以使用您建议的分频器。然而,这些也有多种口味。如果分频比是整数,你可以像你一样使用简单的计数器。对于下一个示例,时钟分频器将始终将输入频率除以 2(例如 50 MHz-> 25 MHz),然后再除以所设置的比率(例如 25/3 = 8 1/3 MHz)
library ieee;
use ieee.std_logic_1164.all;
entity simp_clk_div is
generic(
half_clk_div_ratio : positive);
port(
input_clk : in std_logic;
output_clk : out std_logic);
end entity;
architecture rtl of simp_clk_div is
constant clk_div_cnt : natural := half_clk_div_ratio - 1;
signal cnt : natural := clk_div_cnt;
signal output_clk_i : std_logic := '0';
begin
divide : process(input_clk) begin
if rising_edge(input_clk) then
if cnt = 0 then
cnt <= clk_div_cnt;
output_clk_i <= not output_clk_i;
else
cnt <= cnt - 1;
end if;
end if;
end process;
output_clk <= output_clk_i;
end architecture;
entity simp_clk_div_tb is end entity;
library ieee;
architecture behavior of simp_clk_div_tb is
use ieee.std_logic_1164.all;
signal input_clk, output_clk : std_logic;
begin
DUT : entity work.simp_clk_div
generic map(
clk_div_ratio => 3)
port map(
input_clk => input_clk,
output_clk => output_clk);
clk_stim : process begin
input_clk <= '0', '1' after 1 ns;
wait for 2 ns;
if (now > 200 ns) then wait; end if;
end process;
end architecture;
如果您想要更多自由度,例如将 50MHz 转换为 3MHz,您可以使用分数时钟分频器。但是,此组件需要更多资源。另外,时钟输出上有很多抖动,以不等长时钟脉冲的形式出现。但这通常不是低速时钟的大问题。
library ieee;
use ieee.std_logic_1164.all;
entity frac_clk_div is
generic(
input_freq : positive;
output_freq : positive);
port(
input_clk : in std_logic;
output_clk : out std_logic);
end entity;
architecture rtl of frac_clk_div is
constant cnt_sub : positive := output_freq*2;
signal cnt : natural := input_freq;
signal output_clk_i : std_logic := '0';
begin
divide : process(input_clk) begin
if rising_edge(input_clk) then
if cnt < cnt_sub then
cnt <= input_freq - (cnt_sub - cnt);
output_clk_i <= not output_clk_i;
else
cnt <= cnt - cnt_sub;
end if;
end if;
end process;
output_clk <= output_clk_i;
end architecture;
entity frac_clk_div_tb is end entity;
library ieee;
architecture behavior of frac_clk_div_tb is
use ieee.std_logic_1164.all;
signal input_clk, output_clk : std_logic;
begin
DUT : entity work.frac_clk_div
generic map(
input_freq => 50_000_000,
output_freq => 3_000_000)
port map(
input_clk => input_clk,
output_clk => output_clk);
clk_stim : process begin
input_clk <= '0', '1' after 1 ns;
wait for 2 ns;
if (now > 200 ns) then wait; end if;
end process;
end architecture;