这是我的verilog代码:
//state reg
(* syn_encoding = "safe" *)reg [3:0] ns_sig, cs_sig;
//state parameters
localparam
sLOW = 4'b0001,
sTO_HIGH = 4'b0010,
sHIGH = 4'b0100,
sTO_LOW = 4'b1000;
always @(posedge clk or negedge rst_n)
if (!rst_n)
cs_sig <= sLOW;
else
cs_sig <= ns_sig;
always @(*)
begin
ns_sig = cs_sig;
case (cs_sig)
sLOW:
if (sig == `HIGH)
ns_sig = sTO_HIGH;
sTO_HIGH:
if (valid_HIGH == `ON)
ns_sig = sHIGH;
else if (sig == `OFF)
ns_sig = sLOW;
sHIGH:
if (sig == `OFF)
ns_sig = sTO_LOW;
sTO_LOW:
if (valid_LOW == `ON)
ns_sig = sLOW;
else if (sig == `ON)
ns_sig = sHIGH;
default:
ns_sig = sLOW;
endcase
end
always @(posedge clk)
begin
if (cs_sig == sTO_HIGH)
cnt_HIGH <= cnt_HIGH + {{(pWIDTH-1){1'b0}}, 1'b1};
else
cnt_HIGH <= {(pWIDTH){1'b0}};
end
assign
valid_HIGH = (cnt_HIGH == pHIGH_DEPTH -1)? `ON:`OFF;
always @(posedge clk)
begin
if (cs_sig == sTO_LOW)
cnt_LOW <= cnt_LOW + {{(pWIDTH-1){1'b0}}, 1'b1};
else
cnt_LOW <= {(pWIDTH){1'b0}};
end
assign
valid_LOW = (cnt_LOW == pLOW_DEPTH - 1)?`ON:`OFF;
always @(posedge clk)
begin
if (cs_sig == sHIGH)
sig_sf <= `HIGH;
else if (cs_sig == sLOW)
sig_sf <= `LOW;
end
它是一个二进制信号滤波器模块,旨在确定物理端口上的毛刺,并且可以同时用作延迟器。
它在模拟上运行良好,但不在船上。我在Altrea EP2C35芯片上运行代码,它时不时出错。通常,sig_sf
将pLOW_DEPTH
(我将其设置为200)clks在输入sig
后面,但有时只会落后2个。
我添加了一个信号标记,看看发生了什么,结果发现状态机出了问题。 signaltap上的有效值为:sLOW, sTO_LOW, sHIGH, s_TO_HIGH
,就像我设置的那样。但它在4'h1
的某个负边缘转到sig
并重置为sLOW
。
但我不明白为什么,我确信来自发电机的输入波很好。
所以请帮助我,谢谢!!
答案 0 :(得分:2)
您的always @(*)
根据内部(时钟)信号和外部输入创建组合逻辑。外部输入可以随时改变,因此有时在always @(posedge clk)
块中注册的逻辑会出现毛刺,因为组合逻辑的输出不符合FPGA中寄存器所需的建立和保持时间。在您可以对输入进行“大规模”去毛刺之前,您需要对输入进行单clk缩放去毛刺。您可以使用同步器执行此操作。
请参阅Understanding Metastability in FPGAs以获取Altera关于此主题的白皮书。如果您使用Google同步器/亚稳态,您会发现大量的参考资料。
您可能想知道为什么模拟没有显示问题。时间分析器会检测到这种问题,但您必须在约束文件中告诉它您的信号,以便它知道发生了什么。您的代码没有任何问题。问题是物理信号sig
。如果时序分析仪知道它位于与clk
无关的时钟域中,它可能会发出警告。
此外,您已经发现状态机中存在单热编码的危险:您的4位状态变量有4个有效值和12个无效的“漏洞”,您可能会陷入困境。