In C, the first program a person writes is often known as a “Hello, World!” program. It does nothing but print “Hello, World!” to the screen and exit. While this is a wonderful first program for the C programmer, it is wholly inappropriate for either the FPGA programmer or the embedded programmer.

The FPGA or embedded programmer must work to get the serial port or the C-library working, if he has either. Instead, he has a simple LED to work with. Hence the first program, blinky, simply blinks that LED.

Why blinky?

Blinky is a very important program: it proves that you can 1) program the FPGA, that you 2) have a working clock, and that 3) you have a working LED. These are very important steps in programming a new board. Indeed, they are so profound, I still run blinky as my first program on any FPGA board today. Even after your first configuration, blinky is still important, because it can tell you if the problem is your design versus the ability to load the board.

What is blinky?

Below is a very simple version of the blinky program, written in Verilog. Remember, simple is better at this point.

//
`default_nettype none
//
module blinky(i_clk, o_led);
  input wire i_clk;
  output wire o_led;

reg	[25:0]	counter;
always @(posedge i_clk)
  counter <= counter + 1'b1;
assign o_led = counter[25];

endmodule

While there’s not much to the design, the “not much” that is there is important.

  • Notice that I mark my inputs with the prefix i_, and my outputs with the prefix o_. You’ll find this consistent notation through all of my work.

  • Notice the default_nettype directive. We’ll come back to it later. For now, I highly recommend every Verilog design you build start with it.

  • Notice the counter. Many beginners place an LED in their design without the counter, and then wonder why things don’t work. An FPGA runs faster than your eye can see. Without the counter, you wouldn’t be able to see this LED blink.

  • I have 26 bits in my counter (25+1). This is just about right for most of the projects I’ve worked on. It divides the clock by 2^26, creating a clock rate at around one Hertz. If you pick a number too low, you won’t see the LED blink. If you pick a number too high, you’ll get bored waiting for the LED to blink while wondering if your FPGA works.

A better blinky

With no more than just a clock and an LED, can you figure out how fast your clock is running?

This was a challenge of mine when first firing up my icoboard. The schematic for that board initially identified the clock as being at 25MHz, the examples identified it as being at 100MHz. (The team has since fixed the schematic, to properly reflect the 100MHz clock.) How should I tell which of the two was the right answer?

Here was my solution:

//
`default_nettype none
//
module clktest(i_clk, o_led);
  input wire i_clk;
  output wire o_led;

// We use a larger, 32-bit, counter here so as to get some better time
// precision.
reg	[31:0]	counter;
always @(posedge i_clk)
  counter <= counter + 32'd43; // Valid if clk rate = 100MHz

// Blink the LED sharply at the top of each second, so that
// it remains on for a quarter of a second only before turning
// off
assign o_led = (counter[31:30] == 2'b00);

endmodule

Did you notice the 32’d43 value? This value is set to 2^32 divided by the clock rate. Since the clock rate on this board is 100 MHz, 2^32 divided by 100 MHz is about 43. Hence, if the counter starts at zero, then after 100 million clock ticks, the counter should equal 2^32 and roll over to zero again. In this case, though, since 2^32/100M isn’t exactly 43, our clock will run about 5% too fast. Still … it should be close enough that we can use a stop watch to verify that we are in about the right clock range.

If you are interested, this method of clock division is also used within the Real-Time Clock project used by the ZipCPU. The project, though, uses a 48-bit counter to get much better time accuracy–assuming that the oscillator is that good.

Using blinky for debugging

If you ever find yourself debugging with nothing but an LED, you can use the LED for your debugging. It’s not the best means of debugging: it can only return one bit of information, and sometimes not even that, but it may be the only means you have.

The basic idea is to set the LED to on any time some condition takes place. The trick is … you need to reset the LED so that you can see if that condition takes place again later, and you need to make certain that the condition (whatever it is) takes place so rarely that you can understand what’s going on.

Here’s an updated blinky, therefore, that can be used within a design to help debug it:

reg	[24:0]	counter;
always @(posedge i_clk)
  if (debug_event)
    // Reset the counter if our event ever takes place
    counter <= 0;
  else if (!counter[24])
    // Increment the counter, to hold the LED for a period of time
    // long enough for us to observe it ... before turning the LED
    // back off again
    counter <= counter + 1'b1;

// Since the reset condition sets this high order bit low and holds
// it low for a period of time, and since the light "on" usually
// indicates the condition has taken place, negate the top bit of
// the counter so that the LED will turn _on_ any time your event
// takes place.
assign o_led = !counter[24];

As before, the choice of the length of the counter is important.

This time, though, we’ve used “debug_event”, a variable coming from elsewhere in the design, to check to see if something ever happens. If this event ever happens, the counter is set to zero, and the LED is turned on. The counter then holds the LED on for 2^24 clocks, before stopping and waiting for a new event.

While better approaches exist, most of those require more logic that needs to be debugged first. As a result, I’ve used this approach to debug my serial port controller, since most of my debugging logic depends upon a working serial port. I’ve also used this approach to track how much time the ZipCPU is spending in interrupts, and if and when the ZipCPU has frozen in designs that are too tight to fit a better debugging infrastructure.

What next?

Once you have blinky running, it’s time to move on to other tasks. These tasks, though, will be easier because you have a clock and an LED that works. Indeed, you can use blinky to your advantage as you struggle to get those newer tasks running.