Menu Close

高速通信中的信道编码–加扰与解扰(加性加扰实验)

在上篇文章中,我们讨论并实现了加性/加扰的算法,原理,以及实现方式。在文章中,揭示了算法的实现,设计了利用加扰,解扰演示实例,但是这个演示实例不是非常完善通信工程(目的是演示加扰,解扰的算法)。对于接收端的通讯实现,需要发送端的同步信号,这种方法对于真实的通讯来说,是很难实现的(发送端和接收端都是异步通讯的)。本文中将修改之前的工程,增加preamble + SFD , 实现工程收发同步。 这样,在接收端就可以利用preamble + SFD 所提供的同步信息, 提取出同步字,实现解扰的算法。

仿真工程代码:

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

parameter SYNC1 = 8'b1010_1010;
parameter SYNC2 = 8'b1010_1011;

parameter PERIOD = 20 ;    //周期20
reg pll_rst;     //实体模块PLL的rst信号
wire tx_rx;      // 收发在testbench的回环信号

wire clk_100M;
wire pll_locked;    //实体PLL锁定信号
wire rst = !pll_locked;     //Testbench内生成复位信号

reg [ 7: 0 ] tx_data;      //待发送数据

wire rx_vld;
wire rx_rdy;
wire [ 7: 0 ] rx_data;
reg inclk ;       // 模拟板级提供的输入时钟

reg [ 2: 0 ] tx_st;

initial
begin
    inclk = 1'b0;
    #( PERIOD / 2 );

    forever
        #( PERIOD / 2 ) inclk = ~inclk;
end

//always #10 inclk=~inclk;

initial
begin
    pll_rst = 1'b1;
    tx_data = 0;
    #50 pll_rst = 1'b0;
end

wire tx_rdy;
reg  tx_vld = 0;
reg  tx_en = 0;

reg [5:0] send_cnt = 0;
always@( posedge clk_100M or posedge rst )

    if ( rst )
    begin
        tx_en <= 0;
        tx_st <= 0;
        tx_data <= 0;
    end
    else
    begin
        case ( tx_st )
            0:
            begin
                tx_en <= 0;
                send_cnt <= 0;
                tx_data <= 0;
                tx_vld <= 0;
                tx_st <= 1;
            end
            1:
            begin
                tx_vld <= 1;
                tx_st <= 2;
            end
            2:
            begin
                if(tx_rdy)
                begin
                    tx_data <= 0;
                    tx_en <= 1;
                    send_cnt <= send_cnt + 1;
                    
//                    if(send_cnt == 7)
                        tx_st <= 3;
                end
            end
            3:
            begin
                tx_en <= 0;
                if(tx_rdy)
                begin
                    tx_en <= 1;
                    tx_data <= tx_data + 1;
                    send_cnt <= send_cnt + 1;

//                    if ( send_cnt == 23 )
                    if ( send_cnt == 31 )
                    begin
                        send_cnt <= 0;
                        tx_st <= 7;
                    end
                end
            end
            6:
            begin
                if(tx_rdy)
                begin
                    tx_data <= 8'hff;
                    send_cnt <= send_cnt + 1;
                    
                    if(send_cnt == 31)
                    begin
                        send_cnt <= 0;
                        tx_st <= 7;
                    end
                end
            end
            7:
            begin
                tx_en <= 0;
                tx_vld <= 0;           
                send_cnt <= send_cnt + 1;
                
                if(&send_cnt)
                begin
                    tx_st <= 0;
                end
            end

            default:
                tx_st <= 0;

        endcase
    end


hs_txrx hs_txrx_inst
(
    .inclk      ( inclk ),
    .pll_rst    ( pll_rst ),

    .tx_data    ( tx_data ),
    .tx_en      ( tx_en ),
    .tx_rdy     ( tx_rdy ),
    .tx_vld     ( tx_vld ),

    .tx         ( tx_rx ),
    .rx         ( tx_rx ),

    .rx_vld     ( rx_vld ),
    .rx_rdy     ( rx_rdy ),
    .rx_data    ( rx_data ),

    .clk_100M   ( clk_100M ),
    .pll_locked ( pll_locked )

);

endmodule

 

顶层文件:

module hs_txrx
#(
    parameter SCRAMB_SYNC = 15'b000_0000_1010_1001,
    parameter SYNC1 = 8'b1010_1010,
    parameter SYNC2 = 8'b1010_1011
)
(
    input inclk,
    input pll_rst,


    input [ 7: 0 ] tx_data,
    input  tx_en,
    output tx_rdy,
    input  tx_vld,
    
    output tx,
    input rx,


    output rx_rdy,
    output rx_vld,
    output [ 7: 0 ] rx_data,

    output clk_100M,
    output pll_locked
);


