• 正文
  • 相关推荐
申请入驻 产业图谱

【FPGA实战】:一个展宽移位 CDC 模块的设计与实战

08/19 08:31
113
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

在多时钟域的FPGA设计中,跨时钟域(CDC,Clock Domain Crossing)问题犹如一颗定时炸弹。处理不当,轻则数据错乱,重则系统崩溃。虽然简单的单比特信号可以用“打两拍”解决,但在实际工程中,我们经常面临更复杂的场景:不仅要传信号,还要传数据,且要确保万无一失。

今天,我们就通过一个经典的 “展宽-移位-握手” 模块,来深入探讨如何优雅地实现跨时钟域的数据透传。

相比于“粗暴”的直接打拍,它提供了更高的可靠性;相比于复杂的异步 FIFO,它实现成本更低,逻辑更清晰。在处理中低频、高可靠性的跨时钟域数据交互时,这是一个非常值得借鉴的参考设计。

一、 模块核心架构

我们分析的 data_clka_clkb 模块,其核心功能是将 clk_a 域的数据安全传输到 clk_b 域。与简单的 FIFO 不同,它采用了一种基于请求-应答握手机制的同步方案。

模块内部架构主要包含三个关键部分:

1. 脉冲展宽

在跨时钟域传输中,快时钟域的窄脉冲很容易被慢时钟域“错过”。因此,第一步关键操作是将输入的窄脉冲信号 i_data_vaild 进行展宽。 代码中巧妙地利用了边沿检测技术:

assign vaild_a_neg = vaild_a_tmp[1] & (~vaild_a_tmp[0]);

值得注意的是,该设计检测的是 i_data_vaild 的下降沿。当检测到下降沿时,拉高 vaild_a 信号,并将其作为“请求信号”发送给接收端。这个信号会一直保持高电平,直到收到接收端的反馈才拉低,从而保证了信号有足够的时长被慢时钟采样。

2. 移位同步

在接收端(clk_b 域),并没有简单地对 vaild_a 进行双触发器同步,而是使用了一个参数化的移位寄存器 vaild_b_dff

vaild_b_dff <= {vaild_b_dff[(DATA_DELAY-1):00], vaild_a};

这种设计一方面完成了跨时钟域的同步(第一级 DFF 解决亚稳态),另一方面通过移位产生的多级延迟,天然形成了一个时间窗口。这比单纯的同步多了一层“时间裕量”的保护,极大地提高了可靠性。

3. 数据采样与握手闭环

数据要在什么时候采样最安全?模块选择了移位寄存器的中间位置

assign vaild_b_pos = (~vaild_b_dff[DATA_DELAY-1]) & vaild_b_dff[DATA_DELAY-2];

这是一个非常稳妥的策略。当同步信号传播到移位链的中间时,意味着它已经完全脱离了亚稳态区域,且远离了变化沿,此时对 i_data 进行采样最为稳妥。 最后,同步链末端的信号被反馈回源时钟域,用于清除展宽信号并生成应答信号 o_data_vaild,完成了一次完美的“请求-应答”闭环。

二、 典型应用场景

该模块的设计特点决定了它非常适合以下场景:

低速控制信号与寄存器配置: 当系统需要跨时钟域配置寄存器(如 ADC 的控制字、PLL 的配置参数)时,数据量不大,但对可靠性要求极高。该模块的握手机制能确保每一次配置都准确送达。

慢时钟域到快时钟域的突发传输: 相比于 FIFO 的流式传输,这种握手机制更适合“事务型”传输。比如 CPU 在快时钟域写好数据,通过握手通知慢时钟域的外设接收。

异步复位同步释放: 模块中显式调用了 xpm_cdc_sync_rst,这表明设计者非常注重复位逻辑的正确性。这种结构保证了复位信号在两个时钟域内都能正确释放,避免了复位释放时的亚稳态。

三、 仿真验证实战

为了验证设计的正确性,我们编写了Testbench。仿真不仅仅是看结果,更是验证时序细节的过程。

1. 时钟与复位

测试平台构建了两个异步时钟:clk_a 为 100MHz(10ns周期),clk_b 为 66.67MHz(15ns周期)。这种快到慢且非整数倍的频率关系。

2. 关键任务封装

在 TB 中,我们将发送逻辑封装为 send_data 任务:

i_data_vaild <= 1'b1;
repeat(3) @(posedge i_clk_a);
i_data_vaild <= 1'b0;   // 产生下降沿触发传输
wait(o_data_vaild == 1'b1); // 阻塞等待应答

这段代码完美复现了协议要求:先拉高有效信号,保持稳定一段时间(模拟数据建立时间),产生下降沿触发传输,然后阻塞等待应答。模拟了真实上游模块的行为,必须等待握手完成才能进行下一次操作。

3. 验证结果分析

通过仿真波形,可以清晰地看到“展宽-移位”的效果:

触发时刻:当 i_data_vaild 变低的瞬间,vaild_a 信号立即拉高并保持。

同步过程:在 clk_b 域,我们可以看到 vaild_b_dff 寄存器像流水一样依次变高,这正是移位同步的过程。

采样点:在移位链的中间位置,o_data 成功捕获了 i_data 的值。

应答反馈:当同步链末端变高,反馈信号传回 clk_a,拉低 vaild_a,同时拉高 o_data_vaild,传输结束。 测试用例覆盖了单次传输、连续传输以及全0全1的边界测试。仿真日志显示,所有数据比对均通过,验证了模块逻辑的正确性。

 

我是小灰灰的FPGA,关注我,带你从入门到精通数字逻辑设计

相关推荐