ZYNQ多通道数据采集与LWIP传输系统

Zynq数据采集系统

  • 一、系统设计

系统结构如图所示。

ZYNQ多通道数据采集与LWIP传输系统_第1张图片

PS将网络传输进来的参数通过BRAM传递到PL;

PL将AD采样数据通过DMA传输到PS,PS收到中断后通过LWIP发送到上位机。

PL驱动8路ADS8681进行数据采样,每路AD可独立配置采样率以及是否使能。

采样模式有连续采样、触发采样;触发方式有内触发、外触发;触发延时有正延时、负延时可设。

8路数据传输采用依次轮训的方式,按包长度大小将每路数据分别发送。

  • 二、Block Design

ZYNQ多通道数据采集与LWIP传输系统_第2张图片

ZYNQ多通道数据采集与LWIP传输系统_第3张图片

  • 三、PL端设计

  • 1.conv模块实现采样率配置,根据上位机配置下来的频率控制字生成相应频率的转换信号,来控制AD的采样。

// conv.v
`timescale 1ns / 1ps
//

//


//

module conv (
    input 			    rst_n           ,
    input 			    clk_200M_in     ,
    input   [31:0]      fre_word_i      ,
    input               fre_word_valid_i,
    
    output 		        ad_conv_o
);

    reg     [31:0]      fre_word_ff     ;
    reg     [32:0]      fre_word_add_ff ;
    wire                fre_add_cout    ;
    reg                 high_fre_ff     ;
    reg                 high_fre_ff_d1  ;
    wire                high_fre_up     ;
    reg                 ad_conv_ff      ;
    reg     [7:0]       ad_conv_div_cnt ;      
    
    assign  ad_conv_o = ad_conv_ff ;

    always @ ( posedge  clk_200M_in or negedge rst_n ) begin
        if(!rst_n) begin
            fre_word_ff <= 32'hFFFFFFFF; //默认1MHz采样率 
        end
        else if(fre_word_valid_i) begin
		    fre_word_ff <= fre_word_i[31:0]; //采样率参数计算公式=4294.96*freq(Hz)   
        end
        else begin
            fre_word_ff <= fre_word_ff ;
        end 
    end 
        
    always @ (posedge clk_200M_in or negedge rst_n) begin//loop add
        if(!rst_n) begin
		    fre_word_add_ff <= 33'h1ffffffff;
        end  
	    else begin
	        fre_word_add_ff <= fre_word_ff[31:0] +  fre_word_add_ff[31:0];
	    end 
    end
    
    assign  fre_add_cout = fre_word_add_ff[32];//cout
   
    always @ (posedge clk_200M_in or negedge rst_n) begin//2_div
        if(!rst_n) begin
            high_fre_ff <= 1'b0;
        end 
	    else if(fre_add_cout) begin
	        high_fre_ff <= !high_fre_ff;
	    end 
	    else begin
	        high_fre_ff <= high_fre_ff;
	    end 		        
    end

//div  100/


    always @ (posedge clk_200M_in ) begin
	    high_fre_ff_d1 <= high_fre_ff;
    end

    assign  high_fre_up = high_fre_ff & ! high_fre_ff_d1;

    always @ (posedge clk_200M_in  or negedge rst_n) begin
        if(!rst_n) begin
		    ad_conv_ff      <= 1'b0;
		    ad_conv_div_cnt <= 8'd0;
	    end
	    else if(high_fre_up) begin
		    if(ad_conv_div_cnt == 8'd19) begin//100					  
			    ad_conv_div_cnt <= 8'd0;
			    ad_conv_ff      <= !ad_conv_ff;
		    end
		    else begin
		        ad_conv_div_cnt <= ad_conv_div_cnt + 1'b1;
		        ad_conv_ff      <= ad_conv_ff;
		    end 				    
        end
	    else begin
	        ad_conv_div_cnt <= ad_conv_div_cnt;
		    ad_conv_ff      <= ad_conv_ff;
	    end 
    end

endmodule


  • 2.Tx_data_gen模块实现8路数据的轮训,依次判断第1路到第8路AD是否完成包长度的采样,并将完成的数据写入DMA控制器,发送到PS。

`timescale 1ns/1ps
module tx_data_gen#(
    parameter   TCP_TX_LENTH    =   16'd1024
)(
    input           clk_i   ,
    input           rst_n   ,
    
    input           ch1_tx_start_i  ,
    input   [15:0]  ch1_tx_data_i   ,
    input           ch1_tx_dvalid_i ,
    output  reg     ch1_rd_req_o    ,
    
    input           ch2_tx_start_i  ,
    input   [15:0]  ch2_tx_data_i   ,
    input           ch2_tx_dvalid_i ,
    output  reg     ch2_rd_req_o    ,
    
    input           ch3_tx_start_i  ,
    input   [15:0]  ch3_tx_data_i   ,
    input           ch3_tx_dvalid_i ,
    output  reg     ch3_rd_req_o    ,
    
    input           ch4_tx_start_i  ,
    input   [15:0]  ch4_tx_data_i   ,
    input           ch4_tx_dvalid_i ,
    output  reg     ch4_rd_req_o    ,
    
    input           ch5_tx_start_i  ,
    input   [15:0]  ch5_tx_data_i   ,
    input           ch5_tx_dvalid_i ,
    output  reg     ch5_rd_req_o    ,
    
    input           ch6_tx_start_i  ,
    input   [15:0]  ch6_tx_data_i   ,
    input           ch6_tx_dvalid_i ,
    output  reg     ch6_rd_req_o    ,
    
    input           ch7_tx_start_i  ,
    input   [15:0]  ch7_tx_data_i   ,
    input           ch7_tx_dvalid_i ,
    output  reg     ch7_rd_req_o    ,
    
    input           ch8_tx_start_i  ,
    input   [15:0]  ch8_tx_data_i   ,
    input           ch8_tx_dvalid_i ,
    output  reg     ch8_rd_req_o    ,
    
    input           tcp_tx_busy_i   ,
    output  reg[15:0]  tx_data_o       ,
    output  reg        tx_dvalid_o 
);

    localparam              TX_IDLE     =   0   ,
                            TX_CH1      =   1   ,
                            TX_CH1_D    =   2   ,
                            TX_CH2      =   3   ,
                            TX_CH2_D    =   4   ,
                            TX_CH3      =   5   ,
                            TX_CH3_D    =   6   ,
                            TX_CH4      =   7   ,
                            TX_CH4_D    =   8   ,
                            TX_CH5      =   9   ,
                            TX_CH5_D    =   10  ,
                            TX_CH6      =   11  ,
                            TX_CH6_D    =   12  ,
                            TX_CH7      =   13  ,
                            TX_CH7_D    =   14  ,
                            TX_CH8      =   15  ,
                            TX_CH8_D    =   16  ,
                            TX_DONE     =   17  ;
    
    reg     [17:0]  cur_s       ;
    reg     [17:0]  next_s      ;
    reg             ch1_tx_en   ;
    reg             ch2_tx_en   ;
    reg             ch3_tx_en   ;
    reg             ch4_tx_en   ;
    reg             ch5_tx_en   ;
    reg             ch6_tx_en   ;
    reg             ch7_tx_en   ;
    reg             ch8_tx_en   ;
    reg             tx_data_done;
    reg     [15:0]  tx_data_cnt ;

    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch1_tx_en <= 1'b0 ;
        end 
        else if (ch1_tx_start_i == 1'b1) begin
            ch1_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH1_D]) begin
            ch1_tx_en <= 1'b0 ;
        end 
    end
    
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch2_tx_en <= 1'b0 ;
        end 
        else if (ch2_tx_start_i == 1'b1) begin
            ch2_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH2_D]) begin
            ch2_tx_en <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch3_tx_en <= 1'b0 ;
        end 
        else if (ch3_tx_start_i == 1'b1) begin
            ch3_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH3_D]) begin
            ch3_tx_en <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch4_tx_en <= 1'b0 ;
        end 
        else if (ch4_tx_start_i == 1'b1) begin
            ch4_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH4_D]) begin
            ch4_tx_en <= 1'b0 ;
        end 
    end 
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch5_tx_en <= 1'b0 ;
        end 
        else if (ch5_tx_start_i == 1'b1) begin
            ch5_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH5_D]) begin
            ch5_tx_en <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch6_tx_en <= 1'b0 ;
        end 
        else if (ch6_tx_start_i == 1'b1) begin
            ch6_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH6_D]) begin
            ch6_tx_en <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch7_tx_en <= 1'b0 ;
        end 
        else if (ch7_tx_start_i == 1'b1) begin
            ch7_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH7_D]) begin
            ch7_tx_en <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            ch8_tx_en <= 1'b0 ;
        end 
        else if (ch8_tx_start_i == 1'b1) begin
            ch8_tx_en <= 1'b1 ;
        end 
        else if (cur_s[TX_CH8_D]) begin
            ch8_tx_en <= 1'b0 ;
        end 
    end
        
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            cur_s       <=  'd0     ;
            cur_s[TX_IDLE] <=  1'b1    ;
        end 
        else begin
            cur_s   <=  next_s  ;
        end 
    end 
    
    always @ ( * ) begin
        next_s = 'd0 ;
        case(1'b1)
            cur_s[TX_IDLE] : begin
                if (!tcp_tx_busy_i) begin
                    next_s[TX_CH1] = 1'b1 ;
                end 
                else begin
                    next_s[TX_IDLE] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH1] : begin
                if ((!tcp_tx_busy_i) && (ch1_tx_en == 1'b1)) begin
                    next_s[TX_CH1_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch1_tx_en == 1'b0)) begin
                    next_s[TX_CH2] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH1] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH1_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH2] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH1_D] = 1'b1 ;
                end
            end 
            cur_s[TX_CH2] : begin
                if ((!tcp_tx_busy_i) && (ch2_tx_en == 1'b1)) begin
                    next_s[TX_CH2_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch2_tx_en == 1'b0)) begin
                    next_s[TX_CH3] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH2] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH2_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH3] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH2_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH3] : begin
                if ((!tcp_tx_busy_i) && (ch3_tx_en == 1'b1)) begin
                    next_s[TX_CH3_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch3_tx_en == 1'b0)) begin
                    next_s[TX_CH4] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH3] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH3_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH4] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH3_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH4] : begin
                if ((!tcp_tx_busy_i) && (ch4_tx_en == 1'b1)) begin
                    next_s[TX_CH4_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch4_tx_en == 1'b0)) begin
                    next_s[TX_CH5] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH4] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH4_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH5] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH4_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH5] : begin
                if ((!tcp_tx_busy_i) && (ch5_tx_en == 1'b1)) begin
                    next_s[TX_CH5_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch5_tx_en == 1'b0)) begin
                    next_s[TX_CH6] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH5] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH5_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH6] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH5_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH6] : begin
                if ((!tcp_tx_busy_i) && (ch6_tx_en == 1'b1)) begin
                    next_s[TX_CH6_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch6_tx_en == 1'b0)) begin
                    next_s[TX_CH7] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH6] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH6_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH7] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH6_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH7] : begin
                if ((!tcp_tx_busy_i) && (ch7_tx_en == 1'b1)) begin
                    next_s[TX_CH7_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch7_tx_en == 1'b0)) begin
                    next_s[TX_CH8] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH7] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH7_D] : begin
                if (tx_data_done) begin
                    next_s[TX_CH8] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH7_D] = 1'b1 ;
                end
            end
            cur_s[TX_CH8] : begin
                if ((!tcp_tx_busy_i) && (ch8_tx_en == 1'b1)) begin
                    next_s[TX_CH8_D] = 1'b1 ;
                end
                else if ((!tcp_tx_busy_i) && (ch8_tx_en == 1'b0)) begin
                    next_s[TX_DONE] = 1'b1 ;
                end  
                else begin
                    next_s[TX_CH8] = 1'b1 ;
                end 
            end 
            cur_s[TX_CH8_D] : begin
                if (tx_data_done) begin
                    next_s[TX_DONE] = 1'b1 ;
                end 
                else begin
                    next_s[TX_CH8_D] = 1'b1 ;
                end
            end
            cur_s[TX_DONE] : begin
                if (!tcp_tx_busy_i) begin
                    next_s[TX_IDLE] = 1'b1 ;
                end 
                else begin
                    next_s[TX_DONE] = 1'b1 ;
                end 
            end 
            default : next_s[TX_IDLE] = 1'b1 ;
        endcase
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            tx_data_cnt <= 16'd0 ;
        end
        else begin
            ch1_rd_req_o <= 1'b0 ;
            ch2_rd_req_o <= 1'b0 ;
            ch3_rd_req_o <= 1'b0 ;
            ch4_rd_req_o <= 1'b0 ;
            ch5_rd_req_o <= 1'b0 ;
            ch6_rd_req_o <= 1'b0 ;
            ch7_rd_req_o <= 1'b0 ;
            ch8_rd_req_o <= 1'b0 ;
            case(1'b1)
                next_s[TX_CH1_D] : begin                     
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch1_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch1_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH2_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch2_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch2_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH3_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch3_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch3_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH4_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch4_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch4_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH5_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch5_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch5_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH6_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch6_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch6_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH7_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch7_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch7_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                next_s[TX_CH8_D] : begin
                    if (tx_data_cnt < TCP_TX_LENTH - 1 ) begin                        
                        if (ch8_tx_dvalid_i) begin
                            tx_data_cnt <= tx_data_cnt + 1'b1 ;
                        end 
                        else begin
                            tx_data_cnt <= tx_data_cnt ;
                        end
                        ch8_rd_req_o <= 1'b1 ; 
                    end 
                    else begin
                        tx_data_cnt <= tx_data_cnt ;
                    end
                end
                default :  tx_data_cnt <= 16'd0 ;
            endcase
        end   
    end 
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            tx_data_done <= 1'b0 ;
        end 
        else if (tx_data_cnt == TCP_TX_LENTH - 1) begin
            tx_data_done <= 1'b1 ;
        end 
        else begin
            tx_data_done <= 1'b0 ;
        end 
    end
    
    always @ (posedge clk_i) begin
        if (!rst_n) begin
            tx_data_o   <= 16'd0 ;
            tx_dvalid_o <= 1'b0  ;
        end 
        else if (cur_s[TX_CH1_D]) begin
            tx_data_o   <= ch1_tx_data_i    ;
            tx_dvalid_o <= ch1_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH2_D]) begin            
            tx_data_o   <= ch2_tx_data_i    ;
            tx_dvalid_o <= ch2_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH3_D]) begin           
            tx_data_o   <= ch3_tx_data_i    ;
            tx_dvalid_o <= ch3_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH4_D]) begin            
            tx_data_o   <= ch4_tx_data_i    ;
            tx_dvalid_o <= ch4_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH5_D]) begin           
            tx_data_o   <= ch5_tx_data_i    ;
            tx_dvalid_o <= ch5_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH6_D]) begin            
            tx_data_o   <= ch6_tx_data_i    ;
            tx_dvalid_o <= ch6_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH7_D]) begin           
            tx_data_o   <= ch7_tx_data_i    ;
            tx_dvalid_o <= ch7_tx_dvalid_i  ;
        end
        else if (cur_s[TX_CH8_D]) begin            
            tx_data_o   <= ch8_tx_data_i    ;
            tx_dvalid_o <= ch8_tx_dvalid_i  ;
        end
        else begin
            tx_data_o   <= 16'd0 ;
            tx_dvalid_o <= 1'b0  ;
        end  
    end  
    
 

