AXI_lite总线配置JESD204 IP核

一、简介       

         J204B接口布线简单,传输速率快。正逐渐代替LVDS和CMOS接口,成为新一代的采样数据的传输接口。FPGA可以通过JESD204这一IP核进行使用J204B接口。

        JESD204在进行使用前需要利用AXI总线对其进行配置后,IP核才能正常工作下面利用Verilog代码通过状态机配置其寄存器, 可以通过不同的需求进行修改。

        读写操作利用状态机实现。

二、写状态机:

        awready=1代表从机准备好接收地址,wready=1代表从机准备好接收数据,bvaild=1代表本次的写数据有效

三、读状态机: 

        arready=1代表从机准备好接收地址,rvaild=1代表本次的读数据有效。

四、 读写时序

1、写时序

2、读时序

五、通道握手信号之间的依赖性:​​​​​​​

        单箭头指向的信号能在箭头起点信号之前或之后断言;双箭头指向的信号必须在箭头起点信号断言之后断言

1、读握手依赖关系

2、写握手依赖关系

六、注意事项:

        虽然 J204B接口布线简单,但是JESD204这一IP核的时钟网络复杂,要注意时钟的分配,还有复位,以及利用AXI总线配置J204B寄存器。

        AXI总线配置J204B寄存器要在收发器的时钟来到之后进行配置,这样才能成功建立数据通路。

七、代码实现

1、写操作

module axi_write(
    input               s_axi_aclk      ,   //时钟
    input               s_axi_aresetn   ,   //低电平复位
    input               s_axi_awready   ,   //写入地址就绪
    input               s_axi_wready    ,   //写入数据就绪
    input               s_axi_bvalid    ,   //写入响应有效
    input      [1:0]    s_axi_bresp     ,   //写入响应
    output reg [31:0]   s_axi_awaddr    ,   //写入地址
    output reg          s_axi_awvalid   ,   //写入地址有效
    output reg [31:0]   s_axi_wdata     ,   //写入数据
    output reg          s_axi_wvalid    ,   //写入数据有效
    output reg          s_axi_bready    ,      //写入数据就绪
    output reg          axi_write_done      //数据全部写入
    );
//*******************数据链路层的参数配置**********************
    localparam pLanes = 1       ;       //lane数
    // F = 1 K = 20                     //BUFF的值
    localparam  [2:0] pF        = 2-1    ;       //F
    localparam  [8:0] pK        = 32-1   ;       //K

    // Setup the link configuration parameters.
    localparam [7:0] pDID      = 8'h55      ;    //Device ID 设备ID
    localparam [3:0] pADJCNT   = 4'h0       ;    //ADJCNT (Phase Adjust Request) [Subclass 2 Only]. Binary value.
    localparam [3:0] pBID      = 4'hA       ;    //Bank ID
    localparam       pADJDIR   = 1'b0       ;    //ADJDIR (Adjust Direction) [Subclass 2 Only]. Binary value.
    localparam       pPHADJ    = 1'b0       ;    //PHADJ (Phase Adjust Request) [Subclass 2 Only]. Binary value.
    localparam       pSCR      = 1'b0       ;    //Scrambling Enable
    localparam [4:0] pL        = (pLanes-1) ;    //L lane数
    localparam [7:0] pM        = 2          ;    //M 转换器数   
    localparam [1:0] pCS       = 2'd0       ;    //CS 每帧周期中每个采样样本所需的控制位数   
    localparam [4:0] pN        = 5'd16      ;    //N 转换器的分辨率   
    localparam [4:0] pNt       = 5'd16      ;    //N' 样本传输的总位数   
    localparam [2:0] pSUBCV    = 3'b001     ;    //SUBCLASS: 000=Subclass0  001=Subclass1 010=Subclass2
    localparam [2:0] pJESDV    = 3'b001     ;    //J204版本  000=JESD204A  001=JESD204B
    localparam [4:0] pS        = 5'd0       ;    //S 每帧周期每个转换器采样数;   
    localparam       pHD       = 1'b0       ;    //HD  HD=0 则样本在一个通道中,HD=1 则样本被分配在多个通道中;    
    localparam [4:0] pCF       = 5'd0       ;    //CF  CF=0 则控制位在采样样本后面,CF=1 则控制位单独组成控制字;   
    localparam [7:0] pRES1     = 8'h5A      ;    //RES1 (Reserved Field 1)
    localparam [7:0] pRES2     = 8'hA5      ;    //RES2 (Reserved Field 2)
