Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
19524 Discussions

MAX10/DE10-Lite clock skew issue

Honored Contributor II

As a simple demo, I wrote verilog code for an updown counter on the DE10-Lite board using buttons, LEDs and switches. KEY[1] is used as clock and KEY[0] is used as synchronous reset. 


The counter has a bug when programmed into the DE10. When the three LSB are '111' the next count (up) will always be '001' instead of '000'. We've tried various changes to the updown counter code and the problem remains. It appears to be some kind of clock skew problem. It's not a debounce problem because it only happens when the LSB are '111'. Otherwise, it always counts correctly. It works correctly counting down. Is there a good way to fix this so a button can reliably be used as a clock for simple finite state machines? The problem can be fixed using the 50 MHz clock and generating an enable signal based on a rising edge of KEY[1], but I'm looking for directly clocking a FSM. Thanks. 


Here is the verilog: 


// This code is generated by Terasic System Builder 




module updown( 



//////////// SEG7 ////////// 

output [7:0] HEX0, 

output [7:0] HEX1, 

output [7:0] HEX2, 

output [7:0] HEX3, 

output [7:0] HEX4, 

output [7:0] HEX5, 



//////////// KEY ////////// 

input [1:0] KEY, 



//////////// LED ////////// 

output [9:0] LEDR, 



//////////// SW ////////// 

input [0:0] SW 





// REG/WIRE declarations 


wire Clock, Reset_n, Updown; 

reg [15:0] Count; 

reg [15:0] next_Count; 




// Structural coding 


assign Clock = KEY[1]; 

assign Reset_n = KEY[0]; 

assign Updown = SW[0]; 

assign LEDR = Count[9:0]; 

assign HEX0 = 8'b11111111; 

assign HEX1 = 8'b11111111; 

assign HEX2 = 8'b11111111; 

assign HEX3 = 8'b11111111; 

assign HEX4 = 8'b11111111; 

assign HEX5 = 8'b11111111; 



always @(Updown, Reset_n, Count) begin 

if (Reset_n == 0) 

next_Count <= 0; 

else if (Updown)  

next_Count <= Count + 1; // if Updown, increment Count 


next_Count <= Count - 1; // else decrement Count 




always @(posedge Clock) // flip-flops 

Count <= next_Count; // count on rising clock edge 




0 Kudos
2 Replies
Honored Contributor II

If you haven't done so, set a clock constraint like: 


create_clock -name clk -period 1000 [ get_ports KEY[0] ] ; Constraining as a 1 MHz clock; TimeQuest can't (couldn't?) handle very low frequency clocks 


Then run TimeQuest and see if the meets timing of if you have failing paths.
Honored Contributor II

Your code:always @(Updown, Reset_n, Count) begin if (Reset_n == 0) next_Count <= 0; else if (Updown) next_Count <= Count + 1; // if Updown, increment Count else next_Count <= Count - 1; // else decrement Count end always @(posedge Clock) // flip-flops Count <= next_Count; // count on rising clock edge 


The problem is your fundamental design: 

* The first always block is completely unclocked asynchronous logic. 

* The second always block you have a one-rank synchronizer that synchronizes a multibit value (next_Count) to the clock. 


The first always block will end up generating a large blob of combinatorial logic involving the Reset_N, Count[], and UpDown signals. Both UpDown and Reset_N are not clock synchronous. 


Moving the design to be a fully synchronous counter, and adding input synchronization to the button push signal, should be much more tolerant of placement/routing timing variations: 


Revised code:reg UpDownSync1, UpDownSync2; always @(posedge Clock) begin UpDownSync1 <= UpDown; UpDownSync2 <= UpDownSync1; end always @(posedge Clock or negedge Reset_n) begin if (Reset_n == 0) Count <= 0; else if (UpDownSync2) Count <= Count + 1; // if Updown, increment Count else Count <= Count - 1; // else decrement Count end