Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> VHDL

Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example

A finite‑state machine (FSM) is a deterministic logic model whose output depends not only on the current input but also on the sequence of past inputs and outputs. In FPGA design and time‑dependent VHDL algorithms, an FSM is the go‑to abstraction for capturing stateful behaviour.

FSMs in VHDL are typically implemented as clocked processes that use a state signal to remember the last configuration. The state signal acts as an internal register, allowing the design to react to events that span multiple clock cycles.

Basic VHDL Tutorials – Part 3

Traffic Lights as an FSM

Consider a four‑way intersection controlled by traffic lights. The lights cycle through a finite set of visible states – for example, North/South red, North/South green, West/East red, etc. The timing of each state (5 s for red or yellow, 60 s for green) is driven by elapsed clock cycles.

Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example

We model these behaviours by defining an enumerated type that lists all possible states:

type t_State is (NorthNext, StartNorth, North, StopNorth,
                 WestNext, StartWest, West, StopWest);

Then we declare a signal of that type to hold the current state:

signal State : t_State;

With the state signal in place, the FSM logic lives inside a single clocked process that uses a case statement. Each when branch corresponds to a distinct state and contains the output assignments for that state. A counter tracks the elapsed time and drives the transition to the next state when its value reaches a predefined threshold.

One‑Process FSM Template

process(Clk) is
begin
    if rising_edge(Clk) then
        if nRst = '0' then
            State   <= <reset_state>;
            Counter <= 0;
        else
            case State is
                when <state_name> =>
                    <set_outputs_for_this_state_here>
                    if <state_change_condition_is_true> then
                        State <= <next_state_name>;
                    end if;
                ...
            end case;
        end if;
    end if;
end process;

Note: You can implement FSMs using one‑, two‑, or three‑process styles. See FSM Styles Explained.

Practical Exercise

Below is a complete, synthesizable example that implements a traffic‑light controller. The design uses a 100 Hz clock to simplify simulation while still demonstrating realistic timing.

Testbench

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

entity T20_FiniteStateMachineTb is
end entity;

architecture sim of T20_FiniteStateMachineTb is
    constant ClockFrequencyHz : integer := 100; -- 100 Hz
    constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;

    signal Clk         : std_logic := '1';
    signal nRst        : std_logic := '0';
    signal NorthRed    : std_logic;
    signal NorthYellow : std_logic;
    signal NorthGreen  : std_logic;
    signal WestRed     : std_logic;
    signal WestYellow  : std_logic;
    signal WestGreen   : std_logic;
begin
    i_TrafficLights : entity work.T20_TrafficLights(rtl)
        generic map(ClockFrequencyHz => ClockFrequencyHz)
        port map(
            Clk         => Clk,
            nRst        => nRst,
            NorthRed    => NorthRed,
            NorthYellow => NorthYellow,
            NorthGreen  => NorthGreen,
            WestRed     => WestRed,
            WestYellow  => WestYellow,
            WestGreen   => WestGreen);

    Clk <= not Clk after ClockPeriod / 2;

    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);
        nRst <= '1';
        wait;
    end process;
end architecture;

State‑Machine Module

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

entity T20_TrafficLights is
    generic(ClockFrequencyHz : integer);
    port(
        Clk         : in std_logic;
        nRst        : in std_logic; -- Active low reset
        NorthRed    : out std_logic;
        NorthYellow : out std_logic;
        NorthGreen  : out std_logic;
        WestRed     : out std_logic;
        WestYellow  : out std_logic;
        WestGreen   : out std_logic);
end entity;

architecture rtl of T20_TrafficLights is
    type t_State is (NorthNext, StartNorth, North, StopNorth,
                     WestNext, StartWest, West, StopWest);
    signal State : t_State;
    signal Counter : integer range 0 to ClockFrequencyHz * 60;
begin
    process(Clk) is
    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';
            else
                -- Default outputs
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';
                Counter <= Counter + 1;

                case State is
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= StartNorth;
                        end if;
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= North;
                        end if;
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        if Counter = ClockFrequencyHz * 60 - 1 then
                            Counter <= 0;
                            State   <= StopNorth;
                        end if;
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= WestNext;
                        end if;
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= StartWest;
                        end if;
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= West;
                        end if;
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        if Counter = ClockFrequencyHz * 60 - 1 then
                            Counter <= 0;
                            State   <= StopWest;
                        end if;
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        if Counter = ClockFrequencyHz * 5 - 1 then
                            Counter <= 0;
                            State   <= NorthNext;
                        end if;
                end case;
            end if;
        end if;
    end process;
end architecture;

Running the simulation for five minutes produces a waveform that shows the FSM cycling through its eight states, with green phases lasting one minute each.

Designing a Finite‑State Machine in VHDL: A Practical Traffic Light Example

Analysis

Key takeaways from the code:

The resulting waveform confirms that the FSM advances correctly: the State signal toggles through the eight defined states, and each green phase persists for one minute.

Takeaway

Proceed to the next tutorial for advanced FSM techniques.

VHDL

  1. Maximizing Performance of Qt State Machines
  2. Creating String Lists in VHDL: Best Practices & Example
  3. Implementing a PWM Controller in VHDL: Design, Simulation, and FPGA Demo
  4. Designing a Robust VHDL Ring Buffer FIFO in Block RAM
  5. Implementing a Dynamic Linked List in VHDL with Protected Types and Access Pointers
  6. Build a Reliable Timer in VHDL: Counting Clock Cycles to Hours
  7. Building a Clock‑Triggered Process in VHDL: A Practical Guide
  8. Mastering Concurrent Statements in VHDL: A Practical Guide
  9. Mastering std_logic_vector: Creating Signal Vectors in VHDL
  10. Using Sensitivity Lists in VHDL Processes for Reliable RTL Design