三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

【面试】【数字IC基础】跨时钟域处理一(CDC,Clock Domain Crossing)(一)

【面试】【数字IC基础】跨时钟域处理一(CDC,Clock Domain Crossing)(一)

【缘起】最近投实习有问到CDC,但是那会儿只会双DFF所以后来稍微整理了一下(超入门篇)

想着用最通俗易懂的语言记录一下,以及难get的点详细说明了一下

一、概述

跨时钟域处理主要分为单比特和多比特的处理方法,这一篇先讲单比特的处理方法。

二、单bit信号跨时钟域处理方法

2.1电平信号

无论是快时钟域→慢时钟域,还是慢时钟域→快时钟,都直接用双DFF就好,如下图的电路图:

电平信号无论是高电平还是低电平,都会持续较久的时间;脉冲信号是只持续一个周期

类似这样,(看上面电路图)比如我们用clk2去采用clk1下的这个电平信号,就是有可能会采到上升/下降沿对吧,那么就会产生亚稳态,我们又知道亚稳态会在后面的组合逻辑里一直往下传递甚至放大,这样输出的结果就不对。所以我们采用打拍的方式,当加了第一个触发器后由于亚稳态发生的概率公式可知已经减小很多了,通过第二个触发器,亚稳态传播到后续逻辑的概率会大幅降低(通常降到 10−15 量级,即可接受范围,是在我们可以接受的范围内。(感兴趣的可以去看一下详细的公式推导)具体代码及解析如下:

关于上述电路图:如果 a 本身是 clk1 域产生的信号,这一步(AA)可以省略;如果 a 是外部异步输入,则需要先用 clk1 采样一次消除毛刺。

2.2脉冲信号

1.慢到快:先双DFF,再边沿检测;

再看由快时钟去采慢时钟的信号(vld1是慢时钟产生的一个脉冲信号,较宽)可以看到在clk2下会产生vld2,但是clk2较快所以产生的vld2就不是一个脉冲信号了(途中持续了两个周期)

2.快到慢:先脉冲信号展宽(转换为电平信号)再双DFF最后边沿检测得到脉冲信号

用一个慢速时钟去采快速时钟的时候(如图)可能每次都错过上升沿每次都采到的是0,就相当于采不到,因此我们要先拓宽脉冲。

上图展示了由慢速去采样快速时钟域具体是如何做CDC的。

①信号a是由clk1产生的,我们的目的是让clk2不把a当作毛刺给过滤掉,在图中我们可以看得到clk2无论哪个上升沿都采不到信号a,而且a只是一个脉冲信号非常非常短,很有可能直接当毛刺过掉了,所以我们需要构造一个a_latch把它变成电平信号(信号展宽),当clk2采样后再拉低

②现在a_latch是一个电平信号,就回到我们上面电平信号的CDC处理方式,得到b_latcch_r,但是我们还需要构造一个b_lach_2r,检测上升信号的脉冲沿(也会同时将其转换为脉冲信号),得到clk2上的b信号;

③构造反馈信号:当clk2上采到信号后(即b拉高就会产生反馈信号,告诉外界已经采样完毕)这样会形成一个闭环的CDC;

④把反馈信号跨到clk1上(方法同理,还是双DFF)

⑤最后产生一个busy信号拒绝新的握手请求

【上述握手协议主要针对快 → 慢场景(脉冲最危险的方向)。如果明确是慢 → 快,可以简化为'双 DFF + 边沿检测',不需要展宽和反馈。但握手协议在时钟频率比不确定时也能安全工作,鲁棒性更强。】

2.3数据信号

总的原则就是等数据稳定后再CDC,那什么时候稳定呢?我们可以让valid先跨时钟,等valid过去后,说明数据已经维持某一个值较长时间了,就不会采到亚稳态时的值。因此,先对valid跨时钟,再用跨完时钟后的valid去采样数据。(如下图)

代码就是先对valid2用脉冲的CDC处理方式,最后加上data的处理就好

三、总结

3.1知识点总结

这节主要讲单bit信号和数据传输,表格汇总如下:

数据CDC则在此基础上用跨完后的valid控制信号去采样即可

信号类型快 → 慢(同步到慢时钟域)慢 → 快(同步到快时钟域)
电平信号(如busyenable直接双 DFF直接双 DFF
脉冲信号(如startdone展宽成电平 → 双 DFF → 边沿检测还原脉冲双 DFF → 边沿检测还原脉冲

3.2记住小技巧

1.知识体系

如果看这个博客是正准备秋招或者面试ddl,可以主要看下面这个目录,记得CDC不同类型解决方法(⭐⭐⭐)、跨时钟域主要的问题(⭐⭐)

2.本节记忆

如果前期积累不太深厚+ddl的压力的话可能记不住尤其是快到慢和慢到快具体是谁需要展宽,可以这样形象记忆:

/*=========慢时钟就是一个内敛慢热的,快时钟就是热情开朗的===========

快采样慢(慢跨到快):因为热情开朗嘛所以散发的信号很明显,就不用搞那么复杂(直接双DFF+边沿采样就好)。这个就是快时钟去采样慢时钟(也就是慢时钟跨到快时钟这里来,你想嘛人家慢时钟都跨越千山万水来了,所以肯定是主人(快时钟)要主动(采样呀))

慢采样快(快时钟域到慢时钟):那慢热的散发的信号就很含蓄,人热情开朗大大咧咧很可能就get不到呀,那么怎么办呢?就需要慢热的持续久一点总有一天能get到咯~(也就是咱们说的要先展宽脉冲嘛)。

具体来说,因为慢时钟的采样频率低,它可能连续多个周期都“错过”了快时钟域里那个短暂的高电平脉冲。为了让慢时钟能稳定地捕捉到这个信号,我们必须先在快时钟域内将这个脉冲“展宽”——也就是通过一个锁存器(latch)或触发器,把脉冲信号变成一个持续多个快时钟周期的电平信号。这样,即使慢时钟的采样点比较稀疏,也有足够高的概率在电平信号为高时采样到它。展宽后的电平信号再经过双 DFF 同步到慢时钟域,最后通过边沿检测电路还原成一个干净的脉冲信号。这个 过程就像两个性格不同的人沟通:急性子(快时钟)说话快、动作快,但慢性子(慢时钟)反应慢,所以急性子需要把重要的话多说几遍、持续久一点,慢性子才能听清楚并做出回应。

(嘿嘿~这么浪漫的比喻当然要用一个漂亮的颜色咯~)

*/

如果时间充裕的话,还是建议手写代码,理解会深刻很多

3.3小小面经

我面的两个关于这一节都是会在单bit的详细问了后向多bit的过渡,单bit的快→慢和慢→快都会问,然后再过渡和引导到异步FIFO如何设计,一般这一节面试官都是会让画时序图,所以时间充裕可以画画以及提前演练讲解。

四、参考资料

1.原创讲解视频

全网最好玩儿的跨时钟域(CDC)教程_哔哩哔哩_bilibili

2.参考资料

【数字IC基础】跨时钟域(CDC,Clock Domain Crossing)-CSDN博客

《数字IC设计入门》2.23 跨时钟域异步处理方法_哔哩哔哩_bilibili

附录 问题汇总

【这一part主要是汇总在学习过程中可能产生的问题,基础较好的或者没啥疑问的可自行略过】

1.边沿检测原理

因为边沿检测原理还是很可能会被面试官问到,而且可能初学者一开始没那么懂所以放到这儿:

(波形图不明白的话可以看真值表比较好理解)

b_2r (上一拍)b_r (现在)b = b_r & ~b_2r含义
000一直是低,没变化
011上一拍低,现在高 → 上升沿!
100上一拍高,现在低 → 下降沿
110一直是高,没变化

只有第二行输出 1。这就是"检测到上升沿"的数学表达。

1.关于 b_latch_2r 的作用

b_latch_2r唯一目的边沿检测(检测b_latch_r的上升沿)。而"产生单周期脉冲"只是边沿检测的自然结果,不是额外目的。

如果没有 b_latch_2r 做边沿检测:

  • b_latch_r是一个持续多拍的电平(因为a_latch被展宽了);

  • 如果直接把b_latch_r当输出用,clk2 域收到的就是一个长电平,不是脉冲;

  • 边沿检测把它还原成了"只高 1 拍"的脉冲

2.为什么脉冲要先展宽成电平,再跨时钟域?

假设不展宽,直接跨:

  • clk1 = 200MHz,周期 5ns;

  • clk2 = 50MHz,周期 20ns;

  • a脉冲只持续5ns(1 个 clk1 周期);

  • clk2 每 20ns 才采样一次。

三种可能:

情况结果概率
a脉冲刚好落在 clk2 上升沿附近clk2 采样到,但可能亚稳态很低
a脉冲落在 clk2 上升沿之间clk2 完全看不到这个脉冲很高
a脉冲跨越 clk2 两个沿被采样到中等

核心问题:快时钟的窄脉冲,慢时钟大概率漏掉。

展宽成电平后:

  • a_latcha置 1 后,持续保持高电平

  • 不管 clk2 什么时候来采样,它一定能看到a_latch=1

  • 采到后通过反馈机制清零,准备下一次。

这就是"脉冲 → 电平 → 跨时钟域 → 边沿检测还原脉冲"的完整逻辑。

如果是慢时钟域 → 快时钟域(50MHz → 200MHz),慢时钟的脉冲宽度 = 20ns,快时钟周期 = 5ns,快时钟一定能采到,不会漏。但快时钟会采到连续 4 次 1,所以也需要边沿检测还原成单脉冲。

3.为什么两个触发器就能解决亚稳态?三个或四个不行吗?

这是概率问题,不是"能不能"的问题。

亚稳态的物理本质:触发器进入亚稳态后,输出不会永远震荡。它会指数衰减,最终稳定到 0 或 1(具体是哪个不可预测,但一定会稳定)。根据概率公式可知通过两级后已经能降低到我们能接受的范围。

4.为何要构造b_feedback_latch?

如果没有,则是开环的CDC:

clk1: a_latch=1 ──CDC──► clk2: 采样到了吗?不知道...

clk1: a_latch 什么时候清零?不知道...

我们需要构造闭环的CDC:

clk1 发请求 ──► clk2 收到 ──► clk2 发 ACK ──► clk1 收到 ACK ──► clk1 清零
↑___________________________________________________________↓

那就到这咯,祝大家学有所成、面试全过。

← 返回列表