FSM enters impossible state - vhdl

I have a FSM consisting of 3 states: STATIC, UP and DOWN.
The FSM starts in the STATIC state and if I press the up arrow key, it will move to the UP state, thereafter returning to the STATIC state. Same thing for DOWN.
At first the FSM works well but suddenly after a random amount of key presses it will enter an unspecified state. The FSM consists of two processes:
type ALL_STATES is (STATIC, UP, DOWN);
signal STATE, NEXT_STATE: ALL_STATES;
signal posBarraYTOP, posBarraYBOT: std_logic_vector(11 downto 0);
signal movTeclado: std_logic_vector(1 downto 0);
-- ...
Keybd: keyboard port map (input, movTeclado); -- keyboard output
-- ...
bar_FSM_sincrono: process(CLK, RST) -- CLK is the FPGA's clock
begin
if RST='1' then
STATE <= STATIC;
elsif (CLK'event and CLK = '1') then
STATE <= NEXT_STATE; -- in each CLK cycle we move to the next state.
end if;
end process bar_FSM_sincrono;
bar_FSM_cambioest: process(STATE)
begin
case STATE is
when STATIC=>
seg <= "1001001";
if (movTeclado = "01" and posBarraYTOP > 20) then
NEXT_STATE <= UP;
elsif (movTeclado = "10" and posBarraYBOT < 980) then
NEXT_STATE <= DOWN;
else
NEXT_STATE <= STATIC;
end if;
when UP | DOWN =>
NEXT_STATE <= STATIC;
seg <= "1111110";
when others =>
NEXT_STATE <= STATIC;
seg <= "0110111";
end case;
end process bar_FSM_cambioest;
movTeclado is a 2-bit signal that shows when the user presses the up 01 or down 10 key. It's 00 if no key is pressed. movTeclado doesn't give me any problems.
posBarraYTOP and posBarraYBOT are two signals to describe a boundary, and these conditions are always met.
I use seg as a signal for the 7-segment display to debug and find out in what state the FSM is at. At first it always displays the STATIC seg, as it should since UP seg and DOWN seg are only displayed for one cycle. But then when the error happens it's when it starts displaying the others seg, as well as the STATIC seg. It's a back-and-forth between STATIC and others, which I don't understand since when STATE = STATIC, it should only transition to UP or DOWN.
Thank you for reading this far, does anyone know what's going on?

As other comments have suggested, you should never drive a signal from more than one process block. Personally I don't like writing state machines like this, with 2 process blocks, because I find it confusing.
But regardless, your 2nd process block (the combinational one) should only be assigning NEXT_STATE, it should never make an assignment to STATE since that's taken care of by the first process block.

One issue is that your bar_FSM_cambioest sensitivity list is incomplete. It needs to include all signals who's changes will affect the process's output.
bar_FSM_cambioest: process(STATE, movTeclado, posBarraYTOP, posBarraYBOT)
My next question would be how fast is your clock? Are you trying to go from the STATIC segment display to the UP/DOWN one and back faster than the 7-segment display can reliably update?

Related

vhdl code bug counter with debouncing of push button

I need to implement counter to 100 that increase his count every push button press, it has debouncing circuit using rising edge detector, I got mistakes in the simulation, the counter increases without syncing the push press button. I’m not sure where in the problem, please help me.
the clk is 100Mhz
here is the code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use IEEE.std_logic_unsigned.all;
entity counter is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
button : in STD_LOGIC;
count : out STD_LOGIC_VECTOR (6 downto 0)
);
end counter;
architecture Behavioral of counter is
signal debounced_button : std_logic;
signal prev_debounced_button : std_logic := '0';
signal counter_value : unsigned(6 downto 0) := (others => '0');
begin
-- Debounce the button signal using a rising edge detector
process (clk)
begin
if rising_edge(clk) then
if button = '1' and prev_debounced_button = '0' then
debounced_button <= '1';
else
debounced_button <= '0';
end if;
prev_debounced_button <= debounced_button;
end if;
end process;
-- Count up when the button is pressed
process (clk, reset)
begin
if reset = '1' then
counter_value <= (others => '0');
elsif rising_edge(clk) then
if debounced_button = '1' then
if counter_value = 100 then
counter_value <= (others => '0');
else
counter_value <= counter_value + 1;
end if;
end if;
end if;
end process;
-- Convert the counter value to a std_logic_vector for output
count <= std_logic_vector(counter_value);
end Behavioral;
--test bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity counter_tb is
end counter_tb;
architecture Behavioral of counter_tb is
component counter
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
button : in STD_LOGIC;
count : out STD_LOGIC_VECTOR (6 downto 0)
);
end component;
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal button : std_logic := '0';
signal count : std_logic_vector(6 downto 0);
-- Stimulus process to generate clock and input signals
begin
uut: counter port map (
clk => clk,
reset => reset,
button => button,
count => count
);
clk_gen: process
begin
clk <= '0';
wait for 5 ns;
clk <= '1';
wait for 5 ns;
end process clk_gen;
stim_proc: process
begin
-- hold reset state for 100 ns.
reset <= '1';
wait for 20 ns;
reset <= '0';
wait;
end process;
process
begin
button <= '0';
wait for 40ns;
button <='1';
wait for 40ns;
button <= '0';
wait for 40ns;
button <='1';
wait for 40ns;
button <= '0';
wait for 40ns;
button <='1';
wait for 40ns;
end process;
end Behavioral;
I think I have problem in the test bench, I'm not sure
the simulation attachedenter image description here
You have two processes. The second process is a simple counter with an asynchronous reset -- no issues here. But let's look at the first.
process(clk)
begin
if rising_edge(clk) then
if button = '1' and prev_debounced_button = '0' then
debounced_button <= '1';
else
debounced_button <= '0';
end if;
prev_debounced_button <= debounced_button;
end if;
end process;
You have three signals, which I'll call button, debounced and prev. Note that they're signals, declared at the architecture level, and not variables within the process. Signals and variables are fundamentally different, as we'll see.
You also declare in the process' sensitivity list that it is sensitive only to clk. The simulator will only run this process whenever clk changes.
On the first rising edge of the clock, this process checks if the button is pressed, and if prev is zero. If so, it sets debounced to 1, else, it's set to 0. But debounced is a signal, which in this process is both being set and used. In a real system, this is called a race condition, and it's indeterminate which operation happens first. Your simulator handles this by always using the value of the signal in the previous time step. At time t-1, debounced was 0, so any statement that uses debounced at time t will use 0. Even if debounced is being changed to 1.
In other words, you have button high, debounced was just set high, and prev stays low.
On the second rising edge of the clock, it's likely buttonis still high as button presses last on the order of a million clock cycles. Since prev is still 0, debounced stays at 1, but this time the last debounced was 1 so prev is now set to 1.
Third rising edge, debounced goes to 0, since prev is now 1. prev stays 1.
Fourth rising edge, prev is still reading as 1, so debounced stays 0. prev now reads the old debounced and is now set to zero.
Fifth rising edge, prev reads as zero, so debounced goes to 1. But prev stays at 0 until the next tick.
This pattern continues as long as button is pressed. Once button goes to 0, then debounced is guaranteed to go to 0 on the next rising edge, and prev will go to 0 on the following tick.
In other words, debounced goes 1-1-0-0-1-1-0-0... oscillating at half the clock frequency for as long as the button is pressed. This isn't a debouncer. It's just using a button to turn on an oscillator. Any time button is 1, debounced_button will toggle; any time button is 0, debounced stays 0.
It's worth noting at this time that the second process uses debounced_button.
On to the simulation. Your system starts with previous at 0. At 40 ns, button goes high. What happens?
Nothing, at first -- you need a rising edge, which comes at 45 ns. Simultaneously, two processes run. The debouncer sees a button press, and sets debounced to 1. The counter uses the old value of debounced, and does nothing. prev uses the old value of debounced, and stays 0.
Next rising edge (55 ns), button is still high and prev is still low, so debounced stays at '1'. prev now goes to 1. Since debounced was high, the counter uses the old value, and now it increments.
65 ns: prev reads as 1, so debounced goes low. But since it was high a moment ago, the count increments again.
75 ns: debounced reads low, the counter doesn't increment.
85-115 ns: button is low, so debounced stays low, and the counter doesn't increment.
125 ns: button is high, so debounced goes high, but as should be obvious by now, the count won't increment.
Finally, note counter_value and count: count isn't being set inside a process with a sensitivity list, so it just changes immediately after counter_value, i.e. on the next simulator time step. Your processes run only when the simulator detects a change in a signal on its sensitivity list, and runs using a "snapshot" of the state of the signals at the start of the process. If you were using variables instead of signals, those are changed immediately and used identically to how sequential logic works in a standard programming language like C.
In reality, if you synthesize this design, you'll find that the behaviour is indeterminate. Your specific FPGA chip and the results of place and route will determine whether a signal is read before or after it's written.
When you have logic that changes a value and consumes it at the same time, the behaviour is indeterminate. You don't know which will happen first. I recommend having all outputs change on one clock edge (e.g. rising), and latch your inputs on the other clock edge (e.g. falling), to ensure that your inputs are stable before you try to use them.
Finally, debugging's a lot easier if you look at the internal signals. I simulated your code for 200 ns and got this:
Here, you can see exactly what's happening with prev and debounced, and immediately understand that there's a one-clock delay in the signal propagation.
Also, you can immediately see that your simulation's different from mine. It helps if you actually run the code you post here.

