本随笔是参考如下等人的分享并在个人理解上学习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,也就是乒乓传输的思想,这是我个人的想法,是否有效还请实际验证,不确认有效。





浙公网安备 33010602011771号