endmodule
  • 3.Dma_data_gen模块实现控制DMA的数据写入。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/03/10 11:25:16
// Design Name: 
// Module Name: data_gen
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module dma_data_gen(
    input           pl_clk          ,
    input           ps_clk          ,
    input     		rst_n		    ,
    input           gpio_en         ,
    input           dma_fifo_wr_en  ,
    input   [15:0]  dma_fifo_din    ,
    output          dma_fifo_afull  ,
      	
    input    		S_AXIS_tready	,
    output  		S_AXIS_tvalid	,
    output  		S_AXIS_tlast	,
    output  [15:0] 	S_AXIS_tdata    ,
    output  [1:0]   S_AXIS_tkeep    ,
    output  [1:0]   debug_state
);
    reg             S_AXIS_tvalid   ;
    reg             S_AXIS_tlast    ;
    reg [15:0]      S_AXIS_tdata    ;
    reg [2:0]       state           ;
    
    reg             dma_fifo_rd_en  ;
    wire    [15:0]  dma_fifo_dout   ;
    wire            dma_fifo_dvalid ;
    wire            dma_fifo_full   ;
    wire            dma_fifo_empty  ;
    wire            dma_fifo_pfull  ;
    reg     [15:0]  dma_data_cnt    ;
    
    reg         rst_n_ff1   ;
    reg         rst_n_ff2   ;
    reg         rst_n_ff3   ; 
    
    assign S_AXIS_tkeep = 2'b11;
    assign debug_state = state[1:0] ;


