VHDL traffic lights FSM using LPM counter: where to set/reset counter? - vhdl

This one has been boggling my mind for the last two days so i've came to the internets for help.
Bit of background info first...
I'm working on a traffic lights project for uni using an Altera DE0 board. I'm a complete n00b with regards to VHDL and this first assignment was more or less a case of "here's an example of a finite state machine and an example of an LPM counter, go make some traffic lights". I think the idea's just to get a feel for using VHDL and mess about with the code to get something working.
We were given an example from a textbook (Free Range VHDL p93 iirc) on an FSM then shown how to make an LPM counter using the Megawizard Plugin Manager in Quartus and basically just had to merge/expand them. Its the first thing i've done using VHDL.
The traffic lights are supposed to be for an intersection of a major road and minor road. The default state will be major road green and minor road red. It should stay in this state until it detects a pushbutton (i.e. a car at the minor road) then go amber then red, then the minor road will go from red to green and stay in green for 10 seconds. It will stay in each other state for 1 second.
I've used 9 states (A-I) and one LPM counter and i'm just looking for a 1 in bit 26 and 29 of the "q" output(?) of the counter for the 1 and 10 second delay.
My problem is that i'm not sure where to set and reset the timer. Technically it should be reset after moving into each state then set (i.e. allowed to count) when moving to the next state.
I'll paste my code below, currently the timer_rst bits are commented out. I've tried placing them in all different lines in the code but the closest i've came to having it work is setting and resetting the timer where those commented out set and reset parts are. When i un-comment them out one at a time and run it each time it'll go from state A to B then C but after that it'll just skip to E then it moves through states so quick all the LEDs light and it seems to jump randomly through different states. Obviously this isn't how it should be done!
Can anyone help me out then?
I hope i've given a decent enough explanation here. I'll paste a link to a video of the board running my code and you can check the code out below too.
Thanks for any help provided!
--Finite state machine using DE0 board implementing a set
--of traffic tights at a major road/minor road junction.
--Major road is green until car present at minor road
--then goes to red while minor road goes to green.
--8 states, A-H. A is 'default' state
--1 sec delay: state B,C,D,F,G,H, 10 sec delay: state E,I.
--Maj Rd lights: LEDG(5 downto 3) Red/Amber/Green.
--Min Rd lights: LEDG(2 downto 0) Red/Amber/Green.
--State vector printed on LEDG(9 downto 6) in binary
--library declarations
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY lpm; --allows use of Altera LPM functions
USE lpm.all;
--entity
entity TRAFFICLIGHTS is
port(
KEY : in std_logic_vector(1 downto 0); --minor rd car present KEY(1) & reset KEY(0)-ACTIVE LOW!
CLOCK_50 : in std_logic;
LEDG : out std_logic_vector(9 downto 0); --6 lights 2 * (red/amber/green) & state vector
HEX0 : out std_LOGIC_VECTOR(7 downto 0) --display current state
);
end TRAFFICLIGHTS;
-- architecture
architecture TRAFFICLIGHTS_arch of TRAFFICLIGHTS is
type state_type is (A,B,C,D,E,F,G,H,I);
signal PS, NS : state_type;
signal timer_rst : std_logic; --wiring to delay components , one_sec, ten_sec
signal timer_q : std_logic_vector(29 downto 0); --output from timer
--LPM counter
component timer
PORT
(
aclr : IN STD_LOGIC ;
clock : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (29 DOWNTO 0) --uses bit 29 for 10 secs, bit 26 for 1 sec
);
end component;
begin
--wiring up LPM counter to signals
U1 : timer
PORT MAP (
aclr => timer_rst,
clock => clock_50,
q => timer_q
);
--detects change in clock, next state or reset key press
sync_proc: process (clock_50, NS, KEY(0))
begin
if (KEY(0)='0') then --if reset pressed, return to state A
PS <= A;
elsif (rising_edge(clock_50)) then --else put present state in next state
PS <= NS;
end if;
end process sync_proc;
--detect change in present state or KEY(1) i.e. minor road car present
comb_proc: process (PS, KEY(1))
begin
case PS is
when A => --when in A: MajRd green, MinRd red, no delay
--show state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0001";
HEX0(7 downto 0) <= "10001000"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '1'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (KEY(1) = '0') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= B; --if car present #MinRd, next state is B
else NS <= A;
end if;
when B => --when in B: MajRd amber, MinRd red, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0010";
HEX0(7 downto 0) <= "10000011"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '1'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= C;
else NS <= B;
end if;
when C => --when in C: MajRd red, MinRd red, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0011";
HEX0(7 downto 0) <= "11000110"; --display state on 7 seg
LEDG(5) <= '1'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= D;
else NS <= C;
end if;
when D => --when in D: MajRd red, MinRd red/amber, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0100";
HEX0(7 downto 0) <= "10100001"; --display state on 7 seg
LEDG(5) <= '1'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '1'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= E;
else NS <= D;
end if;
when E => --when in E: MajRd red, MinRd green, 10 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0101";
HEX0(7 downto 0) <= "10000110"; --display state on 7 seg
LEDG(5) <= '1'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '0'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '1'; --MinGreen
if (timer_q(29) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= F;
else NS <= E;
end if;
when F => --when in F: MajRd red, MinRd amber, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0110";
HEX0(7 downto 0) <= "10001110"; --display state on 7 seg
LEDG(5) <= '1'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '0'; --MinRed
LEDG(1) <= '1'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= G;
else NS <= F;
end if;
when G => --when in G: MajRd red, MinRd red, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0111";
HEX0(7 downto 0) <= "10010000"; --display state on 7 seg
LEDG(5) <= '1'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= H;
else NS <= G;
end if;
when H => --when in H: MajRd red/amber, MinRd red, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "1000";
HEX0(7 downto 0) <= "10001001"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '1'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= I;
else NS <= H;
end if;
--new state allows MajRd to stay green (10 sec) if car at MinRd or not
when I => --when in I: MajRd green, MinRd red, 10 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "1001";
HEX0(7 downto 0) <= "11111001"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '1'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(29) = '1') then
--timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= C;
else NS <= A;
end if;
when others => -- the catch-all condition
PS <= A; -- if anything else, return to state A
end case;
end process comb_proc;
end TRAFFICLIGHTS_arch;
Video:
https://www.dropbox.com/s/70tkr67zdjj8pyk/File%2018-03-2015%2017%2057%2054.mov?dl=0
Tried adding intermediate states, here's the code from the case statement for the first few below. Its just starting and jumping straight to state B now and not going anywhere.
case PS is
when A => --when in A: MajRd green, MinRd red, no delay
--show state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0001";
HEX0(7 downto 0) <= "10001000"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '0'; --MajAmber
LEDG(3) <= '1'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (KEY(1) = '0') then
timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= B; --if car present #MinRd, next state is B
else NS <= A_1;
end if;
when A_1 =>
--LEDs and 7 seg same as A
LEDG(9 downto 0) <= "0001001100";
HEX0(7 downto 0) <= "10001000"; --display state on 7 seg
timer_rst <= '0'; -- allow timer to count
NS <= B;
when B => --when in B: MajRd amber, MinRd red, 1 sec delay
--print state vector using 4 bit binary 1-8
LEDG(9 downto 6) <= "0010";
HEX0(7 downto 0) <= "10000011"; --display state on 7 seg
LEDG(5) <= '0'; --MajRed
LEDG(4) <= '1'; --MajAmber
LEDG(3) <= '0'; --MajGreen
LEDG(2) <= '1'; --MinRed
LEDG(1) <= '0'; --MinAmber
LEDG(0) <= '0'; --MinGreen
if (timer_q(26) = '1') then
timer_rst <= '1'; -- reset timer
--timer_rst <= '0'; -- allow timer to count
NS <= B_1;
else NS <= B;
end if;
when B_1 =>
--LEDs and 7 seg same as B
LEDG(9 downto 0) <= "0010010100";
HEX0(7 downto 0) <= "10000011"; --display state on 7 seg
timer_rst <= '0'; -- allow timer to count
NS <= C;

