本随笔是参考如下等人的分享并在个人理解上学习LWIP协议栈和xczu15eg的记录。
https://blog.csdn.net/little_soldier/article/details/122851442?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8-122851442-blog-117993851.235^v43^pc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-8-122851442-blog-117993851.235^v43^pc_blog_bottom_relevance_base2&utm_relevant_index=16
https://gitee.com/wamogu/FPGA/blob/master/tcp_transmission.c
https://pan.baidu.com/s/1XjqxWZ-PYAMbhAlK8-CSjg#list/path=%2Fsharelink1102113311042-974029376530730%2F【正点原子】MPSoC-P15开发板资料盘(A盘)%2F2_文档教程&parentPath=%2Fsharelink1102113311042-974029376530730
参考章节,第十章-定时器中断,第二十二章 AXI DMA环路测试,第二十八章 基于lwip的echo server实验
以下是代码实例。

全局变量文件

点击查看代码
#ifndef GLOBALS_H
#define GLOBALS_H

#include "xparameters.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "xaxidma.h"
#include "xscugic.h"
#include "xemacps.h"
#include "lwip/init.h"
#include "lwip/tcp.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "xttcps.h"

#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR //0x00000000    DDR基地址
#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x01100000) //0x01100000
#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) //0x01200000
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) //0x01400000
#define TEST_START_VALUE 0x0 //测试起始值
#define MAX_PKT_LEN 0x100 //发送包长度

// 全局变量
struct netif netif;                        //lwIP网络接口实例化用作以太网初始化及主函数中的xemacif_input()函数
XAxiDma axi_dma;                           // DMA 实例
XScuGic intc;                              // 中断控制器

err_t error;                            

uint8_t *tx_buffer;   // 接收缓冲区
uint8_t *rx_buffer;   // 发送缓冲区

int status;
volatile uint16_t    NUMBER;

// 状态标志
volatile int dma_tx_done_cnt;              // DMA 发送完成标志
volatile int dma_tx_flag;                  // DMA 发送完成标志
volatile int dma_rx_done_cnt;              // DMA 接收完成标志
volatile int dma_rx_flag;                  // DMA 接收完成标志

volatile int lwip_rx_done_cnt;             // lwIP 接收完成标志
volatile int lwip_tx_done_cnt;             // lwIP 发送完成标志
volatile int TcpFastTmrFlag ;
volatile int TcpSlowTmrFlag ;

#endif // GLOBALS_H

初始化文件头

点击查看代码
#ifndef MY_INIT_H
#define MY_INIT_H

#include "globals.h"

// 定义网络参数
#define DEFAULT_MAC_ADDRESS "0.10.53.0.1.2" // MAC地址
#define DEFAULT_IP_ADDR     "192.168.1.10"  // PS 端 IP
#define DEFAULT_NET_MASK    "255.255.255.0" // 子网掩码
#define DEFAULT_GW_ADDR     "192.168.1.1"   // 网关地址

#define INTC_DEVICE_ID		    XPAR_SCUGIC_SINGLE_DEVICE_ID//SCUGIC的器件 ID
#define DMA_DEV_ID              XPAR_AXIDMA_0_DEVICE_ID     //AXI_DMA的器件 ID
#define EMAC_BASEADDR           XPAR_XEMACPS_0_BASEADDR     //EMAC地址
#define TTC_DEVICE_ID           XPAR_XTTCPS_0_DEVICE_ID     //TTC0 的器件 ID
#define TTC_INTR_ID             XPAR_XTTCPS_0_INTR          //TTC0 的中断 ID

/* server port to listen on/connect to */
#define TCP_CONN_PORT 5001                  //TCP端口号

#define PLATFORM_TIMER_INTR_RATE_HZ (4)

#define ETH_LINK_DETECT_INTERVAL 4

/************************** Function Prototypes ******************************/
int my_setup_XScuGic_init(void);
int dma_init(void);
int eth_init(XScuGic intc);



#endif // MY_INIT_H

初始化源文件

点击查看代码
#include "my_init.h"

static XTtcPs TimerInstance;	//该定时器实例化仅作用于当前文件,为以太网LWIP服务。

