FPGA1—ROM存储经千兆以太 口到Qt上位机显示2022-10-23

1.场景:

将存储在FPGA片上BlockRAM中的图片数据通过 口传输到上位机显示目标是FPGA通过 口发送图片,其大小为1920*1200,位深为8bit,30fps,上位机可以实时显示即可。这个小项目中考虑的问题①使用FPGA的Block Memory Generate IP,②开发图片数据转换成coe文件的软件,①②两步实现将图片数据存储到FPGA片上。③通过千兆以太 口将ROM图片数据传输到上位机。④使用Qt开发 口数据接收上位机,先可以显示一张图片,然后通过多线程配置使之能够动态显示图片流即视频数据。该项目主要用来验证, 口传输到上位机多线程显示两个问题,ROM图片数据可以看成是模拟的视频流,实际应用可以来自其他数据源如CMOS图像传感器等。大的验证步骤分为两个,一个是验证静态图片即一张图片的数据流,在此基础上验证视频流传输与显示。该小项目开发环境基于Qt5.15.2,vivado2020.2,winsock2.h ,以及xc7a35tfgg芯片。

2.实现思路:

  1. 使用qt制作coe文件生成程序,生成coe文件。先用画图板构造一个1920*1200(注意像素生成错了为1900*1200费了好大的劲才找见)大小的图片,在qt程序中,只写前面1920*100个像素数据到coe文件中(据缓存大小决定)参考C5—Qt生成特定应用的COE文件 2021-11-18修改部分代码即可,我在此基础上修改了图像像素大小,并且将最后一行的逗 改为分 。如下图所示。

  2. 创建FPGA工程(为验证单张图片的工程)。程序概述:上电后,等待上位机发出ARP请求(因此上位机程序应主动发出ARP请求,此处也是程序需要完善的地方,只能应答ARP而不能发出ARP请求),当收到ARP请求,可在PC端通过arp – a查看arp映射表的情况,按键按下一次只发送一张图片(即发送12次ROM数据),让上位机接收,以验证单张图像的显示。此处关于 口的描述可参考E1–千兆以太 接口测试应用2022-09-07
  3. 使用qt制作 口数据显示程序,发现 上和Qt官方有一直言论Qt5对于UDP Socket的支持不完善,果断采用Windows对于 络编程的支持,即socket编程。对于socket编程的简介请看下节。
  4. 关于发送格式的确定。添加从ROM到 口的数据,每一张图片都12部分相同的数据组成,每一次传输(一个UDP数据包)1232B数据包,其中包含32B帧头信息和1200B图片信息,一张图片由1920个图像帧传输完成;帧头信息采用以下结构体。(上述3,4部分均要遵循)
  5. 开始测试,明确下位机关于配置,端口为6000,IP地址为192.168.1.10,Mac地址为0x00-11-22-33-44-55,本地端口为6001,应该设置本地IP为同一个 段,即手动ip设为192.168.1.102。(使用arp -a命令查看ARP地址映射表)
  6. 查看结果如下,单张图片显示正常,以下两图分别为原图和复原图。(注单张图片显示的上下位机代码未贴出,只贴出最后动态显示的代码)

  7. 下面考虑发送视频流时数据的恢复,基于单张显示成功的FPGA工程创建V2 FPGA工程,控制每30fps速度发送ROM至 口;开发上位机程序,划分为主线程、接收线程、处理线程三个线程。主要开发的代码是 口数据接收、数据解码、图片恢复、多线程控制等内容。主要考虑的问题是线程同步和线程安全。即缓存大小、类型、位置以及共享内存信 量和互斥量的设计。其数据流向简要如下:

3.Win Socket编程

据 上多数开发者经验,以及Qt creator书,Qt5版本的Network模块并不完善,在使用UdpSocket套接字接受数据时,无论是否使用线程去接收,常常出现丢包的现象。索性直接使用win socket编程,其实就是用微软官方提供的关于 口编程的库winsock2.h。

环境搭建

添加头文件#include “Winsock2.h”,并且在.pro文件中添加LIBS += -lWS2_32,即可使用windows 络编程。

流程

与Qt提供的UDP Socket相比,获取 口收发数据的流程大同小异,socket()–>bind( )–>listen()–>accept()–>read()/write()—>close()。关于UDP Socket可参考Day30Qt实现UDP传输2022-01-07,关于socket的教程 上很多,下面我把用到的几个函数罗列如下。

①初始化 DLL

②创建套接字

    af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址  type 为数据传输方式/套接字类型,流格式套接字(Stream Sockets)(TCP套接字)数据 格式套接字(SOCK_DGRAM)(UDP套接字)protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议 如果使用 SOCK_DGRAM 传输方式,且位ipv4,那么满足这两个条件的协议只有 UDP返回值是 SOCKET 类型,用来表示一个套接字。
③结构体sockaddr_in

④将一个无符 短整型数值转换为 络字节序,即大端模式(big-endian)。htonl函数可以用来进行 络字节和主机字节的转换。

⑤bind()函数:

⑥INADDR_ANY

    作为接收端,当你调用bind()函数绑定IP时使用【INADDR_ANY】,表明接收来自任意IP、任意 卡的发给指定端口的数据。作为发送端,当你调用bind()函数绑定IP时使用【INADDR_ANY】,表明使用 卡 最低的 卡进行发送数据,也就是UDP数据广播。

⑦setsockopt   

⑧recvfrom函数

4.上位机代码分析

默认main.cpp文件

主线程widget文件-widget.h

该文件主要是创建数据接收线程类对象和数据处理线程类对象,声明必要的函数和变量,具体功能在cpp文件中描述。


  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include "recvthread.h"
  11. #include "handlethread.h"
  12. QT_BEGIN_NAMESPACE
  13. namespace Ui { class Widget; }
  14. QT_END_NAMESPACE
  15. class Widget : public QWidget
  16. {
  17. Q_OBJECT
  18. public:
  19. Widget(QWidget *parent = nullptr);
  20. ~Widget();
  21. private slots:
  22. //udp recv thread slot
  23. void serverStartedSlot(bool bok);
  24. //handle thread slot
  25. void showPixmapSlot(QPixmap pix);
  26. void slotSpeedOut();
  27. void on_startBtn_clicked();
  28. void on_stopBtn_clicked();
  29. void recvThdMessage(QString);
  30. void on_clearBtn_clicked();
  31. private:
  32. Ui::Widget *ui;
  33. QUdpSocket *udpSocket;//udp管理对象
  34. recvThread* recvthread;

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年9月21日
下一篇 2022年9月21日

相关推荐