wire clk_400M;

wire rst = !pll_locked;



trans_data
#(
    .SCRAMB_SYNC(SCRAMB_SYNC),
    .SYNC1( SYNC1 ),
    .SYNC2( SYNC2 )
)
trans_data_inst
(
    .rst        ( rst ),
    .clk_100M   ( clk_100M ),
    .tx_data    ( tx_data ),    // 100M的时钟对应的数据
    .tx_en      ( tx_en ),
    .tx_vld     ( tx_vld ),
    .tx_rdy     ( tx_rdy ),
    .tx_out     ( tx )
);

           
rev_pcs
#(
    .SCRAMB_SYNC( SCRAMB_SYNC ),
    .SYNC1( SYNC1 ),
    .SYNC2( SYNC2 )
)
recv_pcs_inst
(
    .rst        ( rst ),
    .clk_100M   ( clk_100M ),
    .clk_400M   ( clk_400M ),
    
    .rx_vld     ( rx_vld ),
    .rx_data    ( rx_data ),
    .rx_rdy     ( rx_rdy ),

    .rx         ( rx )
);


pll1 pll1_inst
(
    .areset ( pll_rst ),    //1'b0;
    .inclk0 ( inclk ),
    .c0     ( clk_10M ),
    .c1     ( clk_100M ),
    .c2     ( clk_400M ),
    .locked ( pll_locked )
);


endmodule

 

trans_data.v文件:

module trans_data
#(
    parameter SCRAMB_SYNC = 15'b000_0000_1010_1001,
    parameter SYNC1 = 8'b1010_1010,
    parameter SYNC2 = 8'b1010_1011
)
(
    input  rst,
    input  clk_100M,

    output reg tx_rdy = 0,

    input  tx_vld,
    input  tx_en,

    input  [ 7: 0 ] tx_data,    // 100M的时钟对应的数据
    output tx_out
);


reg [ 14: 0 ] scrambler;
reg scb_en = 0;
reg [7:0] scb_bit_vector = 0;

integer i;
always@( posedge clk_100M )
if ( ~tx_vld )
begin
    scb_bit_vector = 0;
    scrambler = SCRAMB_SYNC;
end
else if(scb_en)
begin
    for (i = 0; i < 8; i = i + 1) begin
        scb_bit_vector[ i ] = scrambler[ 14 ] ^ scrambler[ 13 ];
        scrambler = {scrambler[13:0], scb_bit_vector[ i ]};
    end
end

reg [7:0] tx_pma_in = 0;
reg tx_pma_en = 0;
wire tx_pma_req;
reg [ 2: 0 ] scb_st;
always@( posedge clk_100M or posedge rst )
if ( rst )
begin
    scb_st <= 0;
    tx_rdy <= 0;
end
else
begin
    case ( scb_st )
        0:
        begin
            tx_pma_en <= 0;
            tx_rdy <= 1'b0;
            tx_pma_in <= SYNC1;

            if ( tx_vld)
            begin
                scb_st <= 1;
            end
        end
        1:
        begin
            tx_pma_en <= 0;
            if(tx_pma_req)
            begin
                tx_pma_en <= 1;
                tx_pma_in <= SYNC1;
                scb_st <= 2;
            end
        end
        2:
        begin
            tx_rdy <= 0;

            tx_pma_en <= 0;
            if(tx_pma_req)
            begin
                tx_pma_en <= 1;
                tx_pma_in <= SYNC2;
                tx_rdy <= 1;
                scb_en <= 1;
                scb_st <= 3;
            end
        end
        3:
        begin
            tx_rdy <= 0;
            scb_en <= 0;
            tx_pma_en <= 0;

            if ( tx_pma_req )
            begin
                tx_pma_en <= 1;
                tx_pma_in <= tx_data ^ scb_bit_vector;
                scb_en <= 1;
                
                if ( ~tx_vld ) scb_st <= 4;
                else tx_rdy <= 1;
            end
        end
        4:
        begin
            scb_en <= 0;
            tx_rdy <= 0;

            tx_pma_en <= 0;
            if(tx_pma_req)
            begin
                tx_pma_en <= 1;
                tx_pma_in <= SYNC1;
                scb_st <= 0;
            end
        end
        default:
            scb_st <= 0;

    endcase
end

    
    
