Skip to main content

To Code a Stopwatch in Verilog

The stopwatch coded here will be able to keep time till 10 minutes. It will be a 4 digit stopwatch counting from 0:00:0 till 9:59:9. The right most digit will be incremented every 0.1 second, when it reaches 9 it will increment the middle two digits, which represent the second count. When it reaches 59 seconds it will increment the right most minute display. The stopwatch will be in the format M:SS:D.

How to Create an Accurate Delay in Verilog:


To make the stop watch an accurate device we need to be able to produce an accurate 0.1 second delay. I have already explained how to do this before in my decimal counter in verilog post. But since it is of great importance to the design will be explained in more detail here.

Since we know that the BASYS2 (the one I am using, yours may be different) has a 50 MHz clock which means that the clock cycle is repeated 50M times in one second. So to create a 0.1 second delay we multiply the clock with the required time:

50MHz * 0.1 sec = 5000000

So the clock cycle is repeated 5M times in 0.1 second. The next step is to calculate the size of the register that will hold this count. This is done by using the log formulas. Here x is the unknown:

2exp(x) = 5000000

Taking log on both sides:

log 2exp(x) = log 5000000

(x) log (2) = log 5000000

x = log 5000000 / log 2

x = 22.3

Hence a 23 bit wide register will be able to hold a count of 5000000.

The code for the stopwatch is given below, as with all other posts involving the seven segment display LED multiplexing is performed here. I will not comment or explain it here as I have already made a detailed post regarding that here: Display LED Multiplexing in Verilog

module stopwatch(
    input clock,
    input reset,
    input start,
    output a, b, c, d, e, f, g, dp,
    output [3:0] an
    );

reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
reg [22:0] ticker; //23 bits needed to count up to 5M bits
wire click;


//the mod 5M clock to generate a tick ever 0.1 second

always @ (posedge clock or posedge reset)
begin
 if(reset)

  ticker <= 0;

 else if(ticker == 5000000) //if it reaches the desired max value reset it
  ticker <= 0;
 else if(start) //only start if the input is set high
  ticker <= ticker + 1;
end

assign click = ((ticker == 5000000)?1'b1:1'b0); //click to be assigned high every 0.1 second

always @ (posedge clock or posedge reset)
begin
 if (reset)
  begin
   reg_d0 <= 0;
   reg_d1 <= 0;
   reg_d2 <= 0;
   reg_d3 <= 0;
  end
  
 else if (click) //increment at every click
  begin
   if(reg_d0 == 9) //xxx9 - the 0.1 second digit
   begin  //if_1
    reg_d0 <= 0;
    
    if (reg_d1 == 9) //xx99 
    begin  // if_2
     reg_d1 <= 0;
     if (reg_d2 == 5) //x599 - the two digit seconds digits
     begin //if_3
      reg_d2 <= 0;
      if(reg_d3 == 9) //9599 - The minute digit
       reg_d3 <= 0;
      else
       reg_d3 <= reg_d3 + 1;
     end
     else //else_3
      reg_d2 <= reg_d2 + 1;
    end
    
    else //else_2
     reg_d1 <= reg_d1 + 1;
   end 
   
   else //else_1
    reg_d0 <= reg_d0 + 1;
  end
end

//The Circuit for Multiplexing - Look at my other post for details on this

localparam N = 18;

reg [N-1:0]count;

always @ (posedge clock or posedge reset)
 begin
  if (reset)
   count <= 0;
  else
   count <= count + 1;
 end

reg [6:0]sseg;
reg [3:0]an_temp;
reg reg_dp;
always @ (*)
 begin
  case(count[N-1:N-2])
   
   2'b00 : 
    begin
     sseg = reg_d0;
     an_temp = 4'b1110;
     reg_dp = 1'b1;
    end
   
   2'b01:
    begin
     sseg = reg_d1;
     an_temp = 4'b1101;
     reg_dp = 1'b0;
    end
   
   2'b10:
    begin
     sseg = reg_d2;
     an_temp = 4'b1011;
     reg_dp = 1'b1;
    end
    
   2'b11:
    begin
     sseg = reg_d3;
     an_temp = 4'b0111;
     reg_dp = 1'b0;
    end
  endcase
 end
assign an = an_temp;

reg [6:0] sseg_temp; 
always @ (*)
 begin
  case(sseg)
   4'd0 : sseg_temp = 7'b1000000;
   4'd1 : sseg_temp = 7'b1111001;
   4'd2 : sseg_temp = 7'b0100100;
   4'd3 : sseg_temp = 7'b0110000;
   4'd4 : sseg_temp = 7'b0011001;
   4'd5 : sseg_temp = 7'b0010010;
   4'd6 : sseg_temp = 7'b0000010;
   4'd7 : sseg_temp = 7'b1111000;
   4'd8 : sseg_temp = 7'b0000000;
   4'd9 : sseg_temp = 7'b0010000;
   default : sseg_temp = 7'b0111111; //dash
  endcase
 end