Chris, check "FINITE STATE MACHINES IN HARDWARE...", V. A. Pedroni, MIT Press, page 166.

Related

Contolling an LCD display in VHDL on Nexys A7 100T

I'm looking to control an external display where the pins are connected to the ports JA and JB on the Nexys A7 100T, I've configured the state machine below according to the instructions in the datasheet but nothing is being displayed. Since this is the first time I'm controlling a display through VHDL, I suspect that either the display is not working or something is not being initialized in the correct manner.
--- Initialization and Data transfer of LCD display---
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;
entity LCD is
generic(
display_lines : std_logic := '0'; --Amount of displaylines: (0 = 1-line, 1 = 2-lines)
font_type : std_logic := '0'; -- Font type: (0 = 5x8 font, 1 = 5x11 font but only available for 1 line mode)
display_on : std_logic := '1'; -- Diplay ON/OFF: (0 = OFF, 1 = ON)
display_off : std_logic := '0';
cursor : std_logic := '0'; -- Cursor ON/OFF: (0 = OFF, 1 = ON)
blink : std_logic := '0'; -- Blink ON/OFF: (0 = OFF, 1 = ON)
I_D : std_logic := '1'; -- Increment/Decrement (0 = Decrement(move left), 1 = Increment(Move right))
shift : std_logic := '1'; -- Shift of display( 0 = Shift not perfomed, 1 = shift done according to I/D)
LCD_freq : integer := (100e6/270e3) - 1 -- Operating frequency of display
);
port(
CLK100MHZ, reset: in std_logic; -- 100MHZ clock and reset signal
LCD_RW: out std_logic; -- Read/write bit for LCD
LCD_RS: out std_logic; -- Register Select for LCD
LCD_E: out std_logic; -- Enable bit for the LCD
data: out std_logic_vector(7 downto 0) -- Data being sent to LCD including setup bits.
);
end entity;
architecture arch of LCD is
Type control is (RESET_1,RESET_2,RESET_3, FUNCTION_SET, DISPLAY_OFF1, DISPLAY_CLEAR, DISPLAY_ON1, ENTRY_MODE_SET, WRITE_T, RETURN_HOME,TOGGLE_E, HOLD);
signal freq_div :std_logic_vector(9 downto 0);
signal clk270 : std_logic; -- LCD clock
signal state, next_cmd: control;
begin
-- Clock for the LCD frequency
process(CLK100MHZ, reset)
begin
if reset = '1' then
freq_div <= (others => '0');
elsif rising_edge(CLK100MHZ) then
if freq_div = LCD_freq then
clk270 <= '1';
freq_div <= (others => '0');
else
clk270 <= '0';
freq_div <= freq_div + 1;
end if; -- freq_div
end if; -- reset
end process;
-- State diagram controlling display
process(CLK100MHZ, reset)
begin
if reset = '1' then
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00111000";
state <= TOGGLE_E;
next_cmd <= RESET_1;
elsif rising_edge(CLK100MHZ) then
if clk270 = '1' then
case state is
when RESET_1 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00111000";
state <= TOGGLE_E;
next_cmd <= RESET_2;
when RESET_2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00111000";
state <= TOGGLE_E;
next_cmd <= RESET_3;
when RESET_3 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00111000";
state <= TOGGLE_E;
next_cmd <= FUNCTION_SET;
--- Initilization steps done individually ---
when FUNCTION_SET => -- sets the function for the display
LCD_RS <= '0';
LCD_RW <= '0';
data <= "0011" & display_lines & font_type & "00";
LCD_E <= '1'; -- Enables function for display
state <= TOGGLE_E;
next_cmd <= DISPLAY_OFF1;
when DISPLAY_OFF1 => -- Turns the display off
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00001" & display_off & cursor & blink;
state <= TOGGLE_E;
next_cmd <= DISPLAY_CLEAR;
when DISPLAY_CLEAR => -- Clears the display
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00000001";
state <= TOGGLE_E;
next_cmd <= DISPLAY_ON1;
when DISPLAY_ON1 => -- Turns on the display
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00001" & display_on & cursor & blink;
state <= TOGGLE_E;
next_cmd <= ENTRY_MODE_SET;
when ENTRY_MODE_SET => -- Sets the increment and shift
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "000001" & I_D & shift;
state <= TOGGLE_E;
next_cmd <= WRITE_T;
when WRITE_T =>
LCD_RS <= '1';
LCD_RW <= '0';
LCD_E <= '1';
data <= "01000101"; --Letter T
state <= TOGGLE_E;
next_cmd <= RETURN_HOME;
when RETURN_HOME =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
data <= "00000010";
state <= TOGGLE_E;
next_cmd <= WRITE_T;
-- Toggles a falling edge for Enable.
when TOGGLE_E =>
LCD_E <= '1';
state <= HOLD;
when HOLD =>
state <= next_cmd;
end case;
end if; -- clk270kHz
end if; -- reset
end process;
end arch;
The display is of the archetype ST7066U. Any feedback is appreciated.

