Controlling LEDs using Slide Switches

A second experience using Vivado with the Boolean board

3114

This second tutorial demonstrates how to describe a basic digital circuit using Verilog, and in particular, how to connect circuit inputs and outputs to physical devices on the Boolean board. In this tutorial, slide switch inputs are connected through the FPGA to the LED outputs, without any logic in between. This simple exercise is intended to demonstrate how input and output devices are connected to your circuits – in the next exercise, you will add logic circuits between the inputs and outputs.

Digital circuits receive information from the “outside world” in the form of digital signals. Recall digital signals are voltage signals that are constrained to be at the circuits “high” voltage (typically 3.3V, also called a ‘1’), or the circuits “low” voltage (or ground, also called a ‘0’). Although signals are wires that transport voltage, we tend to think of digital signals as transporting information (a ‘0’ or a’1’).

A digital circuit combines and manipulates information transported by input signals (‘0’ or ‘1’) using various logical constructs like AND’ing or OR’ing, and produces one or more output signals that return information to the “outside world”. Within the digital circuit, there are typically several signals that transport information between devices inside the circuit, and that never see the outside world; and there are several signals called ports that communicate with the outside world. In the example circuit shown below, the input port signals A, B, and C are connected to pushbuttons, and the output ports are connected to LEDs.

Figure 1. A simple/basic digital circuit
Figure 1. A simple/basic digital circuit

There are many devices and sources that can drive input port signals, including pushbuttons, slide switches, keyboards, touch panels, other electronic devices. Likewise, there are many devices that might receive output port signals, like LEDs, speakers, actuators, other electronic devices, etc. Your Real Digital board contains several input and output devices that can produce and consume I/O port signals. In this tutorial, a slide switch is used as an input device, and an LED is used as an output.

A Simple Circuit

We will build a simple circuit called led_sw that passes a signal through the FPGA, from an input slide switch to an output LED, without using any other components. The input port is called “sw”, and the output port is called “led”. Only a single assign statement is needed in the Verilog code to connect the “sw” input to the “led” output, and this is shown below. But recall the Verilog description is only part of the solution - we must also connect the “logical” circuit names in our design (i.e., sw and led) to the physical pins on the Xilinx device – in this case, to the pins connected to the switch and LED we wish to use.

To connect logical signal names in a Verilog source file to physical pins on the FPGA, Xilinx requires “pin mapping” statements in an .xdc file (xdc stands for “Xilinx Design Constraints”). Part of the Boolean board schematic is shown below, together with a view of a FPGA chip and the Boolean board. The green boxes in the schematic show LD0 is connected to FPGA pin G1, and SW0 to pin V2. Those same two pins are shown on the FPGA pinout graphic, and also on a photo of the bottom side of the FPGA. When the FPGA is soldered to the circuit board, small copper wires on the board electrically connect pin G1 to LD0, and pin V2 to SW0. Since LD0 is connected to pin G1, any Verilog signal name in your design tied to pin G1 will drive the LED. Likewise, any Verilog signal name in your design tied to pin V2 will be driven to a 1 or 0 depending on the position of SW0. All that remains is to associate your named Verilog signals with physical FPGA pins, and that’s what the .xdc file does. A little later in this tutorial, we’ll show you how to create the required entries in the .xdc file.

Figure 2. Boolean board FPGA pin connections
Figure 2. Boolean board FPGA pin connections

Step 1: Create a new project

Create an empty project named requirement_2 (or something similar) following the procedure introduced in the previous tutorial.

Step 2: Design the circuit in Verilog HDL

Create and add a Verilog source file named “led_sw” to your project. If you can’t remember how, refer to the previous tutorial. Note that when defining a new Verilog source file, Vivado opens a “Define Module” dialog box after you choose a filename. This dialog allows you to enter input and output signal names, and then those signals will be automatically added to your new Verilog file. This is entirely optional – you can always skip this step by clicking OK, and then type the signal names into the source file. For now, you can skip this step - in later projects, you may wish to type signal names into this dialog box.

