一、背景

数据的跨时钟域处理是FPGA开发过程中的常见问题,存在两种情况

    1. 慢时钟向快时钟同步:只需在快时钟域打两拍即可。其RTL如下:

    打拍同步的原理:大家在初学FPGA时,经常听过FPGA中对信号打拍可以有效得避免亚稳态,而且一般要打两拍,其数学本质是如果打一拍发生错误得概率是1/1000,那么打两拍发生错误得概率就是1/1000000,这从统计意义上已经无限接近0。

    从电路本身的角度上讲,如果一个信号的更新频率与当前时钟域内的信号更新频率不同步,那么其和当前时钟域内的信号做任何运算,都有可能导致结果出现毛刺或者不满足下级寄存器的建立或保持时间。因此,为了确保新引人的这个非本时钟域的信号不会对本时钟域造成毁灭性打击,必须对其进行同步化处理,而方法就是使用当前时钟地域的时钟对其进行采样。而进行两次打拍是让异步信号打两拍可以让异步过来的电平信号达到一个比较“健壮”的电平区间,二避免了由于建立时间、多级扇出导致的逻辑电平不稳定的情况。以下摘自《FPGA之道》:

“为什么要采样两次呢?

采样一次,已经完成了非本时钟域信号的同步操作,那么为什么还要采用两级采样法呢?虽然从逻辑上来看,两级采样法就跟移位寄存器一样,并不能改变信号的逻辑值,而且还会增加信号传递进来的延迟,但是这绝对不是画蛇添足,而是非常必要的,原因如下:请大家思考一下,进行第一级采样的那个寄存器,其建立和保持时间是不否能够得到满足?显然在有些情况下,其建立和保持时间是无法得到满足的,因为它和当前时钟域时钟信号的变化并不同步,因此总会碰到问题。例如,当asynsignal从0变化到1时,如果在过这前后时间内,clk共经历了3个上升沿,那么unsafesignal的输出可能是001,也可能是011,其中,第二次采样由于建立或者保持时间不满足,所以无法确定其是0还是1,不过值得欧慰的是,无论是001,还是011,都至少正确捕捉到了原始信号的变化。也许你会觉得,异步逻辑本身就不可能在时间上被精确地捕捉到,既然能够正确捕捉到信号的变化,那不就够了么?没错,从逻辑上来说是够了,但是从驱动能力上来说,也许不够。大家都知道,FPGA内部的工作电压一般为1.5V,也就是说,理想情况下,逻辑1对应电压1.5V,逻辑0对应电压0V。但是现实是残酷的,逻辑1不可能精确地是1.5V,逻辑0也不可能是精确地0V,事实上,也许业界公认0.5V以上就可以判定为逻辑1,反之则可以被判定为逻辑0,这也是为什么数字信信号比模拟信号更能抗干扰的原因。所以,如果现在问你,FPGA内部有两个触发器的输出都是逻辑1,那么它俩的物理电压相等吗?答案显然是不一定。为什么触发器能够给出正确地输出结果的前提是输入信号要满足其建立、保持时间要求?其实原因很简单,就是要给数字电路以充足的时间来进行充电或者放电操作,从而让其输出的逻辑1更接近于1.5V,逻辑0更接近于0V;反之,如果一个逻辑电平1、0对应的物理电平更接近于1.5V或者0V,那么它就更容易在规定时间内对其后级触发器进行充分的充电或放电控制,从而使其后级触发器的输出也更加"强壮"。那么现在,我们在回过头来审视unsafesignal的物理电压,由于输出unsafesignalf的触发器,很可能出现建立或保持时间要求不满足的情况,因此,在这种情况下,它的充、放电操作都很不充分,输出的逻辑1或者逻辑0的物理电压都不会太好。例如,如果unsafesignalj为逻辑1,那么其物理电压很可能为0.6V,如果当前时钟域中有很多地方都用到了unsafesignal,那么0.6V电压的扇出能力显然会比较差,因此等传递到后续各个用到unsafe signal的地方,物理电压可能就变为0.4V、0.5V、0.55V等等,那么这时 unsafe signal就会被不同的触发器认成不同的逻辑电平,于是错误便诞生了。为了避免这种情况的发生,我们对unsafesignal再次进行采样。由于unsafesignal和safesignal是同步的,因此对于输出safesignal的触发器来说,建立时间已经远远超出了其建立时间要求,因此,即使0.6V的电压对其充电比较慢,但由于充电时间足够,充电电流也有保障,所以也能让safesignal达到一个比较健壮的物理电压,例如1.4V。接下来,我们再将safesignal连接到各个需要使用它的地方,其扇出能力就不会再有任何问题了。”

  1. 2.快时钟域向慢时钟域同步

    第一种简单的方式是在快慢时钟域间添加一个FIFO,这样就可以避免时钟不同步的问题。

    第二种方式是hand shanking机制,简单来说就是一种握手机制,其时序图可以用下图表示:



    在数据有效后,主机发起同步请求req,直至检测到从机的ACK信号后,req拉低,标志一次同步结束。而req信号在从机进行采样同步,并经过两拍后,从机对主机的DATA信号进行采样同步,完成从快时钟域到慢时钟域的数据同步。

    代码如下:
  `// ************************ ***************************************

// Copyright (C) xx Coporation
// File name: hand_shanking.v
// Author: Dongyang
// Date: 2024-11/16
// Version: 1.0
// Abstract: CDC multi bit sync,use hand shanking to sync data
//***************************************************************** `
`timescale 1 ns/1 ns
module hand_shanking_module# (
parameter integer DATA_WIDTH = 8
)
(
input i_clk_f , //
input i_sys_rst_n , //外部异步复位信号
input [DATA_WIDTH-1 : 0] i_src_data , //外部输入信号,
input i_src_data_valid , //数据有效标志 input i_clk_s ,
output o_des_ack , //应答完成信号,取上升沿后可作为i_clk_s 的o_des_data 的valid 信号
output reg [DATA_WIDTH-1 : 0] o_des_data //在i_clk_s 时钟域同步后的信号
); //******************** siganl define ***********************
reg r_src_req ;
reg r_src_ack_sync1 ;
reg r_src_ack_sync2 ; reg r_des_req_sync1 ;
reg r_des_req_sync2 ; reg r_des_ack ; //************** combination logic *************************
assign o_des_ack = r_des_ack;
// step 1 , generate r_src_req
always @(posedge i_clk_f or negedge i_sys_rst_n) begin
if (~i_sys_rst_n) begin
r_src_req <= 1'b0;
end
else begin
if (i_src_data_valid) begin //once datavalid , generate r_src_req
r_src_req <= 1'b1;
end
else if (r_src_ack_sync2) begin // when i_clk_s domain ack successfully,r_src_req reset
r_src_req <= 1'b0;
end
end
end //step 2 and 3, under i_clk_s domain, sync r_src_req from i_clk_f domain,generate ack ok siganl
always @(posedge i_clk_s or negedge i_sys_rst_n) begin
if (~i_sys_rst_n) begin
r_des_req_sync1 <= 1'b0;
r_des_req_sync2 <= 1'b0;
r_des_ack <= 1'b0;
end
else begin
r_des_req_sync1 <= r_src_req ;
r_des_req_sync2 <= r_des_req_sync1;
r_des_ack <= r_des_req_sync2;
end
end
//step 3, once r_des_req_sync2 set, sync o_des_data
always @(posedge i_clk_s or negedge i_sys_rst_n) begin
if (~i_sys_rst_n) begin
o_des_data <= 'b0;
end
else begin
if(r_des_req_sync2) begin
o_des_data <= i_src_data;
end
end
end //step 4 ,sync r_des_ack to i_clk_f domain
always@(posedge i_clk_f or negedge i_sys_rst_n) begin
if(~i_sys_rst_n) begin
r_src_ack_sync1 <= 1'b0;
r_src_ack_sync2 <= 1'b0;
end
else begin
r_src_ack_sync1 <= r_des_ack;
r_src_ack_sync2 <= r_src_ack_sync1; end
end endmodule

TestBench:

`timescale 1 ns/1 ns
module tb_hand_shanking(); parameter integer DATA_WIDTH = 8; reg clk_f = 'b0;
reg clk_s = 'b0;
reg sys_rst_n = 'b0;
reg [DATA_WIDTH- 1 : 0 ] src_data = 'b0;
reg data_valid = 'b0; always # 10 clk_f = ~ clk_f;
always # 30 clk_s = ~ clk_s; initial begin
clk_f = 'b0;
clk_s = 'b0;
sys_rst_n = 'b0;
src_data = 'b0;
data_valid = 'b0;
#50
sys_rst_n <= 1'b1;
#100
src_data <= 8'h5A;
data_valid <= 1'b1;
#20
data_valid <= 1'b0;
#500
src_data <= 8'h6A;
data_valid <= 1'b1;
#20
data_valid <= 1'b0; end hand_shanking_module
#(
.DATA_WIDTH(DATA_WIDTH)
)
U_hand_shanking_module_0
(
.i_clk_f (clk_f),
.i_sys_rst_n (sys_rst_n),
.i_src_data (src_data),
.i_src_data_valid (data_valid),
.i_clk_s (clk_s),
.o_des_ack (),
.o_des_data () ); endmodule

