In FPGA designs, there are situations where you want a clock signal with a small frequency(or high time period). But in most of FPGA boards the frequency of the crystal oscillators available are of the range of tens of MHz.

One solution to the above problem is to take the high frequency clock available on board and convert it to a lower frequency clock. This is called frequency down conversion. I have shared a code here for a general purpose clock down converter.

The entity clk_gen takes a high frequency clock,

divide_value = (Frequency of Clk) / (Frequency of Clk_mod).

For example if you want to convert a 100 MHz signal into a 2 MHz signal then set the divide_value port as "50".

Without much further explanation I will give you the code:

One solution to the above problem is to take the high frequency clock available on board and convert it to a lower frequency clock. This is called frequency down conversion. I have shared a code here for a general purpose clock down converter.

The entity clk_gen takes a high frequency clock,

**Clk**and an integer value**divide_value**as inputs and produces the converted clock at**Clk_mod.**The divide_value is defined as follows:divide_value = (Frequency of Clk) / (Frequency of Clk_mod).

For example if you want to convert a 100 MHz signal into a 2 MHz signal then set the divide_value port as "50".

Without much further explanation I will give you the code:

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

entity clk_gen is

port( Clk : in std_logic;

Clk_mod : out std_logic;

divide_value : in integer

);

end clk_gen;

architecture Behavioral of clk_gen is

signal counter,divide : integer := 0;

begin

divide <= divide_value;

process(Clk)

begin

if( rising_edge(Clk) ) then

if(counter < divide/2-1) then

counter <= counter + 1;

Clk_mod <= '0';

elsif(counter < divide-1) then

counter <= counter + 1;

Clk_mod <= '1';

else

Clk_mod <= '0';

counter <= 0;

end if;

end if;

end process;

end Behavioral;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

entity clk_gen is

port( Clk : in std_logic;

Clk_mod : out std_logic;

divide_value : in integer

);

end clk_gen;

architecture Behavioral of clk_gen is

signal counter,divide : integer := 0;

begin

divide <= divide_value;

process(Clk)

begin

if( rising_edge(Clk) ) then

if(counter < divide/2-1) then

counter <= counter + 1;

Clk_mod <= '0';

elsif(counter < divide-1) then

counter <= counter + 1;

Clk_mod <= '1';

else

Clk_mod <= '0';

counter <= 0;

end if;

end if;

end process;

end Behavioral;

The testbench code used for testing the code is given below:

LIBRARY ieee;

USE ieee.std_logic_1164.ALL;

USE ieee.numeric_std.ALL;

ENTITY testbench IS

END testbench;

ARCHITECTURE behavior OF testbench IS

signal clk,clk_mod : std_logic;

signal divide_value : integer;

constant clk_period : time := 10 ns;

begin

-- Component Instantiation

uut: entity work.clk_gen PORT MAP(

clk => clk,

clk_mod => clk_mod,

divide_value => divide_value );

simulate : process

begin

divide_value <= 10; --divide the input clock by 10 to get 10(100/10) MHz signal.

wait for 500 ns;

divide_value <= 19; --divide the input clock by 19 to get 5.3(100/19) MHz signal.

wait;

end process;

clk_process :process --generates a 100 MHz clock.

begin

clk <= '0';

wait for clk_period/2; --for 5 ns signal is '0'.

clk <= '1';

wait for clk_period/2; --for next 5 ns signal is '1'.

end process;

END;

USE ieee.std_logic_1164.ALL;

USE ieee.numeric_std.ALL;

ENTITY testbench IS

END testbench;

ARCHITECTURE behavior OF testbench IS

signal clk,clk_mod : std_logic;

signal divide_value : integer;

constant clk_period : time := 10 ns;

begin

-- Component Instantiation

uut: entity work.clk_gen PORT MAP(

clk => clk,

clk_mod => clk_mod,

divide_value => divide_value );

simulate : process

begin

divide_value <= 10; --divide the input clock by 10 to get 10(100/10) MHz signal.

wait for 500 ns;

divide_value <= 19; --divide the input clock by 19 to get 5.3(100/19) MHz signal.

wait;

end process;

clk_process :process --generates a 100 MHz clock.

begin

clk <= '0';

wait for clk_period/2; --for 5 ns signal is '0'.

clk <= '1';

wait for clk_period/2; --for next 5 ns signal is '1'.

end process;

END;

**Note :-**The code was simulated and synthesised successfully using Xilinx Webpack version 13.1. It should work fine under other tools as well.

Again, as in previous posts, your code results in clocks being taken of the low-skew global clock paths in the device. This is bad and as the previous commenter pointed out, WILL give problems at high frequencies.

ReplyDeleteA better solution is to use a downsampled clock enable on your blocks. In this way the clock is still on the low-skew paths and you will make timing at high frequencies.

Very good post. Thanks again. For odd integer clock division the duty cycle isn't 50% though.

ReplyDeletehow can we write a code for the conversion of 1mhz to 1khz.

ReplyDeletedivide_value = (Frequency of Clk) / (Frequency of Clk_mod).

Deleteso divide_value = 1000000/1000 = 1000.

Hi, thanks for your examples.

ReplyDeleteI simplified your code and added reset signal as below:

architecture Behavioral of main is

signal clk_div : STD_LOGIC := '0';

signal scnt : INTEGER := 2;

begin

clk_div_proc: process(clk, rst)

variable count : INTEGER := 0;

begin

if rst = '1' then

clk_div <= '0';

count := 0;

elsif( rising_edge(clk) ) then

if(count < scnt/2-1) then

count := count + 1;

else

clk_div <= not clk_div;

count := 0;

end if;

end if;

end process;

end Behavioral;

Best regards.

Hi i have 48MHz clock frequency anda i have to conver it to 20 MHz.

ReplyDeleteBut 48/20= 2.4 so it is not an integer what can be done to do this?

Thanks for your help