请教: 输入信号为什么必须要时钟同步?
module test1 ( input nRST,
input clk,
input Ctrl,
output Pulse,
output led );
reg cnt;
reg state;
/*---------------------------------*/
//reg CTRL;
//always @( posedge clk )
// CTRL <= Ctrl;
/*---------------------------------*/
always @( posedge clk )
begin
if(!nRST )
begin
cnt <= 4'd0;
state <= 2'd0;
end
else
case(state)
0:
if(Ctrl) state <= 2'd1; //这里用CTRL没有问题
1:
if(cnt==0)
cnt <= cnt+4'd1;
else
begin
cnt <= 4'd0;
state <= 2'd2;
end
2:
if(cnt==0)
cnt <= cnt+4'd1;
else
begin
cnt <= 4'd0;
state <= 2'd0;
end
default:
state <= 2'd0;
endcase
end
assign Pulse = ( state==2'd2);
assign led = ~Ctrl;
assign led = ~Pulse;
assign led = 2'b11;
endmodule
上面代码用Ctrl控制产生脉冲,实际下载到板子不能工作,复位后如果Ctrl为高,可以输出脉冲,但只要切换Ctrl后,就再也不输出脉冲了。如果用时钟同步的CTRL(注释部分),则工作正常,不明白为什么?
两次编译出来消耗的资源是一样的么?有可能被优化掉了。 这个就是亚稳态问题了吧亲。
外部来的信号,必须经过两次D触发器进行时钟同步之后,才能当作内部信号来用。
第一次经过D触发器时假如外部信号被采集为亚稳态信号(外部信号的电压 被采集为处于逻辑电平0和1之间,称为亚稳态),则输出是“不定态”,但是这个不定态是可以被当作“逻辑电平0和1”使用的。
就是第一个D触发器输出结果非0即1。
第二次经过D触发器,只是为了防止经过第一次D触发器之后,电平仍是“亚稳态”的这种意外情况。说白了第二个D触发器,只是为了防止意外,保险起见。
其实你可以理解,经过第一个D触发器是在把外部信号同步到内部。
还可以理解为 为了增强外部信号的驱动能力。
最主要的,是防止亚稳态情况出现。
涉及到外部信号输入时,一定要注意亚稳态情况!!
串口、SPI、IIC等等接收的信号,都是外部信号。。。
不知道说的对不对。。。互相交流
被编译器编译成什么东东了?
我觉得这个程序比较简单,可以到RTL层直接分析硬件实现
分析到底哪里出了问题 ziruo2002ab 发表于 2016-3-22 20:54
被编译器编译成什么东东了?
我觉得这个程序比较简单,可以到RTL层直接分析硬件实现
分析到底哪里出了问题 ...
其实编译没什么问题,比较了下,用同步过的外部信号仅仅只是多了个D触发器。而且我用仿真2个都是没问题的,后来想了下,仿真的时候用的是同一个时钟,所以外部信号实际上是同步的,也就是不能说明问题 状态机你也敢用异步信号来推!!一个亚稳态就不知道进到哪个状态里死掉了。 WM_CH 发表于 2016-3-22 18:14
这个就是亚稳态问题了吧亲。
外部来的信号,必须经过两次D触发器进行时钟同步之后,才能当作内部信号来用。 ...
说的很在理一般情况用两个寄存器来将输入数据存储起来,这样使用的数据亚稳态几率小很多;你说的这个可以理解成用同步寄存器链来消除亚稳态问题 本帖最后由 jm2011 于 2016-3-23 11:23 编辑
我的看法:
1: 当你将Ctrl拉低,状态机一直在case 0,结果本来就是这样的,不知道你说的不再输出脉冲是什么意思,(是不是先拉低再拉高,这个时候依然不能输出脉冲?);当然在实际的使用上应该把异步信号打上两拍是最好的;
2:要是我做的话,我会将cnt抽出来,形成一个单独的always来做;不知道我这样想的对不对,有一个单独的计数器,输出一个信号到一个状态机,这个状态机会根据这个计数器的信号来判断自己的 状态;我觉的这样更像一个硬件结构,如下图所示:
对于第二点,需要得到大家的意见,相互学习,相互提高:) jm2011 发表于 2016-3-23 11:09
我的看法:
1: 当你将Ctrl拉低,状态机一直在case 0,结果本来就是这样的,不知道你说的不再输出脉冲是什 ...
一般来说,写状态机要控制流和数据流分开,就是说状态跳转时就不要给数据流赋值,数据流根据状态在另外一个always中,这样写清晰。 far_infrared 发表于 2016-3-23 11:22
一般来说,写状态机要控制流和数据流分开,就是说状态跳转时就不要给数据流赋值,数据流根据状态在另外一 ...
控制流的产生一个always,数据流的产生一个always,状态转移一个always;这个是不是就是所谓的三段式的写法? jm2011 发表于 2016-3-23 11:25
控制流的产生一个always,数据流的产生一个always,状态转移一个always;这个是不是就是所谓的三段式的写 ...
对,我比较喜欢这样用,看着简洁,调试也方便。 far_infrared 发表于 2016-3-23 11:36
对,我比较喜欢这样用,看着简洁,调试也方便。
这次真的是学习了{:handshake:} ,让你这样一说,我也清晰了好多;
以前一直不知道为什么要三段式的; 跨时钟域的问题,这是很常见的 far_infrared 发表于 2016-3-23 11:22
一般来说,写状态机要控制流和数据流分开,就是说状态跳转时就不要给数据流赋值,数据流根据状态在另外一 ...
谢谢,受益匪浅 jm2011 发表于 2016-3-23 11:09
我的看法:
1: 当你将Ctrl拉低,状态机一直在case 0,结果本来就是这样的,不知道你说的不再输出脉冲是什 ...
先拉低再拉高,这个时候依然不能输出脉冲。谢谢,受益匪浅 xyzabc 发表于 2016-3-23 15:09
先拉低再拉高,这个时候依然不能输出脉冲。谢谢,受益匪浅
明天去单位跑一下板子去,抓一下波形看看 。。。。
感觉这个问题很奇怪。 本帖最后由 jm2011 于 2016-3-24 09:46 编辑
在DE0-NANO的板子上实测了一下,没有发现楼主说的问题,Crtl来回的切换都能看见LED的闪烁;
我的时钟比较高,只修改了计数器的范围,其它的和楼主的一样;个人认为这个简单的电路,对Ctrl打不打一排不会影响状态机的运行;
我现在主要不理解的是,1:如果Ctrl第一次是亚稳态的时候状态机会跑到那里去,2:如果Ctrl从亚稳态恢复到稳态,这个状态机还能不能继续跑下去?
javascript:; jm2011 发表于 2016-3-24 09:43
在DE0-NANO的板子上实测了一下,没有发现楼主说的问题,Crtl来回的切换都能看见LED的闪烁;
我的时钟比较 ...
谢谢你的热心,我用的芯片是EPM240,之前试过很多次,刚才又试了下,确实不行。但按照你说的将cnt独立出来改成下面的代码,确实可以
module test( inputnRST,
inputclk,
inputCtrl,
outputPulse,
outputled );
reg cnt;
reg state;
reg cntRst;
wire cntEnd;
/*------------------------------------*/
always @( posedge clk )
begin
if( !nRST || cntRst )
cnt <= 25'd0;
else
cnt <= cnt+25'd1;
end
/*------------------------------------*/
always @( state )
begin
case(state)
0,2:
cntRst = 1;
1,3:
cntRst = 0;
endcase
end
/*------------------------------------*/
always @( posedge clk )
begin
if(!nRST )
state <= 2'd0;
else
case(state)
0:
if(Ctrl) state <= 2'd1;
1:
if(cntEnd) state <= 2'd2;
2:
state <= 2'd3;
3:
if(cntEnd) state <= 2'd0;
endcase
end
assign cntEnd = cnt;
assign Pulse = ( state==1'b1);
assign led = ~Ctrl;
assign led = ~Pulse;
assign led = 2'b11;
endmodule
页:
[1]