我有一个带有50MHz晶体的Xilinx FPGA板。我需要在VHDL中将其划分为2Hz。我该怎么做呢?
我有一个带有50MHz晶体的Xilinx FPGA板。我需要在VHDL中将其划分为2Hz。我该怎么做呢?
Answers:
基本上,有两种方法可以做到这一点。首先是使用Xilinx本机时钟合成器内核。这样做的优点之一是Xlinx工具将识别出时钟并通过所需的路径进行路由。这些工具还可以处理任何时序约束(在这种情况下实际上不适用,因为它是2Hz时钟)
第二种方法是使用计数器来计算较快时钟脉冲的数量,直到较慢时钟周期的一半过去为止。例如,对于您的情况,构成一个低时钟周期的一个时钟周期的快速时钟脉冲数为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;
注意事项:
编辑:clk_2Hz_i用于缓冲输出信号。当VHDL还是输出时,它不喜欢使用分配右侧的信号。
if prescaler = 50_000_000/4 then ...
and prescaler <= prescaler + 1;
会更简单。
clk_2Hz
是输出的事实,但是在此行中正在读取它的值clk_2Hz <= not clk_2Hz;
。我已经在修复程序中进行了编辑。
prescaler <= (others => '0');
和之间有什么区别prescaler <= '0';
?
others
阅读我拥有的VHDL书籍时所用的内容。这只是宣告所有的“其他”位通用价值,而不是使用类似的快捷方式“000000000000000000 ......”等等
使用时钟预分频器。
您的预分频器值为(clock_speed / desired_clock_speed)/ 2,因此(50Mhz(50,000,000)/ 2hz(2))/ 2 = 12,500,000,二进制值为101111101011110000100000。
更简单地:(50,000,000)/ 2)/ 2 = 12,500,000 转换为二进制-> 101111101011110000100000
下面是一些操作代码:将newClock用于需要2hz的任何地方...
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;
使用您的时钟频率和所需的使能频率创建几个常数,然后使用自记录代码启动。
我宁愿建议使用Xilinx primitice数字时钟管理器IP。
它具有图形设置界面,您可以在其中指定所需的频率。它将生成一个具有所需输出作为频率的分量。
可以在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;