具有小数的VHDL时钟分频器

时间:2012-06-18 08:36:47

标签: decimal vhdl clock divider

我正在尝试将50MHz时钟降至25.175MHz以用于VGA控制器。我已经有一个时钟分频器,但是当每个当前时钟速度和所需时钟速度的分频不是一个整数时,我就无法减慢时钟速度。 I.E. 50000000/25175000~1.98。时钟分频器编译并运行,但如果除法是十进制数,则不输出任何内容。这是我的代码:

    LIBRARY IEEE;
    USE  IEEE.STD_LOGIC_1164.ALL;

    ENTITY Clockdiv IS PORT (
        Clkin: IN STD_LOGIC;
        Clk: OUT STD_LOGIC);
    END Clockdiv;

    ARCHITECTURE Behavior OF Clockdiv IS
        CONSTANT max: INTEGER := 50000000/25175000;
        CONSTANT half: INTEGER := max/2;
        SIGNAL count: INTEGER RANGE 0 TO max;
    BEGIN
        PROCESS
        BEGIN
            WAIT UNTIL Clkin'EVENT and Clkin = '1';

            IF count < max THEN
                count <= count + 1;
            ELSE
                count <= 0;
            END IF;

            IF count < half THEN
                Clk <= '0';
            ELSE
                Clk <= '1';
            END IF;
        END PROCESS;
    END Behavior;

我在谷歌搜索,发现使用REAL数据类型将允许你使用小数,但当我改变我用于REALs的变量时,Quartus给了我错误:Error (10414): VHDL Unsupported Feature error at Clockdiv.vhd(12): cannot synthesize non-constant real objects or values

然后,如果我将“count”更改为CONSTANT类型,则会收到错误:Error (10477): VHDL error at Clockdiv.vhd(18): name "count" must represent signal

有人知道如何将时钟降低到25.175MHz吗?另外,有没有人知道如何减慢时钟速度,以便编译器对结果除法是十进制值感到满意?

由于

2 个答案:

答案 0 :(得分:4)

实际上,实际上,实数不可合成,因此您需要提出一个基于整数的解决方案。

这个比例相当棘手,因为它几乎是2:1,但并不完全。大多数基于边沿的时钟分频器电路仅在原始时钟的一个边沿上工作,因此可以除以的最低比率为2.在这种情况下,您将必须在时钟的两个边缘上工作。

一旦你得到了它,你需要一个计数器,它以你的比率的分母递增,并且它超过了分子,然后输出一个时钟边缘。

PROCESS
    BEGIN
        WAIT UNTIL Clkin'EVENT;

        IF count < max THEN
            count <= count + DENOMINATOR;
        ELSE
            count <= 0;
        END IF;

        IF count > NOMINATOR THEN
            Clk <= ~Clk;
        END IF;
    END PROCESS;

对于这个比例,我认为你能代表它的最小方式是2000/1007。

这样做的问题在于你将获得一个基本上为25MHz的时钟,但偶尔(每个2000/7次迭代)你将获得额外的优势。它不会是25.175MHz的时钟。没有PLL,从50MHz获得25.175MHz是不可能的。

答案 1 :(得分:2)

我已经编写了大量的VGA控制器,而使用25 MHz时钟从来就不是一个问题。如果你绝对想要靠近,你的FPGA可能有某种类型的时钟管理器(我只熟悉Xilinx器件),它允许你通过乘以和分频输入时钟来合成输出时钟。

此外,在这种情况下,使用派生/门控时钟(在进程中直接设置值的时钟)可能对您有用,但它可能会导致很多难以调试的问题。更好的解决方案是生成时钟使能,然后在相同(快速)时钟上运行所有内容。

最后一点,尽管它可能是首选样式的问题,但我通常使用时钟流程语句而不是WAIT语句(如下所示,带有上升沿触发,同步复位和时钟使能) 。我发现阅读和理解更加清晰,并且不太容易编写不可合成的结构,例如wait for 10ns;或具有多个WAIT的语句。

process(clk)
begin
    if(rising_edge(clk)) then
        if(sync_reset = '1') then
            --Reset logic
        elsif(clk_enable = '1') then
            --Actual functionality
        end if;
    end if;
end process;