fatecsa
fatecsa

Reputation: 17

my vhdl code for implementing some fsm is not working correctly

library IEEE;
use IEEE.std_logic_1164.all;

entity INCUBATOR2 is
    port(temperature: in std_logic_vector(7 downto 0);
    CLK,RESET: in std_logic;
    on_cooler,on_heater: out std_logic;
    CRS:out std_logic_vector(3 downto 0));

end entity INCUBATOR2;

architecture ARCH of INCUBATOR2 is



TYPE STATE_TYPE_left IS (S1, S2, S3);
SIGNAL STATE,NEXT_STATE   : STATE_TYPE_left;

TYPE STATE_TYPE_right IS (S_OUT,S_1, S_2, S_3);
SIGNAL cooler_STATE,cooler_NEXT_STATE   : STATE_TYPE_right;


begin
    --T<= temprature;
    REG: process (clk, reset) begin
        if reset='1' then
            STATE <= S1 ;
            cooler_STATE<=S_OUT;
        elsif clk'event and clk='1' then
            STATE <= NEXT_STATE ;
            cooler_STATE<=cooler_NEXT_STATE;
        end if ;    
    end process REG ;
   
    CMB:process(STATE,temperature   ,cooler_STATE) 
    begin
        case STATE is
            when S1 => 
                if(temperature  > "00100011" ) then
                    NEXT_STATE<=S2;
                    
                elsif(temperature < "00001111") then
                    NEXT_STATE<= S3;
                end if;
                --cooler_NEXT_STATE<=S_OUT;
            when S2 =>
                if(temperature < "00011001" ) then
                    NEXT_STATE<=S1;
                end if;
                case cooler_STATE is
                    when S_OUT=>
                        if(temperature>"00100011") then
                            cooler_NEXT_STATE<=S_1;
                        end if;
                    when S_1=>
                        if(temperature>"00101000") then
                            cooler_NEXT_STATE<=S_2;
                        elsif(temperature<"00011001") then
                            cooler_NEXT_STATE<=S_OUT;
                        end if;
                    when S_2=>
                        if(temperature>"00101101") then
                            cooler_NEXT_STATE<=S_3;
                        elsif(temperature<"00100011") then
                            cooler_NEXT_STATE<=S_1;
                        end if;
                    when S_3=>
                        if(temperature<"00101000") then
                            cooler_NEXT_STATE<=S_2;
                        end if;
                end case;
                

                
            when S3 => 
                if(temperature>"00011110" ) then
                    NEXT_STATE<=S1;
                end if;
                --cooler_NEXT_STATE<=S_OUT;
        end case;
        
    end process CMB;
  --  with STATE select
--  heater<= '0' when S1|S2,
--      '1' when S3;
--  cooler<= '0' when S1|S3,
--      '1' when S2;
  --  label if( cooler='1') generate
    --  modul: COOLER port  map(temprature=>T,CRS=>CRS,clk=>clk,reset=>reset);
     --end generate;
    
    OUTPUT : process(STATE,cooler_STATE) 
    begin
            
        case STATE is
            when S1 =>
                on_heater<='0';
                on_cooler<='0';
                
            when S2 =>
                on_cooler<='1';
                on_heater<='0';

                
                case cooler_STATE is
                    when S_OUT =>
                        CRS<="0000";
                    when S_1 =>
                        CRS<="0100";
                    when S_2 =>
                        CRS<="0110";
                    when S_3 =>
                        CRS<="1000";
                    when others=>
                        CRS<="0000";
                end case;
                
            when S3 =>
                on_heater<='1';
                on_cooler<='0';

        end case;
        
    end process OUTPUT;

    
end ARCH;

and here is the testbench:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

entity incubator_tb is
end entity;

architecture testbench of incubator_tb is

component INCUBATOR2 is
    port(temperature: in std_logic_vector(7 downto 0);
    CLK,RESET: in std_logic;
    on_cooler,on_heater: out std_logic;
    CRS:out std_logic_vector(3 downto 0));