int my_setup_XScuGic_init(void){
    static XScuGic_Config *IntcConfig;
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    status = XScuGic_CfgInitialize(&intc, IntcConfig, IntcConfig -> CpuBaseAddress);
	if (status != XST_SUCCESS) {
        xil_printf("XScuGic_init failed %d\r\n", status);
        return XST_FAILURE;
    }
	 /* Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &intc);
    Xil_ExceptionEnable();
	return XST_SUCCESS;
}

int dma_init(void) {
    static XAxiDma_Config *config;
    config = XAxiDma_LookupConfig(DMA_DEV_ID);
    if (!config) {
        xil_printf("No config found for %d\r\n", DMA_DEV_ID);
        return XST_FAILURE;
    }
    status = XAxiDma_CfgInitialize(&axi_dma, config);
    if (status != XST_SUCCESS) {
        xil_printf("Initialization failed %d\r\n", status);
        return XST_FAILURE;
    }

    if (XAxiDma_HasSg(&axi_dma)) {
        xil_printf("Device configured as SG mode\r\n");
        return XST_FAILURE;
    }

    return XST_SUCCESS;
}

//LWIP协议栈初始化,包括定时器和定时器中断初始化,在该函数之前尽量先XCUGIC初始化。


// 将字符串形式的 IP 地址转换为 lwIP 的 ip4_addr_t 类型
static int string_to_ip4(const char* str, ip4_addr_t* ip) {
    return ip4addr_aton(str, ip);
}

static XInterval Interval;
static u8 Prescaler;

static int setup_timer(void)
{
	XTtcPs_Config *Config;
	Config = XTtcPs_LookupConfig(TTC_DEVICE_ID);
	status = XTtcPs_CfgInitialize(&TimerInstance, Config, Config->BaseAddress);
	if (status != XST_SUCCESS) {
		xil_printf("In %s: Timer Cfg initialization failed\r\n",__func__);
		return XST_FAILURE;
	}
	XTtcPs_SetOptions(&TimerInstance, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE);
	XTtcPs_CalcIntervalFromFreq(&TimerInstance, PLATFORM_TIMER_INTR_RATE_HZ, &Interval, &Prescaler);
	XTtcPs_SetInterval(&TimerInstance, Interval);
	XTtcPs_SetPrescaler(&TimerInstance, Prescaler);
	return XST_SUCCESS;
}

static int timer_clear_interrupt(XTtcPs * TimerInstance)
{
	u32 StatusEvent;
	StatusEvent = XTtcPs_GetInterruptStatus(TimerInstance);
	XTtcPs_ClearInterruptStatus(TimerInstance, StatusEvent);
	return XST_SUCCESS;
}
static void timer_callback(XTtcPs *TimerInstance)
{
	static int DetectEthLinkStatus = 0;
	/* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified
	 * by lwIP. It is not important that the timing is absoluetly accurate.
	 */
	static int odd = 1;
#if LWIP_DHCP==1
    static int dhcp_timer = 0;
#endif
	DetectEthLinkStatus++;
    TcpFastTmrFlag = 1;
	odd = !odd;
	if (odd) {
#if LWIP_DHCP==1
		dhcp_timer++;
		dhcp_timoutcntr--;
#endif
		TcpSlowTmrFlag = 1;
#if LWIP_DHCP==1
		dhcp_fine_tmr();
		if (dhcp_timer >= 120) {
			dhcp_coarse_tmr();
			dhcp_timer = 0;
		}
#endif
	}

	/* For detecting Ethernet phy link status periodically */
	if (DetectEthLinkStatus == ETH_LINK_DETECT_INTERVAL) {eth_link_detect(&netif);
		DetectEthLinkStatus = 0;
	}

	timer_clear_interrupt(TimerInstance);
}

