Menu Close

UART 接收器设计(RXD)–判多

上节内容讲解了过采样原理以及利用过采样进行数据中间位置的采样,从而消除采样时由于采样点相位不确定带来的亚稳态、抗干扰差,数据误判等因素。本节内容介绍另外一种常用的方法,即将过采样的每个值进行统计,观察在一个数据位的采样中0与1的比例,从而判定该位是0还是1。例如在位的采样中,如果是8倍过采样,则每个数据位总共采样8次,理论上讲如果该数据位为0,则8次采样的值都应该为0。如果该位为1,采样的8次结果都应该为1,但由于频率偏移,采样相位偏移,噪声等各种因素的影响,最终会出现非全1和非全0的情况。因此需要利用判决。下面就起始位的判多采样为例进行介绍。如图1,2

%title插图%num

图1

%title插图%num

图2

  1. 判多的方式依然需要边沿检测配合

边沿检测可以正确定位数据的位置。如图1,由于0采样点为高电平,1采样点为低电平,可以知道在此处有下降沿变化。由此推断采样点1,2…8应该分布在整个数据为上。图2可以看出,如果不考虑边沿检测,从采样点1到8可能随机分布在不同的接收位上,极端的情况如图2,一半采样在IDLE位(高电平),一半在起始位,在这种情况下,判多方法也一样无法正确将接收的位提取出来。

2. 判决方法

如图1,一旦边沿确定后,利用采样点1…8的值就可以进行判决,判决方法如下:采样点1…8中1的个数大于等于5,判定该数据位为1,否则为。

3. 其它接收位的判定

起始位正确定位后,紧随起始位的其它位(数据位、校验位、停止位等)不用判断边沿,直接从下一个的0采样点开始统计每个位的1的个数即可。

例1,利用判多设计RX的参数化接收程序。

module rx_more_one
#(
   parameter PARITY = "ODD",    //"ODD"--odd parity, "EVEN"--even parity, others-->  no parity
   parameter STOP_BIT = 1
)
(

   input sys_clk,
   input rst,
   
   input rx,
   
   input bd8_rate,

   output reg rx_data,
   output reg rx_rdy


);


localparam [ 3: 0 ]
           IDLE0 = 0,
           IDLE1 = 1,
           START = 2,
           FIRST_BIT = 3,
           SEC_BIT = 4,
           THIRD_BIT = 5,
           FOUTH_BIT = 6,
           FIF_BIT = 7,
           SIX_BIT = 8,
           SEVN_BIT = 9,
           EIGTH_BIT = 10,
           PAR_BIT = 11,
           STOP1_BIT = 12,
           STOP2_BIT = 13;


reg [ 1: 0 ] rx_r;
reg rx_nedge; //
reg [ 7: 0 ] rx_data_tmp;
reg [ 1: 0 ] rx_rdy_tmp;
reg [ 7: 0 ] sample_bit;

wire [ 3: 0 ] count_one;
wire rx_bit;


reg rx_bit_r;
reg [ 3: 0 ] sample_st_cs, sample_st_ns;

reg [ 6: 0 ] sample_count_cs, sample_count_ns;
reg [ 6: 0 ] sample_count_cs_r;


assign count_one = sample_bit[ 0 ] + sample_bit[ 1 ] + sample_bit[ 2 ] + sample_bit[ 3 ] + sample_bit[ 4 ] + sample_bit[ 5 ] + sample_bit[ 6 ] + sample_bit[ 0 ];

assign rx_bit = ( count_one > 4 ) ? 1'b1 : 1'b0;

always@( posedge sys_clk or posedge rst )
if ( rst )
begin
    rx_r <= 0;
    rx_nedge <= 0;
end
else
begin
    if ( bd8_rate )
    begin
        rx_r <= { rx_r[ 0 ], ~rx };         //rx shift left
        rx_nedge <= rx_r[ 1 ] & rx_r[ 0 ];   //capture the falling edge
    end
end


always@( posedge sys_clk or posedge rst )
if ( rst )
begin
    sample_st_cs <= IDLE0;
end
else
begin
    sample_st_cs <= sample_st_ns;
end


always@( posedge sys_clk or posedge rst )
if ( rst )
begin
    sample_count_cs <= 0;
end
else
begin
    sample_count_cs <= sample_count_ns;
end


