Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> VHDL

Build a Reliable Timer in VHDL: Counting Clock Cycles to Hours

In earlier tutorials we used the wait for statement to delay time in simulation. However, wait for cannot be employed in production designs because a real circuit cannot be instructed to pause. The practical way to measure time in a VHDL module is to count clock cycles.

Every digital design has access to a stable clock signal that oscillates at a known frequency. If the clock runs at 100 MHz, one second equals 100 million clock ticks. By counting these ticks we can reliably generate seconds, minutes, hours, and beyond.

This article is part of the Basic VHDL Tutorials series.

We implement a counter that increments on every rising edge of the clock. When the counter reaches the clock frequency value, one second has elapsed and a secondary “Seconds” counter is incremented. A similar approach is used for minutes (increment after 60 seconds) and hours (increment after 60 minutes). Additional counters can be chained for days, weeks, or months, limited only by FPGA/ASIC resources and the required counter width.

While longer counters consume more logic resources, they also increase propagation delay. The critical path through the counter chain must fit within the clock period, otherwise synthesis will fail.

Exercise: Implementing the Timer

The following VHDL testbench demonstrates a simple 10 Hz clock to keep simulation time reasonable. The DUT is a timer that outputs Seconds, Minutes, and Hours signals.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T18_TimerTb is
end entity;

architecture sim of T18_TimerTb is

    -- Slow clock for fast simulation
    constant ClockFrequencyHz : integer := 10; -- 10 Hz
    constant ClockPeriod      : time := 1000 ms / ClockFrequencyHz;

    signal Clk     : std_logic := '1';
    signal nRst    : std_logic := '0';
    signal Seconds : integer;
    signal Minutes : integer;
    signal Hours   : integer;

begin

    -- Device Under Test (DUT)
    i_Timer : entity work.T18_Timer(rtl)
        generic map(ClockFrequencyHz => ClockFrequencyHz)
        port map (
            Clk     => Clk,
            nRst    => nRst,
            Seconds => Seconds,
            Minutes => Minutes,
            Hours   => Hours);

    -- Clock generator
    Clk <= not Clk after ClockPeriod / 2;

    -- Testbench sequence
    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);

        -- Release reset
        nRst <= '1';

        wait;
    end process;

end architecture;

Below is the timer module itself. It counts ticks, seconds, minutes, and hours, resetting all counters when the negative reset (nRst) is asserted.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T18_Timer is
    generic(ClockFrequencyHz : integer);
    port(
        Clk     : in std_logic;
        nRst    : in std_logic; -- Negative reset
        Seconds : inout integer;
        Minutes : inout integer;
        Hours   : inout integer);
end entity;

architecture rtl of T18_Timer is

    -- Count clock periods
    signal Ticks : integer;

begin

    process(Clk) is
    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                Ticks   <= 0;
                Seconds <= 0;
                Minutes <= 0;
                Hours   <= 0;
            else
                if Ticks = ClockFrequencyHz - 1 then
                    Ticks <= 0;
                    if Seconds = 59 then
                        Seconds <= 0;
                        if Minutes = 59 then
                            Minutes <= 0;
                            if Hours = 23 then
                                Hours <= 0;
                            else
                                Hours <= Hours + 1;
                            end if;
                        else
                            Minutes <= Minutes + 1;
                        end if;
                    else
                        Seconds <= Seconds + 1;
                    end if;
                else
                    Ticks <= Ticks + 1;
                end if;
            end if;
        end if;
    end process;

end architecture;

Waveforms confirm the correct operation: Seconds increments every tick, Minutes after 60 seconds, and Hours after 60 minutes.

In simulation we ran a 50‑hour test with run 50 hr in ModelSim, using a 10 Hz clock to keep runtime manageable. Adjusting the clock frequency in the testbench is a common strategy to accelerate verification.

In real hardware, the counter chain must finish within one clock period. As the counter width grows, propagation delay increases, potentially exceeding the period and causing timing violations. The exact limit depends on the FPGA/ASIC family and clock speed.

Key Takeaways

Proceed to the next tutorial for advanced timer features.

VHDL

  1. Creating String Lists in VHDL: Best Practices & Example
  2. Implementing a PWM Controller in VHDL: Design, Simulation, and FPGA Demo
  3. Designing a Robust VHDL Ring Buffer FIFO in Block RAM
  4. Implementing a Dynamic Linked List in VHDL with Protected Types and Access Pointers
  5. Mastering VHDL Functions: A Practical Guide to Efficient Design
  6. Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example
  7. Building a Clock‑Triggered Process in VHDL: A Practical Guide
  8. Mastering Concurrent Statements in VHDL: A Practical Guide
  9. Mastering std_logic_vector: Creating Signal Vectors in VHDL
  10. Using Sensitivity Lists in VHDL Processes for Reliable RTL Design