Search code examples
vhdlsimulationfsm

In behavioral simulation, my FSM have a state that take more than 1 clock cycle ... And i don't like it


Please forgive myself if you will find some trivial errors in my code .. I'm still a beginner with VHDL.

Well, I have to deal with a serial interface from an ADC. The interface is quite simple ... there is a wire for the serial data (a frame of 24 bits), a signal DRDY that tells me when the new sample data is available and a serial clock (SCLK) that push the bit into (rising edge). Everything is running continuously...

I need to capture correctly the 24 bit of the sample, put them on a parallel bus (shift register) and provide a "data valid" signal for the blocks that will process the samples ...

Due to the fact that my system clock is x4 the frequency of the serial interface, i was thinking that doing the job with a FSM will be easy ...

When you look into the code you will see a process to capture the rising edges of the DRDY and SCLK.

Then a FSM with few states (Init, wait_drdy, wait_sclk, inc_count, check_count).

I use a counter (cnt unsigned) to check if I've already captured the 24 bits, using also to redirect the states of the FSM in "check_count" state. Here a picture:

signal diagra and FSM

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity serial_ads1675 is
    Port ( 
            clk     : in STD_LOGIC;
            reset   : in STD_LOGIC;
            sclk    : in std_logic;
            sdata   : in std_logic;
            drdy    : in std_logic;
            pdata   : out std_logic_vector(23 downto 0);
            pdready : out std_logic
    );
end serial_ads1675;

architecture Behavioral of serial_ads1675 is

-- Internal declarations
signal ipdata : std_logic_vector (23 downto 0);
signal ipdready : std_logic;
signal tmp1, tmp2, tmp3, tmp4 : std_logic;
signal rise_drdy, rise_sclk : std_logic;
signal cnt : unsigned (4 downto 0);

type state is (init, wait_drdy, wait_sclk, inc_count, check_count);
signal actual_state, next_state : state;




begin

-- Concurrent statements
pdata <= ipdata;
pdready <= ipdready;
rise_drdy <= '1' when ((tmp1 = '1') and (tmp2 = '0')) else '0';
rise_sclk <= '1' when ((tmp3 = '1') and (tmp4 = '0')) else '0';



-- Process

process (clk, reset)
begin
    if(reset = '0') then
        tmp1 <= '0';
        tmp2 <= '0';
        tmp3 <= '0';
        tmp4 <= '0';
    elsif (falling_edge(clk)) then
        tmp1 <= drdy;
        tmp2 <= tmp1;
        tmp3 <= sclk;
        tmp4 <= tmp3;
    end if;
end process;

process (reset, clk)
begin
    if (reset = '0') then
        actual_state <= init;
    elsif (rising_edge(clk)) then
        actual_state <= next_state;
    end if;
end process;

process (rise_sclk, rise_drdy)   -- Next State affectation
begin
    case actual_state is
    
        when init =>
            next_state <= wait_drdy;
            ipdata <= (others => '0');
            ipdready <= '0';
            cnt <= (others => '0');
            
        when wait_drdy =>
            if (rise_drdy = '0') then
                next_state <= actual_state;
            else
                next_state <= wait_sclk;
            end if;
            cnt <= (others => '0');
            
        when wait_sclk =>
            if (rise_sclk = '0') then
                next_state <= actual_state;
            else
                next_state <= inc_count;
            end if;
            ipdready <= '0';
                        
        when inc_count =>
            next_state <= check_count;
            cnt <= cnt + 1;
            ipdready <= '0';
            ipdata(23 downto 1) <= ipdata(22 downto 0);
            ipdata(0) <= sdata;
            
        when check_count =>
            case cnt is
                when "11000" =>
                    next_state <= wait_drdy;
                    ipdready <= '1';
                when others =>
                    next_state <= wait_sclk;
                    ipdready <= '0';
            end case;
                        
        when others =>
            next_state <= init;
    end case;
end process;



end Behavioral;

My problem is during the check_count state ...

I'm expecting that this state should last one system clock cycle, but actually it last much more.

Here a snapshot of the behavioral simulation:

Wave Window

Due to the fact that this state last more than expected, i miss the following SCLK pulse and don't record the next bit ...

I don't understand why this state last so many system clock cycles instead of just one ...

Anyone has some clues and bring some light in my dark night ?

Thanks in advance.

Edit: I've tried to change the signal cnt for an integer variable internal to the process of the FSM ... Same results


Solution

  • The error is this:

    process (rise_sclk, rise_drdy)   -- Next State affectation
    begin
        -- code omitted, but does generally this:
        next_state <= SOME_VALUE;
    end process;
    

    Because the sensitivity list includes only the signals rise_sclk and rise_drdy, the process is "executed" only if any of these signals changes. You can follow this in the wave diagram.

    You don't have a synchronous design running on clk. Put clk on the sensitivity list and base the decisions on the levels of rise_sclk and rise_drdy. As an excerpt:

    process (clk)   -- Next State affectation
    begin
        if rising_edge(clk) then
            case actual_state is
    
            when init =>
                next_state <= wait_drdy;
                -- and so on
       
            end case;
        end if;
    end process;