always@( * )
begin
    sample_count_ns <= sample_count_cs;
    sample_st_ns <= sample_st_cs;

    if ( bd8_rate )
    begin
        case ( sample_st )
        IDLE0:
        begin     //idle state, waiting for ta least 10bits 1
            if ( sample_count_cs == 80 )
                sample_st_ns <= IDLE1;
            else if ( rx_r[ 1 ] )
                sample_count_ns <= sample_count_cs + 1;
            else
                sample_count_ns <= 0;
        end
        IDLE1:
        begin //waiting for start_bit's edge
            sample_count_ns <= 0;
            if ( rx_nedge )
                sample_st_ns <= START;
        end
        START:
        begin
            sample_count_ns <= sample_count_cs + 1;
            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                if ( rx_bit )
                    sample_st_ns <= IDLE1;
                else
                    sample_st_ns <= FIRST_BIT;
            end
        end
        FIRST_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= SEC_BIT;
            end
        end
        SEC_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= THIRD_BIT;
            end
        end
        THIRD_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= FOUTH_BIT;
            end
        end
        FOUTH_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= FIF_BIT ;
            end
        end
        FIF_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns = 0;
                sample_st_ns <= SIX_BIT;
            end
        end
        SIX_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= SEVN_BIT;
            end
        end
        SEVN_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= EIGTH_BIT;
            end
        end
        EIGTH_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;

                if ( ( PARITY == "ODD" ) || ( PARITY == "EVEN" ) )
                    sample_st_ns <= PAR_BIT;
                else
                    sample_st_ns <= STOP1_BIT;
            end
        end
        PAR_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= STOP1_BIT;
            end
        end
        STOP1_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;

                if ( STOP_BIT == 2 )
                    sample_st_ns <= STOP2_BIT;
                else
                    sample_st_ns <= IDLE1;
            end
        end
        STOP2_BIT:
        begin
            sample_count_ns <= sample_count_cs + 1;

            if ( sample_count_cs == 7 )
            begin
                sample_count_ns <= 0;
                sample_st_ns <= IDLE1;
            end
        end
        endcase
    end
end


always@( posedge sys_clk or posedge rst )
if ( rst )
begin
    sample_bit <= 0;
    rx_rdy_tmp[ 0 ] <= 1'b0;
    rx_data_tmp <= 0;
end
else
begin
    rx_rdy_tmp <= 1'b0;

    if ( sample_st_cs == IDLE1 )
        sample_bit <= rx_r[ 1 ];

    case ( sample_st_cs )
        START, FIRST_BIT, SEC_BIT, THIRD_BIT, FOUTH_BIT, FIF_BIT, SIX_BIT, SEVN_BIT, EIGTH_BIT, PAR_BIT, STOP1_BIT, STOP1_BIT :
        begin
            if ( bd8_rate )
                sample_bit <= { sample_bit[ 6: 0 ], rx_r[ 1 ] };
        end
    endcase

    sample_count_cs_r <= sample_count_cs;

    if ( sample_count_cs_r == 7 )
    begin //delay one clock
        case ( sample_st_cs )
            FIRST_BIT:  rx_data_tmp[ 0 ] = rx_bit;
            SEC_BIT:    rx_data_tmp[ 1 ] = rx_bit;
            THIRD_BIT:  rx_data_tmp[ 2 ] = rx_bit;
            FOUTH_BIT:  rx_data_tmp[ 3 ] = rx_bit;
            FIF_BIT:    rx_data_tmp[ 4 ] = rx_bit;
            SIX_BIT:    rx_data_tmp[ 5 ] = rx_bit;
            SEVN_BIT:   rx_data_tmp[ 6 ] = rx_bit;
            EIGTH_BIT:
            begin
                rx_data_tmp[ 7 ] = rx_bit;
                rx_rdy_tmp = 1'b1;
            end
            default: ;
        endcase
    end
end


always@( posedge sys_clk )
begin
    if ( rx_rdy_tmp )
    begin
        rx_data <= rx_data_tmp;
        rx_rdy <= rx_rdy_tmp;
    end
end

endmodule

 

由于判多相对于中心对齐的采样相对复杂,因此例1对判多的描述采用了3段式状态机实现,第一段采用实现次态(sample_st_ns)到现态(sample_st_cs)的转换。第二段描述了次态逻辑,根据sample_count_cs的值实现状态跳转。第三段描述了rx的数据采样及实现。

 

Posted in FPGA, FPGA, Quartus II, Verilog, Verilog, Vivado, 教材与教案, 文章

发表评论

相关链接