dma_fifo udma_fifo (
    .rst        (!rst_n         ),// input wire rst   
    .wr_clk     (pl_clk         ),// input wire wr_clk
    .rd_clk     (ps_clk         ),// input wire rd_clk
    .din        (dma_fifo_din   ),// input wire [15 : 0] din
    .wr_en      (dma_fifo_wr_en ),// input wire wr_en
    .rd_en      (dma_fifo_rd_en ),// input wire rd_en
    .dout       (dma_fifo_dout  ),// output wire [15 : 0] dout
    .full       (dma_fifo_full  ),// output wire full
    .almost_full(dma_fifo_afull ),// output wire almost_full
    .empty      (dma_fifo_empty ),// output wire empty
    .valid      (dma_fifo_dvalid),// output wire valid
    .prog_full  (dma_fifo_pfull ) // output wire prog_full
);


    always @ (posedge ps_clk) begin
        rst_n_ff1   <=  rst_n       ;
        rst_n_ff2   <=  rst_n_ff1   ;
        rst_n_ff3   <=  rst_n_ff2   ;
    end 


    always@(posedge ps_clk) begin
        if(!rst_n_ff3) begin
            S_AXIS_tvalid  <= 1'b0 ;
            S_AXIS_tlast   <= 1'b0 ;
            S_AXIS_tdata   <= 16'd0;
            dma_fifo_rd_en <= 1'b0 ;
            dma_data_cnt   <= 16'd0;
            state <= 0;
        end
        else begin
            case(state) //状态机
                0: begin
                    if (gpio_en) begin
                        state <= 1;
                    end 
                    else begin
                        state <= 0 ;
                    end 
                end 
                1: begin
                    if(dma_fifo_pfull&&S_AXIS_tready) begin //启动信号到来且FIFO可写
                        dma_fifo_rd_en <= 1'b1; //设置读DMA FIFO有效
                        state <= 2;
                    end
                    else begin
                        dma_fifo_rd_en <= 1'b0;
                        state <= 1;
                    end
                end
                2:begin
                    if(S_AXIS_tready) begin //FIFO可写                       
                        if (dma_fifo_dvalid) begin
                            dma_data_cnt <= dma_data_cnt + 1'b1 ;
                            S_AXIS_tvalid <= 1'b1;
                            S_AXIS_tdata   <= dma_fifo_dout;                            
                        end
                        
                        if (dma_data_cnt <= 16'd509) begin
                            dma_fifo_rd_en <= 1'b1         ; //设置读DMA FIFO有效
                        end 
                        else begin
                            dma_fifo_rd_en <= 1'b0         ; //设置读DMA FIFO有效
                        end
                         
                        if (dma_data_cnt == 16'd511) begin
                            state <= 3;
                            S_AXIS_tlast <= 1'b1;//发送最后一个数据
                        end 
                        else begin
                            state <= 2;
                            S_AXIS_tlast <= 1'b0;
                        end 
                    end
                    else begin//等待FIFO可写
                        dma_fifo_rd_en <= 1'b0;
                        S_AXIS_tdata <= S_AXIS_tdata;
                        state <= 2;
                    end
                end
                3:begin
                    dma_fifo_rd_en <= 1'b0;
                    dma_data_cnt   <= 16'd0 ;
                    if(!S_AXIS_tready) begin //FIFO满则等待
                        S_AXIS_tvalid <= 1'b1;
                        S_AXIS_tlast <= 1'b1;
                        S_AXIS_tdata <= dma_fifo_dout;
                        state <= 3;
                    end
                    else begin //写入结束
                        S_AXIS_tvalid <= 1'b0;
                        S_AXIS_tlast <= 1'b0;
                        S_AXIS_tdata <= 16'd0;
                        state <= 0;
                    end
                end
                default: state <=0;
            endcase
        end
    end


endmodule
  • 四、PS端设计

1.DMA数据发送

PS 的 dma 数据接收采用了乒乓操作的模式,两个缓冲区交替进行数据接收。XAxiDma_SimpleTransfer 函数中 Length,以字节为单位,每次发起 dma 时,设置的 Length 的值必须大于或等于 PL 实际传输的数据长度,否则会出现错误。本例程中设置的长度 为 1024字节。first_trans_start 是为了进行第一次先进行一次 DMA 中断传输,这样完成后设置 first_trans_start 为 0。以 后每次完成网络传输后,再启动 DMA 接受。TCP 数据包的发送主要依赖于 tcp_write 和 tcp_output 两个函数,tcp_write 将所需要发送的数 据写入 tcp 发送缓冲区等待发送,tcp_output 函数则将缓存区内数据包发送出去。在发送 TCP 数据包时,这两个函数往往要同时配合使用。

void send_dma_data()

{

#if __arm__

int copy = 3;

#else

int copy = 0;

#endif

err_t err;

int Status;

struct tcp_pcb *tpcb = connected_pcb;









/*initial the first axdma transmission, only excuse once*/

if(!first_trans_start)

{

Status = XAxiDma_SimpleTransfer(&AxiDma, (u32)RxBufferPtr[0],

(u32)(PAKET_LENGTH), XAXIDMA_DEVICE_TO_DMA);

if (Status != XST_SUCCESS)

{

xil_printf("axi dma failed! 0 %d\r\n", Status);

return;

}



first_trans_start = 1;

}



/*if the last axidma transmission is done, the interrupt triggered, then start TCP transmission*/

if(packet_trans_done)

{



if (!connected_pcb)

return;





if (tcp_sndbuf(tpcb) > SEND_SIZE)

{



err = tcp_write(tpcb, RxBufferPtr[packet_index & 1], SEND_SIZE, copy);

if (err != ERR_OK) {

xil_printf("txperf: Error on tcp_write: %d\r\n", err);

connected_pcb = NULL;

return;

}

err = tcp_output(tpcb);

if (err != ERR_OK) {

xil_printf("txperf: Error on tcp_output: %d\r\n",err);

return;

}



Xil_DCacheFlushRange((u32)RxBufferPtr[(packet_index)&1], (u32)(PAKET_LENGTH));   //刷新Data Cache



packet_index++;



packet_trans_done = 0;





Status = XAxiDma_SimpleTransfer(&AxiDma, (u32)RxBufferPtr[(packet_index)&1],

(u32)(PAKET_LENGTH), XAXIDMA_DEVICE_TO_DMA);

if (Status != XST_SUCCESS)

{

xil_printf("axi dma %d failed! %d \r\n", (packet_index), Status);

return;

}





}

}

}

2.main 函数的主要流程:

1):初始化并配置 PL 侧的 AXI GPIO

2):初始化并配置 PL 侧的 AXI DMA

