Digital clock is a popular assignment topic for students of FPGA courses in universities. What I have shared here is a basic version of a digital clock. The clock will start ticking as soon as the FPGA is programmed with the bit file. There is no option to set the time or pause the clock etc.. But I believe, it is still a great code to learn many important VHDL topics. If you are looking for an advanced digital clock, then check out this digital clock with time setting feature.
What can you learn from this code?
If you are a beginner in VHDL, try to understand the following concepts used in this code.
- How to generate a low frequency clock from a high a frequency clock? For example how can you generate a 1 second clock from a 100 Mhz clock.
- How does nested if else's work in VHDL?
- When does signals get updated with their newly assigned values?
- How to write a testbench for your design?
- How to instantiate a VHDL component with entity instantiation and name association.
- How to use wait for statement in testbenches?
Without further ado, let me share the code for the simple digital clock.
digital_clock.vhd:
-- library declarations library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- entity declaration entity digital_clock is generic (CLOCK_FREQ : integer := 100_000_000); --system clock frequency is customizable via this generic
port (Clk : in std_logic; seconds : out unsigned(5 downto 0); --6 bit seconds output minutes : out unsigned(5 downto 0); --6 bit minutes output hours : out unsigned(4 downto 0) --5 bit hours output ); end digital_clock; architecture Behavioral of digital_clock is -- declaring internal signals signal sec,min,hour : integer range 0 to 60 :=0; signal count : integer :=1; signal clk_1sec : std_logic :='0'; begin --the internal signals are type casted from integer to unsigned type. seconds <= to_unsigned(sec,6); minutes <= to_unsigned(min,6); hours <= to_unsigned(hour,5); --generates a clock of period 1 second and duty cycle 50%. process(Clk) begin if(rising_edge(Clk)) then count <= count+1; if(count = CLOCK_FREQ/2) then --half way across the count, the clock is toggled. clk_1sec <= not clk_1sec; count <=1; end if; end if; end process; --increment and reset seconds, minutes and hours of the digital clock. process(clk_1sec) --period of clk_1sec is 1 second. begin if(rising_edge(clk_1sec)) then sec <= sec+ 1; if(sec = 59) then sec<=0; --seconds is reset to zero after it counts 60 times. min <= min + 1; --min is incremented when seconds count 60 times. if(min = 59) then hour <= hour + 1; --hours is incremented when minutes count 60 times. min <= 0; --minutes is reset to zero after it counts 60 times. if(hour = 23) then hour <= 0; --hours is reset to zero after it counts 24 times. end if; end if; end if; end if; end process; end Behavioral;
I believe that the code is well commented and needs no further explanation. If you dont understand something, feel free to leave a comment.
Remember the following points when using this design.
- Set the generic parameter, CLOCK_FREQ, with the frequency of the clock available in your FPGA.
- There are three unsigned output signals, one each for seconds, minutes and hours. They can be mapped to LED's on the board. If you want to display the values on seven segment displays on board, you would need to do few more steps. Check out this post for the same.
Testbench : tb_digital_clock.vhd
-- library declarations library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; --entity for testbench is always empty entity tb_digital_clock is end tb_digital_clock; architecture Behav of tb_digital_clock is --temporary signals, constants etc are declared here constant CLOCK_FREQ : integer := 100_000_000; --Frequency of the system clock. 100 Mhz is 1 followed by 8 zeros. --What does the below constant do? --Inside "System_Clock_Generation" process, we are waiting for 1 ns after incrementing count. --In one second, there are 10^9 "1 nanoseconds". --If the CLOCK_FREQ is high we dont need to wait too long before toggling the Clock signal. --Thats why we are dividing 10^9 by CLOCK_FREQ. constant CLOCK_COUNTS_IN_NS : integer := 1000_000_000/CLOCK_FREQ; --used for creating the clock with any frequency. signal Clock : std_logic := '0'; signal secs : unsigned(5 downto 0); signal mins : unsigned(5 downto 0); signal hrs : unsigned(4 downto 0); signal count : integer := 1; begin --This type of instantiation is known as "entity instantiation with name association" --Instantiating digital clock entity Digi_Clock : entity work.digital_clock --generic map(CLOCK_FREQ => CLOCK_FREQ) -- uncomment this line and comment next line for implementing on fpga. generic map(CLOCK_FREQ => 10) -- comment this line and uncomment above line for implementing on fpga. port map(Clk => Clock, seconds => secs, minutes => mins, hours => hrs); --generates a clock signal of frequency CLOCK_FREQ and duty cycle 50%. System_Clock_Generation : process begin if(count = CLOCK_COUNTS_IN_NS/2) then Clock <= not Clock; --toggle the clock signal after the count variable reaches mid point. count <= 1; else count <= count + 1; end if; wait for 1 ns; --wait for 1 nano second before going through the "process" again. end process; end Behav;
The testbench is well commented as well, so I will spare you from further explanations. The code was simulated using modelsim software. I have shared relevant parts of the simulation waveform below:

2 Comments
Nice code... But I only want to ask one ques, say i have to set clock manually. How will that can be done..
ReplyDeleteawsome! but how will it look like if i want the results to be displayed on the LCD
ReplyDelete