当前位置:网站首页>FPGA刷题——跨时钟域传输(FIFO+打拍+握手)
FPGA刷题——跨时钟域传输(FIFO+打拍+握手)
2022-07-29 13:33:00 【居安士】
继续牛客网的刷题,这一部分是跨时钟域传输,有下面的几道题:

FIFO的编写详见存储器篇:(2条消息) FPGA刷题——存储器(RAM和FIFO的Verilog实现)_居安士的博客-CSDN博客
目录
格雷码计数器

使用自然二进制码计数时,相邻数据之间可能会产生多bit的变化。这会产生较大的尖峰电流以及其他问题。格雷码是一种相邻数据只有1bit变化的码制。
转换公式如下:

最高位保留,gray[最高位]=bin[最高位]
低位由本位和高位异或得到, gray[i]=bin[i]^bin[i+1] 或者 gray=bin^(bin>>1)
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
reg [3:0] bin_cnt;//二进制计数器
reg flag;//
[email protected](posedge clk or negedge rst_n)begin
if(~rst_n)begin
flag<=1'b0;
end
else begin
flag<=~flag;//根据波形图,计数器两个周期变化一次
end
end
[email protected](posedge clk or negedge rst_n)begin
if(~rst_n)begin
bin_cnt<=4'b0;
end
else begin
bin_cnt<=flag?bin_cnt+4'b1:bin_cnt;//产生二进制码
end
end
[email protected](*)begin
gray_out<=bin_cnt^(bin_cnt>>1);
end
endmodule跨时钟多bit数据同步器

这个题要求我们把a时钟域的数据data_in传递到b时钟域的data_out,由a时钟域的使能信号控制
data_in:数据输入;data_en:输入数据有效;dataout数据输出。
步骤如下:
(1)输入数据暂存在data_reg中
(2)使能信号data_en在A时钟域缓存,再打两拍的方式跨时钟域传输到时钟域B
(3)最后data_out根据使能信号更新数据
module mux(
input clk_a ,
input clk_b ,
input arstn ,
input brstn ,
input [3:0] data_in ,
input data_en ,
output reg [3:0] dataout
);
reg [3:0] data_reg;
//a时钟域下数据缓存
[email protected](posedge clk_a or negedge arstn)begin
if(~arstn)begin
data_reg<=4'd0;
end
else begin
data_reg<=data_in;
end
end
//使能信号打拍
reg data_en_a, data_en_b0, data_en_b1;
[email protected](posedge clk_a or negedge arstn) begin//使能信号暂存
if(~arstn)
data_en_a <= 0;
else
data_en_a <= data_en;
end
[email protected](posedge clk_b or negedge brstn) begin//打2拍送到b时钟域
if(~brstn) begin
data_en_b0 <= 0;
data_en_b1 <= 0;
end
else begin
data_en_b0 <= data_en_a;
data_en_b1 <= data_en_b0;
end
end
//使能信号控制输出
[email protected](posedge clk_b or negedge brstn) begin
if(~brstn)
dataout <= 0;
else
dataout <= data_en_b1? data_reg: dataout;
end
endmodule快慢时钟下的脉冲同步电路实现

题目要求将高频率clk下的脉冲信号传递到低频率clk下,直接传输会导致低clk有可能采集不到脉冲信号,如下图:

