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
- Time measurement in VHDL is achieved by counting clock cycles.
- Lowering the testbench clock frequency speeds up simulation without altering the design.
Proceed to the next tutorial for advanced timer features.
VHDL
- Creating String Lists in VHDL: Best Practices & Example
- Implementing a PWM Controller in VHDL: Design, Simulation, and FPGA Demo
- Designing a Robust VHDL Ring Buffer FIFO in Block RAM
- Implementing a Dynamic Linked List in VHDL with Protected Types and Access Pointers
- Mastering VHDL Functions: A Practical Guide to Efficient Design
- Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example
- Building a Clock‑Triggered Process in VHDL: A Practical Guide
- Mastering Concurrent Statements in VHDL: A Practical Guide
- Mastering std_logic_vector: Creating Signal Vectors in VHDL
- Using Sensitivity Lists in VHDL Processes for Reliable RTL Design