UART Receiver Testbench

I am new to VHDL, and I trying to verify UART receiver how is it works.
I synthesized the code below (quoted form the book) and its fine but if needs more let me know :).
The frequency for my board is 100 Mhz and the data I want receive is 8 bits, baud rate is 115200, how the clock and tick should be in the testbench or what is the right testbench here?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity uart_rx is
generic(
data_bits: integer := 8; -- # d a t a b i t s
stop_bit_ticks: integer := 16 -- # t i c k s f o r s t o p b i t s
);
Port ( rx : in STD_LOGIC;
clk : in STD_LOGIC;
reset: in STD_LOGIC;
tick : in STD_LOGIC;
rx_done : out STD_LOGIC;
data_out : out STD_LOGIC_VECTOR (7 downto 0));
end uart_rx;
architecture arch of uart_rx is
type state_type is (idle, start, data, stop);
SIGNAL state_reg, state_next: state_type;
SIGNAL s_reg, s_next: UNSIGNED(3 downto 0);
SIGNAL n_reg, n_next: UNSIGNED(2 downto 0);
SIGNAL b_reg, b_next: STD_LOGIC_VECTOR(7 downto 0);
begin
-- FSMD s t a t e & d a t a r e g i s t e r s
process(clk, reset) -- FSMD state and data regs.
begin
if (reset = '1') then
state_reg <= idle;
s_reg <= (others => '0');
n_reg <= (others => '0');
b_reg <= (others => '0');
--rx_done <= '0';
-- rx <= '1';
elsif (clk'event and clk='1') then
state_reg <= state_next;
s_reg <= s_next;
n_reg <= n_next;
b_reg <= b_next;
end if;
end process;
-- n e x t - s t a t e l o g i c & d a t a p a t h f u n c t i o n a l u n i t s / r o u t i n g
process (state_reg, s_reg, n_reg, b_reg, tick, rx)
begin
state_next <= state_reg;
s_next <= s_reg;
n_next <= n_reg;
b_next <= b_reg;
rx_done <= '0';
case state_reg is
when idle =>
if (rx = '0') then
state_next <= start;
s_next <= (others => '0');
end if;
when start =>
if (tick = '1') then
if (s_reg = 7) then
state_next <= data;
s_next <= (others => '0');
n_next <= (others => '0');
else
s_next <= s_reg + 1;
end if;
end if;
when data =>
if (tick = '1') then
if (s_reg = 15) then
s_next <= (others => '0');
b_next <= rx & b_reg(7 downto 1);
if (n_reg = (data_bits - 1)) then
state_next <= stop;
else
n_next <= n_reg + 1;
end if;
else
s_next <= s_reg + 1;
end if;
end if;
when stop =>
if (tick = '1') then
if (s_reg = (stop_bit_ticks - 1)) then
state_next <= idle;
rx_done <= '1';
else
s_next <= s_reg + 1;
end if;
end if;
end case;
end process;
data_out <= b_reg;
end arch;
Typically, UART receivers run at 8 times the bit rate. If your bit rate is 115200, this means a sample rate of 921600. If you are running at 100Mzh, you will need to create a clock divider to get you from 100 MHz to the desired sample rate. To go from 921600 to 100 MHz the following will work:
100 MHz = 100,000,000 Hz
921600 samples/sec = 921,600 Hz
divider = 100,000,000/921,600 = 108.51.
Thus, you will need a counter that will count up to 109 (we round up as we have to sample at an integer of the clock rate) on rising_edge(clock), then raise an enable signal that tells your component its time to sample the line and reset the counter. The example above assumed 8 samples/bit which is typical to my knowledge. Thus, if you set the period of your main clock in the simulation to be 1ns and set up the counter circuit I described above, you should get the test bench you are looking for.
EDIT: warning about uneven clock division
Almost forgot to mention this. Since your clock rate does not divide evenly into the bit rate for the UART, some extra care must be taken when coding up this circuit. Your sample rate will move later and later in the transmission with the scheme I have proposed. You will probably have to add a simple offset to change your counter to 108 on the even bits to keep you more aligned with the incoming data bits.
See here for some more info: https://electronics.stackexchange.com/questions/42236/uart-receiver-clock-speed

VHDL possible signal misunderstanding in combinational code

My code is intended to be purely combinational. Only one element gives some synchronysm to simulation. it is a 4*4 led matrix where only 3*3 (starting on the top right) is valid. like:
-- LED matrix
-- rows\cols | A | B | C | D |
---------------------------------
-- 1 | 3 | 2 | 1 | 0 |
-- 2 | 7 | 6 | 5 | 4 |
-- 3 | 11 | 10| 9 | 8 |
-- 4 | 15 | 14| 13| 12| <- row not used
-- ^
-- |
-- column not used
---------------------------------
the following code compiles and simulates on an FPGA but not with the desired behaviour. The wanted behabiour is to iluminate a red led if one input is detected, 2 if 2, and if 3 are in a row in the matrix at the same time instead of 3 red led it should show 3 blue ones. no memory involved. The observed behaviour is explained as coments within the code.
entity mt is
PORT (
cD, cC, cB, cA : in std_logic; -- comparators for each column. cA is not necessary / not used.
row : inout std_logic_vector (3 downto 0) := (others => '0'); -- detection of each row.
led_R, led_G, led_B : out std_logic_vector (15 downto 0) := (others => '1') -- '1' indicates they are OFF. 12 to 15 will not be used (as well as 3, 7, 11 positions)
);
end mt;
I have 4 concurrent processes which depend on the signals explained:
architecture arc1 of mt is
signal led_R_in : std_logic_vector (15 downto 0) := (others => '1');
signal led_G_in : std_logic_vector (15 downto 0) := (others => '1'); -- don't think they are necessary
signal led_B_in : std_logic_vector (15 downto 0) := (others => '1'); -- don't think they are necessary
signal counter : std_logic_vector (1 downto 0) := "00";
begin
PROCESS (row, cD, cC, cB, cA) -- execute if any of these change
BEGIN
CASE row IS
WHEN "1000" => -- row 1 --
-- (LEDs are active at logic level 0)
CASE cD IS
WHEN '1' => led_R_in(0) <= '0'; led_G_in(0) <= '1'; led_B_in(0) <= '1';
WHEN OTHERS => led_R_in(0) <= '1'; led_G_in(0) <= '1'; led_B_in(0) <= '1';
END CASE;
CASE cC IS
WHEN '1' => led_R_in(1) <= '0'; led_G_in(1) <= '1'; led_B_in(1) <= '1';
WHEN OTHERS => led_R_in(1) <= '1'; led_G_in(1) <= '1'; led_B_in(1) <= '1';
END CASE;
CASE cB IS
WHEN '1' => led_R_in(2) <= '0'; led_G_in(2) <= '1'; led_B_in(2) <= '1';
WHEN OTHERS => led_R_in(2) <= '1'; led_G_in(2) <= '1'; led_B_in(2) <= '1';
END CASE;
CASE cA IS -- not necessary
WHEN '1' => led_R_in(3) <= '0'; led_G_in(3) <= '1'; led_B_in(3) <= '1';
WHEN OTHERS => led_R_in(3) <= '1'; led_G_in(3) <= '1'; led_B_in(3) <= '1';
END CASE;
WHEN "0100" => -- row 2 --
-- (LEDs are active at logic level 0)
CASE cD IS
WHEN '1' => led_R_in(4) <= '0'; led_G_in(4) <= '1'; led_B_in(4) <= '1';
WHEN OTHERS => led_R_in(4) <= '1'; led_G_in(4) <= '1'; led_B_in(4) <= '1';
END CASE;
CASE cC IS
WHEN '1' => led_R_in(5) <= '0'; led_G_in(5) <= '1'; led_B_in(5) <= '1';
WHEN OTHERS => led_R_in(5) <= '1'; led_G_in(5) <= '1'; led_B_in(5) <= '1';
END CASE;
CASE cB IS
WHEN '1' => led_R_in(6) <= '0'; led_G_in(6) <= '1'; led_B_in(6) <= '1';
WHEN OTHERS => led_R_in(6) <= '1'; led_G_in(6) <= '1'; led_B_in(6) <= '1';
END CASE;
CASE cA IS -- not necessary
WHEN '1' => led_R_in(7) <= '0'; led_G_in(7) <= '1'; led_B_in(7) <= '1';
WHEN OTHERS => led_R_in(7) <= '1'; led_G_in(7) <= '1'; led_B_in(7) <= '1';
END CASE;
WHEN "0010" => -- row 3 --
-- (LEDs are active at logic level 0)
CASE cD IS
WHEN '1' => led_R_in(8) <= '0'; led_G_in(8) <= '1'; led_B_in(8) <= '1';
WHEN OTHERS => led_R_in(8) <= '1'; led_G_in(8) <= '1'; led_B_in(8) <= '1';
END CASE;
CASE cC IS
WHEN '1' => led_R_in(9) <= '0'; led_G_in(9) <= '1'; led_B_in(9) <= '1';
WHEN OTHERS => led_R_in(9) <= '1'; led_G_in(9) <= '1'; led_B_in(9) <= '1';
END CASE;
CASE cB IS
WHEN '1' => led_R_in(10) <= '0'; led_G_in(10) <= '1'; led_B_in(10) <= '1';
WHEN OTHERS => led_R_in(10) <= '1'; led_G_in(10) <= '1'; led_B_in(10) <= '1';
END CASE;
CASE cA IS -- not necessary
WHEN '1' => led_R_in(11) <= '0'; led_G_in(11) <= '1'; led_B_in(11) <= '1';
WHEN OTHERS => led_R_in(11) <= '1'; led_G_in(11) <= '1'; led_B_in(11) <= '1';
END CASE;
WHEN OTHERS => Null; -- not necessary, although for avoiding latches creation I will have to assign them.
END CASE;
END PROCESS;
PROCESS (led_R_in) -- executes when led_R_in changes
BEGIN
-- leds are ON at '0' value
-- the problem is that, when initialising, the first row of leds will be blue, which means that
-- led_R_in 0, 1, 2 are 0, but they should be 1 as stated in their default values
-- the second and third row initialises correctly to green values, although the response to changes in the inputs are not only affecting them but also their neighbours, which I think it could be a problem of the FPGA pin assignment.
if (led_R_in(0)='0' AND ((led_R_in(1)='0' AND led_R_in(2)='0') OR (led_R_in(4)='0' AND led_R_in(8)='0') OR (led_R_in(5)='0' AND led_R_in(10)='0'))) then
led_B(0) <= '0';
led_R(0) <= '1';
led_G(0) <= '1';
else
led_R(0) <= led_R_in(0);
led_G(0) <= '0';
led_B(0) <= '1';
end if;
if (led_R_in(1)='0' AND ((led_R_in(0)='0' AND led_R_in(2)='0') OR (led_R_in(5)='0' AND led_R_in(9)='0'))) then
led_B(1) <= '0';
led_R(1) <= '1';
led_G(1) <= '1';
else
led_R(1) <= led_R_in(1);
led_G(1) <= '0';
led_B(1) <= '1';
end if;
if (led_R_in(2)='0' AND ((led_R_in(0)='0' AND led_R_in(1)='0') OR (led_R_in(10)='0' AND led_R_in(6)='0') OR (led_R_in(5)='0' AND led_R_in(8)='0'))) then
led_B(2) <= '0';
led_R(2) <= '1';
led_G(2) <= '1';
else
led_R(2) <= led_R_in(2);
led_G(2) <= '0';
led_B(2) <= '1';
end if;
if (led_R_in(4)='0' AND ((led_R_in(0)='0' AND led_R_in(8)='0') OR (led_R_in(5)='0' AND led_R_in(6)='0'))) then
led_B(4) <= '0';
led_R(4) <= '1';
led_G(4) <= '1';
else
led_R(4) <= led_R_in(4);
led_G(4) <= '0';
led_B(4) <= '1';
end if;
if (led_R_in(5)='0' AND ((led_R_in(2)='0' AND led_R_in(8)='0') OR (led_R_in(1)='0' AND led_R_in(9)='0') OR (led_R_in(0)='0' AND led_R_in(10)='0') OR (led_R_in(6)='0' AND led_R_in(4)='0'))) then
led_B(5) <= '0';
led_R(5) <= '1';
led_G(5) <= '1';
else
led_R(5) <= led_R_in(5);
led_G(5) <= '0';
led_B(5) <= '1';
end if;
if (led_R_in(6)='0' AND ((led_R_in(2)='0' AND led_R_in(10)='0') OR (led_R_in(5)='0' AND led_R_in(4)='0'))) then
led_B(6) <= '0';
led_R(6) <= '1';
led_G(6) <= '1';
else
led_R(6) <= led_R_in(6);
led_G(6) <= '0';
led_B(6) <= '1';
end if;
if (led_R_in(8)='0' AND ((led_R_in(2)='0' AND led_R_in(5)='0') OR (led_R_in(4)='0' AND led_R_in(0)='0') OR (led_R_in(9)='0' AND led_R_in(10)='0'))) then
led_B(8) <= '0';
led_R(8) <= '1';
led_G(8) <= '1';
else
led_R(8) <= led_R_in(8);
led_G(8) <= '0';
led_B(8) <= '1';
end if;
if (led_R_in(9)='0' AND ((led_R_in(1)='0' AND led_R_in(5)='0') OR (led_R_in(10)='0' AND led_R_in(8)='0'))) then
led_B(9) <= '0';
led_R(9) <= '1';
led_G(9) <= '1';
else
led_R(9) <= led_R_in(9);
led_G(9) <= '0';
led_B(9) <= '1';
end if;
if (led_R_in(10)='0' AND ((led_R_in(9)='0' AND led_R_in(8)='0') OR (led_R_in(5)='0' AND led_R_in(0)='0') OR (led_R_in(6)='0' AND led_R_in(2)='0'))) then
led_B(10) <= '0';
led_R(10) <= '1';
led_G(10) <= '1';
else
led_R(10) <= led_R_in(10);
led_G(10) <= '0';
led_B(10) <= '1';
end if;
END PROCESS;
PROCESS -- executes at the beginning (when is equal to "00") and changes its value every 10 ms
BEGIN
counter <= counter + "01"; -- there is an intended combinational loop here, so that it does this forever changing the row.
WAIT for 10 ms;
END PROCESS;
PROCESS (counter) -- executes at the beginning (when is equal to "00") and when counter changes (every 10 ms)
BEGIN
CASE counter IS
WHEN "00" => row <= "1000";
WHEN "01" => row <= "0100";
WHEN "10" => row <= "0010";
WHEN OTHERS => Null; -- for avoiding the automatic generation of latches due to non existing assignments. although it could also be row <= "0001"
END CASE;
END PROCESS;
END arc1;
why is it not working with the behaviour that I want?

why the elevator stuckes in a state?

this is vhdl code for an elevator for 7 floors
the coding is encapsulated into 3 states s0=no move ,s1=move up , s2 =move down
if it is in s0 it should wait for 2 cycles after that move up/down according to the desired floor or called floor on the next positive edge .
The problem is that the elevator is stuck in s1 state
could anyone help me please ?
-- Cad Project
-- Project Name : Elevator
-- Date : 18\12\2013
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--Entity Decleration
entity Elevator is
port (call, clk, press : in std_logic;
-- Call To Call The Elevator ,press if a key is pressrd from the pannel inside the elevator .
Desire_floor, Call_Floor : in std_logic_vector (2 downto 0);
-- Desired_floor is the floor number choosed from inside the elevator .
-- called_floor is the floor number that the "Call" Key has been pressed from .
weight : in std_logic;
Door_open_close, Move_up, move_down, OverWeight : out std_logic;
-- Door_open_close is 1 when opened ,0 when closed .
-- OverWeight is 1 when the weight is over 500 KG.
Current_Floor : buffer std_logic_vector (2 downto 0) := "000";
temp1_state, temp2_state : buffer std_logic_vector (1 downto 0);
o1, o2, o3, o4, o5, o6, o7 : out std_logic_vector (2 downto 0));
end;
--architecture Decleration
architecture Elevator of Elevator is
type state is (s0, s1, s2);
--s0 state represents no move ,s1 state represents move up ,s2 state represents move down .
signal current_state : state := s0;
signal next_state : state;
signal Desired_floor, Called_Floor : std_logic_vector (2 downto 0);
signal X : std_logic := '0'; -- X is a signal used to restart the timer or to resume it's count.
signal counter : std_logic_vector (2 downto 0); -- Timer befor closing/opening the doors "timer".
signal counter2 : std_logic_vector (2 downto 0) := "000"; -- Timer for the elevator to move up or down.
signal temp1, temp2, temp3, temp4, temp5 : std_logic_vector (2 downto 0);
begin
P1 : process (clk , weight, x)
variable s11 : std_logic_vector (2 downto 0) := "000";
-- Variable insted of the counter signal -->to have the direct assigment
begin
if (weight = '1') then
OverWeight <= '1';
current_state <= s0;
elsif (clk'event and clk = '1') then
if (x = '1') then -- if X equals to 1 that means restart the timer.
s11 := "000";
elsif (x = '0') then -- if X equals 0 then count up "keep counting ".
s11 := s11+1;
end if;
current_state <= next_state;
counter <= s11;
OverWeight <= '0';
end if;
counter <= s11;
o5 <= counter;
end process P1;
P2 : process (clk) -- this process if for the 2nd timer.
variable s4 : std_logic_vector (2 downto 0) := "000";
-- Variable insted of the counter2 signal -->to have the direct assigment
begin
if (rising_edge(clk)) then
if (press = '1') then
Desired_floor <= Desire_floor;
if (Current_Floor < Desired_floor) then
s4 := s4 +1;
elsif (Current_Floor > Desired_floor) then
s4 := s4 -1;
end if;
counter2 <= s4;
elsif (call = '1') then
Called_Floor <= Call_Floor;
if (Current_Floor < Called_Floor) then
s4 := s4 +1;
elsif (Current_Floor > Called_Floor) then
s4 := s4 -1;
end if;
end if;
end if;
counter2 <= s4;
o1 <= counter2;
o2 <= Desired_floor;
o3 <= Called_Floor;
counter2 <= s4;
--Desired_floor<=Desire_floor;
end process P2;
P3 : process (counter, current_state)
begin
case current_state is
when s0 =>
if(counter < "001") then
x <= '0';
Current_Floor <= Current_Floor;
next_state <= s0;
temp1_state <= "00";
else
if (press = '1') then
if(Desired_floor > Current_Floor) then
next_state <= s1;
temp2_state <= "01";
elsif (Desired_floor < Current_Floor) then
next_state <= s2;
temp2_state <= "10";
end if;
else
if (call = '1') then
if (Called_Floor > Current_Floor) then
next_state <= s1;
temp2_state <= "01";
elsif (Called_Floor < Current_Floor) then
next_state <= s2;
temp2_state <= "10";
end if;
end if;
end if;
x <= '1';
end if;
Door_open_close <= '1';
Move_up <= '0';
move_down <= '0';
Current_Floor <= counter2;
temp1_state <= "00";
when s1 =>
temp1 <= (Desired_floor - Current_Floor);
temp2 <= (Called_Floor-Current_Floor);
o4 <= temp1;
if ((temp1 /= "000") or (temp2 /= "000")) then
next_state <= s1;
temp2_state <= "01";
Current_Floor <= counter2;
elsif (((Desired_floor-Current_Floor) = "000")or ((Called_Floor-Current_Floor) = "000")) then
next_state <= s0;
temp2_state <= "00";
end if;
Door_open_close <= '0';
Move_up <= '1';
move_down <= '0';
Current_Floor <= counter2;
x <= '1';
temp1_state <= "01";
when s2 =>
temp3 <= (Current_Floor-Desired_floor);
temp4 <= (Current_Floor-Called_Floor);
if ((temp3 /= "000") or (temp4 /= "000")) then
next_state <= s2;
temp2_state <= "10";
Current_Floor <= counter2;
elsif (((Current_Floor-Desired_floor) = "000") or ((Called_Floor-Current_Floor) = "000")) then
next_state <= s0;
temp2_state <= "00";
end if;
Door_open_close <= '0';
Move_up <= '0';
move_down <= '1';
Current_Floor <= counter2;
x <= '1';
temp1_state <= "10";
end case;
end process P3;
end;
**********************************
I mad a lot of changes on the code and still have a problem .How can i save the value of an input at a certain state and ignore it's value until the next entering of the same state
-- Cad Project .
-- Project Name : Elevator .
-- Date : 18\12\2013.
-- Group Number : 13.
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--Entity Decleration
entity Elevator is
port (clk, press : in std_logic;
-- Call To Call The Elevator ,press if a key is pressrd from the pannel inside the elevator .
Desire_floor : in std_logic_vector (2 downto 0);
-- Desired_floor is the floor number choosed from inside the elevator .
-- called_floor is the floor number that the "Call" Key has been pressed from .
weight : in std_logic;
Door_open_close, Move_up, move_down, OverWeight : out std_logic;
-- Door_open_close is 1 when opened ,0 when closed .
-- OverWeight is 1 when the weight is over 500 KG.
Current_Floor : buffer std_logic_vector (2 downto 0) := "000";
temp1_state, temp2_state : buffer std_logic_vector (1 downto 0);
o1, o2, o3, o4, o5, o6, o7 : out std_logic_vector (2 downto 0));
end;
--architecture Decleration
architecture Elevator of Elevator is
type state is (s0, s1, s2);
--s0 state represents no move ,s1 state represents move up ,s2 state represents move down .
signal current_state : state := s0;
signal next_state : state;
signal Desired_floor : std_logic_vector (2 downto 0);
signal X : std_logic := '0'; -- X is a signal used to restart the timer or to resume it's count.
signal counter : std_logic_vector (2 downto 0); -- Timer befor closing/opening the doors "timer".
signal counter2 : std_logic_vector (2 downto 0) := "000"; -- Timer for the elevator to move up or down.
signal temp1, temp2, temp3, temp4, temp5 : std_logic_vector (2 downto 0);
signal temp6 : std_logic;
begin
P1 : process (clk , weight, x)
variable s11 : std_logic_vector (2 downto 0) := "000";
-- Variable insted of the counter signal -->to have the direct assigment
begin
if (weight = '1') then
OverWeight <= '1';
current_state <= s0;
elsif (clk'event and clk = '1') then
if (x = '1') then -- if X equals to 1 that means restart the timer.
s11 := "000";
elsif (x = '0') then -- if X equals 0 then count up "keep counting ".
s11 := s11+1;
end if;
current_state <= next_state;
counter <= s11;
OverWeight <= '0';
end if;
counter <= s11;
o5 <= counter;
end process P1;
P2 : process (clk) -- this process if for the 2nd timer.
variable s4 : std_logic_vector (2 downto 0) := "000";
-- Variable insted of the counter2 signal -->to have the direct assigment
begin
if (rising_edge(clk)) then
if (press = '1') then
if (Current_Floor < Desired_floor) then
s4 := s4 +1;
elsif (Current_Floor > Desired_floor) then
s4 := s4 -1;
end if;
counter2 <= s4;
end if;
end if;
counter2 <= s4;
o1 <= counter2;
o2 <= Desired_floor;
counter2 <= s4;
end process P2;
P3 : process (counter, current_state)
begin
case current_state is
when s0 =>
if(counter < "010") then
x <= '0';
Current_Floor <= Current_Floor;
next_state <= s0;
temp1_state <= "00";
else
if (press = '1') then
if(Desired_floor > Current_Floor) then
next_state <= s1;
temp2_state <= "01";
elsif (Desired_floor < Current_Floor) then
next_state <= s2;
temp2_state <= "10";
end if;
end if;
x <= '1';
end if;
Door_open_close <= '1';
Move_up <= '0';
move_down <= '0';
Current_Floor <= counter2;
temp1_state <= "00";
temp6 <= '1';
when s1 =>
temp1 <= (Desired_floor - Current_Floor);
o4 <= temp1;
if ((temp1 /= "000")) then
next_state <= s1;
temp2_state <= "01";
Current_Floor <= counter2;
elsif ((Desired_floor-Current_Floor) = "000") then
next_state <= s0;
temp2_state <= "00";
end if;
Door_open_close <= '0';
Move_up <= '1';
move_down <= '0';
Current_Floor <= counter2;
x <= '1';
temp1_state <= "01";
temp6 <= '0';
when s2 =>
temp3 <= (Current_Floor-Desired_floor);
if ((temp3 /= "000")) then
next_state <= s2;
temp2_state <= "10";
Current_Floor <= counter2;
elsif ((Current_Floor-Desired_floor) = "000") then
next_state <= s0;
temp2_state <= "00";
end if;
Door_open_close <= '0';
Move_up <= '0';
move_down <= '1';
Current_Floor <= counter2;
x <= '1';
temp1_state <= "10";
temp6 <= '0';
end case;
end process P3;
P4 : process (temp6, clk)
begin
if (clk 'event and clk = '1') then
if (temp6'event and temp6 = '1')then
--if ( current_state =s0 ) then
Desired_floor <= Desire_floor;
else
Desired_floor <= Desired_floor;
end if;
Desired_floor <= Desired_floor;
end if;
end process P4;
end;
It looks like the floor counter is only being incremented when the user presses 'press'.
Explanation
If we're not on the desired floor yet, then Current_Floor is driven by counter2
temp1 <= (Desired_floor - Current_Floor);
o4 <= temp1;
if ((temp1 /= "000")) then
next_state <= s1;
temp2_state <= "01";
Current_Floor <= counter2;
counter2 is driven by s4:
if (rising_edge(clk)) then
if (press = '1') then
if (Current_Floor < Desired_floor) then
s4 := s4 +1;
elsif (Current_Floor > Desired_floor) then
s4 := s4 -1;
end if;
counter2 <= s4; <-
end if;
end if;
counter2 <= s4; <-
o1 <= counter2;
o2 <= Desired_floor;
counter2 <= s4; <-
(Aside, why do you assign s4 to counter2 three times?)
s4 is only changed when press is asserted. So your lift is only going to be moving up or down a floor when someone pushes the button.
General comments
Your process sensitivity lists are all over the place! Your sensitivity lists should either be clock or clock,reset. Asynchronous processes (those without a clock in the sensitivity list) do have their place, but I generally avoid them unless absolutely necessary. I find it a lot easier to visualise the timing behaviour in my head when everything is strictly synchronous.
P1 : process (clk , weight, x) <- BAD
P2 : process (clk) <- GOOD
P3 : process (counter, current_state) <- OKAY
P4 : process (temp6, clk) <- BAD
Indenting has a huge impact on how you read the code. Learn to indent properly. I use the emacs VHDL mode, it has a great beautify function which really helps. I ran your code through it when I edited the comment and wrote this answer.
Your signal names need work. things like temp are a bad idea. you are doing pretty well with commenting though, so that's a plus. keep that up!
I'm going to briefly mention the code redundancy, example:
if (temp6'event and temp6 = '1')then
--if ( current_state =s0 ) then
Desired_floor <= Desire_floor;
else
Desired_floor <= Desired_floor;
end if;
Desired_floor <= Desired_floor;
If it was different before, totally understandable, but clean that stuff up, unnecessary reading for whoever is on the receiving end of your code.

VHDL output declarations with State machine

I'm trying to write a state machine in VHDL that will scan a 4x4 keypad. I want keyP set to 0 at the start and after a Reset. I also want the Col to be set to "1111" at the start and after a Reset.
As I'm not fully versed in VHDL programming I'm sure it's just a stupid syntax error.
The error I get is:
Error (10818): Can't infer register for "Col[0]" at Lab_7_Keypad.vhd(39) because it does not hold its value outside the clock edge
and the same for Col[1], Col[2], Col[3], and for keyP as well.
Here's my code for the start of it all. Can someone give me an idea where I've gone wrong?
Thanks
ENTITY Lab_7_Keypad IS
PORT(
nReset : IN STD_LOGIC;
clk : IN STD_LOGIC;
row : IN STD_LOGIC_VECTOR (3 downto 0);
Col : OUT STD_LOGIC_VECTOR (3 downto 0);
data : OUT STD_LOGIC_VECTOR (3 downto 0);
keyP : OUT STD_LOGIC);
END Lab_7_Keypad;
ARCHITECTURE a OF Lab_7_Keypad IS
TYPE STATE_TYPE IS ( Col1Set, Col2Set, Col3Set, Col4Set );
SIGNAL coltest : STATE_TYPE;
BEGIN
PROCESS (clk, nReset )
BEGIN
keyP <= '0';
Col <= "1111";
IF nReset = '0' THEN -- asynch Reset to zero
coltest <= Col1Set;
Col <="1111";
keyP <= '0';
ELSIF clk'EVENT AND clk = '1' THEN -- triggers on PGT
CASE coltest IS
WHEN Col1Set =>
Col <="1110";
CASE row IS
WHEN "1110"=>--row 1
data <= "0001";
keyP <= '1';
WHEN "1101"=>--row 2
data <= "0100";
keyP <= '1';
WHEN "1011"=>--row 3
data <= "0111";
keyP <= '1';
WHEN "0111"=>--row 4
data <= "1110";
keyP <= '1';
WHEN OTHERS => coltest <= Col2Set;
END CASE;
--And continues with same Case statements three more times.
Your synthesis error is due to the fact that you are assigning to both col and keyP outside of the asynchronous reset or clock edge of your process, this does not correctly describe a register. Remove these assignments and the errors should go away.
PROCESS (clk, nReset )
BEGIN
--keyP <= '0'; <------- BAD!
--Col <= "1111"; <------- BAD!
IF nReset = '0' THEN -- asynch Reset to zero
coltest <= Col1Set;
Col <="1111";
keyP <= '0';
ELSIF clk'EVENT AND clk = '1' THEN -- triggers on PGT
CASE coltest IS
WHEN Col1Set =>
Col <="1110";
CASE row IS
WHEN "1110"=>--row 1
data <= "0001";
keyP <= '1';
WHEN "1101"=>--row 2
data <= "0100";
keyP <= '1';
WHEN "1011"=>--row 3
data <= "0111";
keyP <= '1';
WHEN "0111"=>--row 4
data <= "1110";
keyP <= '1';
WHEN OTHERS => coltest <= Col2Set;
END CASE;
--And continues with same Case statements three more times.

Resources