握手信号法
`timescale 1ns/1ns
module pulse_detect(
input clk_fast ,
input clk_slow ,
input rst_n ,
input data_in ,
output dataout
);
reg fast_req, slow_ack;
reg [2:0] slow_req;
reg [2:0] fast_ack;
//fast时钟域
//将slow时钟域的应答信号打三拍,送到fast时钟域
always @(posedge clk_fast, negedge rst_n) begin
if(!rst_n) begin
fast_ack <= 3'b0;
end else begin
fast_ack <= {fast_ack[1:0], slow_ack};
end
end
//生成请求信号fast_req
always @(posedge clk_fast, negedge rst_n) begin
if(!rst_n) begin
fast_req <= 1'b0;
end else if (data_in) begin
fast_req <= 1'b1;
end else begin
fast_req <= (fast_ack[1] & (~fast_ack[2])) ? 1'b0 : fast_req;
end
end
//slow时钟域
//将fast时钟域的请求信号打三拍,送到slow时钟域
always @(posedge clk_slow, negedge rst_n) begin
if(!rst_n) begin
slow_req <= 3'b0;
end else begin
slow_req <= {slow_req[1:0], fast_req};
end
end
//生成应答信号slow_ack
always @(posedge clk_slow, negedge rst_n) begin
if(!rst_n) begin
slow_ack <= 1'b0;
end else if (slow_req[1] & (~slow_req[2])) begin
slow_ack <= 1'b1;
end else begin
slow_ack <= (slow_req[2] & (~slow_req[1])) ? 1'b0 : slow_ack;
end
end
assign dataout = (~slow_req[2]) & (slow_req[1]);
//
endmodule
边沿检测法
边沿检测法适用于快频率clk下的脉冲信号相隔距离够远,否则低clk仍然可能会采集不到脉冲信号
步骤如下:
(1)在快clk下进行脉冲展宽:脉冲信号每高电平一次,脉冲展宽高低电平转换一次
(2)设置3bit寄存器缓存脉冲展宽值(理解为打三拍,取2、3拍的沿)(第一拍用于避免亚稳态)
(3)当脉冲展宽值不相同时说明脉冲信号输出

`timescale 1ns/1ns //二、基于边沿检测的方式
module pulse_detect(
input clk_fast ,
input clk_slow ,
input rst_n ,
input data_in ,
output dataout
);
reg req;
reg [2:0] req_r;
always @(posedge clk_fast or negedge rst_n) begin
if(!rst_n)
req<=1'b0;
else if(data_in) //req检测到data_in拉高就翻转,保持住,相当于脉冲展宽。但有缺陷,如果data_in两次高电平变化太快,B来不及采样,就会漏采,产生错误。
req<=~req; //题目说A时钟域脉冲之间的间隔很大,无需考虑脉冲间隔太小的问题,则不用考虑data_in变化太快。
end
always @(posedge clk_slow or negedge rst_n) begin
if(!rst_n)
req_r<=3'b0;
else
req_r<={req_r[1:0],req};
end
assign dataout=req_r[1] ^ req_r[2]; //用异或表示连续2次data_in变化都被采样到。
endmodule边栏推荐
- 【模板引擎】微服务学习笔记六:freemarker模板引擎的常用命令介绍
- 【论文阅读】Anomaly Detection in Video via Self-Supervised and Multi-Task Learning
- How to set the explosion rate of legendary humanoid?Humanoid increase tutorial
- 2022年七夕情人节有什么值得推荐的礼物选择?实用且高级礼物推荐
- 【论文阅读】异常检测的视频通过Self-Supervised和多任务学习
- 十种实现延迟任务的方案
- HCIP第十三天笔记(BGP的路由过滤、BGP的社团属性、MPLS)
- 【JS面试题】面试官问我:遍历一个数组用 for 和 forEach 哪个更快?
- 系列文章|云原生时代下微服务架构进阶之路 - Boris
- 程序员入门的第一个程序,打印输出 “ HelloWorld “
猜你喜欢

Project Manager: Not bad!The SSO single sign-on code is written, and the sequence diagram is also drawn?

The new technical director, who is in the form of a isXxx Boolean type definition, tomorrow need not come!

分布式事务方案

少儿编程 电子学会图形化编程等级考试Scratch二级真题解析(选择题)2022年6月

human pose estimation-DEKR2021CVPR

【微信小程序】全局配置

Children's programming electronics (graphical programming Scratch secondary level exam parsing (choice) in June 2022

线程池拒绝策略详解

C#线程操作UI控件

电子游戏的核心原理
随机推荐
R Error in :missing values are not allowed in subscripted assignments of data frames
What is the difference between the legendary server GOM engine and the GEE engine?
Linux下 mysql5.7的彻底卸载
有关包装类的一道经典面试题
【MySQL】ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/tmp/mysql.sock‘
leetcode linked list topic
搞直播啦,千视超高清4K NDI编解码器8月3日19:00准时开播
2022年了!还在用定时器实现动画?赶紧试试requestAnimationFrame吧!
TAP 文章系列-10 | 从应用感知能力谈 TAP 的约定服务
Research on the thinking and application methods of the frontier of ESI research
torchvison里面的数据增强
如何使用MISRA改进嵌入式编程
R错误:缺少值不允许写在下面的作业的数据帧
PAT 甲级 A1021 Deepest Root
【JS面试题】面试官问我:遍历一个数组用 for 和 forEach 哪个更快?
程序员是职业病高发群体,别天真的以为只有秃头那么简单,才不是呢。
企业需要知道的5个 IAM 最佳实践
zabbix一键部署脚本----亲测可用
线程池面试汇总
Leetcode66. 加一