Menu Close

亚稳态消除及边沿提取Verilog实现

在异步串行通信中,能准确的把时钟信息提取出来是后面正确进行数据解调的的保证。下面以4倍过采样为例介绍边沿提取的Verilog程序。由于利用本地异步时钟对接收信号进行采样,会带来亚稳态等不确定因素,因此在采样前需要对被采样信号进行同步化。同步化的结果可以较好的消除亚稳态影响,但对于像glitch(短脉冲干扰)等噪声却不能很好的免疫,当glitch的脉冲宽度可以与过采的时钟相比拟时,glitch信号可能会得到有效的传播,严重影响数据解调效果。对于这个问题我们会在专门的文章中讲解。

1.采样信号同步化

采样信号同步化,一般是利用本地时钟对接收信号采样(寄存器时钟锁存)以消除亚稳态的影响,建议对被采样信号做两级锁存,最低要求也要做一级锁存。

    接收信号同步化程序如下:

module sync_rx
(
    input      loc_clk,   //本地时钟,与rx是异步时钟的关系
    input      rx,
    output reg sync_rx,  //与时钟同步后的信号
    output reg nsync_rx, //反相同步信号
    input  rst
);

reg  rx_r;

always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r	<= 0;
    sync_rx	<= 0;
    nsync_rx    <= 0;     //或者nsync_rx <=1'b1; 根据需要
end
else begin
    rx_r        <= rx;    //first level registered;
    sync_rx     <= rx_r;  //second level registered;
    nsync_rx    <= ~rx_r; //inversed second level registered signal;
end

endmodule

上例中输出了两个与loc_clk同步的信号,分别为sync_rx及反相的nsync_rx。

2.上升沿单脉冲提取

 方法1 :逻辑电路实现

同步化后的信号如果上一次的采样为0,本次采样为1,则可以得到上升沿的脉冲。上升沿单脉冲提取程序如下:

module rising_pulse
(
    input       loc_clk,
    input       rx,
    output reg  rx_rising_pulse,
    input  	rst
);

reg  rx_r;
reg  nsync_rx;
always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r            <= 0;
    nsync_rx        <= 0;
    rx_rising_pulse <= 0;
end
else begin
    rx_r            <= rx;     //first level registered ;
    nsync_rx        <= ~rx_r;  //second level registered ;
    rx_rising_pulse <= rx_r & nsync_rx;
end

endmodule

 

仿真程序 tb_rising_pulse.v 如下:

