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

2024-09-02 09:52

本文主要是介绍【ZYNQ MPSoC开发】lwIP TCP发送用于数据缓存的软件FIFO设计,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

设计背景

       任务是在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;
}

这篇关于【ZYNQ MPSoC开发】lwIP TCP发送用于数据缓存的软件FIFO设计的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129639

相关文章

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

批量导入txt数据到的redis过程

《批量导入txt数据到的redis过程》用户通过将Redis命令逐行写入txt文件,利用管道模式运行客户端,成功执行批量删除以Product*匹配的Key操作,提高了数据清理效率... 目录批量导入txt数据到Redisjs把redis命令按一条 一行写到txt中管道命令运行redis客户端成功了批量删除k

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

python运用requests模拟浏览器发送请求过程

《python运用requests模拟浏览器发送请求过程》模拟浏览器请求可选用requests处理静态内容,selenium应对动态页面,playwright支持高级自动化,设置代理和超时参数,根据需... 目录使用requests库模拟浏览器请求使用selenium自动化浏览器操作使用playwright

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

PyQt5 GUI 开发的基础知识

《PyQt5GUI开发的基础知识》Qt是一个跨平台的C++图形用户界面开发框架,支持GUI和非GUI程序开发,本文介绍了使用PyQt5进行界面开发的基础知识,包括创建简单窗口、常用控件、窗口属性设... 目录简介第一个PyQt程序最常用的三个功能模块控件QPushButton(按钮)控件QLable(纯文本

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使