Project 10: Counter and Clock Divider Revisit

Introduction

A lot of interesting things can be built by combining arithmetic circuits and sequential elements. In this project, we are going to provide arithmetic circuits with timing references by integrating arithmetic circuits with flip-flops. In the first part, we are going to use an adder with a register file (an array of flip-flops) to implement a counter that increases the number by 1 when the rising edge of the clock arrives. In the second part, we are going to revisit clock dividers. We will then implement a clock divider whose frequency can be more precisely calculated compared to the clock divider implemented in the previous projects.

Before you begin, you should:

  • Have Vivado installed.
  • Have your FPGA board set up.
  • Be able to describe digital circuits using logic operators.
  • Be able to write a test bench and simulate circuits using ISim.
  • Be able to describe sequential circuits using always block.

After you're done, you should:

  • Be able to describe counters in Verilog.
  • Be able to design clock dividers with counters.

Inventory

  • Digilent Nexys A7 or Basys 3 FPGA Board
  • Vivado Installation

Step 1: Design an 8-bit Counter

A counter is no more than an adder with a flip-flop for each of the output bits. The block diagram of a counter is shown below in Fig. 1. Figure 1. Block diagram of 8-bit counter.

Figure 1. Block diagram of 8-bit counter.

When reset signal “rst” is asserted, the outputs of the counter (Q[7:0]) are 0. The outputs of flip-flops feed back to the input of the ripple-carry adder and present $0+1=1$ at the input of the flip-flops. When the reset signal is de-asserted, the outputs turn to 1 after the rising edge of the clock arrives. And $1+1=2$ will be presented at the inputs of the flip-flops. After the second rising edge of the clock arrives, 2 will show up on the outputs of the counter. As a result of the analysis, the flip-flops provide a timing reference (clock) to the adder so that the output of the counter is increased by 1 every time the rising edge of the clock arrives.

To describe the circuit structurally in Verilog, you can use the RCA and the flip-flops you implemented in previous projects. Actually, it is a lot easier to code it behaviorally. To describe any sequential circuit, we can use the similar always block as the one we used to describe a D flip-flop. To implement the counter behaviorally, there are three statements we need to make:

  • When will the always block be triggered? The output of the counter will be updated at the rising edge of the clock (functionality of FF) or the rising edge of the reset signal (asynchronous reset).
  • How does output react when reset is asserted? The output of the counter will be reset to '0' when reset is asserted.
  • How does output react when the rising edge of the clock arrives? The output is updated to the output of the adder, which is the output of the counter before the rising edge arrives, plus 1.

So, the code for a counter is shown as follows:

module counter(
    input clk,
    input rst,
    output reg [7:0] Q
    );
 
always @ (posedge(clk), posedge(rst))   // When will Always Block Be Triggered
begin
    if (rst == 1'b1)
        // How Output reacts when Reset Is Asserted
        Q <= 8'b0;
    else
        // How Output reacts when Rising Edge of Clock Arrives?
        Q <= Q + 1'b1;
end
 
endmodule

Step 2: Clock Divider

In the previous project, we explained how to use a flip-flop with an inverter to implement a clock divider that divides the frequency in half. In this section, we can use a counter with a comparator to condition a flip-flop with an inverter to implement a clock divider that can control the output frequency more precisely. The block diagram of such a clock divider is shown in Fig. 2.

Figure 2. Clock divider with a counter and a comparator.

Figure 2. Clock divider with a counter and a comparator.

In the block diagram, the counter increases by 1 whenever the rising edge of clk arrives. It also resets its output to '0' when it reaches the constant number defined in the constant block. The comparator compares the output of the counter with the pre-defined constant and asserts EQ if the output of the counter is equal to the pre-defined constant. When EQ is asserted, the output of the clock divider flips.

Let's assume that the pre-defined number is 3, and the output of the clock divider (clk_div) is initialized to 0. It takes three clock cycles before the output of the counter equals the pre-defined constant, 3. When it reaches 3, the output of the clock divider (clk_div) turns to 1, and the counter resets itself. It takes another three cycles before the output of the counter equals the pre-defined constant, 3. When it reaches 3 again, clk_div turns back to 0. So it takes 6 clock cycles before clk_div goes to 1 and returns to 0 again. As a result, the frequency of clk_div is one-sixth of the frequency of the original clk.

In this example, we are going to use this clock divider to implement a signal of exactly 1 Hz frequency. First, we will need to calculate the constant. As an example, the input clock frequency of the Nexys A7 is 100 MHz. We want our clk_div to be 1 Hz. So it should take 100000000 clock cycles before clk_div goes to '1' and returns to '0'. In other words, it takes 50000000 clock cycles for clk_div to flip its value. So the constant we need to choose here is 50000000. Now we will start to describe the circuit:

1. Create a Verilog module for clock divider.

module ClkDivider (
    input clk,
    input rst,
    output reg clk_div
    );
 
 
endmodule

2. Define the constant as a local parameter:

localparam constantNumber = 50000000;

3. Describe the counter in an always block.

reg [31:0] count;
 
always @ (posedge(clk), posedge(rst))
begin
    if (rst == 1'b1)
        count <= 32'b0;
    else if (count == constantNumber - 1)
        count <= 32'b0;
    else
        count <= count + 1;
end

4. Describe the flip-flop together with the comparator as follows:

always @ (posedge(clk), posedge(rst))
begin
    if (rst == 1'b1)
        clk_div <= 1'b0;
    else if (count == constNumber - 1)
        clk_div <= ~clk_div;
    else
        clk_div <= clk_div;
end

5. Now that we have a counter that increases by 1 when the clock rising edge arrives and a clock divider that can provide a clock signal that is exactly 1 Hz, we can now write a wrapper module. In the wrapper, we can use the output of this clock divider to provide the clock signal for the 8-bit counter we designed in Step 1. Thus, we get a counter that increases every second. Tie the outputs of the counter to the LEDs.


Test Your Knowledge!

Now that you've completed this project, try these modifications:

  1. Can you implement a counter that counts every 100 ms?
  2. Recall the seven-segment display we have implemented in previous projects. Can you display the output of the counter on the seven-segment display?