FPGA学习_跨时钟域问题

文章目录

  • 前言
  • 一、什么是跨时钟域问题
  • 二、单bit跨时钟域(快到慢)
  • 三、单bit跨时钟域(慢到快)
  • 四、单bit跨时钟域(任意时钟域之间)
  • 五、多bit跨时钟域

前言

跨时钟域问题是FPGA以及IC设计中最常见的话题,也几乎是最重要的问题。

一、什么是跨时钟域问题

参考:https://bbs.huaweicloud.com/blogs/283007
只要FPGA设计中的所有资源不全属于一个时钟域,那么就可能存在跨时钟域问题,因为异步逻辑其实也可以看做一种特殊的跨时钟域问题。发生跨时钟域问题的必要条件是不同时钟域之间存在信息交互,如果一个FPGA设计中存在多个时钟域的话,这几乎是无法避免的,否则各个时钟域互不相关,那么就相当于把原设计分解为多个独立的小设计,这样的话FPGA设计的功能就无法通过协作来扩展。
那么当两个不同时钟域之间进行信息交互的时候,到底会存在什么问题呢?
首先介绍亚稳态:
触发器的建立时间和保持时间在时钟上升沿左右定义了一个时间窗口,如果触发器的数据输入端口上数据在这个时间窗口内发生变化(或者数据更新),那么就会产生时序违规。存在这个时序违规是因为建立时间要求和保持时间要求被违反了,此时触发器内部的一个节点(或者要输出到外部的节点)可能会在一个电压范围内浮动,无法稳定在逻辑0或者逻辑1状态。换句话说,如果数据在上述窗口中被采集,触发器中的晶体管不能可靠地设置为逻辑0或者逻辑1对应的电平上。所以此时的晶体管并未处于饱和区对应的高或者低电平,而是在稳定到一个确定电平之前,徘徊在一个中间电平状态(这个中间电平或许是一个正确值,也许不是)。
在这里插入图片描述
那么当两个不同时钟域之间进行信息交互的时候,遇到的情况:

  • 情况一:如果控制两个时钟域的时钟信号有非常高的关联性,例如一个PLL同频不同相的两个输出,又或者干脆就是一个时钟信号的上升沿或下降沿。那么很幸运,此时时序分析仍能够确保隐患的消除,最多再多指定一些简单的信息,例如时钟信号的占空比。
  • 情况二:如果控制两个时钟域的时钟信号有关联,但是不同频,例如一个PLL不同频的两个输出,那么,如果这两个频率之间没有较大的公约数的话,那么可能需要成百上千个时钟周期才能让它们的相位重新对齐。而在此期间,一个时钟的边沿可以以一个很小的相位步进差划过另一个时钟周期的所有相位,所以几乎可以肯定,一定会有某些边沿采样到了另一个时钟域内数据的不稳定状态。
  • 情况三:如果控制两个时钟域的时钟信号没有关联,例如它们分别是由两个不同频率的晶振产生的,那么它们的相位可能要经过上亿个周期后才能对齐,甚至永远不能对齐,因为不同晶振有着不同的频率偏移和抖动参数。这种情况下,也肯定会出现采样到不稳定态的问题。
    针对情况二,还可以通过时序分析加功能仿真确认的方法,虽然比较复杂,但仍能够进行确认是否能消除隐患,但是对于情况三,时序分析已经无能为力了,因为天知道两个晶振起振的相位是多少呢。事实上,除非两个时钟的相关性真的非常高,否则隐患几乎必被激发,那么为了让FPGA设计仍能够有正常的行为,我们必须采取措施!

二、单bit跨时钟域(快到慢)

方法:脉冲展宽和跨时钟域:脉冲展宽,将快时钟域脉冲信号拓展几个时钟周期,至少俩倍于慢时钟域周期。

module single_sync_fast2slow#(
    parameter P_CLK_NUM = 1 //慢时钟与快时钟之间的比值
)(
    input       i_clk_a     ,
    input       i_rst_a     ,
    input       i_single_a  ,

    input       i_clk_b     ,
    input       i_rst_b     ,
    output      o_single_b  
    );

/*--------clk_a--------*/
reg         r_single_a  ;
reg  [7:0]  r_cnt_a     ;

always @(posedge i_clk_a or posedge i_rst_a) begin
    if(i_rst_a)
        r_single_a <= 'd0;
    else if(r_cnt_a == 2 * P_CLK_NUM)
        r_single_a <= 'd0;
    else if(i_single_a)
        r_single_a <= 1;
    else
        r_single_a <= r_single_a;
end

always @(posedge i_clk_a or posedge i_rst_a) begin
    if(i_rst_a)
        r_cnt_a <= 'd0;
    else if(r_cnt_a == 2 * P_CLK_NUM)
        r_cnt_a <= 'd0;
    else if(i_single_a || r_cnt_a > 0)
        r_cnt_a <= r_cnt_a + 1;
    else
        r_cnt_a <= r_cnt_a;