Assign multiple values to a signal during 1 process

If you assign a value to a signal in a process, does it only become the correct value of the signal at the end of the process?
So there would be no point in assigning a value to a signal more than once per process, because the last assignment would be the only one that would be implemented, correct?
I'm a bit desperate because I'm trying to implement the booth algorithm in VHDL with signals and I can't get it baked. It wasn't a problem with variables, but signals make it all more difficult.
I tried a for loop, but that doesn't work because I have to update the values within the loop.
My next idea is a counter in the testbench.
Would be very thanksful for an idea!
my current Code look like this:
architecture behave of booth is
signal buffer_result1, buffer_result2, buffer_result3: std_logic_vector(7 downto 0) := "0000"&b;
signal s: std_logic:= '0';
signal count1, count2: integer:=0;
begin
assignment: process(counter) is
begin
if counter = "000" then
buffer_result1 <= "0000"&b;
end if;
end process;
add_sub: process(counter) is
begin
if counter <= "011" then
if(buffer_result1(0) = '1' and s = '0') then
buffer_result2 <= buffer_result1(7 downto 4)-a;
else if (buffer_result1(0) = '0' and s = '1') then
buffer_result2 <= buffer_result1(7 downto 4)+a;
end if;
end if;
end process;
shift:process(counter) is
begin
if counter <= "011"
buffer_result3(7) <= buffer_result2(7);
buffer_result3(6 downto 0) <= buffer_result2(7 downto 1);
s<= buffer_result3(0);
else
result<=buffer_result3;
end if;
end behave;
Short answer: that's correct. A signal's value will not update until the end of your process.
Long answer: A signal will only update when its assignment takes effect. Some signal assignments will use after and specify a time, making the transaction time explicit. Without an explicit time given, signals will update after the default "time-delta," an "instant" of simulation time that passes as soon as all concurrently executing statements at the given sim time have completed (e.g. a process). So your signals will hold their initial values until the process completes, at which point sim time moves forward one "delta," and the values update.
That does not mean that multiple signal assignment statements to the same signal don't accomplish anything in a process. VHDL will take note of all assignments, but of a series of assignments given with the same transaction time, only the last assignment will take effect. This can be used for a few tricky things, although I've encountered differences of opinion on how often they should be tried. For instance:
-- Assume I have a 'clk' coming in
signal pulse : std_ulogic;
signal counter : unsigned(2 downto 0);
pulse_on_wrap : process(clk) is
begin
clock : if rising_edge(clk):
pulse <= '0'; -- Default assignment to "pulse" is 0
counter <= counter + 1; -- Counter will increment each clock cycle
if counter = 2**3-1 then
pulse <= '1'; -- Pulse high when the counter drops to 0 (after this cycle)
end if;
end if clock;
end process pulse_on_wrap;
Here, the typical behavior is to assign the value '0' to pulse on each clock cycle. But if counter hits its max value, there will be a following assignment to pulse, which will set it to '1' once simulation time advances. Because it comes after the '0' assignment and also has a "delta" transaction delay, it will override the earlier assignment. So this process will cause the signal pulse, fittingly, to go high for one cycle each time the counter wraps to zero and then drop the next - it's a pulse, after all! :^)
I provide that example only to illustrate the potential benefit of multiple assignments within a process, as you mention that in your question. I do not advise trying anything fancy with assignments until you're clear on the difference between variable assignment and signal assignment - and how that needs to be reflected in your code!
Try to think of things in terms of simulation time and hardware when it comes to signals. Everything is static until time moves forward, then you can handle the new values. It's a learning curve, but it'll happen! ;^)

