How to program an FPGA to output a square clock signal with a variable frequency and with two non-overlapping clock signals.
I was having troubles to generate a non-overlapping signal with 2 standard wave generators. They could not be synchronized to generate 2 square oscillations with an interlock delay between them.
–> The relatively fast solution was to program an FPGA with a customized HDL code to generate the exact clock I wanted.
But later I think on the CODE-REUSE idea and decided to create something generic that can be adapted to different purposes. So, any of my workmates or any person who is reading this can make their own clock quickly. Sharing is caring! 🙂
I utilized the Spartan-3 FPGA, but any FPGA could be used.
Let’s start!
Â
The Code for the FPGA
The simple VHDL oscillator
The VHDL code for a simple functional clock generator:
- Fixed frequency with adjusting MAX value (only changeable by loading the bitstream to the FPGA)
- non-overlapping clock
--------------------------------- -- Company: MisCircuitos.com -- Engineer: Alberto Lopez -- alberto@miscircuitos.com -- WWW.MISCIRCUITOS.COM -- Create Date: 12:09:49 06/18/2020 -- Module Name: oscillator- Behavioral -- Description: Frequency divider with interlock delay time -- OUTPUTS -- --> 2 signals with clk and clkn (non-overlapping) ----------------------------------------------------------------------------------library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all; entity oscillator is generic( MAX: unsigned (7 downto 0) := "01000000" ); port( clock50M: in std_logic; --internal clock input reset: in std_logic; clk: out std_logic; clkn: out std_logic ); end oscillator; architecture Behavioral of oscillator is --signals signal counter: unsigned (15 downto 0); signal counter_d: unsigned (15 downto 0); signal clk_sig: std_logic; signal clkn_sig: std_logic; signal clk_sig_d: std_logic; signal clkn_sig_d: std_logic; signal interlock: std_logic; signal interlock_d: std_logic; begin p_combinatorial : process (counter, clk_sig, clkn_sig, interlock) begin if(counter = MAX) then counter_d <= (others => '0'); interlock_d <= '1'; if(clk_sig ='0') then clk_sig_d <= '1'; clkn_sig_d <= '0'; else clk_sig_d <= '0'; clkn_sig_d <= '1'; end if; elsif (interlock = '0') then counter_d <= counter + 1; clk_sig_d <= clk_sig; clkn_sig_d <= clkn_sig; interlock_d <= '0'; else counter_d <= counter; clk_sig_d <= clk_sig; clkn_sig_d <= clkn_sig; interlock_d <= '0'; end if; end process; p_clock: process( clock50M, reset ) begin if(reset = '0') then --RESET counter <= (others => '0'); clk_sig <= '0'; clkn_sig <= '1'; interlock <= '0'; elsif(clock50M'event and clock50M= '1') then counter <= counter_d; clk_sig <= clk_sig_d; clkn_sig <= clkn_sig_d; interlock <= interlock_d; end if; end process; clk <= clk_sig and not(interlock); clkn <= clkn_sig and not(interlock); end Behavioral;
Configurable VHDL clock generator
The full VHDL code for a variable functional clock:
- Configurable frequency with 7 external switches of the FPGA
- Optional of non-overlapping clock or normal clock with a switch
In the following simulation waveform, you can see the non-overlapping functionality changing with the input switch “sw_interlock”.

The configurable frequency is demonstrated in the following waveform diagram:

---------------------------------------------------------------------------------- -- Company: MisCircuitos.com -- Engineer: Alberto Lopez -- alberto@miscircuitos.com -- WWW.MISCIRCUITOS.COM -- Create Date: 10:09:49 06/18/2020 -- Module Name: clock - Behavioral -- Description: Frequency divider with interlock --inputs -- -->1 switch is for enable or disable the non-overlapping function -- -->7 switch to program or select the frequency divider -- OUTPUTS -- --> 2 signals with clk and clkn ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all; entity clock is generic( MAX: unsigned (7 downto 0) := "01000000" ); port( clock50M: in std_logic; --internal clock input reset: in std_logic; sw_interlock: in std_logic; sw: in std_logic_vector (6 downto 0); clk: out std_logic; clkn: out std_logic ); end clock; architecture Behavioral of clock is --signals signal counter: unsigned (7 downto 0); signal counter_d: unsigned (7 downto 0); signal clk_sig: std_logic; signal clkn_sig: std_logic; signal clk_sig_d: std_logic; signal clkn_sig_d: std_logic; signal clk_sig_inter: std_logic; signal clkn_sig_inter: std_logic; signal interlock: std_logic; signal interlock_d: std_logic; signal input_freq: unsigned (7 downto 0); begin input_freq <= unsigned(sw)& '0'; p_combinatorial : process (counter, clk_sig, clkn_sig, interlock, input_freq) begin if(counter = input_freq) then counter_d <= (others => '0'); interlock_d <= '1'; if(clk_sig ='0') then clk_sig_d <= '1'; clkn_sig_d <= '0'; else clk_sig_d <= '0'; clkn_sig_d <= '1'; end if; elsif (interlock = '0') then counter_d <= counter + 1; clk_sig_d <= clk_sig; clkn_sig_d <= clkn_sig; interlock_d <= '0'; else counter_d <= counter; clk_sig_d <= clk_sig; clkn_sig_d <= clkn_sig; interlock_d <= '0'; end if; end process; p_clock: process( clock50M, reset ) begin if(reset = '1') then --RESET counter <= (others => '0'); clk_sig <= '0'; clkn_sig <= '1'; interlock <= '0'; elsif(clock50M'event and clock50M= '1') then counter <= counter_d; clk_sig <= clk_sig_d; clkn_sig <= clkn_sig_d; interlock <= interlock_d; end if; end process; p_interlock: process(counter, clk_sig, clkn_sig, interlock, sw_interlock) begin if(sw_interlock = '1') then clk_sig_inter <= clk_sig and not(interlock); clkn_sig_inter <= clkn_sig and not(interlock); else clk_sig_inter <= clk_sig; clkn_sig_inter <= clkn_sig; end if; end process; clk <= clk_sig_inter; clkn <= clkn_sig_inter; end Behavioral;
The Test Bench
If you want to test the code, I created a simple Vivado block diagram with a Stimuli RTL as follows:

I explain in this other article how to create a general-purpose test bench in Vivado. Also the VHDL for the Stimuli can be found here:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity Stimu is Port ( tb_clock50 : out std_logic; tb_reset : out std_logic; tb_sw_overlap: out std_logic; tb_sw: out std_logic_vector (6 downto 0) ); end Stimu; architecture Behavioral of Stimu is constant clock50: time := 20 ns; -- clock constant begin -- Clock clock50M_process: process begin tb_clock50 <= '0'; wait for clock50/2; tb_clock50 <= '1'; wait for clock50/2; end process; -- Switches simulator switches: process begin tb_sw <= (others => '0'); wait for 1ns; tb_sw <= "0000001"; wait for 5us; tb_sw <= "0000010"; wait for 15us; tb_sw <= "0000011"; wait for 10us; tb_sw <= "0100000"; wait for 22us; tb_sw <= "1000000"; wait for 22us; tb_sw <= "0000100"; wait for 15us; tb_sw <= "0000100"; wait for 15us; tb_sw <= "1111000"; wait for 10us; tb_sw <= "0100000"; wait for 22us; tb_sw <= "1000000"; wait for 22us; wait; end process; --overlap p_overlap: process begin tb_sw_overlap <= '0'; wait for 100us; tb_sw_overlap <= '1'; wait; end process; -- Reset stim_proc: process begin tb_reset <= '0'; wait for 100 ns; tb_reset <= '1'; wait for clock50*10; wait; end process; end Behavioral;
Test on the oscilloscope
I hope this was useful to you!!
Let me know in the comments below if it is working for you or if you have any question or suggestion.