end

/*--------clk_b--------*/
reg  r_single_b1,r_single_b2;
assign o_single_b = r_single_b2;
always @(posedge i_clk_b or posedge i_rst_b) begin
    if(i_rst_b)begin
        r_single_b1 <= 'd0;
        r_single_b2 <= 'd0;
    end
    else begin
        r_single_b1 <= r_single_a;
        r_single_b2 <= r_single_b1;
    end
end

endmodule

P_CLK_NUM参数表示快慢时钟周期之间的比值,要想百分百被慢时钟域正确采集,至少要在快时钟域内将脉冲宽度拓展至慢时钟周期俩倍,因此脉冲拓宽拓宽计数器需要满足:

r_cnt_a == 2 * P_CLK_NUM

仿真波形图:
在这里插入图片描述

三、单bit跨时钟域(慢到快)

方法:打俩拍
如果快时钟域频率大于俩倍慢时钟域频率 f1 > 2 * f2 ,那么打俩拍后快时钟域频率肯定是可以正确采到慢时钟域信号,但如果不满足此条件,打俩拍也可以大大降低亚稳态,保险起见也可以先拓展脉冲宽度,然后再采集。

四、单bit跨时钟域(任意时钟域之间)

方法:握手协议
具体过程:
当时钟域A产生一个脉冲后,紧接着拉高一个传输信号trans_a,直到收到B时钟域的响应信号然后拉低,那么B时钟域必然是可以采集到信号trans_a的,因为它一直为高,一旦检测到trans_a,则拉高r_single_b1,检测r_single_b1的上升沿,即可在B时钟域下也产生一个脉冲,随后产生一个响应信号r_ack_br_ack_b在时钟域B下的持续周期分俩种情况讨论:

  • 倘若时钟域A快于时钟域B,那么r_ack_b在时钟域B当中维持俩个时钟周期即可保证时钟域A收到响应信号
  • 倘若时钟域A慢于时钟域B,那么需要保证r_ack_b被拓宽至至少俩倍钟域A的时钟周期宽度,在代码里我将其拓宽为俩倍然后加1.
    如下:
localparam  P_CNT_END_B = P_CLK_FRQ_A >= P_CLK_FRQ_B ? 2 : ((P_CLK_FRQ_B/P_CLK_FRQ_A) * 2 + 1);

完整代码:

module single_sync_module#(
    parameter   P_CLK_FRQ_A = 50_000_000,
    parameter   P_CLK_FRQ_B = 50_000_000
)(
    input       i_clk_a     ,
    input       i_rst_a     ,
    input       i_single_a  ,

    input       i_clk_b     ,
    input       i_rst_b     ,
    output      o_single_b  
    );
localparam  P_CNT_END_B = P_CLK_FRQ_A >= P_CLK_FRQ_B ? 2 : ((P_CLK_FRQ_B/P_CLK_FRQ_A) * 2 + 1);
/*--------clk_a--------*/
reg         r_trans_a       ;
reg         r_ack_a1        ;
reg         r_ack_a2        ;
/*--------clk_b--------*/
reg         r_single_b      ;
reg         r_single_b1     ;
reg         r_single_b2     ;
reg         r_ack_b         ;  
reg  [7:0]  r_cnt_b         ;

wire        w_single_b_pos  ;

assign      o_single_b      = r_single_b                ;
assign      w_single_b_pos  = r_single_b1 & !r_single_b2;

/*--------clk_a--------*/
always @(posedge i_clk_a or posedge i_rst_a) begin
    if(i_rst_a)
        r_trans_a <= 'd0;
    else if(r_ack_a2)
        r_trans_a <= 'd0;
    else if(i_single_a)
        r_trans_a <= 1;
    else
        r_trans_a <= r_trans_a;
end

always @(posedge i_clk_a or posedge i_rst_a) begin
    if(i_rst_a)begin
        r_ack_a1 <= 'd0;
        r_ack_a2 <= 'd0;
    end
    else begin
        r_ack_a1 <= r_ack_b;
        r_ack_a2 <= r_ack_a1;        
    end
end

/*--------clk_b--------*/
always @(posedge i_clk_b or posedge i_rst_b) begin
    if(i_rst_b)begin
        r_single_b1 <= 'd0;
        r_single_b2 <= 'd0;
    end
    else if(r_trans_a)begin
        r_single_b1 <= 'd1;
        r_single_b2 <= r_single_b1;        
    end
    else begin
        r_single_b1 <= 'd0;
        r_single_b2 <= 'd0;
    end
end

always @(posedge i_clk_b or posedge i_rst_b) begin
    if(i_rst_a)
        r_single_b <= 'd0;
    else if(w_single_b_pos)
        r_single_b <= 1;
    else
        r_single_b <= 'd0;