VHDL finite state machine counter with start

i pretty new of vhdl and i'm trying to learn how to do a FSM with vhdl.
At moment i need a code that after a fixed count value, it give me back a pulse, in order to start a second FSM block. (I have a recurring signal every 100 kHz, i need to count it and release this signal after a fixed number of counts).
Actually it work as free run, every time that it see this signal, it start to count, but realy i want to add a "start" signal, so it must start to count this signal after it see this start signal.
at moment my working code is:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity counter is
Port (
signal_in : in STD_LOGIC := '0'; --segnale di start
clk : in STD_LOGIC; --clock di ingresso
reset : in STD_LOGIC; --ff reset
signal_out: out STD_LOGIC; --gate in uscita
count_val: in std_logic_vector (7 downto 0);
start : in STD_LOGIC := '0'
);
end counter;
architecture behavioral of counter is
type state_type is (idle, count_up);
signal state : state_type;
begin
process (reset, clk, signal_in, start)
variable index : integer :=0;
variable countlen: integer;
variable count_v: std_logic;
variable countlen2 : std_logic;
begin
countlen := to_integer(unsigned(count_val))-1;
if reset = '1' then
count_v := '0';
index := 0;
state <= idle;
else
--if start = '1' and
--if rising_edge(clk) then
if rising_edge(signal_in) then
case state is
when idle =>
count_v :='0';
index := 0;
if (signal_in = '1') then
state <= count_up;
else
state <= idle;
end if;
when count_up =>
if(index < countlen) then
state <=count_up;
index := index + 1;
elsif
index = countlen then
count_v := '1';
state <=idle;
end if;
when others => null;
end case;
end if;
end if;
signal_out <= count_v;
end process;
end Behavioral;
Any attempt to work with cose with "start = 1" will stop the count.
Please some one have some suggestion?
Kind REgards
Fulvio
Welcome om StackOverflow. Your specification is not 100% clear. What difference do you make between signal_in and start? According to your code and to your explanations, they both seem to act as a starter.
Moreover, there are several strange things with your code:
your process seems to be a synchronous one, with asynchronous reset. Its sensitivity list should contain only the clock and the reset. And its body should be:
process(clk, reset)
<variable declarations>
begin
<NOTHING HERE>
if reset = '1' then
<reset code>
elsif rising_edge(clk) then
<regular code>
end if;
<NOTHING HERE>
end process;
you are using signal_in as a clock and as a logic signal. This is extremely strange. Moreover, your if (signal_in = '1') then is always true (in the synthesis semantics) and thus useless.
You are initializing variables at declaration (index). This is not supported by some synthesizers and hardware targets. Moreover, even when supported, it works only at power up. If:
you intend to synthesize your code,
you want it to be portable across synthesizers and hardware targets,
you want to re-initialize signal and variables not only at power up but also when a reset input is asserted,
prefer a real explicit reset, instead, and guarantee that it is always asserted after power up (or at the beginning of a simulation) for proper first initialization.
you declare variable index with a full integer range, that is, 32 bits minimum, while 8 bits would suffice. This is a potential waste of hardware resources.
It is difficult to propose a solution without a clear and complete specification but assuming you want to count only after start has been asserted and only when signal_in is asserted, the following may be a starting point:
process (clk, reset)
variable index: natural range 0 to 255;
begin
if reset = '1' then
state <= idle;
signal_out <= '0';
index := 0;
elsif rising_edge(clk) then
case state is
when idle =>
signal_out <= '0';
index := 0;
if start = '1' then
state <= count_up;
end if;
when others =>
if signal_in = '1' then
if index = to_integer(unsigned(count_val)) - 1 then
state <= idle;
signal_out <= '1';
else
index := index + 1;
end if;
end if;
end case;
end if;
end process;
Note that this is really synchronous of your clock clk. I suspect that you made a very common mistake: as you wanted to increment your counter when signal_in is asserted you decided more or less to use signal_in as a clock. This is not a real synchronous and safe design. In a real safe synchronous design you do not use logic signals as clocks. You have well identified clocks and you use only these as clocks. In your case there is one single clock: clk. If you want to do something synchronously when a logic signal is asserted, wait for the rising edge of your clock and then test the logic signal and take appropriate actions.
thanks for your support.
Yes the point is that i need to "decimate" (or count) a signal.
This signal had a width of 50-100ns and it repeat itself with a frequency of 100 kHz.
so in my mind, this signal will go in to "signal in". My FPGA is an Actel proasic3 with a clock of 40 MHz.
In my setup this signal will be always on, but i don't want that my FSM will start to count as it see the first "signal in" but only when i send a "start" signal for the number of count that i indicate. (Realy they ask to me the possibility to decimate this signal up to 65000 count, so for sure i need to use a 16bit vector instead of 8bit).
The async reset is here "just in case" i need to reset the whole fsm in the middle of some data record.
Hope to be more clear now what this code should do.
For Old fart, yes indeed all my signal coming outside the fpga will be first synchronized with a simple 2 ff synchronizer with the FPGA clock