static int setup_timer_interrupts(void)
{
    //关联 TTC 中断处理函数
    status = XScuGic_Connect(&intc, TTC_INTR_ID, (Xil_ExceptionHandler)timer_callback, (void *)&TimerInstance);
	if (status != XST_SUCCESS) {
		xil_printf("In %s: setup_timer_interrupts failed\r\n",__func__);
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

static int eth_platform_init(void)
{
	status = setup_timer();
	if (status != XST_SUCCESS) {
        xil_printf("setup_timer failed %d\r\n", status);
        return XST_FAILURE;
    }
	status = setup_timer_interrupts();
	if (status != XST_SUCCESS) {
        xil_printf("setup_timer_interrupts failed %d\r\n", status);
        return XST_FAILURE;
    }
	return XST_SUCCESS;
}

static int timer_interrupts_enable(XScuGic intc)
{
	/*
	 * Enable non-critical exceptions.
	 */
	//Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

    XScuGic_Enable(&intc, TTC_INTR_ID); //使能 GIC 中的 TTC 中断
    XTtcPs_EnableInterrupts(&TimerInstance, XTTCPS_IXR_INTERVAL_MASK);//使能 TTC 的间隔中断
	XTtcPs_Start(&TimerInstance);
	return XST_SUCCESS;
}

static void print_ip(char *msg, struct ip4_addr *ip)
{
    print(msg);
    xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip), ip4_addr3(ip), ip4_addr4(ip));
}

static void print_ip_settings(struct ip4_addr *ip,struct ip4_addr *mask,struct ip4_addr *gw)
{
    print_ip("Board IP: ", ip);
    print_ip("Netmask : ", mask);
    print_ip("Gateway : ", gw);
}
///////////////////////////////////////////////////////////////////////////////LWIP协议栈初始化主函数。//////////////////////////////////////////
int eth_init(XScuGic intc){
	ip4_addr_t ipaddr, netmask, gw;
    unsigned char mac_address[6];

    // 将字符串形式的 MAC 地址转换为二进制
    sscanf(DEFAULT_MAC_ADDRESS, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu",
           &mac_address[0], &mac_address[1], &mac_address[2],
           &mac_address[3], &mac_address[4], &mac_address[5]);

    // 将字符串形式的 IP 地址、子网掩码、网关地址转换为 lwIP 的 ip4_addr_t 类型
    if (!string_to_ip4(DEFAULT_IP_ADDR, &ipaddr) ||
        !string_to_ip4(DEFAULT_NET_MASK, &netmask) ||
        !string_to_ip4(DEFAULT_GW_ADDR, &gw)) {
        printf("Error: Invalid IP address format\n");
        return 0;
    }
    eth_platform_init();
    lwip_init();

    if (!xemac_add(&netif, &ipaddr, &netmask, &gw, mac_address, EMAC_BASEADDR)) {
        xil_printf("Error adding N/W interface\n\r");
        return -1;
    }

    netif_set_default(&netif);
    timer_interrupts_enable(intc);
    netif_set_up(&netif);
    print_ip_settings(&ipaddr, &netmask, &gw);

    return XST_SUCCESS;
}

中断头文件

点击查看代码
#ifndef MY_INTR_H
#define MY_INTR_H

#include "globals.h"

#define DMA_RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define DMA_TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID



#define RESET_TIMEOUT_COUNTER 10000 //复位时间

#define INTR_PRIORITY     0xA0
#define TRIGGER_TYPE      0x3
#define RESET_TIMEOUT_MSG() xil_printf("DMA reset timeout!\r\n")


/************************** Function Prototypes ******************************/
int setup_interrupts(void);
int platform_disable_interrupts(void);
int platform_enable_interrupts(void);


#endif // MY_INTR_H

中断源文件

点击查看代码
#include "my_intr.h"

static void handle_dma_error(XAxiDma *axi_dma) {
    error = 1;
    XAxiDma_Reset(axi_dma);
    
    int timeout = RESET_TIMEOUT_COUNTER;
    while (timeout && !XAxiDma_ResetIsDone(axi_dma)) {
        timeout--;
    }
    if (!timeout) {
        RESET_TIMEOUT_MSG();
    }
}

