I'm working on a Verilog project where I have implemented a countdown timer using preset counters. However, I'm encountering a strange issue when I set a time and start the countdown. On the initial start, the timer begins counting down from the wrong value, but after that, it functions correctly. Here's what happens:
If I set the timer to 1 minute, the countdown starts from 1 minute 59 seconds instead of 1 minute. If I set the timer to 10 minutes, it starts from 19 minutes 59 seconds instead of 10 minutes. If I set the timer to 1 hour, it starts from 1 hour 59 minutes instead of 1 hour.
After this initial incorrect behavior, the timer works as expected for subsequent countdowns. I suspect the issue has something to do with the preset values or how the timer initializes, but I'm not sure how to fix it.
//Timer Module
module timer(KEY,SW,oCNT0,oCNT1,oCNT2,oCNT3,oCNT4,oCNT5,CLOCK_50,Done);
input [1:0] KEY;
input [9:0] SW;
input CLOCK_50;
output [3:0] oCNT0,oCNT1,oCNT2,oCNT3,oCNT4,oCNT5;
output wire Done;
wire EN0,EN1,EN2,EN3,EN4,EN5;
wire [3:0] oCNT0, oCNT1,oCNT2,oCNT3,oCNT4,oCNT5;
wire [18:0] oCNT;
assign Done = ({oCNT5,oCNT4,oCNT3,oCNT2,oCNT1,oCNT0}==(24'b000000000000000000000000)) ? 1'b0 : 1'b1;
assign iRSTn=(SW[7]&~SW[6]&~KEY[0]) ? 1'b0 : 1'b1;
reg start;
reg [26:0] press_counter;
reg long_press;
reg button_pressed;
//This part of the code implements logic to perform two different functions using a single key.
always @(posedge CLOCK_50 or negedge iRSTn) begin
if (!iRSTn) begin
press_counter <= 0;
button_pressed <= 0;
long_press <= 0;
start <= 0;
end else begin
if (KEY[1]) begin
press_counter <= press_counter + 1;
button_pressed <= 1;
// 2sec over
if (press_counter >27'd100000000) begin
long_press <= 1;
end
end else if (button_pressed) begin
if (long_press) begin
start <= start; // Preset
end else begin
start <= ~start; //Toggle
end
// reset
press_counter <= 0;
button_pressed <= 0;
long_press <= 0;
end
end
end
COUNTER_LAB
#(.n(23),.k(5000000))
U_Counter_ms_gen(
.iRSTn(iRSTn),
.iCLK(CLOCK_50),
.iEN(start&Done),
.oEN(EN0),
.oCNT(oCNT)
); // 5M Count
COUNTER_PRESET_DOWN
#(.n(4),.k(10))
COUNTER_timer_ms(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn(1'b0), .iEN(EN0), .iDATA_Preset(4'b0000), .oEN(EN1), .oCNT(oCNT0)); // ms
COUNTER_PRESET_DOWN
#(.n(4),.k(10))
COUNTER_timer_s0(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn(1'b0), .iEN(EN1), .iDATA_Preset(4'b0000), .oEN(EN2), .oCNT(oCNT1)); // seconds (units)
COUNTER_PRESET_DOWN
#(.n(3),.k(6))
COUNTER_timer_s1(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn((~KEY[1] & ~long_press) & (SW[5:4] == 2'b00) & (SW[7:6] == 2'b10)), .iEN(EN2), .iDATA_Preset(SW[3:0]), .oEN(EN3), .oCNT(oCNT2)); // seconds (tens)
COUNTER_PRESET_DOWN
#(.n(4),.k(10))
COUNTER_timer_m0(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn((~KEY[1] & ~long_press) & (SW[5:4] == 2'b01) & (SW[7:6] == 2'b10)), .iEN(EN3), .iDATA_Preset(SW[3:0]), .oEN(EN4), .oCNT(oCNT3)); // minutes (units)
COUNTER_PRESET_DOWN
#(.n(3),.k(6))
COUNTER_timer_m1(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn((~KEY[1] & ~long_press) & (SW[5:4] == 2'b10) & (SW[7:6] == 2'b10)), .iEN(EN4), .iDATA_Preset(SW[2:0]), .oEN(EN5), .oCNT(oCNT4)); // minutes (tens)
COUNTER_PRESET_DOWN
#(.n(4),.k(13))
COUNTER_timer_h(.iCLK(CLOCK_50), .iRSTn(iRSTn), .iPRSTn((~KEY[1] & ~long_press) & (SW[5:4] == 2'b11) & (SW[7:6] == 2'b10)), .iEN(EN5), .iDATA_Preset(SW[3:0]), .oEN(), .oCNT(oCNT5)); // hours
endmodule
//Timer Counter
module COUNTER_PRESET_DOWN(
iCLK,
iRSTn,
iPRSTn,
iEN,
iDATA_Preset,
oEN, //roll-over signal
oCNT
);
parameter n=4;
parameter k=10;
input iCLK,iRSTn,iPRSTn,iEN;
input [n-1:0] iDATA_Preset;
output [n-1:0] oCNT;
output oEN;
reg [n-1:0] oCNT;
assign oEN =((oCNT == 0) && (iEN == 1'b1)) ? 1'b1 : 1'b0;
always@(posedge iCLK or negedge iRSTn)
begin
if(~iRSTn)
begin
oCNT <= 0;
end
else if(iPRSTn)
begin
oCNT <= iDATA_Preset;
end
else if(iEN)
begin
if(oCNT==0)
begin
oCNT<=k-1;
end
else
begin
oCNT<=oCNT-1;
end
end
else
begin
oCNT<=oCNT;
end
end
endmodule