(转)跨时钟域数据采集总结
一.典型方法
二.结绳法
1.结绳法1:利用数据的边沿作时钟(例子中上升沿)。(可以将脉冲无限延长,直到可以采集到数据,然后复位,要考虑产生数据的频率)。
实例1
实例2
2结绳法2:利用数据作为异步复位,置位信号。(适合将不足时钟宽度的脉冲扩展1周期)
实例1:输入高脉冲(clka域),输出高脉冲(clkb域)
实例2:输入高脉冲(clka域),输出低脉冲(clkb域)
实例3:输入低脉冲(clka域),输出低脉冲(clkb域)
实例4:输入低脉冲(clka域),输出高脉冲(clkb域)
3结绳法3:输入作为数据输入,同样也是检测高有效后,输出一直为高,异步时钟域可以采集到数据后再复位。
因为没有将输入作为时钟,或者作为异步set,reset,所以这类方便比较常用。
参考代码:http://bb2hh.blogbus.com/files/12357833650.v
//================================================================================ // Created by : Ltd.com // Filename : sync_clk1_clk2.v // Author : Python_Wang // Created On : 2009-02-27 22:47 // Last Modified : 2009-02-28 09:09 // Description : // // //================================================================================ module sync_clk1_clk2( clk1 , rst_n1 , clk2 , rst_n2 , data_clk1_i , data_clk2_o ); input clk1 ; input rst_n1 ; input clk2 ; input rst_n2 ; input data_clk1_i ; output data_clk2_o ; reg data_clk1_q1 ; reg data_clk1_q2 ; reg data_clk2_q1 ; reg data_clk2_q2 ; reg data_clk2_q3 ; reg data_clk2_q4 ; reg data_clk2_q5 ; wire data_clk1 ; assign data_clk1 = data_clk1_i | ( !data_clk2_q5 & data_clk1_q1) ; always@(posedge clk1 or negedge rst_n1) begin if(!rst_n1) begin data_clk1_q1 <= #1 'b0; data_clk1_q2 <= #1 'b0; end else begin data_clk1_q1 <= #1 data_clk1 ; data_clk1_q2 <= #1 data_clk1_q1; end end always@(posedge clk2 or negedge rst_n2) begin if(!rst_n2) begin data_clk2_q1 <= #1 'b0; data_clk2_q2 <= #1 'b0; data_clk2_q3 <= #1 'b0; end else begin data_clk2_q1 <= #1 data_clk1_q1; data_clk2_q2 <= #1 data_clk2_q1; data_clk2_q3 <= #1 data_clk2_q2; end end always@(posedge clk1 or negedge rst_n1) begin if(!rst_n1) begin data_clk2_q4 <= #1 'b0; data_clk2_q5 <= #1 'b0; end else begin data_clk2_q4 <= #1 data_clk2_q2; data_clk2_q5 <= #1 data_clk2_q4; end end assign data_clk2_o = data_clk2_q2 & ~data_clk2_q3 ; endmodule
仿真:
4.结绳法3:利用握手协议:(可以将脉冲无限延长,直到可以采集到数据,然后复位,要考虑产生数据的频率)。
参考代码:http://bb2hh.blogbus.com/files/12357826152.v
//================================================================================ // Created by : Ltd.com // Filename : handover.v // Author : Python_Wang // Created On : 2009-02-19 19:31 // Last Modified : 2009-02-20 08:38 // Description : // // //================================================================================ module handover( rst_n , ClkA , Req_ClkA , Ack_ClkA , ClkB , Dvld_ClkB ); input rst_n ; input ClkA ; input Req_ClkA ; input ClkB ; output Ack_ClkA ; output Dvld_ClkB ; reg Dvalid_ClkB ; reg Q_Dvalid_ClkB ; reg Dvalid_ClkA ; always@(posedge ClkA) begin if(!rst_n) begin Dvalid_ClkA <= #1 1'b0; end else if(Req_ClkA) begin Dvalid_ClkA <= #1 ~Dvalid_ClkA ; end end reg Q1_ClkB ; reg Q2_ClkB ; reg Q3_ClkB ; always@(posedge ClkB) begin if(!rst_n) begin Q1_ClkB <= #1 'b0; Q2_ClkB <= #1 'b0; Q3_ClkB <= #1 'b0; end else begin Q1_ClkB <= #1 Dvalid_ClkA ; Q2_ClkB <= #1 Q1_ClkB ; Q3_ClkB <= #1 Q2_ClkB ; end end wire Req_ClkB = Q2_ClkB ^ Q3_ClkB ; always@(posedge ClkB) begin if(!rst_n) begin Dvalid_ClkB <= #1 'b0; Q_Dvalid_ClkB <= #1 1'b0; end else if(Req_ClkB) begin Dvalid_ClkB <= #1 ~Dvalid_ClkB ; Q_Dvalid_ClkB <= #1 Dvalid_ClkB ; end end always@(posedge ClkB) begin if(!rst_n) begin Q_Dvalid_ClkB <= #1 1'b0; end else begin Q_Dvalid_ClkB <= #1 Dvalid_ClkB ; end end reg Q1_ClkA ; reg Q2_ClkA ; reg Q3_ClkA ; always@(posedge ClkA) begin if(!rst_n) begin Q1_ClkA <= #1 'b0 ; Q2_ClkA <= #1 'b0 ; Q3_ClkA <= #1 'b0 ; end else begin Q1_ClkA <= #1 Dvalid_ClkB ; Q2_ClkA <= #1 Q1_ClkA ; Q3_ClkA <= #1 Q2_ClkA ; end end assign Ack_ClkA = Q2_ClkA ^ Q3_ClkA ; assign Dvld_ClkB = Dvalid_ClkB & ~Q_Dvalid_ClkB; endmodule
仿真:
另外对于为了提高速度和准确度的握手操作中,可以将设置一定的握手模块(n>2(clk1+clk2)/Trd),流水操作
结绳就是将单脉冲延长,以方便采集到数据。
结绳的方法归结为2类:
1.利用脉冲的边沿做时钟;
2.利用脉冲的电平(部分场合要求最小脉冲宽度)做选择器或者异步复位,置位。
另外的关键点就是什么时候结绳结束(采集到了数据就要让对方回到初始状态),
这里的操作也有2种方法:
1.利用采集到的脉冲做异步复位,置位。
2.利用采集到的脉冲再次结绳采集做握手响应信号。
处理的时候应该选择对应的方法。
同时共享一下用到的电子电路图形库(visio的)
http://bb2hh.blogbus.com/files/12350304650.rar