首页 > 其他分享 >【ZYNQ MPSoC开发】lwIP TCP发送用于数据缓存的软件FIFO设计

【ZYNQ MPSoC开发】lwIP TCP发送用于数据缓存的软件FIFO设计

时间:2024-09-02 15:55:18浏览次数:10  
标签:MPSoC lwIP int fifo TCP capacity data FIFO size

设计背景

       任务是在ZYNQ的PS上使用裸机运行lwIP协议栈使用TCP把PL端通过AXI DMA传来的将近100K采样率的ADC数据发送出去,但由于数据带宽很大,有853.3mbps,所以在每一次AXI DMA简单传输结束后,lwIP未必有足够的发送buffer立即把数据发送走,如果是发送完再进行下一次简单传输的思路,则会很大地限制了整个系统的带宽,一个简单的思路是每次传输完成后判断发送buffer是否足够,如果不够,先把数据放进软件FIFO里,等待有buffer时再发出去,如果足够的话,则进行发送,当然必须优先发送FIFO里的数据,而后马上进行下一次简单传输,下面是软件FIFO的代码部分。

软件FIFO代码

       1,FIFO结构体定义如下:

typedef struct {
    unsigned int *data;
    int head;
    int tail;
    int size;
    int capacity;
    int size_max;
} FIFO;

​ data存放FIFO数据放置的地址指针,head头用于读,tail尾用于写,size表示了当前FIFO存放的等待发送出去的数据包的组数(我这里的数据包是8次简单传输的数据量,大家可以根据自己需求定,并不是字节数!!!),capacity是整个FIFO的容量,size_max用于记录FIFO的一定时间间隔内的数组组数的最大值(前期调试用)。

       2,初始化部分如下:

// 初始化FIFO
void sending_fifo_init(FIFO *fifo, int capacity)
{
//    fifo->data = (unsigned int *)malloc(capacity * MY_TCP_SEND_BUFSIZE);
//    if (!fifo->data) {
//        perror("Failed to allocate memory for FIFO");
//        exit(EXIT_FAILURE);
//    }


    fifo->data = (unsigned int *)SEND_FIFO_BASE;
    
    fifo->head = 0;		//头部
    fifo->tail = 0;		//尾部
    fifo->size = 0;		//当前数据大小
    fifo->size_max = 0;	//每个时间间隔size最大值
    fifo->capacity = capacity;		//总容量
    
    if(capacity > FIFO_SIZE_MAX)
    {
        fifo->capacity = FIFO_SIZE_MAX;   
    }
    else
    {
        fifo->capacity = capacity;
    }

}

       这里需要注意的是没有采用malloc去动态分配内存,这主要是因为在ZYNQ这样的嵌入式设备特别是跑裸机时,这样分配很容易报错。

       3,与size相关的函数

​       一是检查FIFO是否已满,1为满,0为不满。

bool fifo_is_full(FIFO *fifo)
{
    return fifo->size == fifo->capacity;
}

       二是检查FIFO是否为空,1为空,0为不空。

bool fifo_is_empty(FIFO *fifo)
{
    return fifo->size == 0;
}

       更灵活的,也给出直接获取size用于打印以及其他辅助调试。

int fifo_get_size(FIFO *fifo)
{
	return fifo->size;
}

       由于我是每5s打印一次这个时间段的带宽,在调试阶段也想看看FIFO的使用情况,就有了以下的记录fifo最大值的函数,然后在每次打印报告时给最大size清零。

void fifo_record_max_size(FIFO *fifo)
{
	int size_current = fifo_get_size(fifo);

	if (size_current > fifo->size_max)
	{
		fifo->size_max = size_current;
	}

}

       4,整个FIFO部分最重要的部分就是入队与出队的操作,入队代码如下:

bool fifo_enqueue(FIFO *fifo,char *lwip_array_ptr)
{
    if (fifo_is_full(fifo)) {
        printf("FIFO is full, cannot enqueue\r\n");
        return;
    }

    memcpy((fifo->data + fifo->tail * MY_TCP_SEND_BUFSIZE / 4), lwip_array_ptr, MY_TCP_SEND_BUFSIZE);
    fifo->tail = (fifo->tail + 1) % fifo->capacity;  // 循环队列处理
    fifo->size++;
    
    fifo_record_max_size(fifo);

}

       首先入队必须要保证FIFO是不为满的,其次是在使用memcpy函数拷贝数据时,注意第一个参数的结果是个什么类型,从而保证每组数据之间是在内存上连续的,不清楚的话,可以先按自己的理解给一个递进制,直接debug看看再进行修改。整个FIFO的运行逻辑是充分利用开辟出来的内存,做一个循环队列处理,而不是size = x的数据放在固定的位置。

