1. 跨时钟域同步:FPGA设计中的“交通警察”
如果你刚开始玩FPGA,可能会觉得写个计数器、做个流水灯挺简单,时钟嘛,一个就够用了。但当你真正开始做项目,比如要把摄像头采集的数据传给DDR,或者把以太网收到的包交给处理器处理时,你很快就会发现,你的系统里不止一个时钟在“滴答滴答”地走。这些时钟可能来自不同的晶振,频率和相位都互不相同,它们管辖的区域,就是我们常说的“时钟域”。当一个信号要从一个时钟域跑到另一个时钟域去,就像一辆车要从一条高速路并到另一条高速路上,如果直接冲过去,十有八九会“撞车”——在数字电路里,我们管这叫“亚稳态”,它会导致系统功能错乱,甚至直接死机。
这个信号跨域的过程,就叫“跨时钟域”(Clock Domain Crossing, CDC)。而处理这个问题的技术,就是CDC设计。今天我们不聊复杂的多比特数据总线同步(那通常用异步FIFO或握手协议),咱们先啃下最基础、也最核心的硬骨头:单比特信号的跨时钟域同步。别看它只有一根线,它是整个CDC大厦的基石,异步FIFO里的握手信号、时钟切换电路的控制信号,都离不开它。处理不好它,你的系统就永远在“抽风”的边缘试探。
我刚开始做项目时,就在这上面栽过跟头。一个简单的按键消抖信号,从低频的按键扫描时钟域送到高速的系统主时钟域,没做任何处理,结果系统时不时就误触发一次。后来才知道,这就是典型的CDC问题。解决单比特信号CDC,业界有三个经典且实用的方案:电平同步器、边沿同步器和脉冲同步器。它们就像三种不同职能的交通警察,有的只管让车安全通过(电平),有的专门报告有车刚开过来(边沿),有的则负责把一闪而过的摩托车(窄脉冲)安全地引导到另一条路上。接下来,我就结合自己踩过的坑和实战代码,带你彻底搞懂这三种方案,让你知道什么时候该派哪位“警察”上场。
2. 方案一:电平同步器——最基础的“安全岗哨”
2.1 原理与工作方式:两级寄存器的智慧
电平同步器,也叫“打两拍”同步器,是你能见到的最简单、最常用的CDC电路。它的结构简单到令人惊讶:在接收时钟域里,用两个(或更多)级联的触发器,对来自发送时钟域的输入信号连续采样两次。
module Level_Sync (
input wire Clk_src, // 发送域时钟
input wire Clk_dst, // 接收域时钟
input wire Rst_n,
input wire Data_in, // 发送域单比特信号
output reg Data_out // 同步后的电平信号
);
reg data_meta; // 第一级寄存器,通常被称为“亚稳态寄存器”
reg data_sync; // 第二级寄存器
// 在发送时钟域先寄存一次(可选,但推荐,使输出更干净)
reg data_src_reg;
always @(posedge Clk_src or negedge Rst_n) begin
if (!Rst_n)
data_src_reg <= 1'b0;
else
data_src_reg <= Data_in;
end
// 核心:接收时钟域的两级同步
always @(posedge Clk_dst or negedge Rst_n) begin
if (!Rst_n) begin
data_meta <= 1'b0;
data_sync <= 1'b0;

2万+

被折叠的 条评论
为什么被折叠?