trans_pma
#(
    .SCRAMB_SYNC(SCRAMB_SYNC),
    .SYNC1      (SYNC1),
    .SYNC2      (SYNC2)
)
trans_pma_inst
(
    .clk_100M   ( clk_100M ),

    .tx_pma_en  ( tx_pma_en ),
    .tx_pma_req ( tx_pma_req ),
    .tx_pma_in  ( tx_pma_in ),

    .tx_out     ( tx_out ),

    .rst        ( rst)
);
    

endmodule

 

trans_pma.v

module trans_pma
#(
    parameter SCRAMB_SYNC = 15'b000_0000_1010_1001,
    parameter SYNC1 = 8'b1010_1010,
    parameter SYNC2 = 8'b1010_1011
)
(
    input clk_100M,

    input  tx_pma_en,
    output reg tx_pma_req = 0,
    input [ 7: 0 ] tx_pma_in,    // 100M的时钟对应的数据
    
    output tx_out,
    
    input rst
);


reg [7:0] tx_data_temp;
always@( posedge clk_100M or posedge rst )
if(rst)
    tx_data_temp <= 8'b1010_1010;
else if ( tx_pma_en )
    tx_data_temp <= tx_pma_in;


reg [7:0] tx_shift;
reg [2:0] tx_cnt = 0;
wire tx_pma_reload = (tx_cnt == 7) ? 1'b1 : 1'b0;

always@( posedge clk_100M or posedge rst )
if(rst)
begin
    tx_pma_req <= 0;
    tx_shift <= 8'b1010_1010;
    tx_cnt <= 0;
end
else
begin
    tx_pma_req <= 0;
    
    if ( tx_pma_reload )
    begin
        tx_pma_req <= 1;
        tx_shift <= tx_data_temp;
    end
    else
        tx_shift <= {tx_shift[ 0 ], tx_shift[ 7: 1 ]};
        
    tx_cnt <= tx_cnt + 1;
end


// pmd
IO_TX IO_TX_inst
(
    .tx_in  ( tx_shift[0] ),
    .tx_out ( tx_out )
);


endmodule

 

rec_pcs.v

module rev_pcs
#(
    parameter SCRAMB_SYNC = 15'b000_0000_1010_1001,
    parameter SYNC1 = 8'b1010_1010,
    parameter SYNC2 = 8'b1010_1011
)
(
    input rx,

    output reg rx_vld = 0,
    output rx_rdy,
    output reg [ 7: 0 ] rx_data,

    input  clk_100M,
    input  clk_400M,
    input  rst
);


wire sync;
wire [7:0] rx_data_scb ;
reg [ 14: 0 ] scrambler;
wire scb_en;
reg [7:0] scb_bit_vector = 0;
integer i;
always@( posedge clk_100M )
if ( ~sync )
begin
    scb_bit_vector = 0;
    scrambler = SCRAMB_SYNC;
end
else if(scb_en)
begin
    for (i = 0; i < 8; i = i + 1) begin
        scb_bit_vector[ i ] = scrambler[ 14 ] ^ scrambler[ 13 ];
        scrambler = {scrambler[13:0], scb_bit_vector[ i ]};
    end
end    
    
recv_data
#(
    .SYNC1( SYNC1 ),
    .SYNC2( SYNC2 )
)
recv_data_inst
(
    .rst              ( rst ),
    .clk_100M         ( clk_100M ),
    .clk_400M         ( clk_400M ),
    .sync             ( sync ),
    .rx               ( rx ),
    .rx_data_100Mr    ( rx_data_scb ),
    .rx_data_vld_100Mr( scb_en )
);

reg [1:0] rx_vld_r = 0;
always @ (posedge clk_100M)
begin
    rx_vld_r <= {rx_vld_r[0], scb_en};
end

always @ (posedge clk_100M)
if(rx_vld_r[0])
begin
    rx_data = rx_data_scb ^ scb_bit_vector;
end

always @ (posedge clk_100M)
if(sync) rx_vld <= 1;
else  if(rx_rdy) rx_vld <= 0;


assign rx_rdy = rx_vld_r[1];



endmodule

 

recv_data.v

module recv_data
#(
    parameter SYNC1 = 8'b1010_1010,
    parameter SYNC2 = 8'b1010_1011
)
(
    input rst,
    input clk_100M,
    input clk_400M,
    input rx,
    output reg sync = 0,
    output reg[ 7: 0 ] rx_data_100Mr,
    output reg rx_data_vld_100Mr
);


wire rx_bit;
wire rx_bit_vld;

reg [ 3: 0 ] bit_count;
reg [ 7: 0 ] bit_sft;
reg [ 7: 0 ] sync_shift = 0;

reg fr_sync1, fr_sync2;
reg fr_sync;

always @ (posedge clk_100M)
sync <= fr_sync;