//********************************************************************

//******************状态机状态*************************************
    localparam [4:0] IDLEW     =  5'b00001  ;     //空闲等待
    localparam [4:0] DRIVEW    =  5'b00010  ;     //准备
    localparam [4:0] ADD_RES   =  5'b00100  ;     //取地址
    localparam [4:0] DAT_RES   =  5'b01000  ;     //取数据
    localparam [4:0] BRES      =  5'b10000  ;     //写数据阶段
    localparam WRITE_NUM       =  14        ;    ///配置寄存器的个数
//*******************************************************************

//*****************内部信号******************************
    reg [4:0]   curr_ws             ,  //状态机的当前状态
                next_ws             ;  //状态机的下一个状态
    reg         write_over          ;
    reg         write_over_delay    ;
    reg [31:0]  wadd                ;   //寄存器地址
    reg [9:0]   w_cnt               ;   //对写入的数据个数进行计数,配置完成将write_over置高
    reg [31:0]  wdata               ;   //寄存器写入数据
    reg [1:0]   resp                ;
//**********************************************************

//状态机
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)  
            curr_ws <= IDLEW    ;
        else               
            curr_ws <= next_ws  ;
    end

    always@(*) begin
        next_ws = 'dx;
        case(curr_ws)
            IDLEW   :   if(write_over==0)       next_ws = DRIVEW    ;  else next_ws = IDLEW     ;
            DRIVEW  :   if(s_axi_awready==1)    next_ws = ADD_RES   ;  else next_ws = DRIVEW    ;
            ADD_RES :   if(s_axi_wready==1)     next_ws = DAT_RES   ;  else next_ws = ADD_RES   ;
            DAT_RES :   if(s_axi_bvalid==1)     next_ws = BRES      ;  else next_ws = DAT_RES   ;  
            BRES    :   if(write_over==1)       next_ws = IDLEW     ;  else next_ws = DRIVEW    ;
            default :   next_ws = IDLEW ;
        endcase
    end

    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    
        if(!s_axi_aresetn)begin
                s_axi_awaddr    <= 0    ;              
                s_axi_awvalid   <= 0    ;
                s_axi_wdata     <= 0    ;              
                s_axi_wvalid    <= 0    ;
                s_axi_bready    <= 0    ;              
                w_cnt           <= 0    ;        
                resp            <= 0    ;
        end
        else case(curr_ws)
                IDLEW:
                begin
                    s_axi_awaddr    <= 0    ;             
                    s_axi_awvalid   <= 0    ;
                    s_axi_wdata     <= 0    ;             
                    s_axi_wvalid    <= 0    ;
                    s_axi_bready    <= 0    ;             
                    w_cnt           <= w_cnt;     
                    resp            <= 0    ;
                end
                DRIVEW:
                begin
                    if(s_axi_awready==1) begin 
                        s_axi_awaddr  <= 0  ;        
                        s_axi_awvalid <= 0  ;   
                    end
                    else begin 
                        s_axi_awaddr  <= wadd   ;     
                        s_axi_awvalid <= 1      ;   
                    end
                    s_axi_wdata   <= wdata  ;         
                    s_axi_wvalid  <= 1      ;
                    s_axi_bready  <= 0      ;             
                    w_cnt         <= w_cnt  ;     
                    resp          <= 0      ;
                end
                ADD_RES:
                begin
                    s_axi_awaddr  <= 0      ;             
                    s_axi_awvalid <= 0      ;
                    if(s_axi_wready==1) begin  
                        s_axi_wdata <= 0    ;        
                        s_axi_wvalid  <= 0  ;  
                        w_cnt <= w_cnt+1    ;
                    end //else keep//每传输一个数据加1
                        s_axi_bready  <= 0  ;             
                    resp <= 0           ;
                end
                DAT_RES:
                begin
                    s_axi_awaddr  <= 0      ;              
                    s_axi_awvalid <= 0      ;
                    s_axi_wdata   <= 0      ;              
                    s_axi_wvalid  <= 0      ;
                    if(s_axi_bvalid==1) begin 
                        s_axi_bready  <= 1  ;        
                        resp <= s_axi_bresp ;
                    end    //else keep
                    w_cnt <= w_cnt          ;
                end
                BRES:
                begin
                    s_axi_awaddr  <= 0      ;             
                    s_axi_awvalid <= 0      ;
                    s_axi_wdata   <= 0      ;             
                    s_axi_wvalid  <= 0      ;       
                    w_cnt <= w_cnt          ;
                    if(s_axi_bready) begin 
                        s_axi_bready <= 0   ;       
                        resp <= 0           ;          
                    end//只持续一个高电平
                    else begin 
                        s_axi_bready <= 1   ;        
                        resp <= s_axi_bresp ;
                    end
                end
                default:
                begin
                   s_axi_awaddr  <= 0       ;              
                   s_axi_awvalid <= 0       ;
                   s_axi_wdata   <= 0       ;              
                   s_axi_wvalid  <= 0       ;
                   s_axi_bready  <= 0       ;              
                   w_cnt         <= 0       ;
                   resp          <= 0       ;
                end
            endcase
    end
