Search code examples
vhdlquartus

Simulation blinking LED using VHDL with Quartus II and ModelSim


I'm new to VHDL, Quartus II and ModelSim. Now I'm doing a lab where we are constructing a blinking LED. How should simulation be handled when the construction deals with relatively long time periods. The frequency of the blinking LED is 1 Hz and the clock on the dev board I'm using (Terasic DE2-115) is 50 MHz. In the code I'm counting the clock pulses and turn on the LED accordingly. However, when I want to verify my code with ModelSim, I get in to troubles dealing with times as long as seconds. So I solved it just by changing the period in the code to a couple of clock cycles to see that the waves behave as expected. For final compilation, I just change the count value that corresponds to 1 second.

But there should be a better way. I don't really want to touch the VHDL code after simulation. Should I use two rtl's, one for synthesis and one for simulation when dealing with time periods approaching 1 ms and higher?

The VHDL code

library ieee;
use ieee.std_logic_1164.all;
entity lab4 is
port(   CLOCK_50 : in std_logic; -- DE2-115 internal clock
KEY      : in std_logic_vector(0 downto 0);   -- Push-buttons, active 0
                                                -- KEY(0) as reset
LEDG     : out std_logic_vector(7 downto 0)); -- Green LEDs
end entity lab4;

architecture lab4_rtl of lab4 is
signal RESET_N : std_logic;
begin

-- Parallel VHDL
constant CLK_FRQ : integer := 50000000;

RESET_N <= KEY(0); -- Here we connect reset to a push-button

-- synch process with asynch reset, i.e. reset as soon as reset is active
p1 : process(CLOCK_50, RESET_N)
variable counter : integer := 0;
variable led_num : integer := 0;
begin

    -- reset part
    if RESET_N = '0' then --KEY is active 0
        counter := 0;      --reset counter 
        LEDG(0) <= '0';    --turn OFF leds

    -- synch part, updates depending on clock
    elsif rising_edge(CLOCK_50) then

        counter := counter + 1; 

        if counter < 50000000 then;
            LEDG(0) <= '1';
        elsif counter >= 50000000 AND counter < 100000000 then
            LEDG(0) <= '0';
        else
            counter := 0;
        end if;
    end if;

 end process p1;

end architecture lab4_rtl;

Solution

  • You have declared a named constant, then ignored it...

    constant CLK_FRQ : integer := 50000000;
    

    First you can rewrite the counter in terms of CLK_FRQ and CLK_FRQ * 2 instead of magic numbers.

    Then you can set different values for CLK_FRQ in sim and synth. There are various ways to do it but my preference is for a function.

    function Clock_Frequency return natural is
    begin
      -- synthesis translate_off
      return 50;
      -- synthesis translate_on
      return 50000000;
    end Clock_Frequency;
    

    It uses the "magic" pragmas translate_off (and _on) which may vary between synthesis tools but are accepted by most. These direct synthesis to ignore bits of the source : in this case, the first Return which is only seen by the simulator.

    Now you can call this function to initialise the constant

    constant CLK_FRQ : integer := Clock_Frequency;
    

    Job done.