====== Seven Segment Controller ====== You will create an eight-digit seven-segment display controller using a sequential counter and dataflow SystemVerilog. ===== Learning Outcomes ===== * Be able to implement a counter using behavioral SystemVerilog and dataflow statements * Use a counter to construct a "shared cathode" seven segment display controller * Implement a dataflow circuit to display different values on the seven segment display controller. ===== Preliminary ===== In the [[archive:old_verilog_labs:seven_segment|seven segment decoder]] laboratory assignment, you created a circuit that can display a hexadecimal value on a single digit. In this lab, we are going to create a seven-segment controller 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 need to 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. {{ :labs:seven_seg_0123_example.png?nolink&700 |}} /* More details on how this is done can be found on Page 6 of the Nexys2 reference manual. */ 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. What do you think will happen to the display if the time to turn on each digit is too short? 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, if 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. For this laboratory, you will need to create a counter that displays each digit for at least 160 us. Determine the minimum number of bits needed for a counter to display a single digit for at least 160us (160000ns). If we add 3 bits to sequence through all 8 digits, what is the total required? /* 160 us / 10 ns = 16,000 clock cycle. This requires 14 bits (16,384). In addition, you will need three additional bits for the top-decoding for a total of 17 bits. */ Assume your counter counts from 0 to 2n-1 where n is the size of your counter. How long it will take to cycle through all eight digits? /* 2^17 * 10 ns = 1.3 ms */ ===== Exercises ===== ==== Exercise #1 - Seven Segment Controller ==== The first exercise of this lab is to create a SystemVerilog module for your seven segment controller. The purpose of this controller is to provide an easy to use interface for others so that they can easily use the seven segment controller without having to figure out all of the details associated with properly sequencing through all of the digits. Your controller will have the following three important inputs: * **Data input (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 will provide a 32-bit data input that indicates what data to display on all 8 of the digits. You will use this 32-bit input data to drive the cathode signals of the display. * **Digit Display (8 bits):** Your seven segment controller does not need to display all eight digits of the display all of the time. In some applications, the user of your module may only want to display four of the eight digits (when there is only 16-bits of data to display). You 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 you should display this digit while a '0' in this bit position indicates that you should turn off the digit. * **Digit Point (8 bits):** There is one digit point in the bottom right corner of each digit of the seven segment display and their 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. Begin this exercise by creating a module with the following input and output ports: ^ Module Name: SevenSegmentControl ^^^^ /* ^ Parameter ^ Type ^^ Function ^ | COUNT_BITS | integer || Determines the number of bits in the digit sequencer counter. | */ ^ 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) | /* Note that this module also contains a parameter, COUNT_BITS, that you can use to indicate the number of bits used by your digit counter. Make sure you provide this parameter in your module (see section B.4 of the textbook). */ The seven segment controller is composed of the following three major sections: - The sequencing counter, - Anode control logic, and - Cathode control logic. Each of these logic sections will be described below. === Sequencing Counter === After creating your module interface, create the counter that will sequence through the eight digits. Create your counter according to Figure 16.6 of the textbook. You will need //n// bits for your counter, where //n// is the number of bits you calculated in the preliminary. You may use behavioral SystemVerilog, as shown in Program 17.5.2. /* To begin, instance //n// flip-flops (use the {{:tutorials:fdce.pdf|FDCE}} primitive) for your counter where //n// is the number of bits of your counter as you answered above in the preliminary. The input to the flip-flops is the "Next State" value and the output is the "Current state". Make your counter a "free-running" counter, meaning it is always running, by hooking up a constant ''1'b1'' to the **Clock Enable** input of the FDCE. Create the "input forming logic" of your counter using a data flow statement (the input forming logic for a counter is '+1'). You do not need to instance discrete gates to implement your dataflow statement (discrete gates are used in the example of Figure 13.6). */ After creating your counter, create a three-bit signal, //digitSelect//, that is used to select which digit is being displayed. You will use this signal in several places throughout the circuit. Remember that this is just the top three bits of your counter so you can use a simple assign statement to set //digitSelect// equal to those three bits. === Anode Logic === As described in the preliminary you will turn on only one anode signal at a time. The anode signal of a digit should only be asserted to a '0' (remember that the anode signal is reversed) under the following two conditions: * The //digitSelect// signal is set to the corresponding digit, and * The corresponding bit of //digitDisplay// is set to a '1'. In all other conditions the anode signal should be set to a '1' (thus turning off the digit). We can accomplish this in three steps: - First implement a 3:8 decoder for the //digitSelect// signal. This will give us an 8 bit signal where only 1 bit is a '1' and the rest are '0'. - Then AND that signal with //digitDisplay//, giving us an 8 bit signal that has a '1' value only if //digitDisplay// is a '1' at the corresponding bit. - Then invert the resulting signal giving us an 8 bit signal of all '1's and possibly a '0' if //digitDisplay// was a '1' for the digit we are selecting. Drawing this out might help you visualize the process. === Cathode Logic === The logic for the cathode signals is fairly straightforward. We will use the //digitSelect// signal to decide which four bits of the //dataIn// to display, connect that to our seven segment decoder, and create logic for our digit point. {{ :labs:seven_segment_mux.png?nolink&450 |}} A four-bit 8:1 multiplexer will select four bits from the 32-bit data input (top left block in figure). The output of the multiplexer then connects to a seven segment decoder that converts the four-bit number into the appropriate cathode signals as you did in the [[archive:old_verilog_labs:seven_segment|Seven Segment Decoder]] lab. First create an 8:1 mux that uses //digitSelect// as your select line and //dataIn// as your input. Then, instead of instancing your old Seven Segment module, create the decoder using dataflow statements and place it in your existing module (you should already have this code from the Dataflow lab). This will make it simpler to reuse your Seven Segment Controller in later labs. Finally, you will need an 8:1 multiplexer for the digit point cathode logic. ** Exercise 1 Pass-off:** Show a TA your completed module and briefly explain how your anode and cathode sections work.\\ \\ ==== Exercise #2 - Seven Segment Controller Verification ==== In this exercise you will simulate your seven segment controller to verify that it functions as you expect it should. This controller is the most complex circuit you have created so far and you will likely have logic problems in your circuit. It is very important that you resolve any logic problems at this point before moving to the top-level design. You will simulate your controller in two ways: with a simple TCL script and a testbench. ** TCL Script ** In the first simulation step, perform a simple simulation by writing a TCL script and testing the primary functions of the controller. You will not need to exhaustively test all of the features of your controller but you should verify that the major functions of the controller are working properly. The TCL script below provides a start for such a simulation. Re-read this tutorial if you want to review [[tutorials:tcl_tutorial| TCL commands ]]. restart # Set a repeating clock add_force clk {0 0} {1 5} -repeat_every 10 add_force reset 1 run 20ns add_force reset 0 # set default values for the inputs add_force -radix hex dataIn 01234567 add_force digitPoint 11111111 add_force digitDisplay 11111111 Extend this script by adding the following: * Add a "run" command to run the simulation long enough to cycle through all eight digits (you determined how long it will take to simulate all digits earlier in the preliminary). * Add "add_force" commands to change the value being displayed and/or the digit point. * Add a final "run" command to cycle through all eight digits again. After running your simulation script, carefully analyze the waveform of the outputs to test the following features of your controller: - Verify that the controller sequences through each of the anode signals one at a time (i.e., more than one anode signal is never asserted at the same time), - Measure the length of the anode signal and verify that it meets the requirements described earlier, and - Review the cathode signals during at least one anode period and verify that they are correct for the digit that is being displayed. Resolve any obvious problems with your controller before proceeding to the testbench simulation. Include a copy of your TCL simulation script ** Testbench ** After resolving any major issues with your seven-segment controller, you can more thoroughly test your controller with a testbench. This simulation testbench tests many different cases and may find problems with your controller that are not obvious. Download the following testbench, add it as a simulation source to your project, and simulate your controller. This simulation will take a relatively long time (about 2 minutes) and you will need to "run" the simulation until you get the "done" message from the console (about 30ms in total). Resolve any problems identified by the testbench and simulate your controller until your controller passes all of the testbench cases. {{ :labs:tb_sevensegmentcontrol.v |}} Include a copy of your seven segment controller SystemVerilog ** Exercise 2 Pass-off:** Show a TA your extended tcl script and your testbench output.\\ \\ ==== Exercise #3 - Top-Level Circuit ==== The final design exercise is to create a top-level module that uses your seven segment display controller to display various settings and values on the buttons. Begin this exercise by creating a new SystemVerilog module with the following name and ports: ^ Module Name: SevenSegmentControlTop ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | 100 MHz System Clock | | CPU_RESETN | Input | 1 | Active-low reset button | | sw | Input | 16 | 16 Slide switches to determine what to display | | btnc | Input | 1 | Assert all segments (test mode) | /* | btnl | Input | 1 | Display ''DEADBEEF'' | */ | btnr | Input | 1 | Blank the display | /* | btnu | Input | 1 | Inverse of switches values on upper anodes, switches value on lower anodes | | btnd | Input | 1 | Switches value on lower and upper anodes | */ | segment | Output | 8 | Cathode signals for seven segment display | | anode | Output | 8 | Anode signals for each of the eight digits | Begin the body of your module by instancing your seven segment controller and attaching the ''clk'' input to the top-level clock, the ''CPU_RESETN'' to the ''reset'' input (remember to invert it), and the ''segment'' and ''anode'' signals to the top-level ''segment'' and ''anode'' signals. You will need to create additional logic to control the other signals of your seven segment controller (dataIn, digitDisplay, and digitPoint). In particular, your logic will generate the values for these signals based on the values of the top-level buttons and switches. The figure below provides a high-level diagram of how you should organize your top-level design. {{ :labs:seven_segment_control_top.png?nolink&500 |}} The statements below describe how the seven segment display should operate under a number of different conditions. You will need to create dataflow logic that uses the buttons and switches from the top-level design and drive the dataIn, digitDisplay, and digitPoint inputs to your seven segment display controller. Note that these statements below are listed from highest to lowest priority (for example, if both **btnc** and **btnr** are pressed at the same time, **btnc**'s function has priority). * **btnc**: Test mode: each digit has all of its segments lit up, including digit points. /* * **btnl**: Display the constant value ''DEADBEEF'' on the segments. The digit point between ''DEAD'' and ''BEEF'' should be turned on but no others. */ * **btnr**: Blank the display (nothing is shown on the display). /* * **btnd**: The upper four segments (16 bits of display) and the lower four segments display both display the value of the switches. No digit points. * **btnu**: The upper four segments (16 bits of display) display the inverse value of the switches and the lower four segments display the value of the switches. No digit points. */ * **Default** (no buttons pressed): Lower four digits display value of switches. Upper four digits are blanked. No digit points are turned on. Note that in the default case you are connecting the switches only to the bottom four digits (both 16 bits wide). Since the top four digits are blank, it does not matter what you assign the top 16 bits of dataIn to. After creating your top-level SystemVerilog file (and resolving any compilation errors), simulate your file to see that it operates as you expect it should. Create a .tcl simulation file that does the following: * Simulates the pressing of each button individually for enough time to display the value on all eight digits * Simulates the pressing of more than one button at a time (for at least two cases) and long enough to display the value on all eight digits Once you are satisfied that your module operates correctly, proceed to the next exercise. Include a copy of your top-level .tcl simulation script Include a copy of your top-level SystemVerilog file Perform the steps of Synthesis, Implementation, and Bitstream Generation. Download your design and experiment with several cases to demonstrate that it is working properly. Provide a summary of your synthesis warnings. Summarize the size of your circuit (LUTs and FFs). ===== Final Pass Off ===== Pass off your laboratory by demonstrating the following to the TA: * Pass offs for Exercise 1 and 2 * Your working circuit on the Nexys4 board How many hours did you work on the lab? Please provide any suggestions for improving this lab in the future. ===== Personal Exploration ===== Here are some ideas for personal exploration in this laboratory: * Experiment with different amounts of time to assert the anode signals and discuss the effect * Provide a different function for the display based on the button and switch inputs * Review the schematic of your design and comment on any interesting findings * Review the layout of your logic on the FPGA Describe your personal exploration activities /* ===== Lab Report ===== * **Header** * Class * Lab * Name * Section * **Preliminary** * Time is short question * Min bits question * How long for all digits question * **Exercise 2** * TCL script * Testbench output * SevenSegmentControl Verilog * **Exercise 3** * TCL script * SevenSegmentControlTop Verilog * Synthesis warnings * Number of LUTs and FFs * Personal exploration description * Hours spent on lab * Feedback */ ---- [[labs:ta:seven_segment_controller|TA Notes and Feedback]]