//

//判断寄存器是否全部写入
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)                      
            write_over <= 0     ;
        else if( w_cnt == WRITE_NUM)            
            write_over <= 1     ;                   //else keep
    end
//

//数据全部写入  
    always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)
            write_over_delay <= 0   ;
        else    
            write_over_delay <= write_over  ;
    end

    always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)
            axi_write_done <= 0 ;
        else 
            axi_write_done <= write_over & ~write_over_delay ;
    end

//写寄存器
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)begin
            wadd <= 0   ;
            wdata <= 0  ;
        end
        else
        case( w_cnt )
            0   :   begin wadd <=32'h008; wdata <= 32'h00000001  ; end
            1   :   begin wadd <=32'h00C; wdata <= {31'b0,pSCR}  ; end
            2   :   begin wadd <=32'h010; wdata <= {31'b0,1'b1}  ; end
            3   :   begin wadd <=32'h014; wdata <= 32'h00000003  ; end
            4   :   begin wadd <=32'h018; wdata <= 32'h00000000  ; end
            5   :   begin wadd <=32'h020; wdata <= {29'b0,pF}    ; end
            6   :   begin wadd <=32'h024; wdata <= {23'b0,pK}    ; end
            7   :   begin wadd <=32'h028; wdata <= {24'b0,8'h01} ; end
            8   :   begin wadd <=32'h02C; wdata <= 32'h00000001  ; end
            9   :   begin wadd <=0      ; wdata <= 0             ; end      //begin wadd <=32'h80C   ;wdata <= {3'b0, pL, 12'b0, pBID, pDID}  ; end
            10  :   begin wadd <=32'h810; wdata <= {6'b0, pCS, 3'b0, pNt, 3'b0, pN, pM}  ; end
            11  :   begin wadd <=32'h814; wdata <= {3'b0, pCF, 7'b0, pHD, 3'b0, pS, 7'b0, pSCR}  ; end
            12  :   begin wadd <=0      ; wdata <= 0             ; end      //begin wadd <=32'h818  ;wdata <= {16'b0, pRES2, pRES1}  ; end
            13  :   begin wadd <=32'h004; wdata <= 32'h00000001  ; end
            default:begin wadd <=32'h008; wdata <= 32'h00000001  ; end
        endcase
    end

endmodule

2、读操作

module axi_read(
    input               s_axi_aclk      ,   //时钟
    input               s_axi_aresetn   ,   //低电平复位
    input               s_axi_arready   ,   //读取地址就绪
    input               s_axi_rvalid    ,   //读取数据有效
    input      [31:0]   s_axi_rdata     ,   //读取数据
    input      [1:0]    s_axi_rresp     ,   //读取响应
    output reg [31:0]   s_axi_araddr    ,   //读取地址
    output reg          s_axi_arvalid   ,   //读取地址有效
    output reg          s_axi_rready        //读取数据就绪

    );
//******************状态机状态*************************************
    localparam [2:0] IDLER      =  3'b001   ;
    localparam [2:0] DRIVER     =  3'b010   ;
    localparam [2:0] RDATA      =  3'b100   ;
    localparam       READ_NUM   =  14       ;
//*******************************************************************    
//*****************内部信号******************************
    reg [4:0]   curr_rs     ,
                next_rs     ;
    reg         read_over   ;
    reg [31:0]  radd        ;
    reg [9:0]   r_cnt       ;
    reg [31:0]  rdata       ;
    reg [1:0]   rresp       ;
