Skip to contentSkip to author details

Implementing a simple binary counter in the Mojo FPGA IDE

Written by Michael Earls
 electronics  FPGA  beginner  tutorial


I recently purchased a Mojo FPGA development board based on the recommendation of my good friend Keith Rome. He's been very helpful in getting me started on my journey into this bizarre technical realm. I've also had a lot of help from my friend Greg Young, as well.

The source code for this project can be found on GitHub at:

github.com/cerkit/fpga-binary-counter

The Verilog source for each of the modules is also located on GitHub in the same project:

github.com/cerkit/fpga-binary-counter/tree/master/work/verilog

One of the things that continues to be repeated while I read articles (and this was something that both Greg and Keith told me over and over) is that FPGA "programming" isn't "programming". It's synthesis, and that makes a world of difference.

I won't go into details about all of this, because I think that's been covered more professionally elsewhere, but I did want to point out that this has been a challenge for me because I've been thinking like a computer programmer since I was 10 years old.

I had to unthink code and rethink logic synthesis. It has been awesome. I love how my brain feels after I successfully figure something out for the first time with the FPGA. When I'm developing a new software system and figure out how to use a new language, it's no big deal because it's "just another programming language". But this is different, this is ANOTHER UNIVERSE!

I have been looking for a simple way to apply the knowledge I had of FPGA projects after completing the first few tutorials on the Embedded Micro tutorials site (they are the manufacturers of the Mojo FPGA board).

I thought about doing a simple binary counter that counts from 0 to 255 (because I have 8 LEDs and that's the highest number they can represent).

I started with the simple blinker tutorial since it outlined how to use flip-flops to do stuff.

I have to be honest, I hacked this solution together from the flip flop code in the tutorial. I'm not entirely sure how it works exactly, but I'll try my best to explain what I did and why I did it. I think the flip-flop acts as a clock divider of some sort for me and slows the process down. The first time I implemented my counter, I noticed that the first few LEDs were slightly "dimmer" than the top ones. I'm guessing it was because it was counting from 0-255 as fast as it could and the lower digits changed far more often then the upper digits, so I got a PWM-style dimming effect.

So, I knew I had to slow the "loop" down for human observation. Since the blinker tutorial describes using the flip flop to "divide" the 50MHz clock (or at least use up lots of cycles counting from 0 to 33554431), I thought that would be the answer. It was, but I had to study the example to figure out how to make it work with the counter.

Here is a quick video showing the results.

To start, simply create a new project in the Mojo IDE: File->New Project

I named mine "BinaryCounter".

Before moving on, let's add a simple counter component to our project to use as the base of our project.

In the main menu, click Project->Add Component. You should see a window like the following:

Add component dialog in Mojo IDE

This will add a really nice counter implementation to your project that is very easy to use. If we just wire that counter to the LEDs outputs, we'll get the effect that I was describing earler.

Since we'd like to add a little more abstraction and create a "slow" counter, let's add a module to our project that will handle the whole count process.

Right click on the "Source" element in the tree and choose "New Source".

Name it "slowCount" and choose "Lucid Source" as the type.

Here is the code for the slowCount module:

module slowCount (
    input clk,  // clock
    input rst,  // reset
    output value[8]
  ) {

  .clk(clk), .rst(rst) {
    dff flip[25];
  }

  counter ctr(.rst(rst));

  always {
    ctr.clk = flip.q[24];
    flip.d = flip.q + 1;
    value = ctr.value;
  }
}

Our inputs are fairly standard. We need them for our internal timing flip-flop.

See Synchronous Logic Tutorial for an explanation on why the flip flop works as a good timer here.

Here is the most important part of the explanation as it relates to what we're doing (the flip-flop was named "counter" in the original text, so I replaced it with the word "flip" to reflect our code changes. It looks a bit confusing).

Let's look at what this module will actually do. Right after the rst signal goes low, flip.q will be 0. That means that flip.d will be 1, since our combinational block assigns it flip.q plus 1.

At the next positive edge of clk, flip.q will be assigned the value of flip.d, or 1. Once flip.q is 1, flip.d must be 2. You should be able to see what will continue to happen. Each clock cycle flip.q will increase by 1. But what happens when flip.q is 25b1111111111111111111111111 (the max value)?

Since we are adding a 1 bit number to a 25 bit number, the result can be up to 26 bits, but since we are storing it into a 25 bit dff we lose the last bit. That means that when flip.q is the max value, flip.d is 0 and the process starts all over again.

Our flip will continuously count from 0 to 33554431 (2^25 - 1).

How do we make an LED blink from this flip-flop? It's simple once you realize that for half the time the most significant bit is 1 and the other half of the time it's 0. This is because if flip.q is less than 16777216 (2^24), then the 24th bit must be 0 and when it is equal or greater, the MSB must be 1. That means we can just connect the LED to the most significant bit of our flip. If you need to convince yourself this is true try writing out the binary values from 0-7 and look at how the MSB (most significant bit) changes.

How fast will the LED blink though? We know that the clock frequency is 50MHz, or 50,000,000 clock cycles per second. Since our flip takes 2^25 cycles to overflow we can calculate the blinker time, 2^25 / 50,000,000 or about 0.67 seconds. The LED will turn on and off every 0.67 seconds. If you wanted to make that time longer, you can just make the flip 26 bits long and the time will double to 1.34 seconds. If you wanted to make it blink faster you can make the flip shorter.

Now, instead of blinking an LED, we're using the output of flip as a clock input of the counter component we added earlier. This will slow the counter down to only increment once for every flip clock pulse.

So, to use our new slowClock component, we merely need to wire it up to clk and rst. Here is our mojo_top.luc file:

module mojo_top (
    input clk,              // 50MHz clock
    input rst_n,            // reset button (active low)
    output led [8]         // 8 user controllable LEDs
  ) {

  sig rst;                  // reset signal

  .clk(clk) {
    // The reset conditioner is used to synchronize the reset signal to the FPGA
    // clock. This ensures the entire FPGA comes out of reset at the same time.
    reset_conditioner reset_cond;

    .rst(rst) {
      slowCount myCount;
    }        
  }

  always {
    reset_cond.in = ~rst_n;    // input raw inverted reset signal
    rst = reset_cond.out;      // conditioned reset

    led = myCount.value;
  }
}

As you can see, I took the shortcut to wire the clk and rst to my slowClock component, since I was already doing it for the reset_conditioner (a component automatically added by the Mojo IDE to synchronize all reset activities (I assume for button debouncing and such)).

Since the clock is driving the counter, all we have to do is continuously set the value of the LED "array" to the output value of the slowClock (because the output is 8-bit binary).

The biggest challenge with this project was understanding how to slow everything down so I could see it. My next challenge will be to speed up or slow down the counting. Perhaps I could even bring in the onboard ADC and use a potentiometer to select the speed.

Even though the rst is wired through to the counter, I can't seem to make it reset to zero when I hit the reset button. I'm going to have to figure that one out, too.