
Traffic Light FSM
April 2026 · VHDL Project
The Problem
Traffic intersections require precise, deterministic control to prevent collisions — both signals can never show Green or Yellow at the same time. The goal of this Discovery Project was to design a digital controller from scratch using VHDL that safely manages a dual-direction traffic light system, cycling through Green → Yellow → Red phases for two roads (A and B) in a guaranteed conflict-free pattern.
This project served as a hands-on introduction to hardware description languages and finite state machine design — core ECE skills that bridge the gap between software logic and actual hardware implementation.
The Process
I started by sketching out the state diagram on paper: four states (S0–S3) arranged in a cycle, where each state defines the exact light for both directions. S0 gives A Green / B Red, S1 gives A Yellow / B Red, S2 flips to A Red / B Green, and S3 gives A Red / B Yellow before looping back.
With the state diagram locked in, I translated it into a VHDL behavioral architecture. The FSM uses a 2-bit state register encoded as a STD_LOGIC_VECTOR, advancing on each rising clock edge. An asynchronous active-high reset forces the machine back to S0. All six output signals (a_red, a_yellow, a_green, b_red, b_green, b_yellow) are derived combinationally from the current state using concurrent signal assignments.
I then wrote a full testbench with a 10 ns clock period, applying reset for 12 ns before releasing it. The simulation runs for 13 full clock cycles, allowing observation of multiple complete rotations through all four states. The testbench separates clock generation and stimulus into independent processes for clean modularity.
Successes & Challenges
The biggest success was getting the FSM to compile, simulate, and produce a correct waveform on the first real attempt. Seeing all eight signals toggle in the exact pattern I designed on paper was a satisfying validation that the state logic was correct.
One early challenge was understanding signal assignment semantics in VHDL — specifically the difference between concurrent assignments (outside a process) and sequential assignments (inside a process). I initially placed the output assignments inside the clocked process, which introduced an unintended one-cycle delay on the outputs. Moving them to concurrent assignments outside the process fixed the timing.
Another roadblock was the reset timing: I initially used a synchronous reset, but the waveform showed the FSM not resetting cleanly when reset was asserted between clock edges. Switching to an asynchronous reset (checking reset before the rising_edge condition) resolved this and matched the intended behavior.
ECE Skills Gained
This project directly developed several core ECE competencies: VHDL hardware description — writing synthesizable RTL using IEEE STD_LOGIC_1164 libraries, entity/architecture pairs, and process blocks. FSM design methodology — translating a state diagram into a case-based state machine with proper encoding. Testbench development — constructing self-checking verification environments with separate clock and stimulus processes.
Beyond the code itself, I gained practical experience reading waveform outputs to debug timing issues, understanding the distinction between combinational and sequential logic, and working with simulation tools to verify that a digital design behaves exactly as intended before it ever touches real hardware.
Final Thoughts
This Discovery Project reinforced my interest in digital design and the hardware side of ECE. Writing VHDL felt fundamentally different from writing software — you're describing physical hardware that runs in parallel, not sequential instructions. That mental shift was one of the most valuable takeaways.
If I were to continue this project, I'd extend it with configurable timing (so each state holds for a realistic duration rather than a single clock cycle), add a pedestrian crossing request input, and target an FPGA board to see it running on real hardware with actual LEDs. The foundation is solid — the FSM structure scales naturally to more complex intersection controllers.
Technologies Used
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity traffic_light is
Port (
clk : in STD_LOGIC;
reset : in STD_LOGIC;
a_red : out STD_LOGIC;
a_yellow : out STD_LOGIC;
a_green : out STD_LOGIC;
b_red : out STD_LOGIC;
b_yellow : out STD_LOGIC;
b_green : out STD_LOGIC
);
end traffic_light;
architecture Behavioral of traffic_light is
signal state : STD_LOGIC_VECTOR(1 downto 0) := "00";
begin
process(clk, reset)
begin
if reset = '1' then
state <= "00";
elsif rising_edge(clk) then
case state is
when "00" => state <= "01";
when "01" => state <= "10";
when "10" => state <= "11";
when others => state <= "00";
end case;
end if;
end process;
a_green <= '1' when state = "00" else '0';
a_yellow <= '1' when state = "01" else '0';
a_red <= '1' when state = "10" or state = "11" else '0';
b_red <= '1' when state = "00" or state = "01" else '0';
b_green <= '1' when state = "10" else '0';
b_yellow <= '1' when state = "11" else '0';
end Behavioral;library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use STD.env.all;
entity traffic_light_tb is
end traffic_light_tb;
architecture testbench of traffic_light_tb is
signal clk : STD_LOGIC := '0';
signal reset : STD_LOGIC := '1';
signal a_red : STD_LOGIC;
signal a_yellow : STD_LOGIC;
signal a_green : STD_LOGIC;
signal b_red : STD_LOGIC;
signal b_yellow : STD_LOGIC;
signal b_green : STD_LOGIC;
begin
uut: entity work.traffic_light
port map (
clk => clk,
reset => reset,
a_red => a_red,
a_yellow => a_yellow,
a_green => a_green,
b_red => b_red,
b_yellow => b_yellow,
b_green => b_green
);
clk_process: process
begin
for i in 0 to 12 loop
clk <= '0';
wait for 5 ns;
clk <= '1';
wait for 5 ns;
end loop;
wait;
end process;
stim_proc: process
begin
wait for 12 ns;
reset <= '0';
wait for 100 ns;
stop;
wait;
end process;
end testbench;