FPGA时钟是整个系统的心跳,如果各个模块的心跳异常,会导致手脚不协调。
跨时钟处理有三种方式:
- 控制信号脉冲检测法,适合于快时钟采慢时钟;
- 握手信号法,适合慢时钟采快时钟;
- 异步fifo法,适合大量数据的传输
脉冲检测法
在快时钟的上升沿,使用两级或三级寄存器,检测慢时钟域的使能信号,然后在快时钟域产生一个周期的脉冲信号。
input clk;
input rst;
input wr_en;
reg wr_r;
reg wr_r2;
wire pos_wr;
always@(posedge clk ,negedge rst)
begin
if(rst)begin
wr_r <= 1'b0;
wr_r2<= 1'b0;
end else
wr_r <= wr_en;
wr_r2 <= wr_r;
end
end
assign pos_wr= !wr_r && wr_r2 ; //写选通信号上升沿,拉高一个周期的脉冲信号
握手信号法
快时钟域产生写请求和data,慢时钟域检测到写请求,锁存数据后产生应答信号,快时钟域检测到应答信号后,撤销写请求,至此完成一次写操作。
module handshack (
input clk,
input rst_n,
input req,
input [7:0] datain,
output ack,
output data_out
)
//****************************
//上升沿信号检测
reg req_r ,req_r2,req_r3 ;
always@ (posedge clk or negedge rst_n)
begin
if (!rst_n)begin
req_r <= 1'b1 ;
req_r2 <= 1'b1 ;
req_r3 <= 1'b1 ;
end else begin
req_r <= req ;
req_r2 <= req_r ;
req_r3 <= req_r2 ;
end
end
//pos_req2 比 pos_req1 延时一个时钟周期,确保数据被稳定锁存
wire pos_req1 = req_r && ~ req_r2 ;
wire pos_req2 = req_r2 && ~ req_r3 ;
//***************************************
// 数据锁存
reg [7:0] dataoutr;
always@(posedge clk or negedge rst_n )begin
if(!rst_n)
dataoutr <= 8'h0;
else if(pos_req1)
dataoutr <= datain ; //检测到req有效后锁存输入数据
end
assign dataout =dataoutr
//**************************************
//产生应答信号ack
reg ackr;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
ackr <= 1'b0;
else if (pos_req2)
ackr <= 1'b1;
else if(!req)
ackr <= 1'b0 ;
end
assign ack =ackr;
endmoudle
异步fifo法
读写时钟各自按照两个时钟域的时钟,控制wreq、和req进行读写命令操作。