Clock

The purpose of this documentation is to demonstrate the implementation of a clock using VHDL.

The clock is designed in such a way that user can input the time digit by digit using a keypad after it is reset.  When the clock is reset, 00:00 is displayed.  The clock is in 24-hour format.  If the user enters an invalid digit, he/she will be asked to enter that digit again.  Furthermore, if the correct input is received, the number will be echoed on the display so that the user can see his/her input.  For instance, if the user enter a "3" for the tenth digit of hour, "0" is still displayed.  However, if "2" is input for the tenth digit of the hour, "2" will be displayed on the clock.  The clock will be running if all four digits are input correctly.  The above functions are done by finite state machine using VHDL.  The complete VHDL codes are as follow:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
entity clock2 is    -- the clock is in h2 h1 : m2 m1
port (
  clk1, reset : in std_logic;
  keypad : in std_logic_vector (3 downto 0);
  enter : in std_logic;
  normal_op : out std_logic;
  cur_time : out std_logic_vector (15 downto 0)
);
end clock2;
-- clk - external clock
-- keypad input to set time
-- enter - signal when any key is pressed from keypad
-- normal_op - when the clock is operation in normal mode
-- cur_time - current time of the clock
 
architecture behavioural of clock2 is
 
-- using clock_inc1 to increment clock
component clock_inc2
port (
  clock :in std_logic;
  reset : in std_logic;
  h2i, h1i, m2i, m1i : in std_logic_vector(3 downto 0) ;
  h2o, h1o, m2o, m1o : out std_logic_vector(3 downto 0) := "0000";
  clock_go  : in std_logic
);
end component;
 
signal clock_go : std_logic := '0'; -- indication of running of the clock
type state_type is (normal, reset_state, enter_h2, enter_h1, enter_m2, enter_m1,
                    wait1, wait2, wait3, sub_normal);
signal next_state : state_type;
signal h2, h1, m2, m1 : std_logic_vector(3 downto 0) := "0000";
signal h2o, h1o, m2o, m1o : std_logic_vector(3 downto 0) := "0000";  -- output time
 
begin
 
time :  clock_inc2 port map
 (clock => clk1,
  reset => reset,
  h2i => h2,
  h1i => h1,
  m2i => m2,
  m1i => m1,
  h2o => h2o,
  h1o => h1o,
  m2o => m2o,
  m1o => m1o,
  clock_go => clock_go);
 
FSM : process (clk1, reset)
  begin
    if (reset = '1') then -- when reset, change cur_time to "00:00" first
                          -- and allow user to input time
      next_state <= reset_state;
      normal_op <= '0';
      clock_go <= '0';
      cur_time <= "0000000000000000";
 
    elsif clk1 = '1' and clk1'event then
      case next_state is
 
        when reset_state =>   -- wait for h2 input
          normal_op <= '0';
          clock_go <= '0';
          if (enter = '1' and keypad <= 2) then
            h2 <= keypad;
            cur_time(15 downto 12) <= keypad;
            next_state <= Enter_h2;
          end if;
 
        when enter_h2 =>
          if enter = '0' then
            next_state <= wait1;
          end if;
 
        when wait1 =>
          if (enter = '1' and h2 = 2 and keypad <= 3) then  -- wait for h1 input
            next_state <= Enter_h1;
            h1 <= keypad;
            cur_time (11 downto 8) <= keypad;
          elsif (enter = '1' and h2 /= 2) then
            next_state <= Enter_h1;
            h1 <= keypad;
            cur_time (11 downto 8) <= keypad;
          end if;
 
        when enter_h1 =>
          if enter = '0' then
            next_state <= wait2;
          end if;
 
        when wait2=>
          if (enter = '1' and keypad <= 5) then  -- wait for m2 input
            next_state <= Enter_m2;
            m2 <= keypad;
            cur_time(7 downto 4) <= keypad;
          end if;
 
        when enter_m2 =>
          if enter = '0' then
            next_state <= wait3;
          end if;
 
        when wait3 =>
          if enter = '1' then       -- wait for m1 input
          next_state <= Enter_m1;
          m1 <= keypad;
          cur_time(3 downto 0) <= keypad;
        end if;
 
        when enter_m1 =>
          if enter = '0' then
            next_state <= sub_normal;
            normal_op <= '1';
            clock_go <= '1';
          end if;
 
        when sub_normal =>        -- delay one clk cycle
          next_state <= normal;
 
        when normal =>         -- pass incrmented time to cur_time
          cur_time(15 downto 12)<= h2o;
          cur_time(11 downto 8)<= h1o;
          cur_time(7 downto 4)<= m2o;
          cur_time(3 downto 0)<= m1o;
          h2 <= h2o;
          h1 <= h1o;
          m2 <= m2o;
          m1 <= m1o;
 
      end case;
    end if;
  end process FSM;
 