end component INCUBATOR2;

signal  CLK, reset: std_logic;
signal  on_cooler,on_heater:std_logic;
signal temperature:std_logic_vector(7 downto 0);
signal CRS: std_logic_vector(3 downto 0);
begin

modul: INCUBATOR2 port map(
temperature => temperature, clk => clk, reset => reset,
on_cooler => on_cooler,on_heater=>on_heater,CRS=>CRS);

stim: process
begin

temperature <= "00100110";
clk <= '0';
reset <= '1';
wait for 20 ns;

temperature <= "00100110";
clk <= '1';
reset <= '0';

wait for 20 ns;

reset <= '0';
clk <= '0';
temperature <= "00001010";
wait for 20 ns;

reset <= '0';
clk <= '1';
temperature <= "00001010";
wait for 20 ns;

reset <= '0';
clk <= '0';
temperature <= "00100110";
wait for 20 ns;
--clk <= '1';

reset <= '0';
clk <= '1';
temperature <= "00100110";
wait for 20 ns;

reset <= '0';
clk <= '1';
temperature <= "00101010";
wait for 20 ns;


wait;

end process;
end architecture testbench;

as in the picture below shows that the outputs of some inputs are being calculated wrong and on_heater never activates...(it is supposed to switch to 1 when the temperature is a)

enter image description here

can anyone tell me that where am i doing wrong?im so confused any help would be really appreciated.

Upvotes: 0

Views: 606

Answers (1)

tim
tim

Reputation: 482

Since you are only supposed to design the right-hand state machine (the cooler), you should concentrate on that separate to the left-hand state machine (the main controller).

Talk to your colleague who's designing the main controller to add an output called enable_cooler to enable the cooler state machine. The Incubator entity could include two entities called MainController and Cooler.

I've extracted the cooler state machine logic into a separate entity called Cooler. It's in three processes which keep the outputs synchronised to both the clock and the state:

  1. State Register and Outputs Register.
  2. Next State Logic.
  3. Next Outputs Logic.

I've also added some else clauses to prevent inferred latches, and added some constants to make it more readable and maintainable.

Cooler State Machine

State Diagram

Cooler state machine Figure 1 – Cooler state machine


VHDL

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

entity Cooler is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        enable: in std_logic;  -- ADDED: From cooler enable signal of modified left-hand state machine.
        temperature: in std_logic_vector(7 downto 0);  -- I've assumed this is a signed temperature.
        crs: out std_logic_vector(3 downto 0)
    );
end entity;

architecture V1 of Cooler is

    type TState is (S_OUT, S_1, S_2, S_3);
    signal state, next_state: TState;

    signal next_crs: std_logic_vector(3 downto 0);  -- ADDED to ensure the outputs are synchronised to the clock and state.

    constant TEMPERATURE_P25: integer := 25;  -- ADDED for readability and maintainability.
    constant TEMPERATURE_P35: integer := 35;
    constant TEMPERATURE_P40: integer := 40;
    constant TEMPERATURE_P45: integer := 45;

    constant RPS_0: std_logic_vector(3 downto 0) := "0000";  -- ADDED for readability and maintainability.
    constant RPS_4: std_logic_vector(3 downto 0) := "0100";
    constant RPS_6: std_logic_vector(3 downto 0) := "0110";
    constant RPS_8: std_logic_vector(3 downto 0) := "1000";

