← Back to list

Seven-Segment Display Driver in Verilog: A Beginner’s Guide to Multiplexed Displays

If blinking an LED was your “Hello, World!” on an FPGA, then lighting up a seven-segment display to show a real number is your first proper…

csjo logicion · 2026-06-12 00:34 · 0 claps · 3.9 min read
#fpga #verilog #hardware #digital-design #asics
Open on Medium ↗

Seven-Segment Display Driver in Verilog: A Beginner’s Guide to Multiplexed Displays

If blinking an LED was your “Hello, World!” on an FPGA, then lighting up a seven-segment display to show a real number is your first proper sentence. It is the moment your board stops looking like a science experiment and starts looking like a digital clock, a counter, or a voltmeter.

In this guide we will build a seven-segment display driver in Verilog from scratch. We will start with a single digit, then learn the time-multiplexing trick that lets one set of wires drive four digits at once. Along the way you will see real, synthesizable code you can drop onto almost any FPGA dev board.

What Is a Seven-Segment Display?

A seven-segment display is just seven LEDs arranged in a figure-eight pattern, plus a dot. Each LED is called a segment and is labeled with a letter from a to g. By turning the right segments on, you can draw every digit from 0 to 9 and even a few letters.


  __a__
 |     |
f|     |b
 |__g__|
 |     |
e|     |c
 |__d__|  o dp

There are two flavors you must know about, and getting this wrong is the single most common beginner mistake. The difference is which way the shared pin is wired:


Type            Shared pin   Segment turns ON when its pin is
Common Cathode  GND          HIGH (1)
Common Anode    VCC          LOW  (0)

In other words, a common-anode display needs active-low outputs: you send a 0 to turn a segment on. We will assume common anode here, because most cheap multi-digit modules use it. If your board is common cathode, simply drop the bitwise NOT in the code below.

Step 1: Decoding One Digit

The heart of the driver is a decoder: combinational logic that turns a 4-bit binary number (0 to 9) into the 7-bit pattern of segments to light. A case statement is the perfect tool for the job.


// Common-anode decoder: 0 = segment ON
// Bit order: seg = {a, b, c, d, e, f, g}
module bcd_to_7seg (
    input  wire [3:0] bcd,  // digit value 0-9    
    output reg  [6:0] seg   // active-low segments
);
    always @(*) begin
        case (bcd)
            4'd0: seg = 7'b0000001;
            4'd1: seg = 7'b1001111;
            4'd2: seg = 7'b0010010;
            4'd3: seg = 7'b0000110;
            4'd4: seg = 7'b1001100;
            4'd5: seg = 7'b0100100;
            4'd6: seg = 7'b0100000;
            4'd7: seg = 7'b0001111;
            4'd8: seg = 7'b0000000;
            4'd9: seg = 7'b0000100;
            default: seg = 7'b1111111; // blank
        endcase
    end
endmodule

Because we chose common anode, a 0 means “lit.” The segment order here is {a, b, c, d, e, f, g}, with segment a in the most significant bit. Always confirm this order against your board’s schematic, because vendors wire the segments in surprising ways.

Step 2: Driving Four Digits With Persistence of Vision

A four-digit display has 4 x 7 = 28 segment lines plus 4 common pins. Driving every segment independently would eat a huge number of FPGA pins. The elegant trick is multiplexing: we light only one digit at a time and switch between them so fast that your eye blends them into a single steady image. It is the same persistence-of-vision effect that turns movie frames into smooth motion.

The recipe is simple: use a refresh counter to step through the digits a few hundred times per second, enable one digit’s common pin at a time, and drive that digit’s value onto the shared segment lines.


module seven_seg_driver (
    input  wire       clk,            // e.g. 50 MHz
    input  wire [3:0] d0, d1, d2, d3, // four BCD digits    
    output reg  [6:0] seg,            // shared segment bus
    output reg  [3:0] an              // active-low digit enables
);
    // Free-running refresh counter
    reg [15:0] refresh = 0;
    always @(posedge clk)
        refresh <= refresh + 1'b1;

    wire [1:0] sel = refresh[15:14];  // 2-bit digit select
    reg  [3:0] digit;

    // Pick which digit is active this slot
    always @(*) begin
        case (sel)
            2'd0: begin an = 4'b1110; digit = d0; end
            2'd1: begin an = 4'b1101; digit = d1; end
            2'd2: begin an = 4'b1011; digit = d2; end
            2'd3: begin an = 4'b0111; digit = d3; end
        endcase
    end

    // Reuse the Step 1 decoder for the active digit
    bcd_to_7seg dec (.bcd(digit), .seg(seg));
endmodule

Notice the elegant move on the last line: rather than copying the decoder, we simply instantiate the bcd_to_7seg module from Step 1 and feed it whichever digit is active this slot. If the display refreshes too slowly, below roughly 60 times per second, the digits visibly flicker. Faster than that costs nothing you can see, so a few hundred hertz is a comfortable target.

Wiring It Up and Common Pitfalls

To put the driver to work, connect the seg outputs and the an digit-enable outputs to the right pins in your constraints file (an XDC file on modern Xilinx tools, a UCF on older ones), feed it four BCD digits, and you have an instant numeric readout. A handful of mistakes trip up almost every beginner.

First, if you forget to invert for a common-anode display, every digit appears as its photographic negative. Second, a refresh rate that is too low causes flicker, while switching wildly fast can make digits ghost into one another. Third, a mismatch between your case-statement bit order and the physical segment pins produces garbled characters. And finally, never drive the segments straight from FPGA pins without current-limiting resistors; your LEDs and your board will thank you.

What’s Next

Right now our driver expects each digit as a separate 4-bit value. Real designs usually hold a single binary number, like an 8-bit sensor reading, so the next challenge is splitting that number into individual decimal digits. There is a beautifully simple hardware algorithm for exactly this, called double dabble. In the next article, Binary to BCD Conversion in Verilog: The Double Dabble Algorithm, we will build it and wire it straight into the display driver from today.

Follow for more FPGA content, and happy hacking!


메타데이터
post_id
3b59a12cbd01
slug
seven-segment-display-driver-in-verilog-a-beginners-guide-to-multiplexed-displays-3b59a12cbd01
url
https://medium.com/@ahe24mobile/seven-segment-display-driver-in-verilog-a-beginners-guide-to-multiplexed-displays-3b59a12cbd01
canonical_url
https://medium.com/@ahe24mobile/seven-segment-display-driver-in-verilog-a-beginners-guide-to-multiplexed-displays-3b59a12cbd01
author_url
https://medium.com/@ahe24mobile
status
ok
fetched_at
2026-06-17 08:20:12