【问题标题】:Generating a 78MHz clock from a 100MHz base clock从 100MHz 基本时钟生成 78MHz 时钟
【发布时间】:2012-11-10 17:40:56
【问题描述】:

我必须使用 VHDL 语言(因此比率为 200/156)从 100MHz 基本时钟(占空比 0.5)生成 78MHz 时钟(占空比 0.5 或 0.7)。 我知道我可以使用 DCM、PLL 或类似的工具,但目前(不幸的是)我不能。

因此我想使用(不包括任何 DCM 或 PLL)一个简单的分频器,但在这种情况下,我也知道频率只能除以整数(并且最小为 2,因为我会使用计数器来做到这一点- 在我的情况下,我必须将基本时钟除以 1,2820512820512820512820512820513...)。

所以我不知道如何在不使用任何 DCM 或其他东西的情况下实现这一点...我想将 100MHz 时钟划分为更小的频率(如 50MHz、25MHz 等)并将它们相加(50+25+3 为例如),但这是正确的方式吗(逻辑上我不这么认为)?

【问题讨论】:

  • 你能容忍多少抖动?
  • 是否需要 50-50 或者您可以接受 35-65 之类的值?
  • 很遗憾,我不能接受 35-65(你的意思是占空比,对吗?)。我只能接受 50% 或 70% 的占空比……@PaulR 我真的不知道我能忍受多少抖动……顺便说一句,我认为这不是问题。
  • 没有更多关于如何解释符号的细节,35-65 占空比(与 65% 相同)优于 70% 占空比(与 30- 70)除非您假设百分比仅表示高时间或类似的东西。
  • 0.7 占空比意味着在 70% 的周期内,该值很高 (1)。对不起我的英语不好^^

标签: vhdl frequency


【解决方案1】:

这是一个通用的分数 M/​​D 时钟分频器设计,应该可以解决您的问题。几年前我写了这个供我自己使用。根据您的目标设备,您可能希望使用 std_logic 而不是 bit。

基本思想是使用累加器跟踪小数时钟相位。这与您实现直接数字合成器 (DDS) 的方式非常相似,但只需要担心时钟。

享受吧! =)

如果不清楚如何使用它,您可以将参数用于 39 的乘数和 50 的除数,如 100 * 39/100 = 78,因此所需的操作数宽度为 6(因为 2**6 = 64)。请注意,由于这是输入时钟速率的一半以上,因此没有同步逻辑可以生成输出时钟信号,因此该模块在该速率下的唯一有效输出将是时钟使能。

另请注意,任何可能的除数值的最坏情况是任何一个周期的 33%/66% 占空比。您对乘数和除数的特定选择可能会更好(我需要做一些数学运算才能知道),但是您无法比在最坏的情况下更好一般使用任何算法使用理性划分。您可以使用真正的硬件 PLL 或 DLL 清理此模块的输出,以过滤相位噪声并将占空比纳入您的目标范围。

-- Copyright © 2010 Wesley J. Landaker <wjl@icecavern.net>
-- 
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- 
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- 
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

library ieee;
use ieee.numeric_bit.all;

-- Clock Divider
-- =============
--
-- Fractionally divides the input clock using simultaneous frequency
-- multiplication and division.
--
-- Outputs both a clock enable and a balanced duty-cycle clock. The clock's
-- duty-cycle is as always close to 50% as possible, worst case is 33%/66%.
--
-- Details
-- =======
--
-- Given:
--
--   Fi = input frequency Hz
--   M  = multiplier
--   D  = divisor
--   Fo = output frequency Hz
--
-- Where:
--
--   M ≤ D
--
-- Then:
--
--        ⎧    M
--        ⎪ Fi·—        if M <= D
--   Fo = ⎨    D
--        ⎪
--        ⎩ undefined   if M > D
--
--
-- If (M/D) is greater than 0.5, only the clock enable is valid.
-- If (M/D) is greater than 1.0, both outputs are invalid.

entity Clock_Divider is
  generic (
    operand_width : positive
    );
  port (
    clock : in bit;
    reset : in bit;

    multiplier : in unsigned(operand_width-1 downto 0);
    divisor    : in unsigned(operand_width-1 downto 0);

    out_enable : buffer bit;
    out_clock  : buffer bit
    );
