How to Measure Pulse Duration Using VHDL

The Classical Method

As you know, the classical method to measure a pulse characteristic is to use an oscilloscope. The oscilloscope can measure amplitude, width, frequency, and many other pulse characteristics, as shown in Figure 1. Many times we do not have an oscilloscope, or we don’t have access to the signal we want to measure.

Figure 1 – Pulse characteristics

Figure 1 – Pulse characteristics

For example, if you want to measure a pulse inside your FPGA, it could be difficult. In this case, you don’t need to know the amplitude of the pulse: it is a digital signal that can get the values ‘0’ or ‘1’.

The amplitude depends on the technology you are using, and it is guaranteed by the FPGA vendors. For instance, modern FPGA cores work at 0.9 V. As you can imagine, the high and low levels of a pulse will be different from what you can probe on an FPGA pin. Anyway, you can output the signal and use a scope, but if you need to measure a pulse on equipment inside a rack, it could be a problem.

Designing the Pulse Width Measurement Circuit in FPGA

Remember you have an FPGA (Field Programmable Gate Array); you can use a small part of its logic gates to implement a simple circuit that provides the required pulse measurement.

Figure 2 – FPGA circuit for pulse length measurement

Figure 2 – FPGA circuit for pulse length measurement

In pulse measurement, we need to detect the rising and falling edges of the pulse itself. Figure 2 shows how to measure the HIGH and LOW levels of the pulse:

  • HIGH phase measurement is between the rising and falling edge.
  • LOW phase measurement is between the falling and rising edge.

As you can see, it is very simple to implement a design capable of computing the measurement:

  • edge detector
  • a counter for HIGH phase
  • a counter for LOW phase
  • simple control logic

The HIGH phase counter will start on a rising edge and stop counting on a falling edge.

The LOW phase counter will start on a falling edge and stop counting on a rising edge.

Real-World Considerations: Synchronization and Resolution

Before diving into the VHDL code, we must consider two crucial real-world details for this implementation:

Metastability and Synchronization: If the pulse you want to measure comes from an external, asynchronous source (like a mechanical switch or another board), you cannot feed it directly into your synchronous edge detector. You must first synchronize the signal to your FPGA clock domain using a classic double flip-flop synchronizer. This prevents metastability issues from corrupting your logic.

Measurement Resolution: The precision of this measurement technique is strictly tied to your FPGA clock frequency. For instance, if your system clock runs at 100 MHz, your counter resolution is 10 ns. Any pulse duration variation shorter than a single clock cycle cannot be reliably measured with this synchronous approach.

The interactive simulation below demonstrates both concepts: click the button to generate a pulse and watch how the synchronized signal (in green) follows the external pulse (in yellow) after a 2-clock-cycle delay, while the counters track the HIGH and LOW phase durations.

Pulse Measurement Simulator

FPGA Pulse Measurement Logic

Interactive simulation of synchronous edge detection and counting

High Phase Counter
0
Low Phase Counter
0

VHDL Implementation of the Pulse Duration Counter

A possible VHDL implementation of a pulse length counter is reported below:

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

entity pulse_len_measure is
generic (
  N                           : integer:=8);
port (
  i_clk                       : in  std_logic;
  i_rstb                      : in  std_logic;
  i_input                     : in  std_logic;
  o_pulse_len_hi              : out std_logic_vector(N-1 downto 0);
  o_pulse_len_lo              : out std_logic_vector(N-1 downto 0));
end pulse_len_measure;

architecture rtl of pulse_len_measure is
constant C_MAX_COUNT           : unsigned(N-1 downto 0):=(others=>'1');
signal r_count_hi_ena          : std_logic;
signal r_count_hi              : unsigned(N-1 downto 0);
signal r_count_lo              : unsigned(N-1 downto 0);
signal r_count_lo_ena          : std_logic;
signal r_rise                  : std_logic;
signal r_fall                  : std_logic;
signal p_input                 : std_logic_vector(0 to 2); -- input pipe

begin

p_edge_detector : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    r_rise       <= '0';
    r_fall       <= '0';
    p_input      <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    r_rise       <= not p_input(2) and p_input(1);
    r_fall       <= not p_input(1) and p_input(2);
    p_input      <= i_input&p_input(0 to p_input'length-2);
  end if;
end process p_edge_detector;

p_count_hi : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    r_count_hi_ena  <= '0';
    r_count_hi      <= to_unsigned(1,N);
    o_pulse_len_hi  <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    if(r_rise='1') then
      r_count_hi_ena  <= '1';
    elsif(r_fall='1') then
      r_count_hi_ena  <= '0';
      o_pulse_len_hi  <= std_logic_vector(r_count_hi);
    end if;

    if(r_count_hi_ena='1') then
      if(r_count_hi<C_MAX_COUNT)then
        r_count_hi      <= r_count_hi + 1;
      end if;
    else
      r_count_hi      <= to_unsigned(1,N);
    end if;
  end if;
end process p_count_hi;

p_count_lo : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    r_count_lo_ena  <= '0';
    r_count_lo      <= to_unsigned(1,N);
    o_pulse_len_lo  <= (others=>'0');
  elsif(rising_edge(i_clk)) then
    if(r_fall='1') then
      r_count_lo_ena  <= '1';
    elsif(r_rise='1') then
      r_count_lo_ena  <= '0';
      o_pulse_len_lo  <= std_logic_vector(r_count_lo);
    end if;

    if(r_count_lo_ena='1') then
      if(r_count_lo<C_MAX_COUNT) then
        r_count_lo      <= r_count_lo + 1;
      end if;
    else
      r_count_lo      <= to_unsigned(1,N);
    end if;
  end if;
end process p_count_lo;

end rtl;

VHDL Simulation and Saturation Logic

In the VHDL code, we introduced saturation in length counting. This implementation avoids counter wrapping, so if you read the maximum value on one of the two counters, you can deduce that the computed length has saturated the counter’s capacity.

Figure 3 – VHDL code simulation for a pulse length HI= 156 clock cycles, LO = 100 clock cycles

Figure 3 – VHDL code simulation for a pulse length HI= 156 clock cycles, LO = 100 clock cycles

Figure 4 – VHDL code simulation for a pulse length HI= saturated, LO = 100 clock cycles

Figure 4 – VHDL code simulation for a pulse length HI= saturated, LO = 100 clock cycles

In the simulation, we tested two conditions: when the counter is not saturated (Figure 3), and when the HIGH pulse exceeds the counter capability (Figure 4).

How to Measure Pulse Duration Using VHDL

Get the complete VHDL code from this article.

Hardware Implementation Video

In the video, you can see an implementation of the pulse length counter on a DE0 Altera board.

Figure 5 – Pulse length counter implementation on DE0 Altera board

Figure 5 – Pulse length counter implementation on DE0 Altera board

To demonstrate how the counters work, we use the 7-segment display provided by the DE0 board to output the counting value. The pulses are generated using the push buttons on the board; therefore, the HIGH and LOW pulse length values are “human-generated” and will be in the order of seconds.

In this case, to measure the length using only 8 bits of the 7-segment display, we need to slow down the clock of the pulse counter, as you can see in the video.