begin

    --
    -- State Register and Outputs Register
    --
    process(clock, reset)
    begin
        if reset then
            state <= S_OUT;
            crs <= RPS_0;  -- ADDED to specify outputs for reset condition.
        elsif rising_edge(clock) then
            state <= next_state;  -- State is synchronised to clock.
            crs <= next_crs;      -- Outputs are synchronised to clock and state.
        end if;
    end process;

    --
    -- Next State Logic
    --
    process(enable, state, temperature)
        variable i_temperature: integer;  -- ADDED for numeric comparisons.
    begin
        if enable then
            i_temperature := to_integer(signed(temperature));  -- I've assumed this is a signed temperature.
            case state is
                when S_OUT =>
                    if i_temperature > TEMPERATURE_P35 then
                        next_state <= S_1;
                    else
                        next_state <= S_OUT;  -- ADDED to prevent inferred latch.
                    end if;
                when S_1 =>
                    if i_temperature > TEMPERATURE_P40 then
                        next_state <= S_2;
                    elsif i_temperature < TEMPERATURE_P25 then
                        next_state <= S_OUT;
                    else
                        next_state <= S_1;  -- ADDED to prevent inferred latch.
                    end if;
                when S_2 =>
                    if i_temperature > TEMPERATURE_P45 then
                        next_state <= S_3;
                    elsif i_temperature < TEMPERATURE_P35 then
                        next_state <= S_1;
                    else
                        next_state <= S_2;  -- ADDED to prevent inferred latch.
                    end if;
                when S_3 =>
                    if i_temperature < TEMPERATURE_P40 then
                        next_state <= S_2;
                    else
                        next_state <= S_3;  -- ADDED to prevent inferred latch.
                    end if;
                when others =>
                    next_state <= S_OUT;
            end case;
        else
            next_state <= S_OUT;  -- Prevent inferred latch.
        end if;
    end process;

    --
    -- Next Outputs Logic
    --
    process(next_state)
    begin
        case next_state is
            when S_OUT =>
                next_crs <= RPS_0;
            when S_1 =>
                next_crs <= RPS_4;
            when S_2 =>
                next_crs <= RPS_6;
            when S_3 =>
                next_crs <= RPS_8;
            when others =>
                next_crs <= RPS_0;
        end case;
    end process;

end architecture;

Main Controller State Machine

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

entity MainController is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        temperature: in std_logic_vector(7 downto 0);
        on_cooler: out std_logic;
        on_heater: out std_logic;
        enable_cooler: out std_logic  -- ADDED to enable cooler when MainController is in state S2.
    );
end entity;

architecture V1 of MainController is

    type TState is (S1, S2, S3);
    signal state, next_state: TState;

    constant TEMPERATURE_P15: integer := 15;  -- ADDED for readability and maintainability.
    constant TEMPERATURE_P25: integer := 25;
    constant TEMPERATURE_P30: integer := 30;
    constant TEMPERATURE_P35: integer := 35;

    signal next_on_cooler: std_logic;  -- ADDED to ensure outputs are synchronised to the clock and state.
    signal next_on_heater: std_logic;

begin

    --
    -- State Register and Outputs Register
    --
    process(clock, reset)
    begin
        if reset then
            state <= S1;
            on_cooler <= '0';  -- ADDED to specify outputs for reset condition.
            on_heater <= '0';
        elsif rising_edge(clock) then
            state <= next_state;          -- State is synchronised to the clock.
            on_cooler <= next_on_cooler;  -- Outputs are synchronised to the clock and state.
            on_heater <= next_on_heater;
        end if;
    end process;

    --
    -- Next State Logic
    --
    process(state, temperature)
        variable i_temperature: integer;  -- ADDED for numeric comparisons.
    begin
        i_temperature := to_integer(signed(temperature));  -- I've assumed this is a signed temperature.
        case STATE is
            when S1 =>
                if i_temperature > TEMPERATURE_P35 then
                    next_state <= S2;
                elsif i_temperature < TEMPERATURE_P15 then
                    next_state <= S3;
                else
                    next_state <= S1;  -- ADDED to prevent inferred latch.
                end if;
            when S2 =>
                if i_temperature < TEMPERATURE_P25 then
                    next_state <= S1;
                else
                    next_state <= S2;  -- ADDED to prevent inferred latch.
                end if;
            when S3 =>
                if i_temperature > TEMPERATURE_P30 then
                    next_state <= S1;
                else
                    next_state <= S3;  -- ADDED to prevent inferred latch.
                end if;
            when others =>
                next_state <= S1;
        end case;
    end process;

    --
    -- Next Outputs Logic
    --
    process(next_state)
    begin
        case next_state is
            when S1 =>
                next_on_cooler <= '0';
                next_on_heater <= '0';
                enable_cooler <= '0';
            when S2 =>
                next_on_cooler <= '1';
                next_on_heater <= '0';
                enable_cooler <= '1';  -- ADDED to enable cooler when MainController is in state S2.
            when S3 =>
                next_on_cooler <= '0';
                next_on_heater <= '1';
                enable_cooler <= '0';
            when others =>
                next_on_cooler <= '0';
                next_on_heater <= '0';
                enable_cooler <= '0';
        end case;
    end process;