end entity;

architecture any of Clock_Divider is
  signal enable_2x : bit;
begin

  -- Divide the clock by accumulating phase using the mulitplier and
  -- subtracting when we pass the divisor value.

  proc_enable : process is
    variable phase : unsigned(operand_width downto 0);
  begin
    wait until rising_edge(clock);
    phase := phase + multiplier;
    if phase >= divisor then
      phase := phase - divisor;
      out_enable <= '1';
    else
      out_enable <= '0';
    end if;
    if reset = '1' then
      phase := (others => '0');
      out_enable <= '0';
    end if;
  end process;

  proc_enable : process is
    variable phase : unsigned(operand_width downto 0);
  begin
    wait until rising_edge(clock);
    phase := phase + (multiplier & '0');
    if phase >= divisor then
      phase := phase - divisor;
      enable_2x <= '1';
    else
      enable_2x <= '0';
    end if;
    if reset = '1' then
      phase := (others => '0');
      enable_2x <= '0';
    end if;
  end process;


  proc_out_clock : process is
  begin
    wait until rising_edge(clock);
    if enable_2x = '1' then
      out_clock <= not out_clock;
    end if;
  end process;

end architecture;

【讨论】:

  • 感谢您的回答!我刚刚使用“实体工作。Clock_Divider(any) generic map(6) port map(clk, '0', to_unsigned(39, 6), to_unsigned(50, 6), clk78_enable, clk78_o);"并创建了一个测试台,但我没有在输出上得到 78MHz 时钟:(
  • 是的,这实际上是预期的。请注意文档中的行:If (M/D) is greater than 0.5, only the clock enable is valid.。 39/50 = 0.78,所以你只有 clock enable 输出才会有效。 (每 78 MHz 周期有一个 100 MHz 时钟周期为高电平)这是同步逻辑所能做的最好的事情。您可以交替生成一个 39 MHz 时钟,该模块将直接执行此操作,并使用外部 PLL 将其加倍。
  • 或先将 100 MHz 输入加倍。
  • 抱歉,也许我错了,但我仍然没有得到 78MHz 的输出...这是模拟的屏幕截图:i.imgur.com/8JaBN.png我错过了什么吗?
  • 如果它仍然不是 100% 清除:当时钟使能与输入时钟一起使用时,它有效地告诉您所需的输出时钟在此输入时钟周期内有一个上升沿。 (您不会获得有关下降沿在哪里的任何信息,因为它们通常在“输入时钟周期之间”。)这并不是您所要求的(一个实际的自立式切换时钟),但您可以使用从 100 MHz 到 78 MHz 的同步逻辑无法获得您想要的结果。 (您可以使用依赖于各个门特性的各种异步逻辑设计)。
【解决方案2】:

完全不合时宜的想法,有些技术特定,因此可能不适合您的目标,而且相当可怕......

很明显,如果没有 (a) PLL、(b) DLL、(c) 更高频率的时钟或 (d) 5ns p-p jitter,您将无法做到这一点。

您需要更多可用的时钟边沿,但(假设)您没有更多时钟边沿,您将不得不生成自己的时钟边沿。 一种特定于技术(Xilinx)的方法是通过多个引脚输入时钟,并在每个引脚上使用不同的 IBUFDELAY 设置。实际设置可能会通过实验(甚至在通电时)进行校准,并且自然会随着温度而漂移。

另一种方法可能是一系列 LUT 连续延迟时钟,并使用逻辑检测第 n 个延迟超过半个周期。 (或整个周期) 然后点击 n/2 大约晚 90 度,n/4 晚 45 度,等等。 (您无法确保这些时序的一致性。不过,布局规划和锁定此内核会在一定程度上有所帮助。)

无论哪种方式,一旦您拥有多个 100MHz 时钟相位,您就可以将它们应用于上述 DDS(小数分频器)。性能不太可能稳定,但应该比目前最好的 5ns...

(是的,我知道这无异于滚动您自己的(和劣等的)DLL。这算作作弊吗?)

对于复杂度较低的方法,您可以尝试使用 Peter Alfke 的延迟/XOR 技巧从 100MHz 时钟中获得 200MHz。无法保证它的 M/S 比率,但它确实为您提供了 4 个优势......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    相关资源
    最近更新 更多