Friday, 27 July 2012

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:

34 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