// 中断处理函数
static void dma_tx_intr_handler(void *callback) {
    XAxiDma *axi_dma = (XAxiDma *)callback;
    u32 irq_status = XAxiDma_IntrGetIrq(axi_dma, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrAckIrq(axi_dma, irq_status, XAXIDMA_DMA_TO_DEVICE);

    if (irq_status & XAXIDMA_IRQ_ERROR_MASK) {
        handle_dma_error(axi_dma);
    }

    if (irq_status & XAXIDMA_IRQ_IOC_MASK) {
        //xil_printf("dma transfer done !!\r\n");
        dma_tx_done_cnt++;
        xil_printf("dma_tx_done_cnt is: %d\n", dma_tx_done_cnt);
        // 如果中断标志为dma发送结束,那就启动 DMA 接收
        dma_tx_flag = 1;
    }
}

static void dma_rx_intr_handler(void *callback) {
    XAxiDma *axi_dma = (XAxiDma *)callback;
    u32 irq_status = XAxiDma_IntrGetIrq(axi_dma, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrAckIrq(axi_dma, irq_status, XAXIDMA_DEVICE_TO_DMA);

    if (irq_status & XAXIDMA_IRQ_ERROR_MASK) {
        handle_dma_error(axi_dma);
    }

    if (irq_status & XAXIDMA_IRQ_IOC_MASK) {
        //xil_printf("dma receive done !!\r\n");
        dma_rx_done_cnt++;
        xil_printf("dma_rx_done_cnt is: %d\n", dma_rx_done_cnt);
        // 如果中断标志为dma接收结束,那就启动 LWIP返回数据
        dma_rx_flag = 1; 
    }
}

int setup_interrupts(void) {

    XScuGic_SetPriorityTriggerType(&intc, DMA_TX_INTR_ID, INTR_PRIORITY, TRIGGER_TYPE);
    XScuGic_SetPriorityTriggerType(&intc, DMA_RX_INTR_ID, INTR_PRIORITY, TRIGGER_TYPE);

    status = XScuGic_Connect(&intc, DMA_TX_INTR_ID, (Xil_InterruptHandler)dma_tx_intr_handler, &axi_dma);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect TX interrupt: %d\r\n", status);
        return status;
    }
    status = XScuGic_Connect(&intc, DMA_RX_INTR_ID, (Xil_InterruptHandler)dma_rx_intr_handler, &axi_dma);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect RX interrupt: %d\r\n", status);
        return status;
    }

    return XST_SUCCESS;
}

int platform_enable_interrupts(void){
    XScuGic_Enable(&intc, DMA_TX_INTR_ID);
    XScuGic_Enable(&intc, DMA_RX_INTR_ID);
    XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrEnable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrEnable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

    return XST_SUCCESS;
}


int platform_disable_interrupts(void) {
  // 先禁用DMA中断
    XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XScuGic_Disconnect(&intc, DMA_TX_INTR_ID);
    XScuGic_Disconnect(&intc, DMA_RX_INTR_ID);
    XScuGic_Disable(&intc, DMA_TX_INTR_ID);
    XScuGic_Disable(&intc, DMA_RX_INTR_ID);

    return XST_SUCCESS;
}

个人代码块头文件

点击查看代码
#ifndef MY_CODE_H
#define MY_CODE_H
#include "globals.h"

#define TCP_PORT           5001           // 自定义端口

/************************** Function Prototypes ******************************/
int dma_transfer(XAxiDma *axidma, u8 *tx_buffer, u32 length);
int dma_receive(XAxiDma *axidma, u8 *rx_buffer, u32 length);

int tcp_server_init(void);

int received_data_back(void);
#endif // MY_CODE_H

个人代码块源文件

点击查看代码
#include "my_code.h"
static struct tcp_pcb *tcp_server_pcb;            // TCP 协议控制块,用作监听
static struct tcp_pcb *tcp_user_pcb = NULL;       // TCP 协议用户控制块,用作传输数据



int dma_transfer(XAxiDma *axidma, u8 *tx_buffer, u32 length) {
    Xil_DCacheFlushRange((UINTPTR)tx_buffer, length);
    int status = XAxiDma_SimpleTransfer(axidma, (UINTPTR)tx_buffer, length, XAXIDMA_DMA_TO_DEVICE);
    if (status != XST_SUCCESS) {
        return XST_FAILURE;
    }
    return XST_SUCCESS;
}

int dma_receive(XAxiDma *axidma, u8 *rx_buffer, u32 length) {
    int status = XAxiDma_SimpleTransfer(axidma, (UINTPTR)rx_buffer, length, XAXIDMA_DEVICE_TO_DMA);
    if (status != XST_SUCCESS) {
        return XST_FAILURE;
    }
    Xil_DCacheFlushRange((UINTPTR)rx_buffer, length);
    return XST_SUCCESS;
}

