I am currently writing my first FSM and am unsure of if I have the logic correct. I am tasked with creating a state diagram for the following logic:
A = 00
B = 01
C = 10
D = 11
Output is 1 when:
BDA
BAA
BAD
So I created the following vhdl code to accomplish this:
So every time I get it to output 1 I send it back to B and make count + 1. This is supposed to display on the LED as the number of times it is found in an 18 bit sequence.
Did I approach this in the correct way? I am confused on how I move it through the 18 bit sequence. I am supposed to us the swtiches on the board as my 18 bits which is represented as SW. Would I replace data_in with SW(17 downto 0)?
This is a comment not an answer I putting it in answer as I am not eligible to comment yet.
I think you have some problem in FSM concepts. Also as in the comment said data_in is std_logic not a vector.
you are taking input serially one bit at a time so accordingly write the processes. you can write code to detect the sequences BDA, BAA, BAD that is sequences "011100","010000" and "010011". I would write a simple FSM code so that you can clear you concepts then you can try.
library ieee;
use IEEE.std_logic_1164.all;
entity mealy is
port (clk : in std_logic;
reset : in std_logic;
input : in std_logic;
output : out std_logic
);
end mealy;
architecture behavioral of mealy is
type state_type is (s0,s1,s2,s3); --type of state machine.
signal current_s,next_s: state_type; --current and next state declaration.
begin
process (clk,reset)
begin
if (reset='1') then
current_s <= s0; --default state on reset.
elsif (rising_edge(clk)) then
current_s <= next_s; --state change.
end if;
end process;
--state machine process.
process (current_s,input)
begin
case current_s is
when s0 => --when current state is "s0"
if(input ='0') then
output <= '0';
next_s <= s1;
else
output <= '1';
next_s <= s2;
end if;
when s1 =>; --when current state is "s1"
if(input ='0') then
output <= '0';
next_s <= s3;
else
output <= '0';
next_s <= s1;
end if;
when s2 => --when current state is "s2"
if(input ='0') then
output <= '1';
next_s <= s2;
else
output <= '0';
next_s <= s3;
end if;
when s3 => --when current state is "s3"
if(input ='0') then
output <= '1';
next_s <= s3;
else
output <= '1';
next_s <= s0;
end if;
end case;
end process;
end behavioral;
Related
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:
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:
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
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;
I have to generate the vhdl code for the signal generator above as a finite state machine. What I cant manage to implement is this. How to generate
the clock values to output. To be more specific, I want for half period
output 0 and the other half 1, when the state machine is in state clock. My implementation, as you can see on the
code below, is output <= clock but this obviously does not work. I made a finite machine with 4 states (s1, s2, s3, s4)
My testbench and my vhdl code are these:
testbench
library ieee;
use ieee.std_logic_1164.all;
entity signal_generator_tb is
end entity;
architecture signal_generator_tb_arch of signal_generator_tb is
signal clock_tb, reset_tb: std_logic;
signal output_tb: std_logic;
component signal_generator
port(clock, reset: in std_logic;
output: out std_logic);
end component;
begin
dut : signal_generator port map(clock_tb, reset_tb, output_tb);
stim_reset : process
begin
reset_tb <= '0'; wait for 10 ns;
reset_tb <= '1'; wait;
end process;
stim_clock : process
begin
clock_tb <= '1'; wait for 10 ns;
clock_tb <= '0'; wait for 10 ns;
end process;
end architecture;
and my vhdl code is that:
library ieee;
use ieee.std_logic_1164.all;
entity signal_generator is
port (clock, reset: in std_logic;
output: out std_logic);
end entity;
architecture signal_generator_arch of signal_generator is
type state_type is (s0, s1, s2, s3); --This is the states of the
finite state machine and we can create signlas with this type
signal current_state, next_state: state_type; --We can only assign
w_open and w_closed because there are type of state_type
begin
STATE_MEMORY : process(clock, reset)
begin
if(reset = '0') then
current_state <= s0;
elsif(falling_edge(clock)) then
current_state <= next_state;
end if;
end process;
NEXT_STATE_LOGIC : process(current_state)
begin
case(current_state) is
when s0 => next_state <= s1;
when s1 => next_state <= s2;
when s2 => next_state <= s3;
when s3 => next_state <= s0;
when others => next_state <= s0;
end case;
end process;
OUTPUT_LOGIC : process(current_state)
begin
case(current_state) is
when s0 => output <= '1';
when s1 => if(rising_edge(clock)) then
output <= '1';
else
output <= '0';
end if;
when s2 => output <= '1';
when s3 => output <= '0';
when others => output <= '0';
end case;
end process;
end architecture;
wave form
Your state machine does not work because of your OUTPUT_LOGIC process. It should also be sensitive to clock and when in state s1 it should output clock itself:
OUTPUT_LOGIC : process(current_state, clock)
begin
case(current_state) is
when s0 => output <= '1';
when s1 => output <= clock;
when s2 => output <= '1';
when s3 => output <= '0';
when others => output <= '0';
end case;
end process;
Note that you could simplify all this by simply passing your clock through a AND gate (to force it to 0) and a OR gate (to force it to 1) and output the result. A two bits counter that you would initialize to "11" and decrement would provide the current state, encoded in a very convenient way to force the output to 0 and 1:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;
entity signal_generator is
port(clock, reset: in std_ulogic;
output: out std_ulogic);
end entity signal_generator;
architecture arc of signal_generator is
signal cnt: std_ulogic_vector(1 downto 0); -- the state
begin
process(clock, reset)
begin
if reset = '0' then
cnt <= "11";
elsif falling_edge(clock) then
cnt <= cnt - 1;
end if;
end process;
output <= (clock and cnt(1)) or cnt(0);
end architecture arc;
Note: always prefer std_ulogic (unresolved) to std_logic (resolved) when you do not plan to have multiple drive situations on a signal. This way, if you accidentally create a multiple drive situation you will get a meaningful error message instead of spending hours trying to understand where all these X values in your waveforms come from.
My VHDL-Code is functionaly correct, in ModelSim every thing works fine. I tested it with many variations and the code is functionaly correct.
But when I put it on the Altera board it displays a "3" on the 7-segment display, but it should show "0".
If I put RESET to "1" it breaks completly and displays only a line in the top segment.
My Inputs X, CLK, RESET are connected to the switches.
LOAD ist connected to a button and DIGIT to the 7-segment display.
It should have a clock signal as I swtich the CLK-switch.
Here my full code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(6 DOWNTO 0) := "1111110";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSIF (CLK'event and CLK='1') THEN
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s0 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s1;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "1111110";
WHEN "001" => DIGIT <= "0110000";
WHEN "010" => DIGIT <= "1101101";
WHEN "011" => DIGIT <= "1111001";
WHEN "100" => DIGIT <= "0110011";
WHEN "101" => DIGIT <= "1011011";
WHEN OTHERS => NULL;
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
I am pretty new to VHDL and am pretty sure it hase to do something with the timings, cause the functional part should be fine, as already said.
Hope for some hints, tips or even solutions.
EDIT: new code without LOAD, is this a valid idea? (non the less the whole code is not working on the FPGA....)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(0 TO 6) := "0000001";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (CLK'event and CLK='1') THEN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSE
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s1 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "0000001";
WHEN "001" => DIGIT <= "1001111";
WHEN "010" => DIGIT <= "0010010";
WHEN "011" => DIGIT <= "0000110";
WHEN "100" => DIGIT <= "1001100";
WHEN "101" => DIGIT <= "0100100";
WHEN OTHERS => DIGIT <= "0000001";
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
EDIT: This is now my version.
It will still show a "0" no matter what I do.
I would assume it has to do with the COUNT and counter.
should i realize this as synchronous too?
Is the numeric and unsigned really that big of a problem? We did it that way at university.
And will it work when i put LOAD onto a slide switch???
Best regards
Adrian
Your code has several problems. Btw. a running simulation does not mean your design is correct, because you can simulate actions which can not be implemented in hardware.
Here is a list of problems:
You can not use a switch button as a clock signal. Buttons are no clock source! Either you implement a signal cleanup circuit (at least a debounce circuit, which requires another clock) or you use you clk signal as an enable.
Moreover, each of your signals needs a debounce circuit if connected to external switch buttons or toggle buttons unless your test board has debounced buttons...
Your state machine has an init state (that's OK), but you must assign the state to state instead of next_state.
Your code uses std_logic_unsigned, which is obsolete. You should use numeric_std and the type unsigned for your counter signal.
Your code intoduces an additional register for COUT is this intended?
Your PISO process uses an asynchronous LOAD signal this is not supported in hardware (assuming an FPGA as target device).
Depending on your synthesis tool it's possible that it will not recognize a FSM because your case statement does not fit the pattern for FSMs.
Seeing a fixed output pattern can be causes by an FSM fault. If your synthesizer recognizes a FSM, you can go to the state diagram and identify false edges or false terminal states.
More ...
Your 7-segment decoder is a combinatorical process. It can not be reset.
Moreover, this process is not sensitive to CLK, just to counter. This cause a mismatch between simulation and hardware. (Synthesis ignores sensitivity lists)
If you fix this, your simulation should have another behavior and, if fixed, work as your hardware :).
The FSM
STATE_CAL : process(state, so)
begin
-- Standardzuweisungen
next_state <= state; -- Bleib im Zustand falls in CASE nichts abweichendes bestimmt wird
Y <= '0';
-- Zustandswechsel
CASE state IS
WHEN s0 =>
IF (so = '1' THEN
next_state <= s1;
END IF;
WHEN s1 =>
IF (so = '1') THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF (so = '0') THEN
next_state <= s3;
END IF;
WHEN s3 =>
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s4;
END IF;
WHEN s4 =>
Y <= '1'; -- Moore-Ausgabe
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s2;
END IF;
END CASE;
END PROCESS;
Paebbels already described many issues of your code. Please check also the warnings of your synthesis tool. They often indicate where the synthesizer actually outputs different logic than you have described in VHDL.
I suspect you have made another two mistakes which are not directly related to VHDL:
Your 7-segment display control lines seem to be low-active because you see only one active segment when you press RESET. This matches the only zero in the vector "1111110" you assigned in this case (via reseting counter to "000").
But even in this case, the enlighted segment should be in the middle instead on the top. Thus, your pin assignments seem to be in the reverse order.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Traffic_Light is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
input : in STD_LOGIC;
output : out STD_LOGIC_VECTOR(1 DOWNTO 0));
end Traffic_Light;
architecture Behavioral of Traffic_Light is
type state_type is (S0,S1,S2); --type of state machine.
signal present_state, next_state: state_type; --current and next state declaration.
begin
process
begin
wait until clk'event and clk = '0';
present_state <= next_state;
end process;
process (clk,reset)
begin
if (reset='1') then
current_state <= S0; --default state on reset.
end if;
end process;
process (present_state, input)
begin
case present_state is
when S0 => --when current state is s0
if(input = '0') then
output <= "10";
next_state <= S1;
else
output <= "00";
next_state <= S2;
end if;
when S1 => --when current state is s1
if(input = '0') then
output <= "01";
next_state <= S0;
else
output <= "00";
next_state <= S2;
end if;
when S2 => --when current state is s2
if(input = '0') then
output <= "01";
next_state <= S0;
else
output <= "11";
next_state <= S2;
end if;
end case;
end process;
end Behavioral;
I cant seem to get every state change to occur only at the falling edge of the clock.
The simulation does not show the various changes in the present state, it just shows S0 all the way through.
All the state changes have been entered correctly. It just requires the synchronous reset an state changes to occur at the falling edge.
First replace current_state with present_state. Then you can't drive present_state from two processes since it's not a resolved type. You have to do something like
process (clk,reset)
begin
if (reset='1') then
present_state <= S0; --default state on reset.
elsif clk'event and clk = '0' then
present_state <= next_state;
end if;
end process;
Below is the a part of a code describing a FSM.
clk_process : process
begin
wait until clk'event ;
if(clk ='0') then
if( state = s2) then
state <= nextstate;
end if;
elsif clk='1' then
state <= nextstate;
end if;
end process clk_process;
state <= nextstate statement is not being executed even when clk='0' , state=s2 and clk event has occurred.
Can anyone reason why this weird behavior is should. What can I do no to do what i intent to do.
Thanx
Edit 1:
library ieee;
use ieee.std_logic_1164.all;
entity machine is
port(clk : in std_logic; out1,out2 : out std_logic);
end entity;
architecture behave of machine is
type statetype is (s0,s1,s2,s3,s4);
signal state,nextstate : statetype :=s0;
begin
-- nextstate<=s0;
comb_process: process(state)
begin
case state is
when s0 =>
nextstate <= s1;
when s1 =>
nextstate <=s2;
out1 <= '1';
out2 <= '1';
when s2 =>
if(clk ='0') then
nextstate <= s3;
out2 <='1';
else
nextstate <=s2;
out1<='0';
out2<='0';
end if;
when s3 =>
nextstate <= s4;
when s4=>
nextstate <= s1;
end case;
end process comb_process;
clk_process : process
begin
wait until clk'event ;
if(clk ='0') then
if( state = s2) then
state <= nextstate;
end if;
elsif clk='1' then
state <= nextstate;
end if;
end process clk_process;
end behave;
This is my full code. What i am trying to do is when state is S2 it should be both positive and negative edge triggered
The problem with your code seems to be that your state machine will get stuck when state = s1 and nextstate = s2. When it gets to this point, the next rising clock edge will cause the clk_process block to change state <= s2. This will cause your comb_process block to trigger while clk = '1', thus causing nextstate <= s2. Once state is equal to nextstate, comb_process will never trigger again.
If you don't care about the number of states bits used for you FSM, you could simply create a state for each clock transition event.