一、设计目标
使用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数据上报
正弦波
方波
三角波
多频音波