多bit信号跨时钟域(CDC)处理方法

参考csdn:

(1)跨时钟域处理解析(一)-CSDN博客

(2)FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_多bit同步 skew约束-CSDN博客

(3)跨时钟传输——多比特_多bit跨时钟域-CSDN博客

1.亚稳态问题

        首先是关于在学习跨时钟域上一篇单bit数据跨时钟域的最后提出的问题,对我当时的代码来说,数据打一拍就足够了,多打拍反而会导致数据传输延后一个周期,不能及时接收数据;但是网上查到的代码都选择了打两拍,因此这个问题存疑。

        这个问题的正解确实是为了避免亚稳态的出现。

        首先来解释一下亚稳态这个概念:

        亚稳态是指在设计正常运行期间的某个时间点,信号在一段时间内不会呈现稳定的0 或1 状态。在多时钟设计中,由于建立时间和保持时间可能不满足要求,所以无法避免亚稳态,但可以减小亚稳态的不利影响。

        而解决亚稳态影响,目前设计最主流、也是最常见的方法就是双触发器同步器(打两拍),同步器图示和经过之后的波形如下图所示。对于大多数同步应用,两个触发器同步器足以消除所有可能的亚稳态,它可以避免将第一级的错误继续传递到第二级,但是在保证数据正确传递的同时,必要的牺牲了一点传输的实时性。而我的设计中因为要讲究数据快速传递,所以只打一拍也是足够了的。

2.多bit跨时钟域和单bit的不同

        在时钟域之间传递多bit信号时,简单的同步器并不能保证数据的安全传输。 

        工程师在进行多时钟设计时经常犯的一个错误是将同一事务中所需的多个 CDC 位从一个时钟域传递到另一个时钟域,而忽视了 CDC 位同步采样的重要性。 

        问题是同步到一个时钟的多bit信号会经历小的数据变化偏斜(skews),偶尔会在第二个时钟域的不同时钟上升沿上采样。即使我们可以完美地控制和匹配多个信号的走线长度,上升和下降时间的差异以及芯片上的工艺变化可能会引入足够的偏斜,从而导致对原本精心匹配的走线的采样失败。 

        总结就是:多bit信号的CDC问题主要来自于到达目的时钟域的时间无法控制一致。如果简单将多bit信号拆分成好几个单bit信号,分别采用寄存器来进行传输,那么由于每个寄存器的位置不同,布局布线会导致每个数据到达下一级寄存器的延时不同,可能会采样的中间变化的任何值。

3.多bit跨时钟域的几种解决方法

        (1)多bit信号合并——字面意思,将多bit信号合并成单bit信号,一般只适用于多个控制信号且控制信号之间有一定逻辑关系。合并之后再采用单bit跨时钟域方式进行传递。这种方法最简单,但是不常见,也没什么要多说明的。

        (2)MUX同步器。

        (3)异步FIFO。

        (4)格雷码编码处理——有局限性,只有在数据在相数值间连续变化的情况下才有用,不适用于大多数信号传输或者数据传输的情况,且这个方法在异步fifo中有被包含到,就不单独说明。

        除此之外,我查到的还有握手协议、多周期路径(Multi-Cycle path,MCP)同步法,不过感觉多bit来说,掌握其中两种比较有代表性的就足够了,因此这两种方法就暂时不详细看了。

        下面就2、3方法进行详细讲述。

4. MUX同步器解决多bit跨时钟域

        使用MUX同步器要求被同步的数据跟随一个使能信号,当使能信号有效时,数据才会被同步。MUX同步器应用在慢到快的CDC时,数据长度应该至少为m+1个目标时钟周期,m指的是同步器数量,此处为m=2。

        具体实现代码如下所示

module  mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	    begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		begin
		    data_out <= b_data_en ? data_in_reg : data_out;
		end
    end	
	
endmodule

        上述代码是针对正常慢时钟域到快时钟域的,但如果B时钟域(接收域)的时钟频率是A时钟域(发送域)的时钟频率的几十倍,甚至上百倍;且data_en为脉冲信号时,data_en在在快时钟域打完几拍的时间相对于慢时钟域是非常短暂的,此时慢时钟域中的多bit数据信号可能还处于冒险中间态,则此时选通进入快时钟域的数据就是“毛刺”。

        针对这种情况,可以在接收域使用边沿同步器,检测data_en的下降沿,以保证此时的多比特数据一定是稳定的。

module mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	reg            edge_reg;
	wire           edge_flag;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	//下降沿检测
	always@(posedge clk_b or negedge brst_n)
	begin
	    if(!brst_n)
	        edge_reg <= 1'b0;
		else
		    edge_reg <= b_data_en;
	end
	assign  edge_flag = ~b_data_en & edge_reg;
	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		    data_out <= edge_flag ? data_in_reg : data_out;
    end	
	
endmodule

        这个方法感觉很熟悉,和单bit数据跨时钟域处理慢时钟域到快时钟域避免重复采样的方法是基本一致的。只不过不同的是,单bit采用的是读取上升沿,而多bit采用的是读取下降沿,要解决的是输入的多bit数据还没有全部传完,输出就完成打两拍开始采集data,因此选择采样下降沿,保证采集到数据的时候已经完全传输完成,这点没有问题。

        上述这两种代码都是处理慢到快时钟域的,对于快到慢时钟域来说,目前我查到的资料说是保证输入的使能信号和数据周期足够长就可以了。目前先存疑一下,感觉也可以通过单bit方法来实现。

        总结,对于MUX同步器来说,其实本质上还是和单bit有相似之处的,就是将valid信号按照单bit的信号进行处理。

5.异步fifo

        异步fifo可以说是解决多bit跨时钟域最常见的方法了,它相当于将源时钟数据缓存起来,然后目标时钟从缓存中取数据,传输速度较快。

        关于异步fifo的详解和设计可以看我的另一篇文章:异步FIFO设计-CSDN博客,这里就不再重写一遍了。

在将FPAG多bit信号从慢时钟域转换到快时钟域时,有两种方法可以选择。第一种方法信号展宽边沿检测。通过在快时钟域中展宽脉冲信号,即将脉冲信号转换成电平信号,并在两次脉冲信号之间保持为电平信号。然后在慢时钟域中,将展宽的脉冲信号打两拍,并进行边沿检测。这样可以实现将脉冲信号从慢时钟域转换到快时钟域。 另一种方法是握手。握手方法在慢时钟域和快时钟域之间建立一个握手协议,通过在慢时钟域中生成请求信号,并在快时钟域中生成应答信号来实现数据传输。由于握手方法需要消耗较大的握手资源,一般情况下不常用。 综上所述,对于FPAG多bit信号从慢时钟域到快时钟域的转换,可以选择信号展宽边沿检测方法或握手方法。其中信号展宽边沿检测方法是较常用的方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【CDC跨时钟域信号处理】单bit_快时钟域到慢时钟域](https://blog.csdn.net/weixin_50952710/article/details/128204972)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [FPGA跨时钟域信号处理——专用握手信号](https://download.csdn.net/download/weixin_38507208/12640627)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值