Can't get simple Bit Sequence Recognizer circuit to work (FSM)

This is a simple exercise for a Hardware course that I am taking. We are required to use Altera Quartus II and ModelSim to test the implementation; tools that I've never used before, so I might be missing something, and my explanations, lacking.
The circuit has 3 inputs (Data, Clock and Reset) and 2 outputs (Locked, Error). The sequence used in this exercise is 10001.
The problem ask to design a circuit that will recognize a sequence of bits. When the correct sequence is entered, you are granted access (the circuit enters the "UNLOCK" state; Locked output is 0). Otherwise, if at any point you enter the wrong bit, you trigger an alarm and you're supposed to remain in the "ERROR" state until the circuit is manually reset.
"Locked" is always 1 unless it gets to the "UNLOCK" state. "Error" is always 0 unless it gets to the "ERROR" state.
The circuit is supposed to always start out in a "RESET" state. Once it gets in the "UNLOCK" state, it stays there as long as the bits provided are 1, or goes to "RESET" if a 0 is encountered.
This is the state diagram that I've worked out:
Any help or ideas are welcome!
It turned out that almost all the logic behind my implementation is correct, the problem was a misunderstanding in using the CLRNs on the flip-flops and a typo in one of the assignments. As such, most of the images were removed to get rid of the clutter.
-- EDIT 1
With the following code (which should be correct), the waveform is not as expected (at least the lock is not)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
entity dlock is
port
(
DATA : IN STD_LOGIC;
RESET : IN STD_LOGIC;
CLOCK : IN STD_LOGIC;
LOCK : OUT STD_LOGIC;
ALARM : OUT STD_LOGIC
);
end dlock;
architecture bdf_type of dlock is
type STATE_type is (S_RESET, S1, S2, S3, S4, UNLOCK, S_ALARM);
signal state : STATE_type := S_RESET;
begin
process (clock) is
begin
if (rising_edge(clock)) then
-- `reset` always puts us back in the reset state
if (RESET = '1') then
state <= S_RESET;
else
case state is
when S_RESET =>
-- Reset; lock active and alarm off
LOCK <= '1';
ALARM <= '0';
if (DATA = '1') then
-- Correct bit, proceed to next state
state <= S1;
else
-- Incorrect bit; ALARM
state <= S_ALARM;
end if;
when S1 =>
if (DATA = '0') then
state <= S2;
else
state <= S_ALARM;
end if;
when S2 =>
if (DATA = '0') then
state <= S3;
else
state <= S_ALARM;
end if;
when S3 =>
if (DATA = '0') then
state <= S4;
else
state <= S_ALARM;
end if;
when S4 =>
if (DATA = '1') then
state <= UNLOCK;
else
state <= S_ALARM;
end if;
when UNLOCK =>
-- Lock inactive!
LOCK <= '0';
if (data = '0') then
state <= S_RESET;
else
state <= UNLOCK;
end if;
when S_ALARM =>
-- Alarm active in ALARM state
ALARM <= '1';
end case;
end if;
end if;
end process;
end bdf_type;
Your reset, as written in the VHDL, is active low. This means you're holding the circuit in reset most of the time. Your data pattern looks like you thought your reset was active high.
Your error signal, insofar as I can see in the image of the waveform posted, is behaving correctly. Every time you exit reset for a cycle, your data is 0, which sends you to the error state. Of course this only persists for one cycle since you immediately reset again.
These are just glitches, if you zoom in you'll see that the phantom unlocks are happening for 0 time (or very small time periods depending on your gate models). This is one reason why the output of combinational logic isn't used for clocking data. Passing the value through a flip-flop will remove glitches.
EDIT:
Furthermore, your state assignment table and your state output table disagree with each other. One lists the Q values from Q2 downto Q0 and the other lists from Q0 to Q2, but both list the unlocked state as "110". This doesn't cause issues for the Error state since "111" reads the same forwards and backwards.
EDIT2:
As far as avoiding glitches... glitches are the nature of combinational logic.
You could have locked sourced directly from a flop without adding latency by having the input to a "locked" flop be dictated by the same preconditions of the unlocked state (i.e. locked_d = not((state=s4 or state=locked) and data=1) and use locked_q.
You could just avoiding having locked be a function of multiple state bits by converting the state machine machine encoding to a one-hot or hybrid one-hot (where there is a dedicated bit for the locked/error states because they drive output bits , but the other 5 states use 3 shared state bits).
Think of a state table like this:
Q4 Q3 Q2 Q1 Q0 State
0 1 0 0 0 Reset
0 1 0 0 1 S1
0 1 0 1 0 S2
0 1 0 1 1 S3
0 1 1 0 0 S4
0 0 X X X Unlock
1 1 X X X Error
1 0 X X X X
0 1 1 0 1 X
0 1 1 1 X X
Where Q4 is your error bit and Q3 is your locked bit
That said, avoiding glitches is usually not important because they don't cause problems when used in sequential logic as the D inputs or clock enables.
I would say you have made your life needlessly more difficult with your approach. You don't need these D and Q signals at all, just code the state machine exactly as you see it in the excellent diagram at the start of your question. I haven't written the full code, but this should show the basic approach that leads to a minimal, easy to read result:
type STATE_type is (S_RESET, S1, UNLOCK, ERROR);
signal state : STATE_type := S_RESET;
...
process (clock) is
begin
if (rising_edge(clock)) then
-- `reset` always puts us back in the reset state
if (reset = '1') then
state <= S_RESET;
else
case state is
when S_RESET =>
-- Reset; lock active and alarm off
lock <= '1';
alarm <= '0';
if (data = '1') then
-- Correct bit, proceed to next state
state <= S1;
else
-- Incorrect bit; error
state <= ERROR;
end if;
when S1 =>
if (data = '0') then
state <= UNLOCK;
else
state <= ERROR;
end if;
when UNLOCK =>
-- Lock inactive!
lock <= '0';
if (data = '0') then
state <= RESET;
end if;
when ERROR =>
-- Alarm active in error state
alarm <= '1';
end case;
end if;
end if;
end process;
You should easily be able to add the other states S2 and onward to this.
If you need the lock and alarm to change state as soon as reset is asserted, you should implement an asynchronous reset, instead of the synchronous reset in the example above:
if (reset = '1') then
state <= S_RESET;
alarm <= '0';
lock <= '1';
elsif (rising_edge(clock)) then
case state is
-- `when` statements
end case;
end if;
Another advantage of writing it this way is that you can easily make the required pattern a constant:
constant PATTERN : std_logic_vector(0 to 4) := "10001";
Then your data comparisons in the various states would look like:
when S_RESET =>
if (data = PATTERN(0)) then
...
when S1 =>
if (data = PATTERN(1)) then
etc. You can then alter the required pattern with a simple one-line change.

Strange spikes in the signal ModelSim VHDL

I'm working on a final project for school and this is my first time working with VHDL in Quartus and ModelSIM. It's supposed to be a control for an elevator that services three floors. I have these strange spikes in a few signals, and I can't seem to find their source.
The one problem I have is a spike in a signal that feeds to an up/down counter that shows the current floor. When it stops at a floor, it ends up counting one additional time and going either one floor too high or one floor too low, while the next floor display seems to show the same floor just fine until another floor is called. The next floor display comes from an FSM, while the current floor display is from an up/down counter.
It's a bit complex to post everything here, so I'm just going to post the waveform for now in case someone's come across this signal spike thing and it ends up being a minor error/easy fix.!
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity FSM_Elevador is
port (Up_Down, Igual, Reset, Clock: in std_logic;
Andar_Dif: out std_logic
);
end FSM_Elevador;
architecture FSM_beh of FSM_Elevador is
type Elev_States is (Start, Wait_State, Pulse_State);
signal Current_State, Next_State: Elev_States;
signal RST, CLK, Sig_Andar_Dif, Cont_Mesmo_Andar: std_logic;
begin
RST <= Reset;
CLK <= Clock;
process(RST, CLK)
begin
if RST = '0' then
Current_State <= Start;
elsif CLK'event and CLK = '1' then
Current_State <= Next_State;
end if;
end process;
process(Current_State, Igual)
begin
case Current_State is
when Start =>
Next_State <= Wait_State;
when Wait_State =>
if Igual = '1' then
Next_State <= Wait_State;
Sig_Andar_Dif <= '0';
else
Next_State <= Pulse_State;
Sig_Andar_Dif <= '1';
end if;
when Pulse_State =>
if Igual = '1' then
Sig_Andar_Dif <= '0';
Next_State <= Wait_State;
else
Sig_Andar_Dif <= '0';
Next_State <= Pulse_State;
end if;
end case;
end process;
Andar_Dif <= Sig_Andar_Dif;
end FSM_beh;
fru1tbat: I use the Elev_pulse to make the counter go up or down once, and yes it enters the counter as a clock. It was suggested by the professor.
Edit: sorry that was the wrong code earlier. Andar_Dif is what sends out the signal that ends up going to the component that has Elev_Pulse
Get rid of the reassignment of Clock and Reset to CLK and RST and just use the signals from the port directly. That is creating a delta cycle delay which is the cause of these kind of spikes. It looks like you have resets with different delays in the design which can also complicate matters. If the removal of the indirection doesn't clear things up you need to scrutinize the ordering of when events are generated on signals and when they are processed.
The outputs from your state machine are unregistered which is also potentially involved. Consider reworking the FSM so that all outputs are registered. This is a better design practice in general as it ensures that you don't have unknown combinational delays affecting downstream logic.

Resources