reg fr_end;
reg [ 7: 0 ] fr_count;

reg[ 7: 0 ] rx_data;
reg rx_data_vld_tmp;

always@( posedge clk_400M or posedge rst )

    if ( rst )
    begin
        rx_data <= 0;
        rx_data_vld_tmp <= 0;
        bit_count <= 0;
        bit_sft <= 0;
        fr_sync1 <= 0;
        fr_sync2 <= 0;
        fr_sync <= 0;
        fr_end <= 0;
        fr_count <= 0;
    end
    else
    begin
        if ( rx_bit_vld )
        begin
            bit_sft <= { rx_bit, bit_sft[ 7: 1 ]};
            sync_shift <= { bit_sft[ 0 ], sync_shift[ 7: 1] };
        end

        if ( fr_sync )
            fr_sync2 <= 1'b0;
        else if ( bit_sft == SYNC2 )
            fr_sync2 <= 1'b1;         //fr----frame
        else
            fr_sync2 <= 1'b0;

        if ( fr_sync )
            fr_sync1 <= 1'b0;
        else if ( sync_shift == SYNC1 )
            fr_sync1 <= 1'b1;
        else
            fr_sync1 <= 1'b0;

        if ( fr_end )
            fr_sync <= 1'b0;
        else if ( fr_sync1 & fr_sync2 & rx_bit_vld )
            fr_sync <= 1'b1;

        if ( fr_sync )
        begin
            if ( rx_bit_vld )
            begin
                if ( bit_count == 7 )
                    bit_count <= 0;
                else
                    bit_count <= bit_count + 1;
            end
        end

        rx_data_vld_tmp <= 0;

        if ( bit_count == 7 )
        begin
            rx_data <= bit_sft;
            rx_data_vld_tmp <= 1'b1;
        end

        fr_end <= 1'b0;

        if ( rx_data_vld_tmp & rx_bit_vld )
            if ( fr_count == 31 )
            begin
                fr_end <= 1'b1;
                fr_count <= 0;
            end
            else
                fr_count <= fr_count + 1;
    end

     
wire rx_data_vld = rx_data_vld_tmp & rx_bit_vld;     

reg rx_data_vld_r;
reg [ 5: 0 ] count_400M;
reg rx_data_vld_x;
reg nrx_data_vld_x;
reg rx_data_vld_xrg;

always@( posedge clk_400M or posedge rst )

    if ( rst )
    begin
        count_400M <= 0;
        rx_data_vld_r <= 0;
    end
    else
    begin
        if ( rx_data_vld )
            rx_data_vld_r <= 1'b1;
        else if ( count_400M == 15 )
            rx_data_vld_r <= 1'b0;

        if ( count_400M == 15 )
            count_400M <= 0;
        else if ( rx_data_vld_r )
            count_400M <= count_400M + 1;
    end

always@( posedge clk_100M or posedge rst )

    if ( rst )
    begin
        rx_data_vld_x <= 1'b0;
        nrx_data_vld_x <= 1'b1;

        rx_data_vld_xrg <= 1'b0;

        rx_data_100Mr <= 0;

        rx_data_vld_100Mr <= 1'b0;
//        rx_data_vld_100Mrr <= 1'b0;

    end
    else
    begin
        rx_data_vld_x <= rx_data_vld_r;
        nrx_data_vld_x <= !rx_data_vld_x;
        rx_data_vld_xrg <= nrx_data_vld_x & rx_data_vld_x;

        rx_data_vld_100Mr <= 1'b0;

        if ( rx_data_vld_xrg )
        begin
            rx_data_100Mr <= rx_data;
            rx_data_vld_100Mr <= 1'b1;
        end
    end


recv_bit recv_bit_inst
(
    .rst        ( rst ),
    .clk_400M   ( clk_400M ),
    .rx         ( rx ),
    .rx_bit     ( rx_bit ),
    .rx_bit_vld ( rx_bit_vld )

);


endmodule

 

仿真结果:

图1

仿真程序中发送数据 8’h00, 8’h01, 8’h02, ….. 8’h1f , 接收端可以正常接收到8’h00, 8’h01, 8’h02, …. 8’h1f。

图2

图3

tx_pma_reload 将tx_data_temp (之前锁存的数据)装载到tx_shift 中, 同时发送tx_pma_req 请求下一个数据,只要下一个数据在reload之前准备好就可以了, 这样就给上层程序预留了很多时间(有一定的弹性)。

quartus 代码

[contend_control]

high_speed_txrx

[/contend_control]

关于程序的更多讲解, 请参照视频文件。

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

1 Comment

发表回复

相关链接