// TCP 接收回调
static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tcp_recv_callback_pcb, struct pbuf *p, err_t err) {
    if (!p) {
        // 连接关闭
        tcp_close(tcp_recv_callback_pcb);
        tcp_recv(tcp_recv_callback_pcb, NULL);
        return ERR_OK;
    }
    // 1.确认接收
    tcp_recved(tcp_recv_callback_pcb, p->len);
    //xil_printf("now sndbuf: %d\n", tcp_sndbuf(tcp_recv_callback_pcb));
    // 2. 拷贝接收数据到 rx_buffer
    //if (p->len <= BUF_SIZE) {
        //if (tcp_sndbuf(tcp_server_pcb) > p->len) {
            //error = tcp_write(tcp_server_pcb, p->payload, p->len, 1);
            status = pbuf_copy_partial(p, (void *)TX_BUFFER_BASE, p->len, 0);
            //xil_printf("pbuf copy number is: %d\n", status);
            xil_printf("Received %d bytes\n", p->len);
            lwip_rx_done_cnt++;
            //xil_printf("lwip_rx SUCCESS !!\r\n");
            xil_printf("lwip_rx_done_cnt is: %d\n", lwip_rx_done_cnt);
            NUMBER  = p -> len;
            status = dma_transfer(&axi_dma, tx_buffer, NUMBER);
            if (status != XST_SUCCESS) {
                xil_printf("dma_transfer failed\n");
            }
        // 2. 回传数据(示例:原样返回)
        //memcpy(tx_buffer, rx_buffer, BUF_SIZE);
        //tcp_write(current_pcb, tx_buffer, p->tot_len, TCP_WRITE_FLAG_COPY);
        //tcp_output(current_pcb);
        //} else
            //xil_printf("no space in tcp_sndbuf\n\r");
    //}
    // 3. 释放 pbuf 
    pbuf_free(p);
    //xil_printf("P->len =  %d\n", p->len);
    return ERR_OK;
}

// TCP 发送回调
static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tcp_sent_callback_pcb, u16_t len) {
    return ERR_OK;
}
static err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t error) {
    static int connection = 1;
    tcp_user_pcb    =   tpcb;
    xil_printf("tcp_server: Connection Accepted\r\n");
	/* set the receive callback for this connection */
	tcp_recv(tcp_user_pcb, tcp_recv_callback);
    tcp_sent(tcp_user_pcb, tcp_sent_callback);
	/* just use an integer number indicating the connection id as the callback argument */
    tcp_arg(tcp_user_pcb, (void*)(UINTPTR)connection);
	xil_printf("Connect Success %d.\r\n",connection);
    /* increment for subsequent accepted connections */
    connection++;
	return ERR_OK;
}

int tcp_server_init(void) {
	/*  创建新的TCP PCB  */
	tcp_server_pcb =tcp_new_ip_type(IPADDR_TYPE_ANY);
	if (!tcp_server_pcb) {
		xil_printf("txperf: Error creating PCB. Out of Memory\r\n");
		return -1;
	}
	/*  绑定本地端口  */
	error = tcp_bind(tcp_server_pcb, IP_ADDR_ANY, TCP_PORT);
	if (error != ERR_OK) {
		xil_printf("tcp_server: Unable to bind to port %d: err = %d\r\n", TCP_PORT, error);
		return -2;
	}
	/*  监听连接  */
	tcp_arg(tcp_server_pcb, NULL);
	tcp_server_pcb = tcp_listen(tcp_server_pcb);
	if (!tcp_server_pcb) {
		xil_printf("tcp_server: Out of memory while tcp_listen\r\n");
		return -3;
	}
	/*  设置accept回调函数  */
	tcp_accept(tcp_server_pcb, tcp_connected_callback);

	xil_printf("TCP echo server started @ port %d\n\r", TCP_PORT);
	xil_printf("tcp connect is done.\r\n");

	return 0;
}