assign {g, f, e, d, c, b, a} = sseg_temp; 
assign dp = reg_dp;


endmodule




Test bench below:


module test;

 // Inputs
 reg clock;
 reg reset;
 reg start;

 // Outputs
 wire [3:0] d0;
 wire [3:0] d1;
 wire [3:0] d2;

 // Instantiate the Unit Under Test (UUT)
 stopwatch uut (
  .clock(clock), 
  .reset(reset), 
  .start(start), 
  .d0(d0), 
  .d1(d1), 
  .d2(d2)
 );

initial
  begin
   clock = 0;
    forever
     #50 clock = ~clock;
  end

 initial begin
  // Initialize Inputs
  reset = 0;
  start = 0;

  // Wait 100 ns for global reset to finish
  #100;
  reset = 1;
  #100;
  reset = 0;
  #100;
  start = 1;
  // Add stimulus here
 end
endmodule

Video demonstration below:

Comments

  1. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. It doesnt work how? Can you tell me the error you are getting? Also did you change the ucf file for your board. If you use my ucf it wont work.

      Delete
    2. yes. i changed the frequency according to nexys3 board. and i have also changed the .ucf file according to the board. when i program the board, it does not start counting, and only the right most 7seg led lighted up showing 0.

      Delete
    3. Interesting.. Do you get any warnings when implementing? Most probably the ISE is truncating some signals where it shouldnt

      Delete
  2. can i get a test bench for this?

    ReplyDelete
    Replies
    1. HOw does the test bench show 'outputs': d0,d1,d2 when you've not assigned them as outputs in the main program?

      Delete
    2. ^i have the same exact question

      Delete
  3. hey, and you pleace then me the vhdl code as a zip file so i can open it directly on vhdl(+ufc so i can try it on my board) ... my email: Sweet_sahar91@hotmail.com

    i also wanna ask if you have a vhdl code for up/down stopwatch, it will be so great if you have! :)

    thanx!

    ReplyDelete
    Replies
    1. hi Sahar.

      I do not have this in VHDL also I don't know how to code in VHDL. All my projects are in Verilog.

      As for the up and down, you can easily add a down version to this code my coding another block that decrements instead of increments.

      Delete
  4. Could you provide a UCF file for the BASYS2?

    ReplyDelete
    Replies
    1. Here you go: http://simplefpga.blogspot.com/2012/06/user-constraint-file-ucf-for-basys2.html

      Delete
  5. Sir I had learn from many of your tutorial about delay generation but none of your tutorial contain delay generation and call in any line ...Actually sir I want to call a delay in any line of Verilog..
    like
    a=1'b0;
    delay(); //maybe task or function
    a=1'b1;
    sir my question is how to do this using task or counter I already tried this using counter but it not works for me......please help and mail me if you know about this-shrikantvaishnav@hotmail.com or publish any post related to it......

    ReplyDelete
    Replies
    1. You are missing the point. This is not C or C++. This is not how Verilog works.

      In Verilog you cannot "call" anything. It just doesn't work like that.

      Delete
    2. sir can I mail/post you my Verilog code and show you the point of error in my code for delay generation........please allow me sir......I know you definitely have the answer please sir...

      Delete
    3. Sorry Shrikant but I cannot give out my email for the purpose of error finding in codes but like I said before you cannot "call" a delay function like you do in other languages. If you want to produce a delay during execution the easiest method is to generate a counter and only let the other always block activate when the counter reaches its desired value, like I did in the code in this post with "ticker". You can also make a module out of this and instantiate it into your main code.

      Delete
  6. Hello How can i assign pin..i mean which pin goes for output...?

    ReplyDelete
    Replies
    1. Hi Seajan,

      For actual pin assignment of your code to your board you will have to use the .ucf file of YOUR board. Read more on it here: http://simplefpga.blogspot.co.uk/2012/06/user-constraint-file-ucf-for-basys2.html

      The ucf given there is for my BASYS 2 board, if thats not the one you have then it wont work for you

      Delete
  7. I am stuck. I want a stop watch using LCD on Spartan 3E. i have done the LCD coding while i cannot understand the logic of implementing the stop watch or its coding.

    ReplyDelete
    Replies
    1. Which board are you trying to implement this on?

      Delete
  8. please help me to implement it in NEXYS 2 board

    ReplyDelete
    Replies
    1. To implement this on the NEXYS2 all you have to do is to change your .ucf file which you have for your board to the inputs and outputs of this code.

      Have a look at the ucf file configuration of my BASYS2 board to get an idea: http://simplefpga.blogspot.co.uk/2012/06/user-constraint-file-ucf-for-basys2.html

      Delete
  9. can i implement this code in nexys 2 board

    ReplyDelete
  10. can you please upload a ucf file of nexys 3? I am a beginner and am not aware of the creation of ucf files..also please advise if we also need to make a bitfile after the generation of ucf file

    ReplyDelete
    Replies
    1. I don't know the pin layout for nexys3, but you should be able to find its ucf file online via a simple google search. And yes you will need a bit file in order to program your board.

      Delete
  11. hey , can send the project with all codes on a rar file to this email ggadeag@gmail.com is thank you in advance .

    ReplyDelete
  12. Hi, i am doing doing stop watch in verilog using SPARTAN-3 FPGA_XC3S400 board. i dont no how to program lcd which displays the stop watch...pls help me.... its urgent.....

    ReplyDelete
    Replies
    1. Is it an LCD or the seven segment led?

      Delete
    2. Is it an LCD or the seven segment led?

      Delete
  13. Hi, i am doing doing stop watch in verilog using SPARTAN-3 FPGA_XC3S400 board. i dont no how to program lcd which displays the stop watch...pls help me.... its urgent.....

    ReplyDelete
  14. How to include stop functionality in this code.

    ReplyDelete
  15. helllo, why in the sentence case used (count[N-1:N-2]) (the 2 MSB's of the counter) for generate a frecuency of Multiplexing the 1000HZ? tanks

    ReplyDelete
  16. Hi Mauricio, Please read my post on the seven segment display to understand the reasoning behind that: http://simplefpga.blogspot.co.uk/2012/07/seven-segment-led-multiplexing-circuit.html

    ReplyDelete
  17. have you added debouncing in it?

    ReplyDelete
  18. Why is local parameter N = 18?

    ReplyDelete
  19. Hello, do you have this code in vhdl?

    ReplyDelete
  20. Could you explain why it is case(count[N-1:N-2]) won't that always make it reference 17:16? How is this right?

    ReplyDelete
  21. I got the error in test bench code line

    #50 clock = ~clock;

    Error (10119): Verilog HDL Loop Statement error at DE1_SOC_golden_top.v(313): loop with non-constant loop condition must terminate within 250 iterations

    How do i get out of this error

    ReplyDelete
  22. Hey, can you please give the .ucf code for this verilog code.
    I'm using xilinx Nexys 3, Spartan 6 family.
    Please mail it to me ASAP :)
    guptak994@gmail.com

    ReplyDelete
  23. Hello! This is very helpful. I would like to incorporate this into a project using a register file. Perhaps something where the times when it is stopped it loaded into a write address and then saved and can be shown? If you have any advice on this, I would appreciate it! Thank you!

    ReplyDelete
  24. WARNING:Xst:2725 - "prooject.v" line 126: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 127: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 128: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 129: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 130: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 131: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 132: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 133: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 134: Size mismatch between case item and case selector.
    WARNING:Xst:2725 - "prooject.v" line 135: Size mismatch between case item and case selector.
    i m facing these errors please help me its urgent

    ReplyDelete
  25. This code isn't working. May be there is problem in ucf file. How to get correct ucf file of stopwatch code in verliog.

    ReplyDelete