仿真波形:

https://img2024.cnblogs.com/blog/3539410/202411/3539410-20241116161229825-134001601.png

一文讲透 FPGA CDC 多bit跨时钟域同步-hand-shanking机制的更多相关文章

  1. FPGA基础学习(3) -- 跨时钟域处理方法

    文章主要是基于学习后的总结. 1. 时钟域 假如设计中所有的触发器都使用一个全局网络,比如FPGA的主时钟输入,那么我们说这个设计只有一个时钟域.假如设计有两个输入时钟,如图1所示,一个时钟给接口1使 ...

  2. FPGA跨时钟域处理方法

    文章主要是基于学习后的总结. 1. 时钟域 假如设计中所有的触发器都使用一个全局网络,比如FPGA的主时钟输入,那么我们说这个设计只有一个时钟域.假如设计有两个输入时钟,如图1所示,一个时钟给接口1使 ...

  3. cdc跨时钟域处理-结绳握手法

    参考文档 https://blog.csdn.net/u011412586/article/details/10009761 前言 对于信号需要跨时钟域处理而言,最重要的就是确保数据能稳定的传送到采样 ...

  4. 基于FPGA的跨时钟域信号处理——专用握手信号

    在逻辑设计领域,只涉及单个时钟域的设计并不多.尤其对于一些复杂的应用,FPGA往往需要和多个时钟域的信号进行通信.异步时钟域所涉及的两个时钟之间可能存在相位差,也可能没有任何频率关系,即通常所说的不同 ...

  5. FPGA跨时钟域握手信号的结构

    FPGA跨时钟数据传输,是我们经常遇到的问题的,下面给出一种跨时钟握手操作的电路结构.先上图 先对与其他人的结构,这个结构最大的特点是使用 req 从低到高或者高到低的变化 来表示DIN数据有效并开始 ...

  6. 一文讲透Dubbo负载均衡之最小活跃数算法

    本文是对于Dubbo负载均衡策略之一的最小活跃数算法的详细分析.文中所示源码,没有特别标注的地方均为2.6.0版本. 为什么没有用截止目前的最新的版本号2.7.4.1呢?因为2.6.0这个版本里面有两 ...

  7. 从零入门 Serverless | 一文讲透 Serverless Kubernetes 容器服务

    作者 | 张维(贤维) 阿里云函数计算开发工程师 导读:Serverless Kubernetes 是以容器和 kubernetes 为基础的 Serverless 服务,它提供了一种简单易用.极致弹 ...

  8. 一文讲透产品经理如何用好ChatGPT

    作者:京东零售 何雨航 "4.0版本的ChatGPT可以有效提升产品经理工作效率,但并无法替代产品经理的角色." 一.引言 3月15日,OpenAI发布了最新的基于GPT-4的Ch ...

  9. 一文讲透静电放电(ESD)保护(转发)

    一直想给大家讲讲ESD的理论,很经典.但是由于理论性太强,任何理论都是一环套一环的,如果你不会画鸡蛋,注定了你就不会画大卫. 先来谈静电放电(ESD: Electrostatic Discharge) ...

  10. 一文讲透Cluster API的前世、今生与未来

    作者:Luke Addison 原文链接:https://blog.jetstack.io/blog/cluster-api-past-present-and-future/ Cluster API是 ...

