In the seven segment decoder laboratory assignment, you created a circuit that can display a hexadecimal value on a single digit.
On this page, you are provided with a Seven-Segment Controller module that can display a unique value on each digit of the eight-digit display. Displaying multiple digits on the display is accomplished by multiplexing the cathode signals and “driving” or displaying one digit at a time. To make it appear to the human eye that more than one digit is displayed, we rapidly turn on each digit and sequence through the digits fast enough so the eye and brain cannot see this sequencing. Even though only one digit is actively displayed at a time, our persistence of vision and slow brain response cannot perceive this single digit display strategy. Instead, it will appear as if all eight digits are being displayed at the same time. If you were to take a high-speed video of the display, you would see this sequential digit display approach in action.
The example shown below demonstrates how the value “0123” is displayed on the first four digits of the display using time multiplexing. In this example, only one digit is being driven on the display at a given time – digit “0” is displayed on digit 3 (the left most digit) during the first time period, digit “1” is displayed on digit 2 during the second time period, digit “2” is displayed on digit 1 during the third time period, and digit “3” is displayed on digit 0 (the right most digit) during the fourth time period. This process of displaying one digit at a time repeats continuously to make it appear that all four digits are being displayed at the same time.
This example demonstrates the signals that must be asserted during each time period to produce the desired display. During the first time period, AN3 is asserted (i.e. is low) and the other annode signals are deasserted. The following cathode signals are asserted (driven low) to display the character “0” on digit 3: CA, CB, CC, CD, CE, and CF. During the next digit period, AN2 is asserted (while AN2 is deasserted) and the following cathode signals are asserted to display the character “1”: CB and CC. Next, AN1 is asserted and the following cathode signals are asserted to display the character “2”: CA, CB, CC, CD, and CE. Finally, AN0 is asserted and the following cathode signals are asserted to display the character “3”: CA, CB, CC, CD, and CG. This process repeats continuously to keep all four values actively highlighted on the four-digit display.
The challenge we have is deciding how long to drive each anode signal. If the “on” time of the anode signals is too long, the eye and brain will detect that only one digit is being displayed at a time and we will see the digits turn on and then off in sequential order. If the “on” time is just right, human brain will perceive all four characters as being displayed at the same time through persistence of vision.
The easiest way to sequence through the eight different digits is to create a “free running” counter. A free running counter is a counter that increments continuously at each clock cycle (See Figure 16.6). When the free running counter reaches all 1's, it will then roll over to zero on the next clock cycle. The top three bits of this free running counter will cycle through the digits, while the rest of the bits of the counter will determine the amount of time to display each digit. For example, suppose you used an 8-bit counter. Then, the top three bits of the counter would determine which digit to display and the bottom 5 bits would be used to count the duration that each digit is displayed. With 5 bits, each digit will be displayed for 25 = 32 clock cycles.
The table below summarizes how the top three bits of this free running counter are used to select the appropriate digit in the display:
Top 3 Bits | Function |
---|---|
000 | Display digit 0 (right most) - Assert AN0 |
001 | Display digit 1 - Assert AN1 |
010 | Display digit 2 - Assert AN2 |
011 | Display digit 3 - Assert AN3 |
100 | Display digit 4 - Assert AN4 |
101 | Display digit 5 - Assert AN5 |
110 | Display digit 6 - Assert AN6 |
111 | Display digit 7 (left most) - Assert AN7 |
The clock we have on the NEXYS 4 board runs at 100 MHz with a clock period of 10 ns. If you use an eight-bit counter to sequence the digits as described above, the top three bits would be used to sequence through each digit and the bottom five bits would be used to count the number of clock cycles to display each digit. Thus, each digit would be displayed for 25 x 10 ns = 320 ns. (The module provided below does not use an 8-bit counter, this is just described here as an example).
The actual module given to you does not use an 8-bit counter, but instead the counter width is parameterizable. Look at the SystemVerilog below to see the default width of the counter.
Here is the SystemVerilog module. To use this in your Vivado project, 1) click the link to download the file directly, 2) move the file to your project directory, and 3) add the file as a source in your Vivado project.
////////////////////////////////////////////////////////////////////////////////// // // Filename: SevenSegmentControl.sv // // Author: Mike Wirthlin, Jeff Goeders // // Description: // // ////////////////////////////////////////////////////////////////////////////////// module SevenSegmentControl( input wire logic clk, input wire logic reset, input wire logic [31:0] dataIn, input wire logic [7:0] digitDisplay, input wire logic [7:0] digitPoint, output logic [7:0] anode, output logic [7:0] segment ); parameter integer COUNT_BITS = 17; logic [COUNT_BITS-1:0] count_val; logic [2:0] anode_select; logic [7:0] cur_anode; logic [3:0] cur_data_in; // Create counter always_ff @(posedge clk) begin if (reset) count_val <= 0; else count_val <= count_val + 1; end // Signal to indicate which anode we are driving assign anode_select = count_val[COUNT_BITS-1:COUNT_BITS-3]; // current andoe assign cur_anode = (anode_select == 3'b000) ? 8'b11111110 : (anode_select == 3'b001) ? 8'b11111101 : (anode_select == 3'b010) ? 8'b11111011 : (anode_select == 3'b011) ? 8'b11110111 : (anode_select == 3'b100) ? 8'b11101111 : (anode_select == 3'b101) ? 8'b11011111 : (anode_select == 3'b110) ? 8'b10111111 : 8'b01111111; // Mask anode values that are not enabled with digit display // (if a bit of digitDisplay is '0' (off), then it will be // inverted and "ored" with the annode making it '1' (no drive) assign anode = cur_anode | (~digitDisplay); // This is a statement to simulate a common student problem with the // anode is "stuck". This statement is used to make sure the testbench catches // this condition. //assign anode = 8'hff; assign cur_data_in = (anode_select == 3'b000) ? dataIn[3:0] : (anode_select == 3'b001) ? dataIn[7:4] : (anode_select == 3'b010) ? dataIn[11:8] : (anode_select == 3'b011) ? dataIn[15:12] : (anode_select == 3'b100) ? dataIn[19:16] : (anode_select == 3'b101) ? dataIn[23:20] : (anode_select == 3'b110) ? dataIn[27:24] : dataIn[31:28] ; // Digit point (drive segmetn with inverted version of input digit point) assign segment[7] = (anode_select == 3'b000) ? ~digitPoint[0] : (anode_select == 3'b001) ? ~digitPoint[1] : (anode_select == 3'b010) ? ~digitPoint[2] : (anode_select == 3'b011) ? ~digitPoint[3] : (anode_select == 3'b100) ? ~digitPoint[4] : (anode_select == 3'b101) ? ~digitPoint[5] : (anode_select == 3'b110) ? ~digitPoint[6] : ~digitPoint[7] ; assign segment[6:0] = (cur_data_in == 0) ? 7'b1000000 : (cur_data_in == 1) ? 7'b1111001 : (cur_data_in == 2) ? 7'b0100100 : (cur_data_in == 3) ? 7'b0110000 : (cur_data_in == 4) ? 7'b0011001 : (cur_data_in == 5) ? 7'b0010010 : (cur_data_in == 6) ? 7'b0000010 : (cur_data_in == 7) ? 7'b1111000 : (cur_data_in == 8) ? 7'b0000000 : (cur_data_in == 9) ? 7'b0010000 : (cur_data_in == 10) ? 7'b0001000 : (cur_data_in == 11) ? 7'b0000011 : (cur_data_in == 12) ? 7'b1000110 : (cur_data_in == 13) ? 7'b0100001 : (cur_data_in == 14) ? 7'b0000110 : 7'b0001110; endmodule
The controller has the following three important inputs:
dataIn
(32 bits): Each digit can display 4-bits of data. With eight digits, the seven segment display can display up to 32-bits of data. You provide a 32-bit data input that indicates what data to display on all 8 of the digits. digitDisplay
(8 bits): The seven segment controller does not need to turn on all eight digits of the display all of the time. In some applications, you may only want to display four of the eight digits (when there is only 16-bits of data to display). The controller can “turn off” or disable individual digits of the display by never asserting their corresponding Anode signals. This digit display input will have one bit for each digit of the display. A '1' in this bit indicates that the controller should turn on the digit, while a '0' turns off the digit. For example, if you always want all digits to be turned on, you can connect 8'b11111111
to the digitDisplay
port.digitPoint
(8 bits): There is one digit point in the bottom right corner of each digit of the seven segment display and there is a corresponding cathode signal for this digit point. This 8-bit input indicates which of the digit points of the display you are to highlight. There is one bit for each of the digits in the display. A '1' indicates that the corresponding digit point should be turned on and a '0' indicates that the corresponding digit point should be turned off. For example, if you only want the leftmost digit point lit up, you can connect 8'b10000000 to the digitPoint
port.Full list of ports for this module:
Module Name: SevenSegmentControl | |||
---|---|---|---|
Port Name | Direction | Width | Function |
clk | Input | 1 | 100 MHz System Clock |
reset | Input | 1 | Active high reset, which resets the counter |
dataIn | Input | 32 | Data value to display |
digitDisplay | Input | 8 | Indicates which digits to display |
digitPoint | Input | 8 | Indicates which digit points to turn on |
anode | Output | 8 | Anode signal for each of the 8 digits |
segment | Output | 8 | Segment signals ([7] is digit point, [6:0] are regular segments) |