Estudante de engenharia eletrônica

  • 0 Posts
  • 10 Comments
Joined 1 year ago
cake
Cake day: June 17th, 2023

help-circle
  • @dejo Whoops, I made a mistake, you don’t need to include the entity when simulating. This line bellow should be the correct one:

    add wave -label "count" -radix unsigned /dut/count
    
    

    This is my .do file (when using Modelsim or Questa, change to the directory with all the .vhd files and the .do file and execute the command do tb.do):

    tb.do

    #Creates project's library
    vlib work
    
    #Compiles project with VHDL93 standard: all files used in the testbench. They should be compiled in order of dependency.
    vcom -93 Kitchen_Timer.vhd testbench.vhd
    
    #Simulates (work is the directory, tb_Kitchen_Timer is the entity's name).
    #The argument -voptargs="+acc" is necessary to disable signal optimization in Questa.
    vsim -voptargs="+acc" -t ns work.tb_Kitchen_Timer
    
    #Show waveforms.
    view wave
    
    #Add specific signals.
    # -radix: binary, hex, dec, unsigned.
    # -label: wave's name.
    add wave -label "clk" -radix binary /clk
    add wave -label "reset" -radix binary /reset
    add wave -label "start" -radix binary /start
    add wave -label "stop" -radix binary /stop
    add wave -label "adjust_interval_up" -radix binary /adjust_interval_up
    add wave -label "adjust_interval_down" -radix binary /adjust_interval_down
    add wave -label "alarm" -radix binary /alarm
    add wave -label "count" -radix unsigned /dut/count
    add wave -label "TbClock" -radix binary /TbClock
    add wave -label "TbSimEnded" -radix binary /TbSimEnded
    
    #Simulate for 1500 ns.
    run 1500ns
    
    # Zoom to fit entire window.
    wave zoomfull
    write wave wave.ps
    
    

    I’ve also included the simulation result.




  • @dejo

    Is the 1/60 Hz set somewhere or is it set in the code itself?

    You would set that on the testbench or on your synthesis code, but that is unnecessary, I only said that in case if you tested it on a actual FPGA. If you do that on your testbench, it would take a very long time to simulate.

    When you say that I must have an “alarming” signal on the simulation, is it actually this “alarm” signal that is presented on the simulation or?

    The alarm signal. The “alarming” is when the alarm signal is in a high logic state.

    And, do I need to have count signal in simulation?

    I wouldn’t say it’s mandatory, but it is a good addition to the simulation, keep it.



  • @dejo

    What do you think about the specifications that the project requires, should I stick to your code or should I add something from my own code?

    I would stick to my code, your alarm isn’t going to work properly due to its comparisons as I mentioned in my previous comments. But if you want to improve the code I modified, you can change the adjust_interval_up and adjust_interval_down buttons to be synchronized to their own states rather than the clock (make their own process with their signals added to the signal sensitivity list and add an extra asynchronous condition to zero the counter on the original process). If you don’t make a change like this your alarm is going to take up to an hour to adjust its timer range.

    Does your simulation correspond to a time of 1 hour and should there be alarming on the simulation?

    Yes, if you have a 1/60 Hertz clock signal. And you must have alarming on the simulation as it is crucial to show that it works.


  • @dejo I have made a few changes to your code:

    Kitchen_Timer.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity Kitchen_Timer is
        port
        (
            clk                  : in std_logic; -- Clock input
            reset                : in std_logic; -- Reset input
            start                : in std_logic; -- Start button input
            stop                 : in std_logic; -- Stop button input
            adjust_interval_up   : in std_logic; -- Button for increasing alarm interval
            adjust_interval_down : in std_logic; -- Button for decreasing alarm interval
            alarm                : out std_logic -- Alarm output
        );
    end entity Kitchen_Timer;
    architecture Behavioral of Kitchen_Timer is
        signal count          : integer range 0 to 60 := 0; -- Adjust range for 1 hour
        signal alarming       : std_logic             := '0';
        signal alarm_interval : integer range 1 to 60 := 1; -- Adjust range for 1 hour
    begin
        process (clk, reset)
        begin
            if reset = '1' then
                count          <= 0;
                alarm_interval <= 1;
            elsif rising_edge(clk) then
                if start = '1' then
                    count <= count + 1;
                end if;
                if stop = '1' then
                    count    <= 0;
                    alarming <= '0';
                end if;
                if count = alarm_interval then
                    alarming <= '1';
                end if;
                if adjust_interval_up = '1' then
                    if alarm_interval < 60 then
                        alarm_interval <= alarm_interval + 1; -- Adjust increment for 1 minute
                    end if;
                    count <= 0; -- Reset count when adjusting interval
                elsif adjust_interval_down = '1' then
                    if alarm_interval > 60 then
                        alarm_interval <= alarm_interval - 1; -- Adjust decrement for 1 minute
                    end if;
                    count <= 0; -- Reset count when adjusting interval
                end if;
            end if;
        end process;
        alarm <= alarming;
    end architecture Behavioral;
    
    

    tb_Kitchen_Timer.vhd

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity tb_Kitchen_Timer is
    end tb_Kitchen_Timer;
    
    architecture tb of tb_Kitchen_Timer is
        signal clk                  : std_logic := '0';
        signal reset                : std_logic := '0';
        signal start                : std_logic := '0';
        signal stop                 : std_logic := '0';
        signal adjust_interval_up   : std_logic := '0';
        signal adjust_interval_down : std_logic := '0';
        signal alarm                : std_logic;
        constant TbPeriod           : time      := 10 ns;
        signal TbClock              : std_logic := '0';
        signal TbSimEnded           : std_logic := '0';
    begin
        dut : entity work.Kitchen_Timer
        port map
        (
            clk                  => clk,
            reset                => reset,
            start                => start,
            stop                 => stop,
            adjust_interval_up   => adjust_interval_up,
            adjust_interval_down => adjust_interval_down,
            alarm                => alarm
        );
    
        -- Clock generation
        TbClock <= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';
    
        -- EDIT: Check that clk is really your main clock signal
        clk <= TbClock;
    
        stimuli : process
            variable num_ticks : natural;
        begin
            -- Reset generation
            reset <= '1';
            wait for 20 ns;
            reset <= '0';
            wait for 20 ns;
            -- Start the timer
            start <= '1';
            wait for 20 ns;
            start <= '0';
            stop  <= '1';
            -- Adjust interval up and down
            adjust_interval_up <= '1';
            wait for 10 ns;
            start              <= '1';
            stop               <= '0';
            adjust_interval_up <= '0';
            wait for 30 ns;
            start                <= '0';
            stop                 <= '1';
            adjust_interval_down <= '1';
            wait for 10 ns;
            start                <= '1';
            stop                 <= '0';
            adjust_interval_down <= '0';
            wait for 20 ns;
            start              <= '0';
            stop               <= '1';
            adjust_interval_up <= '1';
            wait for 600 ns;
            start              <= '1';
            stop               <= '0';
            adjust_interval_up <= '0';
            -- Wait for the timer to reach the alarm interval (60 clocks)
            wait for 600 ns; -- Simulate for the required time
            -- Stop the timer
            start <= '0';
            stop  <= '1';
            wait for 100 ns;
            -- Stop the clock and terminate the simulation
            TbSimEnded <= '1';
            wait;
        end process;
    end tb;
    
    

    This should be easier to simulate, I’ve included a simulation done with Questa.


  • @dejo This is much better, but there is still some room for improvement.

    There is a mismatch between your comparisons count and alarm_interval. Here in the code bellow you can see the issue:

    if stop = '1' or count = alarm_interval then
    
    count <= 0; -- count is 0 here
    
    end if;
    
    [...]
    
    alarming <= '1' when count >= alarm_interval else '0'; -- This condition is never true due to count always being 0 or smaller the alarm_interval.
    alarm <= alarming;
    
    

    As it is right now, the alarming signal is never going to be ‘1’. It is best to split the comparison and write to alarming directly:

    if stop = '1' then
    
    count <= 0;
    alarming <= '0';
    
    end if;
    
    if count = alarm_interval then
    
    alarming <= '1';
    
    end if;
    
    [...]
    
    alarm <= alarming
    
    

    As for the testbench, you should set the start and unset it only after the alarming is ‘1’, and test if alarming is working after adjusting the timer:

    stimuli : process
    
    begin
    
    -- Reset generation
    
    reset <= '1';
    
    wait for 20 us; -- Adjust delay to fit the new clock period
    
    reset <= '0';
    
    -- Add your stimuli and test cases here
    
    -- For example:
    
    start <= '1';
    stop <= '0';
    
    wait for 620 us; -- Wait until alarm is alarming
    
    start <= '0'
    stop <= '1';
    adjust_interval_up <= '1';
    
    wait for 1 us; -- Increment the timer by a minute
    
    start <= '1';
    stop <= '0';
    adjust_interval_up <= '0';
    
    wait for 1220 us; -- Wait until the alarm is alarming
    
    start <= '0';
    stop <= '1';
    adjust_interval_down <= '1';
    
    wait for 1 us; -- Decrement the timer by a minute
    
    start <= '1';
    stop <= '0';
    adjust_interval_down <= '0';
    
    wait for 620 us; -- Wait until the alarm is alarming
    
    start <= '0';
    stop <= '1';
    
    wait for 20 us;
    
    -- ...
    
    -- Stop the clock and hence terminate the simulation
    
    TbSimEnded <= '1';
    
    wait;
    
    end process;
    
    

    I suggest changing the 100 ms time slices you use in the timer to a minute instead. That way your simulation time could be much quicker (though you would also have to change the testbench delays).


  • @dejo

    can you send me the code with the modifications so that I know what exactly you mean?

    I would rather not, as it isn’t a good learning experience for you, and would require some time for me to write the code.

    Though if you have any questions about my previous answer, feel free to ask me about it.

    As a freebie for you, pay attention to the alarming signal, and the condition that has been set: “The device should have buttons/switches to start and stop the timer, as well as to set the desired time interval for the alarm.”. If I wanted the alarm to ring after 50 minutes, how would I do that? And what happens when the timer starts?

    From the code I see here, the alarm is going to ring 10 minutes after being started, and it won’t stop until an hour passes. And it has no way to set a time for it to ring, it always rings after 10 minutes.

    And, not only that, the 'start` signal is never set in the testbench, so the timer is never going to begin.