(我会在EE中发布这个,但似乎这里有更多的VHDL问题......)
背景:我正在使用Xilinx Spartan-6LX9 FPGA和Xilinx ISE 14.4(webpack).
我偶然发现了可怕的"PhysDesignRules:372 - 门控时钟"警告,我看到有很多关于这一点的讨论.一致意见似乎是使用FPGA上的其中一个DCM进行时钟分频但是...我的DCM似乎无法从32 MHz到4.096 KHz(根据向导它在5MHz时达到最低点) 32MHz ......尝试为这种低频目的链接多个DCM似乎很荒谬.
我当前的设计使用clk_in计数到指定值(15265),将该值重置为零并切换clk_out位(因此我最终得到50%的占空比,FWIW).它完成了这项工作,我可以轻松地使用clk_out的上升沿来驱动我设计的下一个阶段.它似乎工作得很好,但是...... 门控时钟(即使它不在时钟偏差的范围内,恕我直言也非常相关).(注意:所有时钟测试都是在对给定时钟敏感的进程中使用rising_edge()函数完成的.)
所以,我的问题:
如果我们谈论从更快的 clk_in中获得相对较慢的clk_out,那么门控还是被认为是坏的吗?或者这种"计数到x并发送脉冲"这一点对FPGA来说非常典型,以生成KHz范围内的"时钟",而其他一些不必要的副作用可能会触发此警告?
有没有更好的方法从MHz范围的主时钟创建一个低KHz范围的时钟,请记住,使用多个DCM似乎在这里是过度的(如果在极低的输出频率下可能的话)?我意识到50%的占空比可能是多余的,但假设一个时钟进入并且不使用板载DCM,那么用FPGA如何进行主要的时钟分频?
编辑:给定以下内容(其中CLK_MASTER是32 MHz输入时钟,CLK_SLOW是所需的慢速时钟,LOCAL_CLK_SLOW是一种存储整个占空比的时钟状态的方法),我了解到这种配置导致警告:
architecture arch of clock is
constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
constant CLK_SLOW_FREQ: natural := 2048;
constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
shared variable counter: natural := 0;
signal LOCAL_CLK_SLOW: STD_LOGIC := '0';
begin
clock_proc: process(CLK_MASTER)
begin
if rising_edge(CLK_MASTER) then
counter := counter + 1;
if (counter >= MAX_COUNT) then
counter := 0;
LOCAL_CLK_SLOW <= not LOCAL_CLK_SLOW;
CLK_SLOW <= LOCAL_CLK_SLOW;
end if;
end if;
end process;
end arch;
Run Code Online (Sandbox Code Playgroud)
鉴于此配置不会导致警告:
architecture arch of clock is
constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
constant CLK_SLOW_FREQ: natural := 2048;
constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
shared variable counter: natural := 0;
begin
clock_proc: process(CLK_MASTER)
begin
if rising_edge(CLK_MASTER) then
counter := counter + 1;
if (counter >= MAX_COUNT) then
counter := 0;
CLK_SLOW <= '1';
else
CLK_SLOW <= '0';
end if;
end if;
end process;
end arch;
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,一切都是缺少其他的(就像我说的那样,50%的占空比最初很有趣,但最终并不是一个要求,而且"本地"时钟位的切换似乎非常巧妙.时间......)我出现在正确的轨道上.
此时我不清楚的是,为什么使用计数器(存储大量位)不会引起警告,但存储和切换的输出位确实会引发警告.思考?
如果您只需要一个时钟来驱动FPGA中另一部分逻辑,那么简单的答案就是使用时钟使能.
也就是说,在与其他所有相同的(快速)时钟上运行慢速逻辑,但我们对它的启用速度很慢.例:
signal clk_enable_200kHz : std_logic;
signal clk_enable_counter : std_logic_vector(9 downto 0);
--Create the clock enable:
process(clk_200MHz)
begin
if(rising_edge(clk_200MHz)) then
clk_enable_counter <= clk_enable_counter + 1;
if(clk_enable_counter = 0) then
clk_enable_200kHz <= '1';
else
clk_enable_200kHz <= '0';
end if;
end if;
end process;
--Slow process:
process(clk_200MHz)
begin
if(rising_edge(clk_200MHz)) then
if(reset = '1') then
--Do reset
elsif(clk_enable_200kHz = '1') then
--Do stuff
end if;
end if;
end process;
Run Code Online (Sandbox Code Playgroud)
200kHz是近似的,但上述内容可以扩展到您需要的任何时钟使能频率.此外,它应该由大多数FPGA中的FPGA硬件直接支持(至少在Xilinx部分).
门控时钟几乎总是一个坏主意,因为人们经常忘记他们正在创建新的时钟域,因此在这些时钟之间接口信号时不采取必要的预防措施.它还在FPGA内部使用了更多的时钟线,因此如果你有很多门控时钟,你可能会快速耗尽所有可用的线路.
时钟使能没有这些缺点.一切都在同一时钟域运行(尽管速度不同),因此您可以轻松使用相同的信号,而无需任何同步器或类似信号.