​       出队同理:

// 出队操作
bool fifo_dequeue(FIFO *fifo,char *lwip_array_ptr)
{
    if (fifo_is_empty(fifo)) {
        printf("FIFO is empty, cannot dequeue\r\n");
        return false;
    }

    memcpy(lwip_array_ptr, (fifo->data + fifo->head * MY_TCP_SEND_BUFSIZE / 4), MY_TCP_SEND_BUFSIZE);
    fifo->head = (fifo->head + 1) % fifo->capacity;  // 循环队列处理
    fifo->size--;
    return true;

}

​       5,后面如果FIFO不用了,可以进行销毁:

// 销毁FIFO
void fifo_destroy(FIFO *fifo)
{
    free(fifo->data);
    fifo->data = NULL;
    fifo->head = fifo->tail = fifo->size = fifo->capacity = 0;
}

标签:MPSoC,lwIP,int,fifo,TCP,capacity,data,FIFO,size
From: https://blog.csdn.net/qq1016019583/article/details/141783363

相关文章

  • TCP是什麽
    TCP(TransmissionControlProtocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它为网络通信提供了可靠的、有序的和错误检查的传输服务。TCP是互联网协议套件(InternetProtocolSuite)的一部分,通常与IP协议一起使用,因此通常被称为TCP/IP。主要......
  • TCP协议与UDP协议相比有哪些优势和劣势?
    TCP(TransmissionControlProtocol,传输控制协议)和UDP(UserDatagramProtocol,用户数据报协议)是互联网上两种主要的传输层协议,它们各自有不同的特点和适用场景。以下是TCP相对于UDP的优势和劣势:TCP的优势:1.可靠性:TCP提供了可靠的数据传输服务。它通过序列号、确认应答......
  • Linux抓包神器 tcpdump 使用指南
    tcpdump是一款强大的网络抓包工具,它使用libpcap库来抓取网络数据包,这个库在几乎所有的Linux/Unix系统中都有。熟悉tcpdump的使用能够帮助用户分析调试网络数据。以下是tcpdump的详细使用指南:一、安装tcpdump在Linux系统中,可以通过包管理器安装tcpdump。对于Debian系系统,可以......
  • python读取txt文本文件-批量更改mysql数据库中一批用户的用户名的python脚本保存及转
    一、python读取txt文本文件-批量更改mysql数据库中一批用户的用户名的python脚本保存    做一个简单的事:使用python读取一个txt文件,里面存储着N行用户id,需要一行行读取后再读取另一个存储用户昵称的txt文件,判断昵称是否有重复,如果没有重复就将数据库中的当前uid用户的昵称......
  • USB TCPM
    USBTCPM(Type-CPortManager)的主要作用是管理USBType-C端口的连接和电源传输协议(USBPowerDelivery,PD),确保设备正确识别、协商和切换数据传输和电源供应的角色。TCPM在USBType-C连接中起到关键管理作用,主要职责包括:管理USBType-C插拔检测:检测设备的插入和拔出事件......
  • 【网络编程通关之路】 Tcp 基础回显服务器(Java实现)及保姆式知识原理详解 ! ! !
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • TCP/IP、UDP/IP协议
    参考链接1、OSI七层模型(1)OSI含义“OSI模型,即开放式通信系统互联参考模型(OpenSystemInterconnectionReferenceModel),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。”(2)OSI定义了网络互连的七层模型(物理层、数据链路层、网络层......
  • Python可控制线程与TCP服务单元编程
    大家好,我之前在我的CSDN博客上面发了一条《C++可控制线程》的文章,里面介绍了在线程中植入类似状态机的东西,进而将多线程编程进化为“服务单元”编程的技术。接下来我们来看一个基于此项目的Python的TCP服务单元代码。------------------------------------------------------......
  • socket与TCP/IP区别
    一、socket:1、准确表述:socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。2、详细介绍(1)套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含......
  • TCP并发服务器
    一、整体框架二、服务器单循环服务器:同一时刻,只能处理一个客户端的任务并发服务器:同一时刻,只能处理多个客户端的任务UDP是具备并发性的,是因为UDP是无连接的,所以处理器可以处理过来TCP实际上是单循环的服务器,只能建立一对一连接,其他人不能再与其建立连接,之前只有一个套......