Search code examples
countvhdlcountersecondsminute

VHDL Pulse counter in one second and in one minute


I am at the very beginning of Learning VHDL and I am have a lot of insecurity on how to procede.

I am not sure if I am doing it right or if there is something wrong because my understanding of the topic is still very partial. I am trying to learn.

MY PROBLEM:

I am trying to make a pulse counter in VHDL with:

  • a 1 bit Pulse_In input;
  • a 1-bit Clock input that receives a 1000 Hz clock signal;
  • two Pulse sec outputs, Pulse _min, each of 16 bits.

I need to count the number of pulses (counting rising edges) that appear at the Pulse_In input. On the Pulse_sec output, I will have the number of pulses in one seconds, while on Pulse_min, the number of pulses in the last minute. And the output needs to be updated at the end of every second.

MY ATTEMPT (MAYBE WRONG I DO NOT KNOW):

-- clock --

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

entity clock_gen is
  port(clock: out bit);
end entity

architecture behav of clock_gen is
  constant frequency: integer:= 1000;
  constant period: time:= 1000ms/frequency;
begin 
 clock: process
 begin 
   clock <= ‘0’,’1’ after period/2;
   wait for period;
 end process clock;
end architecture;

-- counter --

entity PulseCounter is
  port(Pulse_in: in bit;
       Clock: in bit;
       Pulse_sec, Pulse_min: out integer range 15 to 0);
end entity

architecture my_counter of PulseCounter is
  begin
    process
      var seconds: integer:=0;
    begin
      if (Clock='1' and Clock'last_value='0') then
        if (Pulse_in='1' and seconds/=59) then
           Pulse_sec = Pulse_sec + 1;
           Pulse_min = Pulse_min + Pulse_sec;
           seconds = seconds + 1;
        end if;
      end if;
      wait on Clock;
    end process;
end architecture;

                  

-- I am not sure if the entity is correct, given the data above --

-- I do not know if my process is correct --


Solution

  • When writing vhdl you have the actual entity that you want to write and a "testbench" for that entity. The testbench is another vhdl entity with the only purpose to act as a test environment for the entity that you want to write. Without the testbench you end up asking questions like this on SO because you do not have a way of verifying yourself if your design does what it is supposed to do.

    The part of your attempt that generates the clock belongs into the testbench entity since in a real-world example the clock is supplied by some oscillator to the FPGA/ASIC where your vhdl design is implemented. In the testbench entity, you only simulate the existence of this clock. Statements like "period: time:= 1000ms/frequency;" and "clock <= ‘0’,’1’ after period/2;" will not be synthesisable since there is no concept of "1000ms" anymore once you want to actually implement this in an FPGA/ASIC. (synthesisable vhdl is a subset of legal vhdl. In testbenches you can use everything that is legal vhdl since it will never be implemented on a device. For the entity under test you should stick to synthesisable vhdl)

    You should start with 2 separate files. The testbench and your PulseCounter

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity my_counter_tb is
    end entity;
    
    architecture rtl of my_counter_tb is
      constant frequency: integer:= 1000;
      constant period: time:= 1000 ms/frequency;
      signal clock : std_logic := '0';
      signal Pulse_in : std_logic;
      signal Pulse_sec, Pulse_min : std_logic_vector(15 downto 0);
    begin
    
     label_that_is_not_clock_since_clock_is_already_a_signal: process
     begin 
       clock <= '0','1' after period/2;
       wait for period;
     end process;
    
    pulsecounter_inst: entity work.PulseCounter
      port map (
        Pulse_in  => Pulse_in,
        Clock     => Clock,
        Pulse_sec => Pulse_sec,
        Pulse_min => Pulse_min
      );
    
    -- write a process here that does something with Pulse_in 
    
    end architecture;
    

    and

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity PulseCounter is
      port(Pulse_in: in std_logic;
           Clock: in bit;
           Pulse_sec, Pulse_min: out integer range 15 to 0);
    end entity;
    
    architecture rtl of PulseCounter is
      begin
    
      -- your counter implementation
    
    end architecture;
    

    Then you plug these two files into some vhdl simulator and can test the behaviour of your vhdl design yourself, find out where the syntax errors are and so on. (For example Modelsim, ghdl, Questa, Aldec, edaplayground, ... whatever is used in your class)

    A few obvious problems with your code from above:

    • insert a space between 1000 and "ms"
    • integer range 15 downto 0 means you can have integer numbers of max. 15. What you actually want is a signal of 16 bits (std_logic_vector(15 downto 0))
    • your process should have the clock in the sensitivity list and I would go for if (rising_edge(clock)) then .. afterwards
    • you cannot read from Pulse_sec since it is an output (Pulse_sec = Pulse_sec + 1; will not work)
    • avoid variables. There is no reason "seconds" needs to be a variable here. Generally as a beginner don't use variables unless you know exactly why you need it