`timescale 1 ns / 1 ps
module tb_rising_pulse
(
);


parameter PERIOD = 10 ;  		//周期10 ns
reg inclk = 0;
 	
initial  begin
    inclk = 1'b0;
    #(PERIOD/2);
    forever
        #(PERIOD/2) inclk = ~inclk;
end
    
reg   rst;
reg   rx;
wire  rx_rising_pulse;
initial begin
    rst = 1;
    rx = 0;
    #2
    rx = 1'b0;
    
    #10
    rst = 0;
    
    #10
    rx = 0;
    #40
    rx = 1;
    #80
    rx = 0;
    #120
    rx = 1;
    #40
    rx = 0;
    #80
    rx = 0;
    #160
    rx = 1;
    #40
    rx = 0;
$stop;


end

rising_pulse rising_pulse_inst
(
    .loc_clk         (inclk),
    .rx              (rx),
    .rx_rising_pulse (rx_rising_pulse),
    .rst             (rst)
);


endmodule

仿真波形如图1所示:

图1

图1中的波形可以看出,nsync_rx是rx_r的取反锁存,时间上之后rx_r一个过采样时钟,因此二者相与即可得到一个过采样时钟宽度的单脉冲信号。

由于rx_r仅一次锁存就参与了运算,对亚稳态的消除不够理想,因此上述代码也可以再加一级寄存器,修改的程序如下,

module rising_pulse
(
    input      loc_clk,
    input      rx,
    output reg rx_rising_pulse,
    input      rst
);

reg  rx_r;
reg  rx_rr;
reg  nsync_rrx;
always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r		<= 0;
    rx_rr		<= 0;
    nsync_rrx 		<= 0;
    rx_rising_pulse     <= 0;
end
else begin
    rx_r		<= rx;   		//first level registered ;
    rx_rr		<= rx_r;     		//second level registered ;
    nsync_rx		<= ~rx_rr;    		//inverted registered ;
    rx_rising_pulse	<= rx_rr & nsync_rx;	//rising edge pulse;
end


endmodule

方法2 :移位寄存器相邻位为2’b01

相同的功能还可以用更容易理解的方式实现,即采用if语句判断前一个时钟采样为低电平,后一个时钟采样为高电平就可以得到上升沿单脉冲信号。

module rising_pulse_1
(
    input  		loc_clk,
    input  		rx,
    output	reg 	rx_rising_pulse,
    input  		rst
);

reg [2:0]  rx_r;


always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r	    <= 0;
    rx_rising_pulse <= 0;
end
else begin
    rx_r <= {rx_r[1:0], rx};   //left shift register;
 
    if(rx_r[2:1] == 2'b01)
        rx_rising_pulse	<= 1'b1;        //rising edge pulse;
    else 
        rx_rising_pulse	<= 1'b0;
end

endmodule

上例利用了移位寄存器的方式实现亚稳态的消除,在if语句中使用了rx_r[2:1],rx_r[2]和rx_r[1]都是经过两级或两级以上本地时钟锁存的寄存器,对于亚稳态的消除有理想的效果。由于移位寄存器的原因,当前时刻rx_r等于2’b01时,下一时刻无论rx_r[0]为0还是为1,rx_r[2:1]更新后都不可能再为2’b01,因此rx_rising_pulse只能维持一个时钟宽度的脉冲。

3. 下降沿脉冲提取

下降沿的分析原理与上升沿非常类似,仅作非常简单分析,后面给出实现实例

方法1:逻辑电路法

逻辑电路如图2,

图2

verilog程序如下:

module falling_pulse
(
    input  		loc_clk,
    input  		rx,
    output	reg 	rx_falling_pulse,
    input  		rst
);

reg   rx_r;
reg   nrx_r;
reg   nrx_rr;


always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r             <= 0;
    nrx_r            <= 0;
    nrx_rr           <= 0;
    rx_falling_pulse <= 0;
end
else begin
   rx_r             <= rx;           //left shift register;
   nrx_r            <= ~rx_r;
   nnrx_r           <= ~nrx_r;
   rx_falling_pulse <= nrx_r & nnrx_r; //falling edge pulse;

end

endmodule

方法2:移位寄存器法

直接利用if语句判断上寄存器rx_r[2:1]是否为2’b10(一个时钟为高电平,下一个时钟为低电平),来设置下降沿信号rx_falling_pulse, 程序如下,

module falling_pulse_shift
(
    input        loc_clk,
    input        rx,
    output  reg  rx_falling_pulse,
    input        rst
);

reg [2:0]  rx_r;

always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r	     <= 0;
    rx_falling_pulse <= 0;
end
else begin
    rx_r <= {rx_r[1:0], rx};   //left shift register;
 
    if(rx_r[2:1] == 2'b10)
        rx_falling_pulse <= 1'b1;	           //falling edge pulse;
    else 
        rx_falling_pulse <= 1'b0;
end

endmodule

4.  双边沿提取

双边沿提取就是将上升沿与下降沿的提取合并,可以将上述程序合并提取,但如果只想获得双边沿,而不区分双边沿的中的上升沿还是下降沿,可以用异或的方式实现。程序如下,

module dual_edge_pulse_shift
(
    input  		loc_clk,
    input  		rx,
    output	reg 	rx_dual_edge_pulse,
    input  		rst
);

reg [2:0]  rx_r;

always@(posedge loc_clk or posedge rst)
if(rst) begin
    rx_r	       <= 0;
    rx_dual_edge_pulse <= 0;
end
else begin
   rx_r			<= {rx_r[1:0], rx};   //left shift register;
   rx_dual_edge_pulse	<= rx_r[2] ^ rx_r[1]; //dual edge pulse;
end

endmodule

边沿提取对于异步采样的同步化具有非常重要的意义,下节内容将介绍位同步信号提取。

 

Posted in FPGA, FPGA 教材教案, 教材与教案, 文章

发表回复

相关链接