FPGA logo large

Sequential Circuit Design Introduction (meet Blinky)

Last time we built an Exclusive Or circuit. And we talked briefly about the difference between a Combinational circuit and a Sequential circuit. Recall that in a combinational circuit the outputs are purely a function of the inputs. There is no state (or memory). And operation is not synchronized to a clock signal. This time we will design a sequential circuit to turn one of the Basys 3 LED’s on and off.

In doing so, we introduce a few new concepts. First, create a new Verilog project called blinky. If you need instructions on how to create a project in Vivado here are some great step by step instructions. Then copy in the Digilent Basys 3 constraints file. In a previous post introducing design constraints we already learned how to uncomment the lines that define the clk and led signals that we need. While you are editing the constraints file be sure to remember to rename led[0] to led.

Be sure to remember to rename led[0] to led.

Next, create a new Verilog source file. Let’s call it blinky.v. Then we declare our module in Verilog, also called blinky. Don’t worry about declaring any ports via the source creation wizard, we will do that later. The module should have an input port clk and an output port called led. So go ahead and declare those as input and output parameters respectively in the module declaration. At this point our circuit design should look like the following.

module blinky(
    input clk,
    output led
);

endmodule

If you look closely you may notice something different about the port declarations. I left out the wire keyword in the declarations. That is because wire is the default in Verilog and it is assumed if you don’t explicitly declare an explicit type.

Now, we could simply connect the clk port to the led port using a continuous assignment. This would be similar to what we did in the Verilog introduction. But that is not very interesting. Why? Because if we tried this we would find that the led flashes so fast that it appears to be on continuously. To see why this is the case requires understanding a bit more more about the nature of the clk signal.

Understanding the CLK Signal

The clk signal coming into our circuit, at least for the Basys 3, has a frequency of 100Mhz. So if we connect clk to led, the led attempts to flash 100,000,000 times a second! To the human eye, due to persistence of vision effects, anything faster than around 60 to 90Hz appears to be continuous. So clearly that will not work.

What we need is some way to slow down the signal that we connect to led. What if we had a way to count the number of clk transitions (or ticks) and generate a new signal which transitions only after a certain count is reached? Let’s say we want the led to flash at a more reasonable rate, say around 1 to 2 times a second.

One way we can achieve this is if we create a counter variable that can hold a 25-bit value. With such a counter we can count from 0 to 2^25-1 or 33,554,431. And if we tie our output signal to the top-most bit of our counter we will see that bit changes state once every 16,777,216 (2^24) clk ticks or about 6 times per second (100/16). Since there are two state transitions per cycle our flash frequency will be around 3 times per second (6/2), or one on/off cycle every 1/3 of a second.

Introducing the Reg Data Type

Before we look at the Verilog we need to introduce a couple of new concepts. The first concept is the reg data type. This type declares a signal that retains its value until it is changed. This definition implies memory, or state. Whether Verilog actually generates, or infers, memory depends on how you assign values to the signal. For now we’ll assume that a reg value always generates memory. So we declare our reg counter like so.

module blinky(
    input clk,
    output led
    );

    // first attempt at declaring our counter
    reg count = 0;

endmodule

However, a simple reg declaration generates only a single bit of memory and our counter needs to hold 25 bits. To support, this Verilog conveniently allows you to define collections of signals (wire or reg) using a zero-based array syntax. The code below declares a 25-bit reg variable with bit indices ranging from 0 to 24. In Verilog, you can address and manipulate individual bits as well as sub-sets (or slices) of bits. So while we are at it lets use a continous assignment to connect the top bit of our counter to the led signal.

module blinky(
    input clk,
    output led
    );

    // declare a 25-bit counter
    reg [24:0] count = 0;

    // connect the counter high bit to led
    assign led = count[24];
endmodule

Meet the Always block

Now we need a way to increment our counter each time the clk changes state. Doing so requires us to learn about the always block. An always block represents a circuit that is a collection of behaviors that are always processed together. The general form of an always block is shown below. The sensitivity list represents one or more signals that the block is sensitive to and which activate the block.

always @([sensitivity list)
begin
    [statements]
end

In our case, we want our counter to be sensitive to the clk signal. And specifically we choose to be sensitive to the rising, or positive, edge of the clk signal. Verilog provides the posedge keyword to allows you to specify a sensitivity to the positive edge of a signal. So let’s declare our always block and use it to increment our counter register.

always @(posedge clk)
    count <= count + 1;

There is another new concept shown in the code above. Notice the <= operator used to increment the counter? This represents a non-blocking assignment, one of the two types of assignments that can be present in an always block. The other type of assignment is the blocking assignment. The basic rule of thumb is that we use blocking assignments for combinational circuits and non-blocking assignments for sequential circuits. We are creating a sequential circuit, so we use the non-blocking form of assignment.

The basic rule of thumb is that we use blocking assignments for combinational circuits and non-blocking assignments for sequential circuits.

Pulling it all together in Verilog

OK, at this point we have all of the pieces. let’s put it all together and see what it looks like. The code below shows our final circuit design.

module blinky(
    input clk,
    output led
    );
    
    // declare a 25-bit counter
    reg [24:0] count = 0;

    // connect the counter high bit to led
    assign led = count[24];

    // increment count each clock tick
    always @ (posedge clk) 
        count <= count + 1;
    
endmodule

And that is it! We have created our first sequential circuit. This time I didn’t create a simulation, I went right to synthesis to see if our circuit was successful. After synthesizing this circuit and programming the bitstream output to the Basys 3 I see that the on-board led[0] does in fact flash at approximately 3 times per second. The source code for this project is available on the github site for this blog.

Have a comment, question or suggestion regarding this post? Please leave a comment!

Discover more from FPGA Coding

Subscribe now to keep reading and get access to the full archive.

Continue reading