先上代码
module _sync_reg #(parameter INIT = 0,parameter ASYNC_RESET = 0
) (input clk,input rst,input in,output out
);(* ASYNC_REG = "TRUE" *) reg sync1;
(* ASYNC_REG = "TRUE" *) reg sync2;assign out = sync2;generate
if (ASYNC_RESET) beginalways @(posedge clk or posedge rst) beginif (rst) beginsync1 <= INIT;sync2 <= INIT;end else beginsync1 <= in;sync2 <= sync1;endend
end else beginalways @(posedge clk) beginif (rst) beginsync1 <= INIT;sync2 <= INIT;end else beginsync1 <= in;sync2 <= sync1;endend
end
endgenerateendmodule/*clk_estimator #( .EST_BITS ( 24 )) clk_estimator (.rst(),.clk(),.meas_clk(), .cntr_data()
);
*/module clk_estimator #(parameter FRQ = 100*1000*1000
)(input rst,input clk, input meas_clk, output reg [32-1:0] dout ,output reg update
);reg [31:0] c;
reg f = 0 ;
wire of = c >= (FRQ/20) -1 ;
always @(posedge clk) beginif (rst ) begin c <= 0; f<=0; end else if (of)begin f<=~f; c<=0; end else begin c <= c + 1 ;end
endwire out_dclk;_sync_reg self_estim(.clk(meas_clk),.rst(rst),.in(f),.out(out_dclk)
); reg [32-1:0] cntr_clk;
reg [32-1:0] ref_cntr_data_r;
reg prev_out_dclk;
reg update_w ; always @(posedge meas_clk) beginif (rst) beginupdate_w <=0;cntr_clk <= 0;prev_out_dclk <= 0;ref_cntr_data_r <= 0; end else beginprev_out_dclk <= out_dclk; if (prev_out_dclk == 0 && out_dclk == 1'b1) begincntr_clk <= 0;ref_cntr_data_r <= cntr_clk;update_w <=1; end else begincntr_clk <= cntr_clk + 1'b1;update_w <=0;endend
end(* ASYNC_REG = "TRUE" *) reg [4:0] updater; always @ (posedge clk ) updater <= { updater[3:0], update_w };
(* ASYNC_REG = "TRUE" *) reg[31:0] r; reg[31:0] rr,rrr,rrrr;always @ (posedge clk ) rrrr<=rrr;always @ (posedge clk ) rrr<=rr;always @ (posedge clk ) rr<=r;always @ (posedge clk ) r<=ref_cntr_data_r;reg [31:0]watch_dog_cntr ;wire update1= updater[4:3] == 2'b01 ; always @ (posedge clk ) if ( update1 | rst )watch_dog_cntr<=0; else watch_dog_cntr<= ( watch_dog_cntr>= FRQ/4 )?0: (watch_dog_cntr+1);
wire watch_dog_act = watch_dog_cntr >= FRQ/4 ;always @ (posedge clk ) if (watch_dog_act) dout <= 0 ;else if (update1) dout<= rrrr ;always @ (posedge clk ) update <= watch_dog_act ==1 || update1 ==1 ;endmodule
当外部meas_clk有频率信号接入时,每1/10秒就会输出更新一下时钟计数,这里的计数是输入meas_clk的1/10。如果没有频率接入每1/4秒输出一下结果0。
原理是我们已知频率为FRQ的时钟clk每1/20秒翻转一次,这样得到的每次上升边缘就是1/0秒。被测试的时钟meas_clk在1/10秒内数数,数到到多少,之后再传到clk时钟域,输出出来。另外设置了1/4秒的看门狗,当时meas_clk丢失,超过1/4秒没有更新,就触犯看门狗电路自动更新输出0.
这个代码实验通过了,非常好用。可以在编译时候有跨时钟区域的警告,可以通过设置虚假路径来解决。