随机推荐

  1. JavaScript设计模式样例十三 —— 模版方法模式

    模板方法模式(Template Method Pattern) 定义:一个抽象类公开定义了执行它的方法的方式/模板.它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行.目的:一些方法通用 ...

  2. Win32 动态库dll

    这两天学习动态库的练习,分享下方法 实例.封装窗口类的两种状态. 1.自定义窗口类QWnd 2.资源模板窗口对话框类 下面是dll的头文件,类的声明 #pragma once #ifndef _CLA ...

  3. Win32 自绘控件按钮类

    今天学了控件的自绘,初步偿试了下,蹂躏的不行不行的,查了好多的资料,头都弄大了, 有好多还是没弄明白,只是初步实现一个按钮的基本功能,好难呀, 先看下效果: 按下状态 弹起状态 按钮2按下状态 按钮2 ...

  4. hacs安装

    安装 HACS 直接使用 Docker 的可视化管理面板 Portainer 或者通过命令行进入 Docker 容器,然后执行以下安装命令: docker exec -it <容器名称或容器ID ...

  5. 在 Mac 上使用 X11

    有时我们需要在服务器上运行一个 GUI 程序,然而我们是通过 SSH 连接到服务器的,看不到图形界面,怎么办呢?我们可以通过 X11 将 GUI 程序的界面转发到本地. 在 Mac 上使用 X11 需 ...

  6. 设线性表中每个元素有两个数据项k1和k2,现对线性表按一下规则进行排序:先看数据项k1,k1值小的元素在前,大的在后;在k1值相同的情况下,再看k2,k2值小的在前,大的在后。满足这种要求的

    题目: 设线性表中每个元素有两个数据项k1和k2,现对线性表按一下规则进行排序:先看数据项k1,k1值小的元素在前,大的在后:在k1值相同的情况下,再看k2,k2值小的在前,大的在后.满足这种要求的排 ...

  7. vue中代理解决跨域

    跨域是什么 简单的讲就是你在一个地方使用另一个地方的资源,被浏览器给挡下来了,不让不用!当然,它挡下来是有自己理由的:为了安全(╬▔皿▔)╯. 解决跨域 我是用vue开发的,就vue代理模式解决跨域说 ...

  8. .NET 9 的新亮点:AI就绪 ,拥抱她

    .NET 9 即将发布 RC1, 今年初.NET 团队在发布.NET 9 Preview 1版本时写了一篇文章<我们对 .NET 9 的愿景>,其中特别提到了对AI的展望 .NET 9,我 ...

  9. Go 编程-mysql数据库操作

    一.环境准备 在Go语言中连接MySQL数据库通常使用database/sql包配合一个MySQL驱动,比如github.com/go-sql-driver/mysql 安装github.com/go ...

  10. MySQL 用户、权限管理,C/C++连接与使用

    目录 用户 用户管理 查询所有用户 查看当前用户 查看当前连接数 创建用户 删除用户 修改密码规则 查看规则/策略 规则说明 临时设置 持久设置 修改密码 权限 数据库提供的 权限列表 查看权限 给用 ...