end

always @(posedge i_clk_b or posedge i_rst_b) begin
    if(i_rst_a)
        r_ack_b <= 'd0;
    else if(r_cnt_b == P_CNT_END_B - 1)
        r_ack_b <= 'd0;
    else if(w_single_b_pos)
        r_ack_b <= 1;
    else
        r_ack_b <= r_ack_b;
end

always @(posedge i_clk_b or posedge i_rst_b) begin
    if(i_rst_a)
        r_cnt_b <= 'd0;
    else if(r_cnt_b == P_CNT_END_B - 1)
        r_cnt_b <= 'd0;
    else if(r_ack_b)
        r_cnt_b <= r_cnt_b + 1;
    else
        r_cnt_b <= 'd0;
end

endmodule

波形图,先看A慢B快的情况:
A频率为50Mhz,B频率为200Mhz,所以B的响应信号r_ack_b持续了9个时钟周期,其实这样子做的主要目的就是为了保证慢时钟域A一定存在一个上升沿可以在满足建立时间和保持时间的窗口内采集到响应信号。
在这里插入图片描述
波形图,A快B慢的情况:
A频率为200Mhz,B频率为50Mhz,所以B的响应信号r_ack_b持续了2个时钟周期,这足以保证时钟域A采集响应信号,甚至一个时钟周期都够了,当然这主要是为了确保r_ack_b宽度至少大于俩倍的时钟域A周期。
在这里插入图片描述
以上单bit跨时钟处理方法主要是适用于不连续触发的信号,如果连续触发,由于同步一次需要消耗很多时钟周期,会大量漏采数据,不过一般单bit数据主要是控制信号。
如若碰到了连续触发的情况,则需要采用异步RAM和异步FIFO

五、多bit跨时钟域

  1. 异步FIFO
  2. 双端口RAM
  3. 握手,大概就是把每个bit进行一次握手处理,开销较大
  4. 合并信号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/473999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET-Global.asax使用详解

本文介绍了如何使用Global.asax文件来增强ASP.NET Web应用程序的功能。首先&#xff0c;介绍了Global.asax文件的作用和基本功能。接着&#xff0c;详细探讨了在Global.asax中实现定时任务、应用程序级别的错误处理、应用程序启动和结束时执行特定逻辑等功能。随后&#xff0c;…

函数重载(简易)

1.函数重载的原理&#xff1a; 编译器为了实现函数重载&#xff0c;也是默认为我们做了一些幕后的工作&#xff0c;编译器用不同的参数类型来修饰不同的函数名&#xff0c;比如void func&#xff08;&#xff09;&#xff1b;编译器可能会将函数名修饰成_func,当编译器碰到voi…

YOLOV4-车道线检测-车距离预测

1.前言 最近在看华为的CANN框架&#xff0c;发现了一些很有意思的开源算法(本文所有的代码都出自华为开源git发布的代码)&#xff0c;华为最近出了AI PRO开发板&#xff0c;想着现在开发板上用用(不想重新配置环境了&#xff0c;麻烦还累)&#xff0c;看着代码有onnx的模型&…

种植新革命:科技赋能绿色未来

《种植新革命&#xff1a;科技赋能绿色未来》 一、种植技术的颠覆式创新 随着科技的飞速发展&#xff0c;种植技术也在经历一场颠覆式的创新。传统的种植方式&#xff0c;虽然历史悠久&#xff0c;经验丰富&#xff0c;但在面对现代化、大规模、高效的需求时&#xff0c;逐渐…

Centos7部署单节点MongoDB(V4.2.25)

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

学点Java_Day6_基于Copyright和Actions On Save的IDEA自动更新文件最后编辑时间的方法研究(IDEA2021.2及以上)

0 版本要求 IDEA2021.2及以上&#xff0c;我用的IntelliJ IDEA 2023.2.4 1 操作 1.1 Copyright设置 ① CtrlAltS打开设置&#xff08;Settings&#xff09;→ Editor → Copyright   ② Copyright → Copyright Profiles → → 取名 → OK   ③ 复制下面内容到框里&am…

2024蓝桥杯每日一题(并查集)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;奶酪 试题二&#xff1a;合并集合 试题三&#xff1a;连通块中点的数量 试题四&#xff1a;网络分析 试题一&#xff1a;奶酪 【题目描述】 现有一块大奶酪&#xff0c;它的高度为 hℎ…

PyTorch 深度学习(GPT 重译)(六)

十四、端到端结节分析&#xff0c;以及接下来的步骤 本章内容包括 连接分割和分类模型 为新任务微调网络 将直方图和其他指标类型添加到 TensorBoard 从过拟合到泛化 在过去的几章中&#xff0c;我们已经构建了许多对我们的项目至关重要的系统。我们开始加载数据&#xf…

