当前位置:   article > 正文

FPGA跨时域之握手信号

握手信号

FPG跨时域之握手信号-简化篇

------热爱生活 热爱时钟 热爱逻辑------

在面试的时候面试官谈到如何解决跨时域的问题,作为一个初学者只知道用异步FIFO来实现同步。然后在博客里看了一些文章,有一些自己的理解记在这里,肯定有不妥之处,仅仅写一写自己的想法。

一、快时域到慢时域-Freq=100m/Freq=50m

复杂的握手协议后期再工作中继续学习会给出自己的理解,目前水平有限,就只有写出简单的握手协议。下图是自己对握手协议的理解:
在这里插入图片描述
图1.1 握手协议模型图
如上图所示,两个时域之间通过请求和应答信号线进行握手,时域A发送请求发送数据信号req,同时是准备好数据;时域B接收到时域A发送的请求信号后,回应一个应答信号ack,同时将数据接收进行寄存;时域A接收到应答信号后重新发送请求信号req,进行第二个数据传输,依次直到完成时域A数据发送完成。
但是要注意程序设计,不正确的程序设计将会发生数据漏取(快时域到慢时域)或者插入数据(慢时域到快时域)。这种握手信号设计是以牺牲时钟为代价而进行的设计,因为跨时域涉及到亚稳态,亚稳态的重要性以及解决方法在其他博文里有详细的解释,请大家自行搜索,本文在接收数据时采用了两级寄存,以保证数据传输的准确性。下面将详细叙述我的程序设计方案(Verilog HDL)。

二、快时域发送数据,慢时域接收数据设计方案

1、设计方案

在本实际案列中使用100mHz频率作为快时域A,A时域控制ROM地址变化,读取ROM的数据,发送到慢时域B,B时域使用50mHz接收时域A的数据。
在这里插入图片描述
图2.1 架构设计

2、程序设计

A时域检测应答信号 ack为低电平时拉高发送请求信号req(高有效),发送数据,A时域检测到应答信号ack上升沿到来时则拉低请求信号req。
B时域检测到 A时域 req请求信号上升沿到来时拉高应答信号ack,接收数据。
设计顶层模块进行仿真测试。

3、程序清单

  • 1).顶层设计
//----跨时域顶层  仿真使用----
module time_top(
						input	clk,		//输入系统时钟50mHz
						input	rst_n,	
						output	[7:0]data_o,
						);
						wire clk_100m;
						wire	rst_en;
						wire	ack1;
						wire	[7:0]data_r;
						wire	req1;
						wire	[7:0]addr;
						wire [7:0]data;
						
						
//----10mHz频率产生----
my_pll inst_my_pll(
								.areset(!rst_n),
								.inclk0(clk),
								.c0(clk_100m),
								.locked(rst_en)
								);
//----ROM 模块 ----								
my_rom inst_my_rom(
								.address(addr),
								.clock(clk_100m),
								.q(data)
								);
//----快时域A----								
transmit_100m transimt(
								.clk(clk_100m),
								.rst_n(rst_en),
								.ack(ack1),
								.data_in(data),
								.data_out(data_r),
								.req(req1),
								.addr(addr)
										);
//----慢时域B----										
receive_50m	recive(
							.clk(clk),
							.rst_n(rst_n),
							.req(req1),
							.data_in(data_r),
							.data_out(data_o),
							.ack(ack1)
							);	
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 2).A时域程序设计-发送数据,数据源来自ROM.
//---快时域 100mHz  发送ROM中的数数据----
module transmit_100m(
							input	clk,			//100mHz
							input	rst_n,			//低电平复位
							input	ack,			//应答信号
							input	[7:0]data_in,	//数据收入
							output	[7:0]data_out,	//输出数据
							output	reg  req,			//发送请求信号
							output	reg	 [7:0]addr			//ROM地址
							);
//-----接收应答信号并寄存----
reg	ack_r1;
reg	ack_r2;
reg	ack_r3;
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		ack_r1<=0;
		ack_r2<=0;
		ack_r3<=0;
	end
	else begin
		ack_r1<=ack;
		ack_r2<=ack_r1;
		ack_r3<=ack_r2;
	end
