Bootstrap

以太网实战AD采集上传上位机——FPGA学习笔记27

一、设计目标

使用FPGA实现AD模块驱动采集模拟电压,通过以太网上传到电脑上位机。

二、框架设计

数据位宽转换模块(ad_10bit_to_16bit):为了方便数据传输,数据位宽转换模块实现了将十位的 AD 数据转换成十六位,并且为了异步 FIFO 传输将高八位和低八位交换然后传输给数据封装模块。
开始传输模块(start_transfer_ctrl):该模块接收上位机发送的命令来判断是否开启传输以及使用那个通道传输。
数据封装模块(img_data_pkt):该模块调用异步 FIFO 将十六位的 AD 数据转换为传输给以太网部分的八位 UDP 数据,并且控制一包数据的大小和以太网 UDP 开始发送信号。


(1)开始传输模块 start_transfer_ctrl

module start_transfer_ctrl(
    input                 clk                ,   //时钟信号
    input                 rst_n              ,   //复位信号,低电平有效
    input                 udp_rec_pkt_done   ,   //UDP单包数据接收完成信号 
    input                 udp_rec_en         ,   //UDP接收的数据使能信号
    input        [7 :0]   udp_rec_data       ,   //UDP接收的数据 
    input        [15:0]   udp_rec_byte_num   ,   //UDP接收到的字节数   
    output  reg  [1:0]    ctrl               ,                                
    output  reg           transfer_flag          //图像开始传输标志,1:开始传输 0:停止传输    
);    
    
//parameter define
parameter  START_1 = 8'd1;  //通道一开始命令
parameter  STOP    = 8'd0;  //停止命令
parameter  START_2 = 8'd2;  //通道二开始命令

