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


13

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


13
那么,您实际上尝试了什么?
马特·杨

为什么不使用Xilinx时钟管理器IP?
Arturs Vancans

Answers:


19

基本上,有两种方法可以做到这一点。首先是使用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还是输出时,它不喜欢使用分配右侧的信号。


1
不错,但是您可以使用整数对unsigned进行添加/比较,因此:if prescaler = 50_000_000/4 then ...and prescaler <= prescaler + 1;会更简单。
Brian Drummond 2013年

@StaceyAnne尝试此操作,我得到“无法从'out'对象clk_o中读取;使用'buffer'或'inout'”,我错过了什么吗?
躲过

@evading,在输出上需要一个缓冲区。VHDL不喜欢这clk_2Hz是输出的事实,但是在此行中正在读取它的值clk_2Hz <= not clk_2Hz;。我已经在修复程序中进行了编辑。
stanri 2013年

+1好例子。但是,这就是我的无知(VHDL的新功能)。prescaler <= (others => '0');和之间有什么区别prescaler <= '0';
cbmeeks

NVM!我完全错过了others阅读我拥有的VHDL书籍时所用的内容。这只是宣告所有的“其他”位通用价值,而不是使用类似的快捷方式“000000000000000000 ......”等等
cbmeeks

9

使用时钟预分频器。

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

似乎您正在生成两个时钟,一个为0.5 Hz,另一个为1 Hz?(因为您的时钟周期是您的预分频器* 2?)。另外,“ +”将给出错误,因为您要添加slv,无论如何我都不确定以这种方式使用add的溢出属性。为什么不随便去newClock : std_logic := '0',算到prescaler / 2并分配newClk <= not newClk
2013年

谢谢,我的逻辑有些偏离。我现在用一些经过测试的代码以及您的一些建议更新了我的初始帖子:)
MLM

gh-所有这些都为零,并附有评论以说明实际情况!为什么不使用编译器为您完成呢???为什么不使用整数呢?
2013年

我可能是错的,但我认为在架构中定义信号时不能使用默认值,例如“:=(others =>'0')”。
Arturs Vancans

它是可综合的,但基本上只适用于基于SRAM的FPGA,如Xilinx,Altera或Lattice的大多数FPGA。
Yann Vernier

8

通常,您通常不需要时钟缓慢的时钟,只需以正确的速率创建一个启用并在逻辑中使用它:

 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;

使用您的时钟频率和所需的使能频率创建几个常数,然后使用自记录代码启动。


3

我宁愿建议使用Xilinx primitice数字时钟管理器IP

它具有图形设置界面,您可以在其中指定所需的频率。它将生成一个具有所需输出作为频率的分量。

可以在IP向导中找到它。

在此处输入图片说明

然后,您将可以指定所需的频率: 在此处输入图片说明


0

因子=输入信号频率/输出预分频器频率。

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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.