Escolar Documentos
Profissional Documentos
Cultura Documentos
using Mojo V3
By Yury Magda
Fig.1
The Mojo V3 is designed to make digital design easy and cost effective for anyone who is just getting
started.
The detail description of the Mojo V3 board is available at
https://embeddedmicro.com/products/mojo-v3.html. The board features include:
Spartan 6 XC6SLX9 FPGA;
84 digital I/O pins;
8 analog inputs;
8 general purpose LEDs;
1 reset button;
1 LED that indicates when the FPGA is correctly configured;
On board DC voltage regulator capable of handling 4.8V – 12V input voltage. The optimum
input for the board is 5V.
A microcontroller (ATmega32U4) used for configuring the FPGA, USB communications and
reading the analog pins;
On board flash memory to store the FPGA configuration file.
This guide aims to get the readers familiar with basics of Verilog through designing various digital
circuits using the Mojo V3. Aa a development tool for creating and compiling designs, programming
the FPGA, the Xilinx ISE Design Suite 14.7 WebPack Edition running in Windows 10 was used.
Each design is accompanied by a brief description which helps to make things clear and allows the
readers to easily improve the design.
Disclaimer
The design techniques described in this book have been tested on the Mojo V3 FPGA development
board without damage of the equipment. I will not accept any responsibility for damages of any kind
due to actions taken by you after reading this book.
Coding Styles
All examples described in this book are developed in Verilog. Verilog HDL allows to implement a
design in several coding styles. Generally, a Verilog coding style may be based on either of four
different levels of abstraction: behavioral, dataflow, structural and switch levels.
In this guide, we will create digital circuits using the Verilog coding style that is based on the
behavioral level of abstraction. This style provides the following features:
A module can be implemented in terms of the desired design algorithm without knowing
hardware implementation details.
It allows to specify a digital circuit in terms of its expected behavior.
It is the best approach to a natural language description of the circuit functionality.
All designs described in this book use Verilog 2001, 2005 syntax.
Required Software
Before we start off our designs, we should install the Mojo Loader and free
Xilinx ISE Design Suite 14.7 WebPack Edition.
The Mojo Loader utility is required if you need to load a .bin file created outside the Xilinx IDE. In
our case, this program will be used to load the .bin files created with ISE to the Mojo.
You should download the proper version of the loader for your operating system (in this guide, there
was used a version for Windows). The latest version of Mojo Loader to download is
1.3.0 (compatible only with firmware 1.2.0, the Arduino compatible firmware, and above).
This version uses the serial port library JSSC instead of RXTX used in older versions. More details
are available on https://embeddedmicro.com/tutorials/mojo-software-and-updates/installing-mojo-
loader.
Using the Mojo base project
In this book, designing digital circuits with Verilog will be based on a Mojo base project that should
be downloaded from https://github.com/embmicro/mojo-base-project/archive/master.zip.
Alternatively, you can check it out at https://github.com/embmicro/mojo-base-project. The Mojo base
project is a good starting point for any Verilog project created for the Mojo V3 board.
The Mojo base project will be used as a template for all designs described in this guide. In each new
project, we will make several modifications to the template, to adapt the Mojo base project to our
design. For convenience, you can make an empty directory for each Verilog project and then extract
the .zip file with a basic project to this directory.
The file structure of the Mojo base project includes the following:
Mojo-Base – the design name;
ipcore_dir – where IP cores that you generate will go;
iseconfig – used by ISE;
src – where all the source files you write are located;
syn – the working directory for ISE;
Mojo-Base.xise – the ISE project file.
When designing our circuits, we will need to modify only two files from the Mojo base project,
mojo_top.v and mojo.ucf.
Using the Mojo V3 on-board peripherals
Our designs will be built around the Mojo on-board peripherals, without using any additional shields
and/or boards. Many designs use a digital input signal that will be taken from the on-board button
labeled “Reset” that is connected as shown in Fig.2.
Fig.2
The button when released provides a high level (log.”1”) on the net L65N_2 associated with the pin
P38 (not shown here) of the FPGA. When pressed, the button provides a low level (log.”0”) on the
pin P38.
To provide LED visualization of the operations in circuits, we will use the Mojo V3 on-board LEDs
connected as shown in Fig.3.
Fig.3
The signal names and pin assignments for the on-board LEDs are detailed in the table below.
We also need a square wave oscillator (clock) for clocking our circuits. The 50 MHz clocking signal
(labeled CLK) can be taken from the pin 56 of the FPGA (Fig.4).
Fig.4
In order to observe in details how our circuits operate, LED visualization should be implemented at
low speed, with frequencies much less than 50 MHz. For that reason, most circuits in this guide will
use a frequency divider that divides the 50 MHz clocking signal to a few Hz thus providing low-
frequency clocking signal to the rest of a circuit.
Now we know all what is needed to start off our designs. Let’s go to the first project.
The first design with Verilog
In this section, we will design a very simple combinational circuit (Fig.5) using
Xilinx ISE Design Suite. We will pass through all stages required for implementing our circuit in the
FPGA. A similar sequence will be used when designing all circuits described in this guide.
Fig.5
This circuit provides the double inversion of the input signal rst fed from the “Reset” button. The
output led[0] of the NOT gate gate1 drives the on-board LED “LED2” (see Fig.3), while the output
led[1] of the NOT gate gate2 drives the LED “LED3”.
To implement this circuit in the FPGA, in the ISE Design Suite window select and click → Open
Project… (Fig.6).
Fig.6
In the file dialog window, select Mojo-Base.xise from the directory where the Mojo base project
resides (Fig.7).
Fig.7
After the project has been opened, we should see the mojo-top module (mojo_top.v) under the
hierarchy panel on the left side (Fig.8). Double-clicking on the mojo_top.v opens this file thus
allowing us to see its Verilog code.
Fig.8
If, for some reason, the mojo_top.v doesn’t appear as a top module, you should change this manually.
To do that, select mojo_top.v, then select and click Source → Set As Top Module (Fig.9). This way
we define the mojo_top.v as the top module.
Fig.9
The contents of the original mojo_top.v file is shown below (Listing 1).
Listing 1.
1. module mojo_top(
2. // 50MHz clock input
3. input clk,
4. // Input from reset button (active low)
5. input rst_n,
6. // cclk input from AVR, high when AVR is ready
7. input cclk,
8. // Outputs to the 8 onboard LEDs
9. output [7:0] led,
10. // AVR SPI connections
11. output spi_miso,
12. input spi_ss,
13. input spi_mosi,
14. input spi_sck,
15. // AVR ADC channel select
16. output [3:0] spi_channel,
17. // Serial connections
18. input avr_tx, // AVR Tx => FPGA Rx
19. output avr_rx, // AVR Rx => FPGA Tx
20. input avr_rx_busy // AVR Rx buffer full
21. );
28. endmodule
When designing digital circuits, we will add Verilog code after the line 26.
We will also need to change the contents of the mojo.ucf file – a User Constraint File (UCF) which
maps the NET names in Verilog code to the FPGA pin names. The contents of the original mojo.ucf
file is shown in Listing 2.
Listing 2.
In this file, the lines that begin with a # are comment lines – they are not part of the configuration
information, they just describe what is going on.
There are a number of NET commands that define the links from the net name specified in the Verilog
code to the pin location (LOC) in the actual hardware. Finally, at the end of the lines for the
switches, there is a bar symbol followed by the word IOSTANDARD that determines the type of
logical levels for that pin.
In our first design, we should add a few lines at the end of the mojo_top.v file as is shown in Listing
3.
Listing 3.
1. module mojo_top(
2. // 50MHz clock input
3. input clk,
4. // Input from reset button (active low)
5. input rst_n,
6. // cclk input from AVR, high when AVR is ready
7. input cclk,
8. // Outputs to the 8 onboard LEDs
9. output [7:0] led,
10. // AVR SPI connections
11. output spi_miso,
12. input spi_ss,
13. input spi_mosi,
14. input spi_sck,
15. // AVR ADC channel select
16. output [3:0] spi_channel,
17. // Serial connections
18. input avr_tx, // AVR Tx => FPGA Rx
19. output avr_rx, // AVR Rx => FPGA Tx
20. input avr_rx_busy // AVR Rx buffer full
21. );
31. endmodule
Here, our Verilog code begins after the line 28. The statement
drives the six most significant bits corresponding to the on-board LEDs OFF. This statement is
necessary because these nets are configured in the UCF file (mojo.ucf). Without this statement, the
compiler issues an error. In the following examples, we will modify the contents of the UCF file in
order to avoid such problems.
The sequence
It is now time to synthesize the design and generate the programming file to be downloaded onto the
Mojo board. Select the mojo_top entry in the hierarchy, and a number of options will appear below
in the panel labeled Processes. In that panel, double-clicking on Generate Programming File
causes a spinning thing to appear and move through the different stages of those processes (Fig.10).
Fig.10
While generating the programming file, there will be warnings indicated by a little “!” in a yellow
triangle. If we scroll through the warnings, we will see that they are all caused by inputs and outputs
in our design not being used. Since that was intentional, we can ignore these.
If we didn't get any errors and the Generate Programming File stage succeeds, we can invoke the
Mojo Loader utility to load the bin file into the FPGA.
Once Mojo Loader (Fig.11) is opened, we should select the serial port associated with the Mojo V3
board. In my case, Windows 10 provided COM3 for the Mojo. It may take a while for Mojo Loader
to recognize the serial port so check the Serial Port dropdown again if you don't see the port listed.
Then click Open Bin File and navigate to the syn folder in the project folder where you should select
a mojo_top.bin file.
Fig.11
Listing 4.
In this example, the structure of the circuit is specified by the list of Verilog built-in primitive gates
identified by a descriptive keyword (and, not, or). In our case, we use two not gates. The elements
of the list are referred to as instantiations of a gate, each of which is referred to as a gate instance.
Each gate instantiation consists of an optional name (gate1 and gate2, in our case) followed by the
gate output and inputs separated by commas and enclosed within parentheses. The output of a
primitive gate is always listed first (led[0] and led[1], in our case) followed by the inputs (rst,
led[0]).
The output of a primitive must be listed first, but the inputs and outputs of a module may be listed in
any order.
Designing frequency dividers: example 1
This design allows to build a frequency divider with the output frequency of 1 Hz. The input
frequency to the frequency divider is fed from the 50 MHz clock signal available on the pin P56 of
the FPGA. The circuit diagram of the frequency divider is shown in Fig.12.
Fig.12
To visualize the output signal, we will use the on-board LED (output led[0]) that will blink with a
frequency of 1 Hz. The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in
Listing 5.
Listing 5.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active high)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
initial
begin
qdiv <= 1'b0;
led <= 8'd0;
end
// Toggling LED
endmodule
implements the frequency divider whose output frequency is determined by the parameter maxDIV.
The en input enables/disables the counter (variable cntdiv) of the frequency divider. The internal
clock qdiv toggles the LED within an always-block
always @(posedge qdiv)
Listing 6.
The changes introduced into the original mojo.ucf file are shown in bold.
Designing frequency dividers: example 2
This is the modified version of the previous example. With this circuit, we get three different
frequencies (1, 5 and 10 Hz) at three outputs led[0] – led[2]. The circuit diagram of the modified
frequency divider is shown in Fig.13.
Fig.13
The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 7.
Listing 7.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active high)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
initial
begin
qdiv <= 3'b0;
cntdiv0 = 0;
cntdiv1 = 0;
cntdiv2 = 0;
led <= 8'd0;
end
// Toggling LEDs
endmodule
Listing 8.
The changes in introduced into the original mojo.ucf file are shown in bold.
Designing multiplexers: example 1
This design allows to implement the 2-to-1 multiplexer circuit (Fig.14).
Fig.14
In this circuit, the button “Reset” drives the input en of the multiplexer. If en is HIGH (log.”1”,
“Reset” is released), the data byte data2 will be passed to the output led[7:0]. If en is LOW
(log.”0”, “Reset” is pressed), data1 goes to the output led[7:0].
To model the behavior of this circuit in Verilog, we need to modify both mojo_top.v and mojo.ucf
files in the Mojo base project.
The Verilog code contained in the modified mojo_top.v file is shown in Listing 9.
Listing 9.
module mojo_top(
// 50MHz clock input
input clk,
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
data1 = 8'd129;
data2 = ~data1;
end;
endmodule
The variables data1 and data2 may be assigned any suitable values.
Listing 10.
The changes introduced into the original mojo.ucf file are shown in bold.
Designing multiplexers: example 2
In this design, we will implement the 2-to-1 multiplexer circuit capable of passing either 1 Hz or 5
Hz pulse train. Both clock sources are taken from the frequency dividers fed from the 50 MHz on-
board clock available on the pin P56 of the FPGA. Both signals, 1 Hz and 5 Hz, are fed to the inputs
of the multiplexer. The input channel is selected by the sel input driven by the button “Reset”.
The circuit diagram is shown in Fig.15
Fig.15
The Verilog code (contained in mojo_top.v) that models the behavior of this circuit is shown in
Listing 11.
Listing 11.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Output to the onboard LED
output led0,
initial
begin
qdiv <= 2'b00;
cntdiv0 = 0;
cntdiv1 = 0;
end
endmodule
Listing 12.
X0 X1 X2 Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7
0 0 0 1 0 0 0 0 0 0 0
1 0 0 0 1 0 0 0 0 0 0
0 1 0 0 0 1 0 0 0 0 0
1 1 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 1 0 0 0
1 0 1 0 0 0 0 0 1 0 0
0 1 1 0 0 0 0 0 0 1 0
1 1 1 0 0 0 0 0 0 0 1
Fig.16 depicts the 3-to-8 decoder circuit where the input sel is driven by the “Reset” button. A data
byte being taken from the integer array X[0:1] (see Verilog code below) forms the input X (not
defined in Verilog code) of the decoder. Depending of the state of the button “Reset”, either X[0] or
X[1] is fed to X.
The value on the input X drives a corresponding on-board LED (output led[7:0]) through the output
Q[7:0], so we can observe the state of the LEDs when “Reset” pressed/released.
Fig.16
The Verilog code (mojo_top.v) that models the behavior of the above circuit is shown in Listing 13.
Listing 13.
module mojo_top(
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
integer X[0:1];
wire [7:0] Q; // decoder outputs
initial
begin
X[0] = 7;
X[1] = 0;
end
endmodule
Listing 14.
The changes introduced into the original mojo.ucf file are shown in bold. Since a clock signal isn’t
used in this circuit, the corresponding lines are commented.
Designing decoders: example 2
One more decoder circuit is shown in Fig.17. Here the data on the input X of the decoder are
incremented every 0.5 s at the rising edge of the internal clock clk. The on-board LEDs (led[7:0])
reflect the decoder output Q[7:0].
Fig.17
The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 15.
Listing 15.
module mojo_top(
// 50MHz clock input
input clk_50M,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
reg clk;
reg [7:0] Q;
integer X;
initial
begin
cnt = 0;
X = 0;
Q <= 8'd0;
led <= Q;
end
endmodule
implements the frequency divider with an output frequency of 2 Hz (internal clock clk).
Here, the variable X changes from 0 to 7 at each rising edge of clk, thus causing the outputs Q and led
to change accordingly.
Listing 16.
Fig.18
In this circuit, the on-board clock of 50 MHz feeds the counter that increments its value every 0.1 s
(10 Hz) while the input en remains HIGH (log.”1”). The data byte to the inputs A0 – A7 of the
comparator comes from the counter output q[7:0]. Initially, en is brought HIGH thus allowing to start
counting from 0 up to the value determined by the datacomp variable (171, in our example).
When the value of the data byte on A0 – A7 reaches datacomp, the qcomp output goes
HIGH(log.”1”) thus bringing the en input LOW (log.”0”). The low level on the en input disables
counting. To resume counting from 0, we should activate the rst inputs by pressing/releasing the
“Reset” button.
The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 17.
Listing 17.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
initial
begin
q <= 8'd0;
led <= q;
cnt = 0;
datacomp = 171;
qcomp <= 1'b0;
en <= !qcomp;
end
// Enable/disable a counter
always @(qcomp)
en <= !qcomp;
endmodule
increments the cnt variable on each rising edge of clk. The on-board LEDs reflect the state of the
counter output.
The comparator itself is implemented within the block
The qcomp output is pulled HIGH when comparator inputs A and B become equal.
Listing 18.
The changes introduced into the original mojo.ucf file are shown in bold.
Designing counters
This project allows to build a simple 8-bit up counter circuit with the reset (rst) and clock
(clk_50M) inputs (Fig.19).
Fig.19
In this circuit, the clock signal of 50 MHz feeds the counter whose value is incremented by 1 every 1
s. When the counter reaches the value determined by the parameter maxCNT (32, in our case),
counting resumes from 0. The output q[7:0] is connected to the on-board LEDs (output led[7:0])
reflecting the states of the counter output. If the on-board button “Reset” is pressed, the counting
begins from 0.
As usual, this design is based upon the basic Mojo project with a few modifications in the
mojo_top.v and mojo.ucf files.
The Verilog code (mojo_top.v) that models the behavior of the counter is shown in Listing 19.
Listing 19.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
cnt = 0;
cntDiv = 0;
qclk <= 1'b0;
led <= 8'd0;
end
The contents of the UCF (mojo.ucf) looks like the following (Listing 20).
Listing 20.
#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05
NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;
The counter that counts down can be obtained from Listing 19 by introducing a few changes into the
Verilog code (Listing 21.)
Listing 21.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
cnt = maxCNT;
cntDiv = 0;
qclk <= 1'b0;
led <= 8'd32;
end
// these signals should be high-z when not used
assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;
In this circuit, the data byte pLoad (177, in our case) is loaded into the shift register when the input
rst becomes HIGH (button “Reset” is released). As rst goes LOW (button “Reset” is pressed), each
bit of pLoad is shifted out through the output sOut on the rising edge of the internal clock clk (see
Listing 22) every 0.5 s that corresponds to the frequency of 2 Hz. After 8 iterations have passed, the
value of pLoad will be reflected by the on-board LEDs (output led[7:0].
To resume the operation, we should reload pLoad by releasing “Reset”, then press and hold “Reset”
until the shift operation is complete.
The Verilog code (mojo_top.v) that models the behavior of the shift register is shown in Listing 22.
Listing 22.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input rst,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
cnt = 0;
pLoad = 177;
led <= 8'd0;
mask = 1;
i = 0;
end
endmodule
The output of the frequency divider (clk) serves as an internal clock to a shift register.
The following block
implements the shift register. In each of 8 iterations, the least significant bit (LSB) of pLoad is fed to
the serial output sOut, then pLoad is shifted right by 1. The value of sOut is assigned to the output
led[7].
After 8 iterations, the pLoad data byte appears on the output led[7:0].
Listing 23.
The changes introduced into the original mojo.ucf file are shown in bold.
This project illustrates designing a PWM circuit where the duty cycle of an output signal can be
selected by pressing/releasing the button “Reset” (Fig.21).
Fig.21
In this circuit, the base frequency of PWM is set to 2000 Hz. The duty cycle of the PWM signal
(output pwmOUT) can be selected either 32% (button “Reset” is released) or 64% (button “Reset”
is pressed).
The Verilog code (mojo_top.v) that models the behavior of the PWM circuit is shown in Listing 24.
Listing 24.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input sw,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg pwmOUT,
initial
duty = 12500; // the initial duty cycle = 12500/25000 x 100 = 50%
always @(sw)
duty = sw ? 8000: 16000;
endmodule
implements the base frequency for a PWM signal. In our case, the base frequency (2000 Hz) is
determined by the maxDIV parameter.
The initial duty cycle (variable duty) for our PWM circuit is set to 12500 (50%).
Then the duty cycle will be set either to 8000 (32%) when the button “Reset” (input sw = 1) is
released or 16000 (64%) when “Reset” is pressed (sw = 0). This sequence is implemented in the
following block:
always @(sw)
duty = sw ? 8000: 16000;
Driving the PWM output pwmOUT is implemented in the block:
always @(posedge clk_50M)
if (cntdiv > duty) pwmOUT <= 1'b0;
else pwmOUT <= 1'b1;
The changes introduced into the original mojo.ucf file are shown in bold. There were also deleted
lines NET “led<x>”.
Designing Pulse Width Modulators: example 2
This is one more design of a PWM circuit. Here the duty cycle of a PWM signal gradually increases
while the button “Reset” remains pressed. The circuit diagram of PWM is shown in Fig.22.
Fig.22
In this circuit, the base frequency of a PWM signal is 100 Hz. As the duty cycle increases, the
brightness of the on-board LED (output led0) increases as well.
The Verilog code (mojo_top.v) that models the behavior of the circuit is shown in Listing 26.
Listing 26.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input up,
// cclk input from AVR, high when AVR is ready
input cclk,
// Output to the onboard LED 0
output reg led0,
integer duty;
integer cnt, cntdiv; // the current value of a counter
initial
begin
duty = minDUTY;
led0 <= 1'b0;
cnt = 0;
cntdiv = 0;
end
endmodule
implements the frequency divider providing the internal clock signal clk of 100 Hz (determined by the
maxDIV parameter) used for incrementing the duty cycle. The duty cycle is configured within the
following always-block:
Incrementing the duty cycle (variable duty) is performed every 0.01 s while the “Reset” button
remains pressed (up = 0). The value of increment is determined by the inc value. When the duty cycle
reaches 475000, it begins incrementing from minDUTY.
The base frequency of a PWM signal (100 Hz) is determined by the parameter maxCNT. The
following always-block drives the led0 output according to the current duty cycle:
The changes introduced into the original mojo.ucf file are shown in bold.
Designing Pulse Width Modulators: example 3
In this design (Fig.23), the duty cycle of a PWM signal varies between the minDUTY and maxDUTY
values (see the Verilog code below). The duty cycle increases until it reaches the maxDUTY value,
then decreases down to the minDUTY value. The PWM output is connected to the on-board LEDs
(output led[7:0]) that change brightness according to the current duty cycle.
Fig.23
The Verilog code (mojo_top.v) that models the behavior of this PWM circuit is shown in Listing 28.
Listing 28.
module mojo_top(
// 50MHz clock input
input clk_50M,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the onboard LEDs
output reg [7:0] led,
reg clk;
integer duty;
integer cnt, cntdiv;
integer up; // 1 --> inc, 0 --> dec
initial
begin
up = 1;
duty = minDUTY;
led <= 8'd0;
cnt = 0;
cntdiv = 0;
end
endmodule
implements the frequency divider providing the 100 Hz clock signal that is used for changing the duty
cycle in the following always-block:
The base frequency source for the PWM signal is implemented as a counter in the following always-
block:
Here the direction of changing the duty cycle is determined by the up variable. While up = 1, the
value of the duty cycle is incremented by the inc value every 0.01 s. When the duty cycle has reached
maxDUTY, the variable up becomes 0 and the duty cycle begins decrementing until it reaches
minDUTY. At this point, up becomes 1 and this sequence repeats.
Listing 29.
The changes introduced into the original mojo.ucf file are shown in bold.
Programming State Machines with Verilog
This chapter describes a few digital circuits built using state machines. Often, even an apparently
simple circuits may be tricky to develop so using state machines allows to greatly simplify a design.
This approach provides modeling a system behavior in diagrammatic form. A state machine is
completely based on mathematics and frequently is referred to as Finite State Machine (FSM).
The basic concept behind state machines is that a system stays in a stable state until some event
causes it to transition to another state. During this transition, some actions may occur. States drawn on
a diagram are usually represented by boxes or bubbles, while transitions are drawn as lines with
arrows going either from one box to another or from one box back to itself. The transition lines are
drawn with the label(s) near them. The labels describe the condition(s) for the transition to occur and,
optionally, may describe any actions that need to take place during the transition.
The following sections contain a few projects that illustrates designing digital circuits using state
machines. You may realize that entire operations performed by these state machines could also be
implemented using simpler Verilog code, but the state machine presents a clear communication of the
intent of a digital circuit and provide an easy way for improving end modifying your design.
Example 1
This example illustrates how to design a state machine implementing an up/down counter circuit
(Fig.24).
Fig.24
In this circuit, the external clock of 50 MHz is taken from the input clk_50M (pin P56 of the FPGA).
Then the frequency of the input clock is divided by an internal frequency divider that provides the
internal clock of 1 Hz to the counter. The counter output q[7:0] drives the on-board LEDs (led[7:0]).
The input dir determines the direction of counting, either up or down. When dir = 0, a counter is
decremented at each positive edge of the internal clock every 1 s; when dir = 1, the counter is
incremented. The dir input is driven by the on-board button “Reset” connected to the pin P38 of the
FPGA.
The on-board LEDs (led[7:0]) reflect the changes of the counter output.
To design this circuit using a state machine approach, let’s determine the possible states where our
system will stay in and signals (events) causing transitions between states. One possible solution is
shown in Fig.25.
Fig.25
In this system, the IDLE state provides transitions to the CNTUP and CNTDOWN states. Transition
from IDLE to one of the active states (CNTUP or CNTDOWN) will be possible if any of the
following events occurs:
1. The signal dir is active (log.”1”). In this case, transition from the IDLE state to CNTUP takes
place;
2. The signals dir is inactive (log.”0”). In this case, transition from IDLE to CNTDOWN takes
place.
When the system stays in the CNTUP state, the circuit is counting up while dir remains 1. When dir
becomes 0, transition to the IDLE state takes place. The current value of the counter is kept during
transition.
When the system stays in the CNDOWN state, the circuit is counting down while dir remains 0. When
dir becomes 1, transition to the IDLE state takes place. The current value of the counter is kept during
transition.
The Verilog code (mojo_top.v) that models the behavior of our state machine is shown in Listing 30.
Listing 30.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input dir,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
q <= 8'd0;
led <= q;
state_reg <= IDLE;
cnt = minCNT - 1;
end
endmodule
In this code, the state of our system is determined by the set of 2-bit parameters:
We also need to keep a current state in order to provide transitions between states. In this code, the
current state is stored in the 2-bit state_reg variable of the reg type.
The always-block
implements the frequency divider providing the internal clock clk of 1 Hz to the counter. The output
frequency of the divider is determined by the maxDIV parameter.
The case statement in this block describes the required operations in each state and allows to make
transitions between states if the required conditions are satisfied
Listing 31.
The changes introduced into the original mojo.ucf are shown in bold.
In the above Verilog code, all required actions were completely executed in the section related to the
particular state. It is possible, however, to make a code more readable by distinguishing the part
processing a state itself from the rest of code. The following example (Listing 32) is a modified
version of the Verilog code shown in Listing 30.
Listing 32.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input dir,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
initial
begin
q <= 8'd0;
led <= q;
state_reg <= IDLE;
cnt = minCNT;
end
endmodule
Example 2
This example illustrates designing a simple counter (Fig.26) that begins counting up when the input
reload becomes active (log.”0”). This occurs when the button “Reset” associated with reload is
pressed. Counting continues regardless of the state of “Reset” until some predetermined value
(parameter maxCNT) is reached.
At this point, the counter either stops (if the button “Reset” is released) or continues counting from 0
(if “Reset” remains pressed).
The bWait output connected to led[7] toggles when counting is stopped. When counting begins, bWait
becomes 0.
Fig.26
Fig.27
This system stays in the IDLE state while the reload input is inactive (log.”1”) and a counter is
cleared (led = 0). The transition from IDLE to the COUNT states occurs when reload becomes active
(log.”0”) while the counter is still clear (led = 0).
When the system stays in the COUNT state, the circuit is counting up from 0 until maxCNT is
reached. When the value of the counter reaches maxCNT, the counter is stopped and transition to the
RELOAD state takes place.
In the RELOAD state, the counter is cleared (led = 0) and transition to the IDLE state takes place.
The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 33.
Listing 33.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input reload,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
initial
begin
state <= IDLE;
led <= 8'd0;
cnt = 0;
end
endmodule
implements the frequency divider. The divider provides the internal clock clk with a frequency of 5
Hz to the counter. The output frequency is determined by the maxDIV parameter.
Listing 34.
The changes introduced into the original mojo.ucf file are shown in bold.
Example 3
This example illustrates the design of the counter circuit (Fig.28) controlled through the input en
(button “Reset”). This circuit counts down from the value determined by the parameter maxCNT to
0. Counting begins when “Reset” is pressed (log.”0”) and stops when “Reset” is released (log.”1”).
As the counter reaches 0, it is reloaded with the value determined by maxCNT.
The circuit diagram of the counter is shown in Fig.28.
Fig.28
The block diagram of the state machine that implements this circuit is shown in Fig.29.
Fig.29
When in the IDLE state, the system waits until the enable signal en becomes active (log.”0”). When
this event occurs, transition from IDLE to the COUNT state takes place.
In the COUNT state, while en stays active (log.”0”), the counter is counting down from maxCNT to
0. If en becomes inactive (log.”1”) during counting, the counter stops and transition to the IDLE state
takes place. When the counter reaches 0, transition from COUNT to RELOAD takes place.
In the RELOAD state, the counter is reloaded with the predetermined value (parameter maxCNT)
and transition to the IDLE state takes place.
The Verilog code (mojo_top.v) that models the behavior of the above circuit is shown in Listing 35.
Listing 35.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
integer cntdiv;
integer cnt;
initial
begin
cnt = maxCNT;
state <= IDLE;
end
endmodule
Listing 36.
The changes introduced into the original mojo.ucf file are shown in bold.