电力电子转战数字IC20220527day11——单bit跨时钟域

题目:

1.使用Verilog语言,将单bit宽度为10ns的data信号由频率为周期为10ns的时钟域同步至周期为7ns的时钟域,(慢到快)。
2.使用Verilog语言,将单bit宽度为14ns的data由频率为周期为7ns的时钟域同步到周期为20ns的时钟域,确保同步后的频率展宽为一个时钟周期。(快到慢)

问题1

单bit宽度10ns,周期10ns,7ns,20ns具体有什么关系?

问题2

从慢的时钟传到快的时钟,反之,会存在什么问题?

目的1

先解决题目1,宽度10ns的data,周期也是10ns,要变成7ns的周期

方案1

按如下图所示的方法来实现,当data出现时,首先由慢时钟clk1采集到,赋给寄存器datar ,然后触发快时钟clk2,赋给datarr[0],用上次学习的非阻塞赋值打两拍同步输出的方法,再写一个非阻塞赋值[0]给[1],就可以实现打两拍同步输出到clk2。

module onebittwoclk(clk1,clk2,rst,data,dataout);
input clk1;//慢的时钟
input clk2;//快的时钟
input rst;
input data;
output dataout;

reg datar;
reg [1:0] datarr;

always @(posedge clk1 or negedge rst)
begin
if(!rst)
datar<=0;
else
datar<=data;
end

always @(posedge clk2 or negedge rst)
begin
if(!rst)
datarr<=2'd0;
else
	begin
	datarr[0]<=datar;
	datarr[1]<=datarr[0];
	end
end 

assign dataout=datarr[1];

endmodule 
`timescale 1ns/1ps

module onebittwoclktest;

reg clk1;//慢的时钟
reg clk2;//快的时钟
reg rst;
reg data;
wire dataout;

onebittwoclk u1(.clk1(clk1), .clk2(clk2), .rst(rst), .data(data), .dataout(dataout));

always #5 clk1=!clk1;
always #3.5 clk2=!clk2;

initial
begin
clk1=0;clk2=0;data=0;rst=1;
#13 rst=0;
#10 rst=1;
#4 data=1;
#10 data=0;
#40 data=1;
#10 data=0;
#50 data=1;
#10 data=0;
#60 data=1;
#10 data=0;
#70 data=1;
#10 data=0;
#30 $stop;
end

endmodule 

 最后发现问题:有的输出可以正常输出一个快周期,但是有的输出是两个周期,研究过后发现原因可能是:

如果时钟触发的顺序是:慢快快慢,data早就已经消失了,但是慢时钟太慢采不到,快时钟连续两个周期采集到的datar都是1,所以打多了一拍,输出是两个周期。

如果时钟触发的顺序是:慢快慢快,就可以正常输出。

目的2

 将14ns宽的data从周期7ns的快时钟同步到周期20ns的慢时钟,且保证输出是一个周期。

由于data比20ns短,可能会出现20ns采不到data的问题。

方案2

为了保证慢时钟一定可以采集到data,在data出现时进行信号展宽成电平信号,也就是让他一直是高电平。可以用异或门,mux多路器来实现。

具体流程:

 a.首先是当data到来时,用data和寄存器datar做一个异或获得高电平highlevel,data为1datar为0,highlevel为1。

b.当快时钟clk2上升沿到来时,将highlevel赋给datar,此时highlevel变回0,直到data结束变成0,highlevel从此就一直为1。

c.当慢时钟clk1上升沿到来时,寄存器datar的值打两拍给到datarr[1],和慢变快的时候写的是一样的,所以在下个clk1上升沿时datarr1置1。

d.最后是边沿同步,将输出dataout设置为datarr1和dataedge的异或,在c中由于datarr1置1,所以输出为1,在这里将datarr1的值赋给dataedge,打多一拍,再做个异或,相同出0,输出置为0,保证输出为一个慢周期。

module onebittwoclk(clk1,clk2,rst,data,dataout);
input clk1;//慢的时钟
input clk2;//快的时钟
input rst;
input data;
output dataout;

wire highlevel;//存放高电平,数据和数据寄存器异或

reg datar;
reg [1:0] datarr;
reg dataedge;
assign highlevel= data^datar;

//快时钟采集到高电平后赋给寄存器
always @(posedge clk2 or negedge rst)
begin
if(!rst)
datar<=0;
else
datar<=highlevel;
end
//一样是对目标周期慢周期打两拍输出
always @(posedge clk1 or negedge rst)
begin
if(!rst)
datarr<=2'd0;
else
	begin
	datarr[0]<=datar;
	datarr[1]<=datarr[0];
	end
end 
//做一个边沿同步并输出
always @(posedge clk1 or negedge rst)
begin
if(!rst)
dataedge<=0;
else
dataedge<=datarr[1];
end 
assign dataout=dataedge^datarr[1];

endmodule 
`timescale 1ns/1ps

module onebittwoclktest;

reg clk1;//慢的时钟
reg clk2;//快的时钟
reg rst;
reg data;
wire dataout;

onebittwoclk u1(.clk1(clk1), .clk2(clk2), .rst(rst), .data(data), .dataout(dataout));

always #10 clk1=!clk1;
always #3.5 clk2=!clk2;

initial
begin
clk1=0;clk2=0;data=0;rst=1;
#13 rst=0;
#10 rst=1;
#4 data=1;
#7 data=0;
//#40 data=1;
//#7 data=0;
//#50 data=1;
//#7 data=0;
//#60 data=1;
//#7 data=0;
//#70 data=1;
//#7 data=0;
#100 $stop;
end

endmodule 

 

 总结

花了整整一天才搞定的题目。主要有以下几个点:

1  从慢到快,快周期必然可以采集到data。但是从快到慢,由于可能存在data的长度都不够慢周期长,采集不到,需要将data进行展宽。

2 展宽的方法是data和寄存器进行异或,保证data出现后可以进入到datar

3 最后的边沿同步也是用异或的方法实现,在下一个慢时钟上升沿的时候做一个datarr1赋值给dataedge后再异或,就可以将输出置为0,保证输出是一个慢时钟周期。

华为树枝江哥的指导

 单bit慢到快,直接打拍,两三拍,
单bit快到慢,先展宽再打拍,两三拍

多bit的跨时钟,一般有用握手,格雷码,异步fifo,异步ram的方法

目的就是跨时钟域传输数据,保证你的信号到目标时钟域能被正确采样,不会出现亚稳态,那问题来了,什么是亚稳态

是啊,你都同步到目标时钟了,就要按目标时钟的频率来,不然同步就没意义了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值