EEVblog® Electronics Community Forum
Electronics => FPGA => Topic started by: radiolistener on June 11, 2022, 06:12:09 am
-
I have two clocks: clk1 and clk2.
clk1 - has high frequency (about 100 MHz) but sometimes connected/disconnected and is unstable during switch transition
clk2 - has low frequency (about 50 MHz) but it is always on (backup clock)
Clocks are not synchronized.
I want to generate reset signal which should going to 1 when clk1 disconnected or unstable and going to 0 when clk1 is connected and stable. I need it to reset some logic which can going into unstable state when clock is missing or unstable.
What is the reliable way to generate such reset signal in verilog?
-
So, what you are saying is that you want to program a frequency counter running on CLK2 to time CLK1, a counter with really poor accuracy. If that counter sees 100MHz, then you turn off the reset, if it does not see 100MHz, then you turn on the reset.
Doesn't sound too difficult. You only need an accuracy of ~3 bits, where your counter total being 0= no clock, 1=25mhz, 2=50mhz, 3=75mhz, ect... if the result is 3 or larger, then the CLK1 is ~100mhz.
You can also make a counter which resets once every mhz, then you will know the frequency of clk1 within 1 mhz, but you would need a 7 bit counter to see the 99-101mhz result.
-
What is the reliable way to generate such reset signal in verilog?
Verilog is just a language to describe models, what actually happens in hardware is only ever an approximation of that. As soon as you enter the world of asynchronous signals, all bets are off...
-
As soon as you enter the world of asynchronous signals, all bets are off...
It's not really that bad. The easiest way to test for your asynchronous high-speed clock is to code a divide-by-8 that is synchronous to the 100 MHz unknown clock. Take the 12.5 MHz output of that divider and run it through a two or three-stage synchronizer, clocked by your stable 50 MHz clock. You can then test that re-synchronized signal as you like.
You can also (in verilog) design an asynch set-reset flop that operates across two clock domains, but that's less obvious to describe. I think the pre-divider / synchronizer approach is cleaner.
-
the problem here is that clocks are asynchronous, they generated from different clock sources. And I'm not well understand pitfalls and approaches when synchronizing between two clock domains.
Here is my draft. It doesn't works because I'm trying to modify pulse reg from different clock domains, but I think it shows what I'm trying to do.
Is it possible to solve it? Or maybe I'm doing it in a wrong way?
module clock_detect #(
parameter RATE = 5_000_000, // clk1 division factor (testing interval)
parameter N = 100_000 // clk0 detect threshold
)(
input clk0, // testing clock (100 MHz)
input clk1, // backup clock (50 MHz)
output good // clk0 is good
);
reg pulse = 0;
reg [31:0] clk1_cnt = 0;
always @(posedge clk1) begin
if (clk1_cnt < RATE) begin
clk1_cnt <= clk1_cnt + 1;
end else begin
clk1_cnt <= 0;
pulse <= 1;
end
end
reg present = 0;
reg [31:0] clk0_cnt = 0;
integer k;
always @(posedge clk0) begin
// count clk0 edges and assign result
if (!pulse) begin
clk0_cnt <= clk0_cnt + 1;
end else begin
clk0_cnt <= 0;
pulse <= 0;
present <= clk0_cnt >= N;
end
end
assign good = present;
endmodule
-
It's not really that bad. The easiest way to test for your asynchronous high-speed clock is to code a divide-by-8 that is synchronous to the 100 MHz unknown clock. Take the 12.5 MHz output of that divider and run it through a two or three-stage synchronizer, clocked by your stable 50 MHz clock. You can then test that re-synchronized signal as you like.
just tried this, here is my code:
module clock_detect #(
parameter RATE = 5_000_000, // clk1 division factor (testing interval)
parameter N = 100_000 // clk0 detect threshold
)(
input clk0, // testing clock (100 MHz)
input clk1, // backup clock (50 MHz)
output rst // 1 when clk0 is not good
);
// divide clk0 by 10 and transfer to clk1 domain
wire clk0div, clk0div_synced;
clk_div #(.WIDTH(4), .N(5)) clk0div_i(
.clk(clk0),
.clk_out(clk0div));
sync_signal sync_clk1_i(
.clk(clk1),
.in(clk0div),
.out(clk0div_synced));
reg [2:0] shift = 0;
reg [31:0] clk0_cnt = 0;
reg [31:0] clk1_cnt = 0;
reg present = 0;
always @(posedge clk1) begin
// push into shift reg to catch edges
shift <= {shift[1:0], clk0div_synced};
// set result at RATE period
if (clk1_cnt < RATE) begin
clk1_cnt <= clk1_cnt + 1;
// count edges
if (shift[2] ^ shift[1]) begin
clk0_cnt <= clk0_cnt+1;
end
end else begin
clk0_cnt <= 0;
clk1_cnt <= 0;
present <= clk0_cnt >= N / 10;
end
end
// transfer result to clk0 domain
sync_reset #(.N(4)) sync_reset_i (
.clk(clk0),
.rst(~present),
.out(rst)
);
endmodule
module clk_div #(
parameter WIDTH = 3, // Width of the register required
parameter N = 6 // We will divide by 12 for example in this case
)(
input clk,
input reset,
output clk_out
);
reg [WIDTH-1:0] r_reg;
wire [WIDTH-1:0] r_nxt;
reg clk_track;
always @(posedge clk or posedge reset)
begin
if (reset)
begin
r_reg <= 0;
clk_track <= 1'b0;
end
else if (r_nxt == N)
begin
r_reg <= 0;
clk_track <= ~clk_track;
end
else
r_reg <= r_nxt;
end
assign r_nxt = r_reg+1;
assign clk_out = clk_track;
endmodule
module sync_signal #(
parameter WIDTH=1, // width of the input and output signals
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire [WIDTH-1:0] in,
output wire [WIDTH-1:0] out
);
(*preserve*)
reg [WIDTH-1:0] sync_reg[N-1:0];
assign out = sync_reg[N-1];
integer k;
always @(posedge clk) begin
sync_reg[0] <= in;
for (k = 1; k < N; k = k + 1) begin
sync_reg[k] <= sync_reg[k-1];
end
end
endmodule
module sync_reset #
(
parameter N = 2 // depth of synchronizer
)
(
input wire clk,
input wire rst,
output wire out
);
(*preserve*)
(* srl_style = "register" *)
reg [N-1:0] sync_reg = {N{1'b1}};
assign out = sync_reg[N-1];
always @(posedge clk or posedge rst) begin
if (rst) begin
sync_reg <= {N{1'b1}};
end else begin
sync_reg <= {sync_reg[N-2:0], 1'b0};
end
end
endmodule
is it correct?
-
is it correct?
I haven't studied your code in detail, but what I glanced at looks OK.
Here is my cut at it, using non-parameterized code. I also don't have any reset logic since the FPGA I've been using defaults all that. There may be errors, this is non-tested (except for the "synch3" module, which I use a lot.)
/////////////////////
module div8(
input clkHS,
output q
);
reg[2:0] counter;
assign q = counter[2];
always @(posedge clk) counter <= counter + 3'd1;
endmodule
/////////////////////
module synch3(
input clk, // the lower-speed global clock
input d, // asynchronous input, freq < (clk / 2)
output q,
output rising, // positive enable triggered by rising-edge of input d
output falling
);
reg [2:0] sr;
assign rising = (sr[2:1] == 2'b01);
assign falling = (sr[2:1] == 2'b10);
assign q = sr[2];
always @(posedge clk) sr <= {sr[1:0], d};
endmodule
/////////////////////
module testClkHS(
input clkLS; // the lower-speed global clock (50 MHz?)
input clkHS; // the high-speed clock being tested (100 MHz?)
output clkStatus // whatever you want it to be
);
wire clkDiv8;
wire posEdge;
// status will be the result of whatever testing you want to do on the high-speed clock-derived signal
reg status;
//
assign clkStatus = status;
divider div8(
.clkHS (clkHS),
.q (clkDiv8)
);
synch synch3(
.clk (clkLS),
.d (clkDiv8),
.rising (posEdge)
);
//////
// your test circuit goes here -- something like this simple frequency counter (count between 7 and 9 considered OK):
//
reg[3:0] gateTimer; // divides clkLS by 16 for counter gate
reg[3:0] counter; // counts posEdge
wire onFreq = (counter == 4'd7) || (counter == 4'd8) || (counter == 4'd9);
always #(posedge clkLS) gateTimer <= gateTimer + 4'd1;
always #(posedge clkLS) begin
if (gateTimer == 4'd0) begin
status <= onFreq;
counter <= 4'd0;
end else
counter <= counter + 4'd1;
end
//
//
//////
endmodule
/////////////////////
-
the problem here is that clocks are asynchronous, they generated from different clock sources. And I'm not well understand pitfalls and approaches when synchronizing between two clock domains.
Here is my draft. It doesn't works because I'm trying to modify pulse reg from different clock domains, but I think it shows what I'm trying to do.
Is it possible to solve it? Or maybe I'm doing it in a wrong way?
module clock_detect #(
parameter RATE = 5_000_000, // clk1 division factor (testing interval)
parameter N = 100_000 // clk0 detect threshold
)(
input clk0, // testing clock (100 MHz)
input clk1, // backup clock (50 MHz)
output good // clk0 is good
);
reg pulse = 0;
reg [31:0] clk1_cnt = 0;
always @(posedge clk1) begin
if (clk1_cnt < RATE) begin
clk1_cnt <= clk1_cnt + 1;
end else begin
clk1_cnt <= 0;
pulse <= 1;
end
end
reg present = 0;
reg [31:0] clk0_cnt = 0;
integer k;
always @(posedge clk0) begin
// count clk0 edges and assign result
if (!pulse) begin
clk0_cnt <= clk0_cnt + 1;
end else begin
clk0_cnt <= 0;
pulse <= 0;
present <= clk0_cnt >= N;
end
end
assign good = present;
endmodule
Ok, this is one approach, though it has a large set of regs.
Remember that CLK1 is guaranteed, not CLK0 and you want to avoid cross domain communications except for 1 async wire. I would try something like this:
module clock_detect (
input clk0, // testing clock (100 MHz)
input clk1, // backup clock (50 MHz)
output good // clk0 is good
);
// Step 1, make a new 12.5Mhz clock from the unstable CLK0 source
reg [3:0] clk0_div = 4'd0;
wire clk0_12m = clk0_div[3]; // clk0_12m will cycle at 12.5MHz if CLK0 has a 100MHz clock.
always @(posedge clk0) clk0_div <= clk0_div + 1'b1;
// Step 2, on our guaranteed 50MHz clk1, verify that clk0_12m is running at least at 12MHz to
// generate a good signal. This way, we are only analyzing a single wire clk0_12m across a clock domain
// with no async feedback or reset.
reg [1:0] clk0_12m_tr = 2'd0; // A serial shift in register storing clk0_12m from clk0 domain.
wire clk0_toggle_bit = clk0_12m_tr[0] ^ clk0_12m_tr[1] ; // Detect a high or low transition of the clk0_12m.
reg [9:0] clk0_toggle_reg =10'd0; // A serial storage of a train of clk0_toggle_bits.
always @(posedge clk1) begin
clk0_12m_tr <= {clk0_12m_tr[0], clk0_12m }; // serial shift in the clk_12m from the other clock domain
clk0_toggle_reg <= {clk0_toggle_reg[8:0], clk0_toggle_bit} ; // serial shift in the toggle detection
// If enough 12.5Mhz toggles have been summed up in 10 x 50MHz clocks, set the output to GOOD.
outgood <= (clk0_toggle_reg[0] +
clk0_toggle_reg[1] +
clk0_toggle_reg[2] +
clk0_toggle_reg[3] +
clk0_toggle_reg[4] +
clk0_toggle_reg[5] +
clk0_toggle_reg[6] +
clk0_toggle_reg[7] +
clk0_toggle_reg[8] +
clk0_toggle_reg[9]) > 2 ;
end
endmodule
You may adjust my concept, like changing the 'clk0_toggle_reg' into an authentic counter and time how long it takes that counter to reach for example a count of 100 before making the outgood reg. All timing and checks can now be done in the clk1 domain without sending anything back to the clk0 domain.