//解析接收到的数据
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        transfer_flag   <=  1'b0;
    end
    else if (udp_rec_pkt_done && udp_rec_byte_num == 1'b1)begin
        if (udp_rec_data == START_1) begin
            transfer_flag   <=  1'b1;
            ctrl            <=  2'b01;
        end
        else if (udp_rec_data == START_2) begin
            transfer_flag   <=  1'b1;
            ctrl            <=  2'b10;
        end 
        else if (udp_rec_data == STOP) begin
            transfer_flag   <=  1'b0;
            ctrl            <=  2'b00;
        end 
        else begin
            transfer_flag   <=  1'b0;
            ctrl            <=  2'b00;
        end
    end 
end





endmodule

(2)开始传输模块  start_transfer_ctrl

module ad_10bit_to_16bit(
    input                 clk       ,
    input                 rst_n     ,
    input       [1:0]     sel       ,//控制命令
    input       [9:0]     ad_in1    ,//通道一数据
    input       [9:0]     ad_in2    ,//通道二数据
    output  reg [15:0]    ad_out     //输出数据
);

//wire define 
wire [9:0]s_ad_in1;
wire [9:0]s_ad_in2;
  
//十位扩展为十六位	
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        ad_out <= 16'd0;
    end
    else if( sel == 2'b01) begin
        ad_out<={6'd0,ad_in1};//这样补0为了适应上位机
    end
    else if( sel == 2'b10) begin
        ad_out<={6'd0,ad_in2};//
    end
    else begin
        ad_out <= 16'd0;
    end
end

endmodule

(3)数据封装模块    img_data_pkt:

 

(4)UDP顶层修改

主要修改UDP顶层UDP协议接口,对ICMP以及ARP部分进行保留

module eth_top(
    input                   sys_rst_n           ,   //系统复位信号,低电平有效 
    input                   clk_200m            ,
    output                  gmii_rx_clk         ,
    output                  gmii_tx_clk         ,
    //PL以太网RGMII接口                     
    //input
    input                   eth_rxc             ,   //RGMII接收数据时钟
    input                   eth_rx_ctl          ,   //RGMII输入数据有效信号
    input       [3:0]       eth_rxd             ,   //RGMII输入数据
    //output
    output                  eth_txc             ,   //RGMII发送数据时钟    
    output                  eth_tx_ctl          ,   //RGMII输出数据有效信号
    output      [3:0]       eth_txd             ,   //RGMII输出数据       

    //UDP接口
    input                   udp_tx_start_en     ,   //UDP发送开始使能信号 
    input       [7:0]       udp_tx_data         ,   //UDP待发送数据
    input       [15:0]      udp_tx_byte_num     ,   //UDP发送的有效字节数 单位:byte 

    output                  udp_rec_pkt_done    ,   //UDP单包数据接收完成信号   
    output                  udp_tx_done         ,   //UDP发送完成信号 
    output                  udp_tx_req          ,   //UDP读数据请求信号
    output                  udp_rec_en          ,   //UDP接收的数据使能信号
    output      [7:0]       udp_rec_data        ,   //UDP接收的数据
    output      [15:0]      udp_rec_byte_num  	    //UDP接收的有效字节数 单位:byte
    
);

//parameter define
parameter  BOARD_MAC = 48'h00_11_22_33_44_55;       //开发板MAC地址     00-11-22-33-44-55
parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};  //开发板IP地址      192.168.1.10
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;       //目的MAC地址       ff_ff_ff_ff_ff_ff
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102}; //目的IP地址        192.168.1.102     
parameter  IDELAY_VALUE = 15;                       //输入数据IO延时    (如果为n,表示延时n*78ps) 

//wire define
// wire                    clk_200m   		        ;   //用于IO延时的时钟 
                
// wire                    gmii_rx_clk             ;   //GMII接收时钟
wire                    gmii_rx_dv              ;   //GMII接收数据有效信号
wire          [7:0]     gmii_rxd                ;   //GMII接收数据
// wire                    gmii_tx_clk             ;   //GMII发送时钟
wire                    gmii_tx_en              ;   //GMII发送数据使能信号
wire          [7:0]     gmii_txd                ;   //GMII发送数据     
                
//ARP信号
wire                    arp_gmii_tx_en	        ;   //ARP GMII输出数据有效信号 
wire          [7:0]     arp_gmii_txd  	        ;   //ARP GMII输出数据
wire                    arp_rx_done   	        ;   //ARP接收完成信号
wire                    arp_rx_type   	        ;   //ARP接收类型 0:请求  1:应答
wire          [47:0]    src_mac       	        ;   //接收到目的MAC地址
wire          [31:0]    src_ip        	        ;   //接收到目的IP地址    
wire                    arp_tx_en     	        ;   //ARP发送使能信号
wire                    arp_tx_type   	        ;   //ARP发送类型 0:请求  1:应答
wire          [47:0]    des_mac       	        ;   //发送的目标MAC地址
wire          [31:0]    des_ip        	        ;   //发送的目标IP地址   
wire                    arp_tx_done   	        ;   //ARP发送完成信号
                
//ICMP信号
wire                    icmp_gmii_tx_en	        ;   //ICMP GMII输出数据有效信号 
wire          [7:0]     icmp_gmii_txd  	        ;   //ICMP GMII输出数据
wire                    icmp_rec_pkt_done       ;   //ICMP单包数据接收完成信号
wire                    icmp_rec_en             ;   //ICMP接收的数据使能信号
wire          [ 7:0]    icmp_rec_data           ;   //ICMP接收的数据
wire          [15:0]    icmp_rec_byte_num       ;   //ICMP接收的有效字节数 单位:byte 
wire          [15:0]    icmp_tx_byte_num        ;   //ICMP发送的有效字节数 单位:byte 
wire                    icmp_tx_done   	        ;   //ICMP发送完成信号
wire                    icmp_tx_req             ;   //ICMP读数据请求信号
wire          [ 7:0]    icmp_tx_data            ;   //ICMP待发送数据
wire                    icmp_tx_start_en        ;   //ICMP发送开始使能信号

//UDP信号
wire                    udp_gmii_tx_en	        ;   //UDP GMII输出数据有效信号 
wire          [7:0]     udp_gmii_txd  	        ;   //UDP GMII输出数据
// wire                    udp_rec_pkt_done  	        ;   //UDP单包数据接收完成信号
// wire                    udp_rec_en    	        ;   //UDP接收的数据使能信号
// wire          [ 7:0]    udp_rec_data  	        ;   //UDP接收的数据
// wire          [15:0]    udp_rec_byte_num  	        ;   //UDP接收的有效字节数 单位:byte 
// wire          [15:0]    udp_tx_byte_num   	    ;   //UDP发送的有效字节数 单位:byte 
// wire                    udp_tx_done   	        ;   //UDP发送完成信号
// wire                    udp_tx_req    	        ;   //UDP读数据请求信号
// wire          [ 7:0]    udp_tx_data   	        ;   //UDP待发送数据
// wire                    udp_tx_start_en   	    ;   //UDP发送开始使能信号
                
wire          [7:0]	    rec_data			    ;   //FIFO写入数据
wire        		    rec_en			        ;   //FIFO写使能
wire        		    tx_req			        ;   //FIFO读使能
wire          [7:0]	    tx_data	    	        ;   //FIFO读出数据


assign icmp_tx_start_en =   icmp_rec_pkt_done   ;   //ICMP 接收端结束标志,作为 ICMP发送端开始标志
assign icmp_tx_byte_num =   icmp_rec_byte_num   ;   //ICMP 接收端数据个数,作为 ICMP发送端发送数据 

// assign udp_tx_start_en      =   udp_rec_pkt_done    ;   //UDP 接收端结束标志,作为 UDP发送开始使能信号
// assign udp_tx_byte_num      =   udp_rec_byte_num        ;   //UDP 接收端数据个数,作为 UDP发送端发送数据个数

assign des_mac          =   src_mac             ;   //ARP 接收到的 源MAC,作为 ICMP\UDP 目的MAC,实际为电脑端MAC
assign des_ip           =   src_ip              ;   //ARP 接收到的 源IP ,作为 ICMP\UDP 目的IP ,实际为电脑端IP

                                                    //数据位于异步FIFO之中,如需单独使用一侧功能,可以修改FIFO数据
                                                    //需要注意写入有效数据数量要与此处相同,一定要注意 数据个数与FIFO读出数据对齐!!!!!!! 

// //MMCM/PLL 产生200Mhz时钟--> gmii2rgmii
// clk_wiz_0 u_clk_wiz_0
// (
//     .clk_out1           (clk_200m           ),      // output clk_out1
//     .reset              (~sys_rst_n         ),      // input reset
//     .locked             (locked             ),      // output locked
//     .clk_in1            (eth_rxc            )       // PHY侧提供eth_rxc时钟125Mhz
// );  

//GMII接口转RGMII接口
gmii_to_rgmii 
#(
    .IDELAY_VALUE       (IDELAY_VALUE       )
)      
u_gmii_to_rgmii(        
    .idelay_clk         (clk_200m           ),      //IDELAY时钟
    //以太网GMII接口    
    .gmii_rx_clk        (gmii_rx_clk        ),      //GMII接收时钟
    .gmii_rx_dv         (gmii_rx_dv         ),      //GMII接收数据有效信号
    .gmii_rxd           (gmii_rxd           ),      //GMII接收数据
    .gmii_tx_clk        (gmii_tx_clk        ),      //GMII发送时钟
    .gmii_tx_en         (gmii_tx_en         ),      //GMII发送数据使能信号
    .gmii_txd           (gmii_txd           ),      //GMII发送数据   
    //以太网RGMII接口   
    .rgmii_rxc          (eth_rxc            ),      //RGMII接收时钟
    .rgmii_rx_ctl       (eth_rx_ctl         ),      //RGMII接收数据控制信号
    .rgmii_rxd          (eth_rxd            ),      //RGMII接收数据
    .rgmii_txc          (eth_txc            ),      //RGMII发送时钟    
    .rgmii_tx_ctl       (eth_tx_ctl         ),      //RGMII发送数据控制信号
    .rgmii_txd          (eth_txd            )       //RGMII发送数据   
);

//ARP通信
arp                                             
#(
    .BOARD_MAC          (BOARD_MAC          ),      //参数例化
    .BOARD_IP           (BOARD_IP           ),
    .DES_MAC            (DES_MAC            ),
    .DES_IP             (DES_IP             )
)   
u_arp(  
    .rst_n              (sys_rst_n  	    ),      //复位信号,低电平有效

    //GMII接口  
    //input
    .gmii_rx_clk        (gmii_rx_clk	    ),      //GMII接收数据时钟
    .gmii_rx_dv         (gmii_rx_dv 	    ),      //GMII输入数据有效信号
    .gmii_rxd           (gmii_rxd   	    ),      //GMII输入数据
    .gmii_tx_clk        (gmii_tx_clk	    ),      //GMII发送数据时钟
    //output
    .gmii_tx_en         (arp_gmii_tx_en     ),      //GMII输出数据有效信号
    .gmii_txd           (arp_gmii_txd       ),      //GMII输出数据         

    //用户接口                           
    //output
    .arp_rx_done        (arp_rx_done	    ),      //ARP接收完成信号
    .arp_rx_type        (arp_rx_type	    ),      //ARP接收类型 0:请求  1:应答
    .src_mac            (src_mac    	    ),      //接收到目的MAC地址
    .src_ip             (src_ip     	    ),      //接收到目的IP地址 
    //input   
    .arp_tx_en          (arp_tx_en  	    ),      //ARP发送使能信号
    .arp_tx_type        (arp_tx_type	    ),      //ARP发送类型 0:请求  1:应答
    .des_mac            (des_mac    	    ),      //发送的目标MAC地址
    .des_ip             (des_ip     	    ),      //发送的目标IP地址

    //output
    .tx_done            (arp_tx_done	    )       //以太网发送完成信号    
);  

//ICMP通信  
icmp                                             
#(
    .BOARD_MAC          (BOARD_MAC          ),      //参数例化
    .BOARD_IP           (BOARD_IP           ),
    .DES_MAC            (DES_MAC            ),
    .DES_IP             (DES_IP             )
)
u_icmp(
    .rst_n              (sys_rst_n   	    ),      //复位信号,低电平有效

    //GMII接口
    //input
    .gmii_rx_clk        (gmii_rx_clk 	    ),      //GMII接收数据时钟         
    .gmii_rx_dv         (gmii_rx_dv  	    ),      //GMII输入数据有效信号       
    .gmii_rxd           (gmii_rxd    	    ),      //GMII输入数据                 
    .gmii_tx_clk        (gmii_tx_clk 	    ),      //GMII发送数据时钟
    //output
    .gmii_tx_en         (icmp_gmii_tx_en	),      //GMII输出数据有效信号       
    .gmii_txd           (icmp_gmii_txd	    ),      //GMII输出数据

    //用户接口
    //output
    .rec_pkt_done       (icmp_rec_pkt_done  ),      //以太网单包数据接收完成信号  
    .rec_en             (icmp_rec_en        ), 	    //以太网接收的数据使能信号				  
    .rec_data           (icmp_rec_data      ),      //以太网接收的数据				 	    
    .rec_byte_num       (icmp_rec_byte_num  ),      //以太网接收的有效字节数 单位:byte   
    //input
    .tx_start_en        (icmp_tx_start_en   ),      //以太网开始发送信号      
    .tx_data            (icmp_tx_data       ),      //以太网待发送数据					     
    .tx_byte_num        (icmp_tx_byte_num   ),      //以太网发送的有效字节数 单位:byte
    .des_mac            (des_mac     	    ),      //发送的目标MAC地址
    .des_ip             (des_ip      	    ),      //发送的目标IP地址  

    //output
    .tx_done            (icmp_tx_done	    ),      //以太网发送完成信号      
    .tx_req             (icmp_tx_req        )       //读数据请求信号					     
); 