end architecture;

Incubator Top-Level Entity

This connects the two state machines together, i.e. Cooler and MainController.

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

entity Incubator is
    port
    (
        clock: in std_logic;
        reset: in std_logic;
        temperature: in std_logic_vector(7 downto 0);
        on_cooler: out std_logic;
        on_heater: out std_logic;
        crs: out std_logic_vector(3 downto 0)
    );
end entity;

architecture V1 of Incubator is

    signal enable_cooler: std_logic;  -- ADDED to enable cooler when MainController is in state S2.

    component MainController is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            temperature: in std_logic_vector(7 downto 0);
            on_cooler: out std_logic;
            on_heater: out std_logic;
            enable_cooler: out std_logic
        );
    end component;

    component Cooler is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            enable: in std_logic;  -- ADDED: From cooler enable signal of modified left-hand state machine.
            temperature: in std_logic_vector(7 downto 0);  -- I've assumed this is a signed temperature.
            crs: out std_logic_vector(3 downto 0)
        );
    end component;

begin

    MC: MainController
        port map
        (
            clock => clock,
            reset => reset,
            temperature => temperature,
            on_cooler => on_cooler,
            on_heater => on_heater,
            enable_cooler => enable_cooler
        );

    CLR: Cooler
        port map
        (
            clock => clock,
            reset => reset,
            enable => enable_cooler,
            temperature => temperature,
            crs => crs
        );

end architecture;

Test Bench

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

entity Incubator_TB is
end entity;

architecture V1 of Incubator_TB is

    constant CLOCK_PERIOD: time := 50 ns;

    signal halt_sys_clock: boolean := false;

    signal clock: std_logic := '0';
    signal reset: std_logic := '0';
    signal temperature: std_logic_vector(7 downto 0);
    signal on_cooler: std_logic;
    signal on_heater: std_logic;
    signal crs: std_logic_vector(3 downto 0);

    component Incubator is
        port
        (
            clock: in std_logic;
            reset: in std_logic;
            temperature: in std_logic_vector(7 downto 0);
            on_cooler: out std_logic;
            on_heater: out std_logic;
            crs: out std_logic_vector(3 downto 0)
        );
    end component;

begin

    ClockGenerator:
    process
    begin
        while not halt_sys_clock loop
            wait for CLOCK_PERIOD / 2.0;
            clock <= not clock;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus:
    process
    begin
        reset <= '0';
        temperature <= std_logic_vector(to_unsigned(38, temperature'length));
        wait for CLOCK_PERIOD / 4.0;
        reset <= '1';
        wait for CLOCK_PERIOD;
        reset <= '0';
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(12, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(38, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(43, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(48, temperature'length));
        wait for CLOCK_PERIOD * 4;
        temperature <= std_logic_vector(to_unsigned(10, temperature'length));
        wait for CLOCK_PERIOD * 4;
        halt_sys_clock <= true;
        wait;
    end process;
    
    INC: Incubator
        port map
        (
            clock => clock,
            reset => reset,
            temperature => temperature,
            on_cooler => on_cooler,
            on_heater => on_heater,
            crs => crs
        );

end architecture;

Simulation

Simulation of incubator Figure 2 – Simulation of incubator


Quartus RTL Schematics

Incubator RTL Figure 3 – Incubator RTL


Main Controller RTL Figure 4 – Main Controller RTL


Cooler RTL Figure 5 – Cooler RTL


Upvotes: 2

Related Questions