//**********************************************************

//状态机
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)  
            curr_rs <= IDLER    ;
        else                
            curr_rs <= next_rs  ;
    end

    always@(*) begin
        next_rs = 'dx;
        case(curr_rs)
            IDLER   :  
                if(read_over==0 && s_axi_arready==1)   
                    next_rs = DRIVER    ;   
                else   
                    next_rs = IDLER     ;  
            DRIVER  :  
                if(s_axi_arvalid==1)                   
                    next_rs = RDATA     ;    
                else    
                    next_rs = DRIVER    ;
            RDATA   :  
                if(s_axi_rvalid==1)                    
                    next_rs = IDLER     ;    
                else    next_rs = RDATA ;
            default :   next_rs = IDLER ;    
        endcase
    end  
    
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn) begin
            s_axi_araddr  <= 0  ;         
            s_axi_arvalid <= 0  ;    
            s_axi_rready  <= 0  ;  
            rdata         <= 0  ;                 
            rresp         <= 0  ;      
            r_cnt         <= 0  ;   
        end
        else 
            case(curr_rs)                                                                 
                IDLER: 
                begin 
                    rdata <= 0;rresp <= 0; 
                    if(read_over==0 && s_axi_arready==1) 
                    begin
                        s_axi_araddr  <= radd   ;  
                        s_axi_arvalid <= 1      ;    
                        s_axi_rready  <= 0      ;     
                        r_cnt <= r_cnt+1        ;   //控制个数
                    end
                    else
                    begin
                        s_axi_araddr  <= 0      ; 
                        s_axi_arvalid <= 0      ;    
                        s_axi_rready  <= 0      ; 
                        r_cnt <= r_cnt          ;
                    end
                end    
                DRIVER:
                begin
                    rdata <= 0                  ;
                    rresp <= 0                  ;
                    r_cnt <= r_cnt              ;
                    if(s_axi_arvalid==1)   
                    begin
                        s_axi_araddr  <= 0      ; 
                        s_axi_arvalid <= 0      ;
                        s_axi_rready  <= 1      ;    
                    end//else keep
                end       
                RDATA:  
                begin
                    s_axi_araddr    <= 0        ; 
                    s_axi_arvalid   <= 0        ;   
                    r_cnt           <= r_cnt    ;
                    if(s_axi_rvalid==1) 
                    begin              
                        s_axi_rready  <= 0      ; 
                        rdata <= s_axi_rdata    ; 
                        rresp <= s_axi_rresp    ;    
                    end //else keep
                end  
                default: 
                begin
                    s_axi_araddr  <= 0          ; 
                    s_axi_arvalid <= 0          ;
                    s_axi_rready  <= 0          ;                    
                    rdata <= 0                  ;
                    rresp <= 0                  ;  
                    r_cnt <= r_cnt              ;                     
                end                                                  
            endcase
    end
    
    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn)
            read_over <= 0      ;  
        else if( r_cnt == READ_NUM)
            read_over <= 1      ;           //else keep
    end

    always@(posedge s_axi_aclk or negedge s_axi_aresetn) begin
        if(!s_axi_aresetn) 
            radd <= 32'h008 ;   
        else 
            case( r_cnt )
                0   :       radd <= 32'h008  ; 
                1   :       radd <= 32'h00C  ; 
                2   :       radd <= 32'h010  ; 
                3   :       radd <= 32'h014  ; 
                4   :       radd <= 32'h018  ; 
                5   :       radd <= 32'h020  ; 
                6   :       radd <= 32'h024  ; 
                7   :       radd <= 32'h028  ; 
                8   :       radd <= 32'h02C  ;
                9   :       radd <= 32'h80C  ;
                10  :       radd <= 32'h810  ;
                11  :       radd <= 32'h814  ;
                12  :       radd <= 32'h818  ;
                13  :       radd <= 32'h004  ;
                default:    radd <= 32'h004  ;
            endcase
    end 
endmodule


        如果想对AXI总线有更多的了解,或者用Verilog实现AXI总线的读写操作,可以参考如下的文章:

FPGA实现AXI4总线的读写https://blog.csdn.net/QUACK_G/article/details/125951718?spm=1001.2014.3001.5502

猜你喜欢

转载自blog.csdn.net/QUACK_G/article/details/125574534