To display numbers on a seven-segment display using a finite state machine
(FSM) or time-division multiplexing (TDM) on an FPGA like the Digilent BASYS
board, you need to control multiple seven-segment displays by quickly
cycling through them. This gives the illusion that all displays are active
simultaneously.
Here’s how you can implement this:
### Time-Division Multiplexing for Seven-Segment Displays
Most FPGA boards, including the BASYS series, use time-division multiplexing
to control multiple seven-segment displays. The basic idea is to light up one
digit at a time very quickly. If done fast enough, it creates the illusion that all
digits are lit simultaneously.
### Design Steps
1. **Seven-Segment Display Basics**:
- Each digit on the display consists of 7 LEDs arranged in the shape of an
"8", plus an optional decimal point (DP). Each segment is labeled A to G.
- To display a number, you need to turn on or off specific segments for each
digit.
2. **Time-Division Multiplexing**:
- The BASYS board might have four digits in the seven-segment display.
Instead of driving all four digits at once, we'll drive one at a time.
- Use a clock divider to create a slower clock signal for multiplexing (e.g., 1
kHz). The slow clock controls which digit is currently active.
- Cycle through each digit, sending the appropriate segment data to that
digit.
3. **Finite State Machine (FSM) or Control Logic**:
- The FSM will control which digit is active and what value to display on that
digit. The states will represent each digit being displayed.
### Verilog Implementation
Below is a simplified Verilog code to demonstrate the concept:
#### 1. Seven-Segment Decoder Module
This module converts a 4-bit binary input to a 7-segment display format.
```verilog
module seven_seg_decoder(
input [3:0] digit,
output reg [6:0] segments // Segments are A to G
);
always @(*) begin
case(digit)
4'd0: segments = 7'b0000001; // 0
4'd1: segments = 7'b1001111; // 1
4'd2: segments = 7'b0010010; // 2
4'd3: segments = 7'b0000110; // 3
4'd4: segments = 7'b1001100; // 4
4'd5: segments = 7'b0100100; // 5
4'd6: segments = 7'b0100000; // 6
4'd7: segments = 7'b0001111; // 7
4'd8: segments = 7'b0000000; // 8
4'd9: segments = 7'b0000100; // 9
default: segments = 7'b1111111; // Blank or invalid
endcase
end
endmodule
```
#### 2. Clock Divider for Multiplexing
Create a clock divider to generate a slower clock signal for multiplexing.
```verilog
module clock_divider(
input clk, // Input clock (e.g., 100 MHz)
output reg slow_clk // Output slower clock (e.g., 1 kHz)
);
reg [16:0] counter; // 17-bit counter for division
always @(posedge clk) begin
counter <= counter + 1;
slow_clk <= counter[16]; // Divides the clock by 2^17 (128k)
end
endmodule
```
#### 3. Multiplexing Controller and FSM
This is the main module that handles the multiplexing using an FSM or
control logic.
```verilog
module seven_seg_multiplexer(
input clk, // System clock
input [15:0] number, // Input number to display (4 digits)
output reg [3:0] anodes, // Anode control for the 4 displays
output [6:0] segments // Segments control
);
wire slow_clk;
reg [1:0] current_digit; // 2-bit for 4 states (0 to 3)
reg [3:0] digit_value; // Current digit value to display
// Instantiate clock divider
clock_divider clk_div (
.clk(clk),
.slow_clk(slow_clk)
);
// Instantiate seven-segment decoder
seven_seg_decoder decoder (
.digit(digit_value),
.segments(segments)
);
// FSM for digit multiplexing
always @(posedge slow_clk) begin
current_digit <= current_digit + 1; // Move to the next digit
case (current_digit)
2'd0: begin
anodes = 4'b1110; // Enable digit 0
digit_value = number[3:0]; // Display least significant digit
end
2'd1: begin
anodes = 4'b1101; // Enable digit 1
digit_value = number[7:4]; // Display the second digit
end
2'd2: begin
anodes = 4'b1011; // Enable digit 2
digit_value = number[11:8]; // Display the third digit
end
2'd3: begin
anodes = 4'b0111; // Enable digit 3
digit_value = number[15:12];// Display the most significant digit
end
endcase
end
endmodule
```
### Explanation
1. **`seven_seg_decoder`**: Converts a 4-bit binary number to the 7-
segment display format. This module defines how each digit from 0 to 9 is
represented on the display.
2. **`clock_divider`**: Generates a slower clock signal (`slow_clk`) from the
system clock. The slow clock is used to switch between digits fast enough
that they all appear to be lit simultaneously.
3. **`seven_seg_multiplexer`**: Main module that handles multiplexing.
- The FSM is implemented using a counter (`current_digit`) that increments
with every `slow_clk` cycle.
- Based on `current_digit`, it activates one of the four anodes and assigns
the corresponding digit value to `digit_value`.
- The `anodes` signal is used to enable the specific digit on the BASYS
board's seven-segment display.
### Testing and Validation
- **Simulation**: Use simulation software like Xilinx Vivado or ModelSim to
test the modules. Check the waveforms to ensure that each digit is being
displayed correctly and that the multiplexing is functioning properly.
- **Hardware Testing**: Download the synthesized design onto the BASYS
board and observe the seven-segment display. Verify that the numbers are
displayed correctly and are stable.
Would you like further details on any part of the implementation or help with
another aspect?
To implement this design in Xilinx Vivado, you'll need to follow a series of
steps to create a new project, write the Verilog code, synthesize the design,
implement the design, and finally program the BASYS FPGA board. Here is a
detailed step-by-step guide:
### Step-by-Step Implementation in Vivado
#### 1. **Create a New Project**
1. **Open Vivado**: Launch the Xilinx Vivado Design Suite.
2. **Create a New Project**:
- Go to **File** > **New Project**.
- Enter a project name (e.g., `SevenSegmentMultiplexer`) and choose a
location for the project.
- Choose **RTL Project** and check the box for **Do not specify sources at
this time**.
- Click **Next**.
3. **Select the Target Device**:
- Choose the appropriate part number for your Digilent BASYS board (e.g.,
`xc7a35tcpg236-1` for BASYS 3).
- Click **Next** and then **Finish**.
#### 2. **Add Design Sources**
1. **Add Verilog Source Files**:
- In the **Flow Navigator** panel, click **Add Sources** > **Add or Create
Design Sources**.
- Click **Create File** and enter the name for each Verilog file:
- `seven_seg_decoder.v`
- `clock_divider.v`
- `seven_seg_multiplexer.v`
- Click **Finish**.
2. **Enter Verilog Code**:
- Double-click on each newly created file in the **Sources** window to
open the code editor.
- Copy and paste the corresponding Verilog code from the previous answer
for each module (`seven_seg_decoder`, `clock_divider`, and
`seven_seg_multiplexer`).
#### 3. **Add Constraints File**
1. **Create a Constraints File**:
- Click **Add Sources** > **Add or Create Constraints**.
- Click **Create File** and name it `[Link]`.
- Click **Finish**.
2. **Add Pin Constraints**:
- Open the newly created `[Link]` file.
- Add constraints to map FPGA pins to the seven-segment display,
switches, and clock. For the BASYS 3 board, you can use the following
constraints:
```xdc
## Clock Signal
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
## Seven Segment Display Anode Control
set_property PACKAGE_PIN U2 [get_ports {anodes[0]}]
set_property PACKAGE_PIN U4 [get_ports {anodes[1]}]
set_property PACKAGE_PIN V4 [get_ports {anodes[2]}]
set_property PACKAGE_PIN V2 [get_ports {anodes[3]}]
## Seven Segment Display Segments
set_property PACKAGE_PIN W7 [get_ports {segments[0]}]
set_property PACKAGE_PIN W6 [get_ports {segments[1]}]
set_property PACKAGE_PIN U8 [get_ports {segments[2]}]
set_property PACKAGE_PIN V8 [get_ports {segments[3]}]
set_property PACKAGE_PIN U5 [get_ports {segments[4]}]
set_property PACKAGE_PIN V5 [get_ports {segments[5]}]
set_property PACKAGE_PIN U7 [get_ports {segments[6]}]
## Switches (if needed for testing input numbers)
# Add constraints for switches if needed
```
Ensure that you use the correct pin mappings for your board version, as
they may differ.
#### 4. **Run Synthesis and Implementation**
1. **Synthesize the Design**:
- In the **Flow Navigator** panel, click **Run Synthesis**.
- Wait for the synthesis process to complete. If there are errors, resolve
them by checking your Verilog code and constraints.
2. **Implement the Design**:
- After synthesis is completed, click **Run Implementation** in the **Flow
Navigator**.
- Wait for the implementation process to finish.
3. **Generate Bitstream**:
- Once the implementation is successful, click **Generate Bitstream**.
- This process creates a `.bit` file that can be used to program the FPGA.
#### 5. **Program the FPGA**
1. **Open Hardware Manager**:
- In the **Flow Navigator**, click **Open Hardware Manager** > **Open
Target** > **Auto Connect**.
- Ensure that your BASYS board is connected to your computer via USB.
2. **Program the Device**:
- Click **Program Device** and select the generated `.bit` file.
- Click **Program**. The FPGA will be configured with your design.
#### 6. **Test the Design on the Board**
- **Connect Inputs and Observe Outputs**:
- After programming, use the switches to input values and observe the
output on the seven-segment display.
- You should see the numbers being displayed correctly, and they should
cycle through each digit.
#### 7. **Debugging and Iteration**
- If the output is not as expected:
- Verify the connections and constraints.
- Check the Verilog code for any logical errors.
- Use the **Simulation** feature in Vivado to simulate the design and view
the waveforms to debug the logic.
### Conclusion
By following these steps, you will have successfully implemented a seven-
segment display multiplexer with an FSM using Xilinx Vivado and
programmed it onto a Digilent BASYS FPGA board. This will allow you to
display numbers and implement the required functionality using time-
division multiplexing.
Would you like more details on any of the steps or further help with
simulation or debugging?