The seven-segment display is the most iconic FPGA project after blinking an LED. Building the driver correctly teaches you combinational decoders, active-low logic, and time-division multiplexing — all patterns you'll use constantly in real FPGA work. This lesson builds a single-digit decoder and then a full 4-digit multiplexed driver.
| Port | Dir | Width | Meaning |
|---|---|---|---|
| digit | input | 4 | hex digit to display (0x0 – 0xF) |
| seg | output | 7 | segment pattern {a,b,c,d,e,f,g} — active-low |
// 7-segment decoder: 4-bit hex input -> 7-segment output (active-low)
// seg[6:0] = {a, b, c, d, e, f, g} 0 = ON, 1 = OFF
module seg7_decoder (
input wire [3:0] digit,
output reg [6:0] seg // active-low segments
);
always @(*) begin
case (digit)
// abcdefg
4'h0: seg = 7'b000_0001; // 0
4'h1: seg = 7'b100_1111; // 1
4'h2: seg = 7'b001_0010; // 2
4'h3: seg = 7'b000_0110; // 3
4'h4: seg = 7'b100_1100; // 4
4'h5: seg = 7'b010_0100; // 5
4'h6: seg = 7'b010_0000; // 6
4'h7: seg = 7'b000_1111; // 7
4'h8: seg = 7'b000_0000; // 8 (all on)
4'h9: seg = 7'b000_0100; // 9
4'hA: seg = 7'b000_1000; // A
4'hB: seg = 7'b110_0000; // b
4'hC: seg = 7'b011_0001; // C
4'hD: seg = 7'b100_0010; // d
4'hE: seg = 7'b011_0000; // E
4'hF: seg = 7'b011_1000; // F
default: seg = 7'b111_1111; // blank
endcase
end
endmodule`timescale 1ns/1ps
module tb_seg7_decoder;
reg [3:0] digit;
wire [6:0] seg;
seg7_decoder dut(.digit(digit),.seg(seg));
integer errors=0;
task chk(input [3:0]d, input [6:0]exp);
digit=d; #1;
if(seg!==exp)begin $display("FAIL digit=%0h seg=%b exp=%b",d,seg,exp);errors=errors+1;end
else $display("ok digit=%0h seg=%b",d,seg);
endtask
initial begin
chk(4'h0,7'b0000001); // 0
chk(4'h1,7'b1001111); // 1
chk(4'h2,7'b0010010); // 2
chk(4'h8,7'b0000000); // 8 all segments on
chk(4'hF,7'b0111000); // F
if(errors==0) $display("ALL TESTS PASSED"); else $display("%0d FAILED",errors);
$finish;
end
endmoduleok digit=0 seg=0000001 ok digit=1 seg=1001111 ok digit=2 seg=0010010 ok digit=8 seg=0000000 ok digit=f seg=0111000 ALL TESTS PASSED
Real boards have 4 digits sharing the same 7 segment pins. The FPGA cycles through each digit at ~1 kHz, enabling one at a time. Human persistence of vision makes it look like all four are on simultaneously.
// 4-digit multiplexed 7-segment display driver
// Cycles through all 4 digits at ~1 kHz (100MHz / 100_000)
module display4 #(parameter REFRESH = 100_000) (
input wire clk,
input wire rst,
input wire [15:0] data, // {digit3, digit2, digit1, digit0} each 4 bits
output reg [3:0] an, // anode enables — active-low (one LOW at a time)
output wire [6:0] seg // shared segment outputs
);
reg [16:0] cnt;
reg [1:0] sel; // which digit is active
reg [3:0] cur_digit;
// Refresh counter
always @(posedge clk) begin
if (rst) begin cnt<=0; sel<=0; end
else if (cnt==REFRESH-1) begin cnt<=0; sel<=sel+1; end
else cnt<=cnt+1;
end
// Mux digit data and anode
always @(*) begin
case (sel)
2'd0: begin cur_digit=data[3:0]; an=4'b1110; end
2'd1: begin cur_digit=data[7:4]; an=4'b1101; end
2'd2: begin cur_digit=data[11:8]; an=4'b1011; end
2'd3: begin cur_digit=data[15:12]; an=4'b0111; end
default: begin cur_digit=4'h0; an=4'b1111; end
endcase
end
seg7_decoder dec(.digit(cur_digit),.seg(seg));
endmodulean[3:0].clkdiv from Day 9 for a clean refresh rate.Seven LEDs (a-g) arranged to form digits. Turning specific combinations on/off displays 0-9 and letters. Most FPGA boards use active-low: 0 turns a segment ON.
All 4 digits share the same 7 segment pins. The FPGA rapidly enables one digit at a time (~1 kHz). Persistence of vision makes all 4 appear simultaneously lit.
Most boards use common-anode displays (anode to VCC). Driving a pin LOW pulls the cathode down, completing the circuit to light the segment.