Post a Comment

Popular posts from this blog

Seven Segment LED Multiplexing Circuit in Verilog

The seven segment LED circuit uses seven different and individual LED's to display a hexadecimal symbol. It has 7 wires to control the individual LED's one wire to control the decimal point and one enable wire. The demo board I am using here consists of four such 7-segment LED's(As do any other demo board). To reduce the number of wires a multiplexing circuit is used to control the display. Using the multiplexing circuit the number of wires required to light up all 4 displays are reduced from 32 to 12 (8 data bits and 4 enable bits). All bits here are active low, such that to enable them a '0' is required. For example the figure below shows how to display a 3 on the seven segment. The multiplexing circuit can take 4 inputs and have only one output. But the inputs should be displayed on the output fast enough to fool the viewer into thinking all outputs are enabled individually and simultaneously. This is achieved by having an enable signal that changes so fast t...

Random Number Generator in Verilog | FPGA

In verilog a random number can be generated by using the $random keyword but that works only for simulation purposes and cannot be implemented. So when we need a random number for implementation i.e. in hardware it can be achieved using an LFSR (Liner Feedback Shift Register). An LFSR is simply a shift register with some of its bits (known as taps) XOR'd with themselves to create a feedback term. When implementing an LFSR it's width and it's repeatability must be kept under consideration .An N-bit LFSR will be able to generate (2**N) - 1 random bits before it starts repeating. For example a 30 bit LFSR will have 1073741823 random states before repeating, so for most practical purposes this can be considered true random. In an LFSR the MSB will always be the feedback point also the main thing to take care of while coding an LFSR is to know which bits are the taps (to be selected for XOR ). This is confusing as the taps are different for different size registers. For e...