end behavioural;
 

The clock uses clock_inc2 entity to increment time. The characteristic of this entity is that it uses the clock frequency to count 60 seconds and then it increments the time. Therefore, this entity can use any clock frequency as long as within maximum clock frequency. The only thing need to be changed is count1 in the conditional statement (highlighted in blue in the codes).

 
Count1 = clock frequency * 60 - 3
 

When the count1 has reached ?clock frequency * 60 -3?, it will increment the time by one minute. Aftermath, it will check the constraints and then pass the incremented time to clock2 entity. The complete VHDL codes are as follows:

 
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned;
use ieee.std_logic_unsigned."+";
use ieee.std_logic_unsigned.">=";
 
entity clock_inc2 is
port (
  clock :in std_logic;
  reset : in std_logic;
  h2i, h1i, m2i, m1i : in std_logic_vector(3 downto 0) ;
  -- time inputs from entity clock
  h2o, h1o, m2o, m1o : out std_logic_vector(3 downto 0) := "0000";
  -- time output to entity clock
  clock_go : in std_logic
  -- increment clock when it is high
);
end clock_inc2;
-- clk - external clock
-- reset - drives system to startup state
 
 
architecture behavioural of clock_inc2 is
 
type state_type is (a,b,c,d);
signal clock_state, next_state :state_type;
 
begin
 
decision_maker : process(clock, next_state, reset)
  variable count1 : std_logic_vector(6 downto 0) := "0000000";
  variable h1t, m2t, m1t : std_logic_vector(3 downto 0) := "0000";
  begin
 
    if reset = '1' then  -- clock_state goes to state c when reset
      clock_state <= c;
    elsif clock ='1' and clock'event then
      case clock_state is
 
    when a=>
      if count1 = "1110101" then  -- clock frequency * 60 - 3
                                &nbs p; -- in binary format
        clock_state <= b;
        if m1t = "1010" then                    -- is m1t 10?
          m1o <= "0000";                        -- if so, store "0000" into m1o
          if m2t = "0110" then                    -- is m2t 6?
            m2o <= "0000";                         -- if so, store "0000" into m2o
            if(h1t = "0100" and h2i = "0010") then  -- is h1t 2 and is h2i 4?
              h1o <= "0000";                         -- store "0000" into h1o
              h2o <= "0000";                         -- store "0000" into h2o
            elsif(h1t = "1010") then                -- is h1t 10?
              h1o <= "0000";                         -- if so store "0000" into h1o
              h2o <= h2i + "0001";                   -- and increment h2o by 1
            else
              h1o <= h1t;                            -- if not, store the old values
              h2o <= h2i;
            end if;
          else
            m2o <= m2t;                             -- change m2o if m1t is 10
            h1o <= h1i;
            h2o <= h2i;
          end if;
        else
          m1o <= m1t;                              -- change m10 if m1t is not 10
          m2o <= m2i;
          h1o <= h1i;
          h2o <= h2i;
        end if;        
      else
        count1 := count1 + '1';
      end if;
 
    when b =>
      clock_state <= d;
 
    when d =>
      m1t := m1i + '1';
      m2t := m2i + '1';
      h1t := h1i + '1';
      count1 := "0000000";
      clock_state <= a;
 
    when c =>
      if clock_go = '1' then -- store input
        h2o <= h2i;
        h1o <= h1i;
        m2o <= m2i;
        m1o <= m1i;
        clock_state <= b;
      end if;
 
    end case;
  end if;
end process decision_maker;
 
end behavioural;
 

This is the complete implementation of the clock in our project and it is very easy for future EE552 students to use. Our clock can be run under different frequencies by changing a line of code in clock_inc2 entity as I mentioned above. I think it will be very simple to be applied in different projects.



Last Update: April 9, 1998
By Yat Lai, Ritchie Poon, Allen Ong
email: yat@ee.ualberta.ca