FPGA Development boards usually run on a high frequency oscillator in the tens or hundreds of Megahertz range. One way to toggle an IO line at a slower frequency is to use a counter circuit. I will show you how to write some Verilog code that divides down a high clock frequency to a more human friendly time scale, and blink some LEDs!
We will be using an affordable FPGA Development board called the Numato Elbert V2, which contains a Spartan 3 FPGA with 1584 logic cells. The FPGA is a little on the small side, but the board comes with a nice set of IO accessories for the price.
First, we must consider what clock speed this FPGA is being run at. This board has a 12 MHz clock on it, so each clock cycle has a period of T = 1/f ≃ 83.33 ns. We will design a register such that with every clock cycle it’s value is incremented by 1.
If our clock cycle is 83.33 ns, 225 clock cycles will amount to 2.796 s. If we design a register to be 25 bits wide, and it is incremented by 1 each clock cycle, it will overflow (reset) every 2.796 seconds. The bit below the MSB, the 24th bit, will change from o to 1 in 1.398 seconds and from 1 to 0 in 1.398 seconds. We will chose to blink the slowest LED at this frequency by linking the LED state to the state of the 24th bit in the register in our user constraint file.
To blink an LED twice as fast we simply hook up a second LED to bit 23. To blink an LED four times as fast we hook up a third LED to bit 22. We will hook up our 8 LEDs to bits 24-17 of our register, such that each successive LED blinks twice as fast.
Let’s look at the code.
Our module is called universalCounter, and has a parameter N=25 which corresponds to the width of our register we will invoke. Our circuit will have 3 input wires: clk which will be routed to the on board 12 MHz clock, reset which will asynchronously reset the counter, and inc which will activate the counter, letting our LEDs blink. Output array q will route our output from the register to our LEDs.
We next declare two reg arrays which will be used in the register and next-state logic blocks.
Our register behavior is invoked in an always block. The if-else statement invokes a priority routing network, where if the reset input gets a positive edge then 0 is routed to r_reg, else r_next, the next state of the register, is routed to r_reg on each positive clock edge. If we think of the register as being composed of D flip flops, every positive edge of the clock cycle will have the next state of the register stored in it, with r_reg being like q and r_next being like d.
The next state logic always block invokes a priority routing network where if inc is asserted, then then r_reg + 1 adder circuit is routed to r_next, incrementing the value stored, else r_reg routes to r_next, and the register remains unchanged. This determines what the next state of the register will be at each positive edge of the clock.
Lastly bits 24 through 17 are routed to the output q, which will be set to the 8 LEDs in our constraint file.
Finally we have a test module that has our IO variables we will set in the user constraint file. We invoke our universalCounter circuit and route the IO to it. Note that the complement of reset and inc are used, as the pushbuttons on the Elbert board have pullup resistors and are normally asserted.
For completeness the user constraint file used for this circuit on the Elbert V2 is listed above, linking the IO variables to the pins on the FPGA.
The blinking LED behavior is shown at the beginning of this post. As you can see, the left most LED is controlled by the state of bit 24 of the register, which has a period we designed to be 2.796 seconds.
Using my oscilloscope to probe the IO line tied to bit 24 shows the designed period.
Probing the IO line tied to bit 23 shows that is has half the previous period, therefor the LED to the right of the first one blinks twice as fast.
This continues down to the last LED which is tied to bit 17 of the register and has a period of 2.796 / 27 = 21.8 ms! Bingo!