最近看了很多UDP的资料,也参考并实现了很多种方案,但总觉得不完美,有轻量级的UDP方案,但不支持ping功能,这种也能实现UDP通信,但在工程上等同于废物,试想,多点通信时一旦不同,如果ping功能都没有,来怎么排查?所以这种方案直接被pass;其次,也有支持ping功能的方案,但实现过于复杂,时序也够复杂,且不适合大批量数据传输,比如opencorese上面的;其实关于UDP网络通信,Xilinx是有自己的方案的,但只给到了rgmii转gmii这一层,并给出了三速网IP,将rgmii转为axis用户接口的gmii,但并没有给出完整UDP封装的IP核,这一点给了米联客机会,米联客推出了自己的UDP协议栈,用于对接Xilinx的三速网IP,从而解决了改问题,但该UDP协议栈只是网表文件,并未给出源码。 根据官方手册,封装了的UDP协议栈用户接口发送时序如下: 首先等待udp_tx_ready为高,然后拉高app_tx_request信号,并等待UDP应答信号app_tx_ack,若app_tx_ack为高,则拉高app_tx_data_valid并给出发送数据app_tx_data、发送长度app_tx_data_length以及app_tx_data_keep,并在数据包的最后一个数据拉高app_tx_data_last; 需要注意的是,在一包数据期间,app_tx_data_valid必须持续为高,如果不需要数据屏蔽,app_tx_data_keep移植保持0xff; 接收时序如下: 接收就简单多了,app_rx_data_valid为高期间接收app_rx_data就可以了,当app_rx_data_last拉高时表明数据接收完毕,同时也给出了发送的数据长度app_rx_data_length。
协议栈总体框图如下:
实现流程如下图:
Tri_mode_ethernet_mac配置为千兆网,若依时钟是125M,用户接口是8bit的axis接口,而协议栈的用户接口是64bit的,所以对于传单个数据而言,协议栈一侧的时钟应=125X8÷64=15.625M,通过其中1个FIFO实现异步时钟域的转换,1个FIFO实现数 据缓冲和同步Packet mode功能。 Packet mode 是指 FIFO 在输出数据前持续缓存 AXI-Stream 接口输入的数据直至输入端 tlast 信号拉高, 即存满一个完整的数据包时,才开始在 AXI-Stream 输出端口向外输出数据。Packet mode 功能设置如下图所 示。需要注意的是,启用 Packet mode 时,FIFO 必须工作于同步模式。 对于发送路径,启用 Packet mode 是为了防止 FIFO 被 IP 核读空。对于接收路径,是由于米联的 UDP IP 协议栈要求 1 个数据包的 tvalid 信号在数据包持续期间必须恒为 1。
环通测试的波形如下,与官方手册一致。
测试代码如下:
module udp_loop_test(
input reset ,
input dcm_locked ,
input refclk_200m ,
input udp_clk_15_625m ,
input gtx_clk_125m ,
input rgmii_rxc ,
input rgmii_rx_ctl ,
input [3:0] rgmii_rxd ,
output rgmii_txc ,
output rgmii_tx_ctl ,
output [3:0] rgmii_txd
);
(* MARK_DEBUG="true" *) wire core_reset ;
(* MARK_DEBUG="true" *) wire udp_tx_ready ;
(* MARK_DEBUG="true" *) wire app_tx_ack ;
(* MARK_DEBUG="true" *) wire [63:0] app_tx_data ;
(* MARK_DEBUG="true" *) wire dst_ip_unreachable ;
(* MARK_DEBUG="true" *) wire app_rx_data_valid ;
(* MARK_DEBUG="true" *) wire [63:0] app_rx_data ;
(* MARK_DEBUG="true" *) wire [15:0] app_rx_data_length ;
(* MARK_DEBUG="true" *) wire udp_rx_error ;
(* MARK_DEBUG="true" *) wire ip_rx_error ;
(* MARK_DEBUG="true" *) wire [8:0] fifo_data_count ;
(* MARK_DEBUG="true" *) reg app_tx_request ;
(* MARK_DEBUG="true" *) reg app_tx_data_valid ;
(* MARK_DEBUG="true" *) reg app_tx_data_last ;
(* MARK_DEBUG="true" *) reg [15:0] app_tx_data_length ;
(* MARK_DEBUG="true" *) reg [7: 0] app_tx_data_keep ;
(* MARK_DEBUG="true" *) reg rd_en ;
(* MARK_DEBUG="true" *) reg [3:0] ST ;
(* MARK_DEBUG="true" *) reg [15:0] udp_tx_length ;
always @(posedge udp_clk_15_625m) begin
if(core_reset) begin
app_tx_request
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?