Figure 3. A block diagram for the led_sw circuit
Figure 3. A block diagram for the led_sw circuit

Begin the Verilog file by typing the module statement. In any Verilog source file, the first statement is the “module” statement that provides a name for the module and declares the input and output port signals. The format shown below is generic. The keyword “module” is followed by an alpha-numeric text string that provides the module’s name, and a list of port signals and their direction (in parenthesis). The keywords “input” and “output” are followed by the names of input and output signals, in any order. Any number of input and output signals can be declared. In this example, you can name the module “led_sw”, and declare one output signal named “led” and one input signal named “sw”.

module led_sw(
    output led,
    input sw
);

The input and output signals “sw” and “led” are recognized as single wires. You can also declare groups of related signals that are organized as “buses”. The statements below declare 16 inputs grouped together as a bus named “sw”, and 16 output signals grouped together as a bus named “led”. This defines sixteen distinct input signals named sw(15), sw(15), etc., and sixteen distinct output signals named led(15), led(14), etc. using one-line declarations. Note you can access individual signals on a bus by using the root name and the signal index in parenthesis (so, for example, sw(4) is the name of the 5th least significant signal on the sw bus).

input [15:0] sw
output [15:0] led;

Following the module statement, you can write any number of “assign” statements to define combinational logic circuits. The keyword “assign” is used in Verilog any time you want to assign a value to a wire. Simple assignments, like “assign led = sw”, can be used to map one signal onto another. More complex assignments can assign the result of logic operations to a wire, like “assign X = A | B & C” – these types of assignment will be used in the next exercise.

assign led = sw;

Assignment statements can work on individual signals or buses. For example, if “led” and “sw” are both declared as wires, then the statement “assign led = sw” will map a single signal. But if “led” and “sw” are declared as busses, then the same assign statement will assign multiple signals. The assignments happen bit by bit, starting with the right-most (least significant) input bus signal and assigning it to the right-most (least significant) output bus signal, then the next-most significant bit, and so on until all input bus signals are assigned. If there are more input bus signals than output bus signals, the extra input bus signals have no effect. If there are more output bus signals than input bus signals, the extra output signals are left unchanged.

When all required assign statements have been added to the Verilog file, the module description is ended with the “endmodule” key word.

Verilog Source File

For this first exercise, one LED will be driven from one switch. When you have completed the previous steps, your Verilog source file should look like this:

`timescale 1ns/1ps
module led_sw(
    output led,
    input sw
);

assign led = sw;

endmodule

Step 3: Add Constraints (XDC)

Recall that before a circuit can be implemented on your Xilinx device, all the external pin connections must be defined in a constraints file. Create and add an empty constraints file to your project. If you can’t remember how, refer to the previous tutorial. Add two entries into your xdc constraints file – one for the input switch, and one for the output LED as shown below. In a later module, the syntax and meaning of the .xdc entries will be explained more fully.

The .xdc file format to define a pin mapping is shown below - these two lines can be added to your .xdc file.

set_property -dict { PACKAGE_PIN V2   IOSTANDARD LVCMOS33 } [get_ports { sw }];
set_property -dict { PACKAGE_PIN G1   IOSTANDARD LVCMOS33 } [get_ports { led }];

Note: When mapping signals defined as a bus (for example, sw[15:0]), each individual wire needs a corresponding pin-mapping statement in the XDC file. Individual signals in a bus are identified by the bus root name followed by the signal number in square brackets. So, for example, the signal name of the first switch on the bus is sw[0], and the fourth switch on the bus is sw[3].

Typing in all the individual pin constraints can be time consuming. Instead, you can download and add the corresponding “master” .xdc file for the Boolean board to your project (or you can create an .xdc file and cut-and-paste the attached file contents into it). The master .xdc file defines all pin connections to all external devices (switches, LEDs, etc). Any “extra” signals defined in the master .xdc file but not referenced in your design will be ignored.

Step 4: Generate a .bit file, and test your design

Run synthesis, implementation, and generate bitstream as shown in the previous tutorial. Download your circuit to your board using the Hardware Manager.