Search code examples
decimalvhdlclockdivider

VHDL Clock Divider With Decimals


I'm trying to slow a 50MHz clock down to 25.175MHz for use in a VGA controller. I have a clock divider already, but am having trouble slowing the clock down whenever the resulting division of the current clock speed and the desired clock speed is not a whole number. I.E. 50000000/25175000 ~ 1.98. The clock divider compiles and runs, but outputs nothing if the division is a decimal number. Here's my code:

    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;

I searched on google, and found using the REAL data type will allow you to use decimals, but when I changed the variables I'm using to REALs, Quartus gives me the error: Error (10414): VHDL Unsupported Feature error at Clockdiv.vhd(12): cannot synthesize non-constant real objects or values.

Then, if I change "count" to a CONSTANT type, I get the error: Error (10477): VHDL error at Clockdiv.vhd(18): name "count" must represent signal.

Does anybody know how I can slow a clock down to 25.175MHz? Also, does anybody know how to slow a clock down so that the compiler is happy with the resulting division being a decimal value?

Thanks


Solution

  • Reals are, in general, not synthesisable, so you'll need to come up with an integer based solution.

    That ratio is quite a tricky one because it's almost 2:1, but not quite. Most edge based clock divider circuits work only on one edge of the original clock, so the lowest ratio you can divide by is 2. In this case you'll have to work on both edges of the clock.

    Once you've got that you need to have a counter that increments by the denominator of your ratio and is it's over the numerator then output a clock edge.

    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;
    

    For this ratio I think the smallest way you can represent it is 2000/1007.

    The trouble with this is that you'll get a clock that's basically 25MHz, but occasionally (each 2000 / 7 iterations) you'll get an extra edge. It won't be a 25.175MHz clock. Getting 25.175MHz from 50MHz is impossible without a PLL.