//UDP通信
udp                                             
#(
    .BOARD_MAC          (BOARD_MAC          ),      //参数例化
    .BOARD_IP           (BOARD_IP           ),
    .DES_MAC            (DES_MAC            ),
    .DES_IP             (DES_IP             )
)
u_udp(
    .rst_n              (sys_rst_n          ),      //复位信号,低电平有效

    //GMII接口
    //input
    .gmii_rx_clk        (gmii_rx_clk        ),      //GMII接收数据时钟 
    .gmii_rx_dv         (gmii_rx_dv         ),      //GMII输入数据有效信号
    .gmii_rxd           (gmii_rxd           ),      //GMII输入数据
    .gmii_tx_clk        (gmii_tx_clk        ),      //GMII发送数据时钟   
    //output 
    .gmii_tx_en         (udp_gmii_tx_en     ),      //GMII输出数据有效信号
    .gmii_txd           (udp_gmii_txd       ),      //GMII输出数据 

    //用户接口
    //outpur
    .rec_pkt_done       (udp_rec_pkt_done   ),      //以太网单包数据接收完成信号 
    .rec_en             (udp_rec_en         ),      //以太网接收的数据使能信号
    .rec_data           (udp_rec_data       ),      //以太网接收的数据      
    .rec_byte_num       (udp_rec_byte_num   ),      //以太网接收的有效字节数 单位:byte      
    //input
    .tx_start_en        (udp_tx_start_en    ),      //以太网开始发送信号      
    .tx_data            (udp_tx_data        ),      //以太网待发送数据        
    .tx_byte_num        (udp_tx_byte_num    ),      //以太网发送的有效字节数 单位:byte      
    .des_mac            (des_mac            ),      //发送的目标MAC地址      
    .des_ip             (des_ip             ),      //发送的目标IP地址    

    //output 
    .tx_done            (udp_tx_done        ),      //以太网发送完成信号 
    .tx_req             (udp_tx_req         )       //读数据请求信号   
); 