end
//----两级寄存,原理请参考其他博文-----
wire 	 pos_ack1;
wire	 pos_ack2;
assign pos_ack1=ack_r1	&	(~ack_r2);	//检测ack信号上升沿
assign pos_ack2=ack_r2	&	(~ack_r3);	//ack信号上升沿延时一个周期

//----产生发送数据请求信号-----
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		req<=0;
	end
	else begin
		if(ack==0)begin		//应答信号为低电平时表示数据总线空闲,可以接收数据
			req<=1;		//如果外部控制 req,可引入使能信号,使能信号有效时req拉高
		end
		else if(pos_ack2)begin	//检测到ack应答信号上升沿,请求信号拉低,停止发送数据
			req<=0;
		end
	end
end
//----请求信号下降沿检测,当请求信号下降沿到来时,ROM地址加一,为下一次发送数据做好准备----
reg	req1;
reg	req2;
wire	neg_req;
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		req1<=0;
		req2<=0;
	end
	else begin
		req1<=req;
		req2<=req1;
	end
end
assign	neg_req=req2&(~req1);	//检测请求信号req下降沿

//----发送数据状态设计----
reg	[1:0]state;
reg	[7:0]data_r;	//数据寄存器,对输入数据进行寄存
parameter idle=2'd0;	
parameter transimt=2'd1;
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		state<=idle;
		addr<=8'd0;
	end
	else begin
				case(state)
				idle	:	begin
				if(req)begin	//发送数据请求信号到来,则接收输入数据
				state<=transimt;
			  data_r<=data_in;
				end
			 else begin
				state<=idle;
			end
		end
		transimt		:	begin
				if(neg_req)begin	//请求信号下降沿到来,地址加1,为下一次发送数据做好准备
				addr<=addr+1;
				state<=idle;
				end
				else begin
				state<=transimt;
				end
			end			
		default :	state<=idle;		
		endcase
	end
end
assign data_out=data_r;	//将寄存器的数据输出
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 3).B时域接收数据-50mHz接收数据
//----慢时域接收数据----
module receive_50m(
							input   clk,//50m
							input	rst_n,
							input	req,
							input	[7:0]data_in,
							
							output	 [7:0]data_out,
							output	reg ack
							);
//----寄存数据请求信号----
reg req_r1;
reg req_r2;
reg req_r3;

always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		req_r1<=0;
		req_r2<=0;
		req_r3<=0;
	end
	else begin
		req_r1<=req;
		req_r2<=req_r1;
		req_r3<=req_r2;
	end
end
wire pos_req1;
wire	pos_req2;
assign pos_req1=req_r1	&	(~req_r2);//检测req信号上升沿
assign pos_req2=req_r2	&	(~req_r3);//两级寄存
//----进行接收数据----
reg	[7:0]data_r;//数据寄存
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		data_r<=0;
	end
	else if(pos_req1)
			data_r<=data_in;
end
//----应答信号产生----
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		ack<=0;
	end
	else begin
		if(pos_req2)		//检测到 req信号的上升沿,则进行数据接收
			ack<=1;
		else if(!req)		//当检测到 req信号拉底后,应答信号拉低
			ack<=0;
	end
end
assign data_out=data_r;
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

2、仿真测试

  • 1).顶层波形
    在这里插入图片描述
  • 2).快时域A仿真波形
    在这里插入图片描述
  • 3).慢时域B仿真波形
    在这里插入图片描述
    通过波形仿真可以发现该设计满足设计需求,从快时域发送数据到慢时域,数据没有发生遗漏。
    注:本设计尚未设计时序约束。
    慢时域到快时域的设计在下一章总结,涉及到更多的时域就需要仲裁模块,这些也到后面再说。学识有限,一起努力,共同奋进。转载请注明出处。

------热爱生活 热爱时钟 热爱逻辑------

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/206900
推荐阅读
相关标签
  

闽ICP备14008679号