如何在 Xilinx FPGA 上的 VHDL 中将 50MHz 划分为 2Hz

电器工程 视频文件
2022-01-31 03:30:15

我有一个带有 50MHz 晶体的 Xilinx FPGA 板。我需要在 VHDL 中将其划分为 2Hz。我该怎么做呢?

4个回答

基本上,有两种方法可以做到这一点。第一种是使用 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;

注意事项:

  • 复位期间生成的时钟为零。这对于某些应用程序来说是可以的,而对于其他应用程序则不行,这取决于您需要时钟来做什么。
  • 生成的时钟将通过赛灵思综合工具作为正常信号路由。
  • 2Hz 非常慢。模拟一秒钟将需要一段时间。这是少量代码,因此即使模拟 1 秒也应该相对较快,但是如果您开始添加代码,则模拟 2 Hz 时钟周期所花费的时间可能会非常长。

编辑:clk_2Hz_i 用于缓冲输出信号。当它也是输出时,VHDL 不喜欢在分配右侧使用信号。

使用时钟预分频器。

您的预分频器值将是您的 (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;

您通常实际上并不想为任何缓慢的时钟提供时钟,只需以正确的速率创建一个启用并在逻辑中使用它:

 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 向导中找到;

在此处输入图像描述

然后您将能够指定您想要的频率: 在此处输入图像描述