3):初始化并配置 PS 的中断控制器

4):初始化 lwip 协议栈和 PS 的以太网控制器

5):配置 TCP 传输所需的相关参数,并与服务器建立 TCP 连接

6)接收上位机下发的参数,写入BRAM,通知PL读取BRAM数据进行参数解析

7):通过 AXI GPIO 启动 PL 进行数据生成和传输

8):通过 AXI DMA 接收 PL 传输的数据,通过 TCP 发送至 PC 机,并不断循环该过程

  • 五、TCP连接

  • 本系统中ZYNQ 作为客户端,PC 作为服务器。由zynq 向PC 主动发起 TCP 连接请求,通过tcp_connect 函数便可以完成这个过程。该函数的参数包含了一个回调函数指针tcp_connected_fn,该回调函数将在TCP 连接请求三次握手完成后被自动调用。该回调函数被调用时代表客户端和服务器之间的TCP 连接建立完 成。在本例程中,该回调函数被定义为 tcp_connected_callback,在该函数中,拉高连接建立完成信号 tcp_client_connected,并通过tcp_sent 函数配置另一个TCP 发送完成的回调函数。该回调函数在每个 TCP 包发送完成后会被自动调用,代表 TCP 包发送完成。该回调函数在本例程中被定义为tcp_sent_callback, 仅作发送完成数据包的计数。

你可能感兴趣的:(ZYNQ,fpga开发,嵌入式硬件,tcp/ip,硬件工程)