//异步FIFO,实际做同步FIFO使用
async_fifo_2048x8b u_async_fifo_2048x8b (
    //input
    .rst                (~sys_rst_n	        ),      //input wire rst
    .wr_clk             (gmii_rx_clk        ),  	//input wire wr_clk
    .rd_clk             (gmii_rx_clk        ),  	//input wire rd_clk
    .din                (rec_data	        ),      //input wire [7 : 0] din
    .wr_en              (rec_en		        ),    	//input wire wr_en
    .rd_en              (tx_req		        ),    	//input wire rd_en
    //output
    .dout               (tx_data	        ),      //output wire [7 : 0] dout
    .full               (                   ),      //output wire full
    .empty              (                   )    	//output wire empty
);

// //预留调试ILA
// ila_0 ila_0_fifo (
// 	.clk                (gmii_rx_clk        ),      // input wire clk

// 	.probe0             (rec_en             ),      // input wire [0:0]  probe0  
// 	.probe1             (rec_data           ),      // input wire [7:0]  probe1 
// 	.probe2             (tx_req             ),      // input wire [0:0]  probe2 
// 	.probe3             (tx_data            )       // input wire [7:0]  probe3
// );

//以太网控制模块
eth_ctrl u_eth_ctrl(
    //input
    .clk            	(gmii_rx_clk	    ),      //时钟
    .rst_n          	(sys_rst_n		    ),      //系统复位信号,低电平有效 

    //ARP相关端口信号 
    //input
    .arp_rx_done    	(arp_rx_done   	    ),      //ARP接收完成信号
    .arp_rx_type    	(arp_rx_type   	    ),      //ARP接收类型 0:请求  1:应答
    .arp_tx_done    	(arp_tx_done   	    ),      //ARP发送完成信号
    .arp_gmii_tx_en 	(arp_gmii_tx_en	    ),      //ARP GMII输出数据有效信号 
    .arp_gmii_txd   	(arp_gmii_txd  	    ),      //ARP GMII输出数据
    //output
    .arp_tx_en      	(arp_tx_en     	    ),      //ARP发送使能信号
    .arp_tx_type    	(arp_tx_type   	    ),      //ARP发送类型 0:请求  1:应答

    //ICMP相关端口信号
    //input
    .icmp_tx_start_en	(icmp_tx_start_en   ),      //ICMP开始发送信号
    .icmp_tx_done		(icmp_tx_done	    ),      //ICMP发送完成信号
    .icmp_gmii_tx_en	(icmp_gmii_tx_en    ),      //ICMP GMII输出数据有效信号  
    .icmp_gmii_txd		(icmp_gmii_txd	    ),      //ICMP GMII输出数据 
    //ICMP fifo接口信号
    //input
	.icmp_rec_en       	(icmp_rec_en        ),      //ICMP接收的数据使能信号
	.icmp_rec_data     	(icmp_rec_data      ),      //ICMP接收的数据
	.icmp_tx_req       	(icmp_tx_req        ),      //ICMP读数据请求信号
    //output
	.icmp_tx_data      	(icmp_tx_data       ),      //ICMP待发送数据

    //UDP相关端口信号
    //input
    .udp_tx_start_en	(udp_tx_start_en   	),      //UDP开始发送信号
    .udp_tx_done    	(udp_tx_done   	    ),      //UDP发送完成信号    
    .udp_gmii_tx_en 	(udp_gmii_tx_en	    ),      //UDP GMII输出数据有效信号  
    .udp_gmii_txd   	(udp_gmii_txd  	    ),      //UDP GMII输出数据   
    //UDP fifo接口信号
    //input
	.udp_rec_data		(udp_rec_data       ),      //UDP接收的数据		--->      UDP要发送的数据
	.udp_rec_en			(udp_rec_en         ),      //UDP接收的数据使能信号     
	.udp_tx_req			(udp_tx_req         ),      //UDP读数据请求信号   
    //output 
	.udp_tx_data		(                   ),      //UDP待发送数据		

    //fifo接口信号
    //output
	.rec_data			(rec_data	        ),      //待发送的数据	
	.rec_en	        	(rec_en	            ),      //读数据请求信号 
    .tx_req	        	(tx_req	            ),      //接收的数据使能信号
    //input
	.tx_data	    	(tx_data	        ),      //接收的数据

    //GMII发送引脚  
    //output
    .gmii_tx_en     	(gmii_tx_en    	    ),      //GMII输出数据有效信号 
    .gmii_txd       	(gmii_txd      	    )       //GMII输出数据 
);      

endmodule

三、代码架构

四、下载测试

1、ping指令&ARP

2、UDP数据上报

正弦波

方波

三角波

多频音波

五、源码获取工程移植,请后台私信

;