int received_data_back(void){
    if (tcp_sndbuf(tcp_user_pcb) > NUMBER) {
        error = tcp_write(tcp_user_pcb, (void *)RX_BUFFER_BASE, NUMBER, TCP_WRITE_FLAG_COPY);
        if (error != ERR_OK) {
            xil_printf("txperf: Error on tcp_write: %d\r\n", error);
            tcp_user_pcb = NULL;
            return 0;
        }
        error = tcp_output(tcp_user_pcb);
        if (error != ERR_OK) {
            xil_printf("txperf: Error on tcp_output: %d\r\n", error);
            return 0;
        }
        lwip_tx_done_cnt++;
        xil_printf("lwip_tx_done_cnt is: %d\n", lwip_tx_done_cnt);
        //xil_printf("lwip_tx SUCCESS\n");
        xil_printf("Sent %d bytes, now sndbuf: %d\n", NUMBER, tcp_sndbuf(tcp_user_pcb));
        dma_rx_flag = 0;
        }
    else    {
        xil_printf(" lwip_tx fail\n");
        xil_printf("now sndbuf: %d\n", tcp_sndbuf(tcp_user_pcb));
        printf("PCB state: %d\n", tcp_user_pcb->state);
    }
    return XST_SUCCESS;
}

主函数

点击查看代码
#include "my_init.h"
#include "my_intr.h"
#include "my_code.h"
#include "globals.h"

void tcp_fasttmr(void);
void tcp_slowtmr(void);

int main( ){

    tx_buffer = (u8 *)TX_BUFFER_BASE;
    rx_buffer = (u8 *)RX_BUFFER_BASE;

    Xil_ICacheEnable();
    Xil_DCacheEnable();

xil_printf("\r\n--- Entering main() --- \r\n");
    dma_rx_done_cnt = 0;
    dma_rx_flag     = 0;
    dma_tx_flag     = 0;
    dma_tx_done_cnt = 0;
    error           = 0;
//platform 初始化
// 1.初始化 XScuGIC
    my_setup_XScuGic_init();

// 2.初始化 DMA
    if (dma_init()) {
        xil_printf("DMA initialization failed\r\n");
        return XST_FAILURE;
    }
    //xil_printf("DMA initialization SUCCESS\r\n");

// 3.建立中断系统
    if (setup_interrupts()) {
        xil_printf("DMA interrupts initialization failed\r\n");
        return XST_FAILURE;
    }
    //xil_printf("DMA interrupts initialization SUCCESS\r\n");

// 4.初始化网络和 lwIP
    if (eth_init(intc)!= 0) {
        xil_printf("Network init failed\n");
        return XST_FAILURE;
    }
    //xil_printf("LWIP initialization SUCCESS\r\n");

// 5.建立TCP网络和接收回调
    if (tcp_server_init()!= 0) {
        xil_printf("tcp_server_init failed\n");
        return -1;
    }
    //xil_printf("tcp_server_init end\r\n");

// 6.使能中断,为开始循环做准备。
    platform_enable_interrupts();
    xil_printf("初始化结束\r\n");
//开始循环
    while (1)
    {   
        if (dma_tx_flag)        {
            dma_receive(&axi_dma,rx_buffer,NUMBER);
        }
        
        if (TcpFastTmrFlag) {
            tcp_fasttmr();
            TcpFastTmrFlag = 0;
        }
        if (TcpSlowTmrFlag) {
            tcp_slowtmr();
            TcpSlowTmrFlag = 0;
        }
        if (dma_rx_flag)
        {
            received_data_back();
        }
        xemacif_input(&netif);
    }  
    return XST_SUCCESS;
}

代码不解释,有疑问可复制询问deepseek。
下面是下板调试。
初始化之后,会建立好TCP_server,并开始串口打印ip信息。

打开调试助手,建立TCP连接之后,串口会打印连接成功的标志,可断开再连接,会打印第几次连接。

命令提示符里输入arp -a,也能看到以太网建立成功。

如果建立不成功,则如下所示设置电脑以太网接口ipv4的属性

最后是连续发送hello?到开发板将数据通过dma传到pl端再从pl端通过dma拿回来,并通过tcp返回原数据的实际测试。

最后,有一些小问题还未解决,首先是高频连续传输情况下,dma传输会卡死,这个还没有处理,我个人认为是第二次传hello?的时候,第一次触发的dma传输还没结束,也就是频率有点高了,开发板响应不了,这个问题在我后续的实际的场景应用中不会出现,所以这边不解决,大家要解决的话,试试在dma被占用的时候不让lwip接收数据,或者用多个dma,也就是乒乓传输的思想,这是我个人的想法,是否有效还请实际验证,不确认有效。