【遥感入门系列】遥感图像预处理需要哪些步骤

图像预处理是遥感应用的第一步&#xff0c;也是非常重要的一步。目前的技术也非常成熟&#xff0c;大多数的商业化软件都具备这方面的功能。预处理的流程在各个行业、不同数据中有点差异&#xff0c;而且注重点也各有不同。 本小节包括以下内容&#xff1a; 数据预处理一般流…

纵览机器学习前生今世,万字整理谷歌首席科学家 Jeff Dean 一小时演讲

经过算法的改进和机器学习专用硬件的显著提升&#xff0c;我们现在能够构建比以往任何时候都更为强大的通用机器学习系统。 演讲者 | Jeff Dean 整理 | 王启隆 自从 2017 年谷歌发表了题为 “Attention is All You Need” 的重磅论文&#xff0c;其中提出的“自注意力”这一革命…

软考高级:结构化需求分析概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

力扣15. 三数之和

思路&#xff1a;先对数组排序&#xff0c;然后确定第一个数nums[i]&#xff0c;再新建左右双指针&#xff1b; 寻找的3元组&#xff0c;a,b,c,即是 nums[i], nums[letf], nums[right] 数组1&#xff1a;-1,-1,-1,0,1,2; 前面3个-1&#xff0c;只有一个-1是有用的&#xff0c;需…

从键盘到屏幕:C语言中输入输出探秘

在编程中&#xff0c;输入和输出是我们与计算机交流的关键。无论是键盘输入还是屏幕输出&#xff0c;它们贯穿了我们每一行代码的编写。本文将带你深入探索C语言中输入输出的精彩世界&#xff0c;解锁其中的奥秘&#xff0c;助你轻松驾驭键盘和屏幕&#xff01;&#xff08;最后…

模型部署 - onnx的导出和分析 - onnx 的架构和 onnx helper 的使用 - 学习记录

onnx 的架构和 onnx helper 的使用 简介一、onnx 的架构二、onnx 实践2.1、 create - linear.onnx2.1.1、要点一&#xff1a;创建节点2.1.2、要点二&#xff1a;创建张量2.1.3、要点三&#xff1a;创建图 2.2、 create - onnx.convnet2.3、使用 onnx helper 导出的基本流程总结…

Docker-镜像仓库

Docker ⛅Docker-Registry&#x1f320;分类&#x1f320;镜像仓库工作机制&#x1f320;常用的镜像仓库&#x1f320;镜像仓库命令☃️docker login☃️docker pull☃️docker push☃️docker search☃️docker logout &#x1f320;镜像命令[部分]☃️docker images☃️docke…

电源配小了,是不是容易烧?是的!

电源小的话会不会容易烧毁&#xff1f; 是的。 功率电压*电流。 随着功率增大&#xff0c;电压不变&#xff0c;电流增大&#xff0c;发热量增大&#xff0c;可能会烧毁。 今天给大家推荐一款650w的电脑电源&#xff0c;不过在推荐之前&#xff0c;首先要确认自己的电脑功耗…

【Internet结构和ISP,分组延时、丢失和吞吐量】

文章目录 一、Internet结构和ISP1.互联网络结构&#xff1a;网络的网络2.Internet 结构&#xff1a;network of networks 二、分组延时、丢失和吞吐量1.分组丢失和延时是怎样发生的&#xff1f;2.四种分组延时3.分组丢失4.吞吐量 一、Internet结构和ISP 1.互联网络结构&#x…

流畅的 Python 第二版(GPT 重译)(十二)

第五部分&#xff1a;元编程 第二十二章&#xff1a;动态属性和属性 属性的关键重要性在于&#xff0c;它们的存在使得将公共数据属性作为类的公共接口的一部分完全安全且确实可取。 Martelli、Ravenscroft 和 Holden&#xff0c;“为什么属性很重要” 在 Python 中&#xff0…

鲁棒的基于表面势的GaN HEMT集成电路紧凑模型

来源&#xff1a;Robust Surface-Potential-Based Compact Model forGaN HEMT IC Design&#xff08;TED 13年&#xff09; 摘要 我们提出了一种精确且稳健的基于表面势的紧凑模型&#xff0c;用于模拟采用氮化镓高电子迁移率晶体管&#xff08;GaN HEMT&#xff09;设计的电…

利用 Claude 3 on Amazon Bedrock 和 Streamlit 的“终极组合”,开发智能对话体验

概述 通过本文&#xff0c;您将学会如何利用 Streamlit 框架快速搭建前端交互界面。该界面将集成图像上传功能&#xff0c;让用户可以方便地提交待处理图片。在后端&#xff0c;我们将借助 Amazon Bedrock 的 Message API&#xff0c;调用 Claude 3 家族中的 Sonnet 模型对图像…