欢迎光临散文网 会员登陆 & 注册

实验119:下位机FPGA TCP Client客户端 +24位ADC(模拟DSA动态信号采集卡)

2023-04-22 12:58 作者:神电测控  | 我要投稿

实验119:下位机FPGA TCP Client客户端
+24位ADC(模拟DSA动态信号采集卡)

     1、实验内容

        现在很多电脑PC、工控机或者其他嵌入式设备都集成了千兆网卡,可以直接接入一根CAT5+或者CAT6类网线即可实现TCP网络互联;以太网通信的优点是传输距离远(网线内部走的是恒流源驱动),支持热插拔(支持断点续传),传输速度快(理论带宽125MB/s)。对于高速采集、分布式测试测量和边缘计算等领域,TCP网络通信是必不可少的,因为UDP无法替代TCP来完成这些应用。

        因此,很多用户都希望自己的FPGA芯片能够实现TCP协议栈,这样就可以开发出来很多支持TCP网络通信的工业以太网设备、Gige相机和边缘计算等分布式采集终端了。也为后续基于TCP的Modbus和MQTT等网络应用层协议打下坚实的基础。

 

        本节实验我们准备采用IEPE/ICP/DSA动态信号采集模块(ADS127L01),上面有1颗24位高速高精度ADC芯片,结合TCP协议栈实现1路采样率(最大512KS/s)可调节的TCP千兆以太网DSA动态信号采集卡,直接一根网线连到PC或者工控机或者工业树莓派上即可完成高可靠性、长距离数据传输和命令交互。该DSA例程可以直接用于采集声音、振动、加速度等IEPE传感器。

        下面我们先来回顾一下TCP千兆以太网口和ADS127L01硬件模块等相关内容。

        黑金设计的ARTIX7-100T FPGA开发板(AX7103)上集成了两路千兆以太网PHY芯片KSZ9031,如图119-1所示,当然如果用户自己做板子的话,也可以将昂贵的KSZ9031换成台湾瑞昱的RTL8211F或者国产廉价的YT8511C这类完全兼容的PHY芯片。

                                             

图119-1:带有两路千兆以太网PHY网口的Aritx7 FPGA开发板(黑金AX7103)

         用户可以直接将这个开发板通过一根CAT5+或者CAT6类网线接到工控机或者电脑的网口里面;当然,如果超薄笔记本电脑,没有千兆网口的话,也可以在网上买一个雷电转千兆网口的扩展坞,方便后续做实验。

        由于我们已经把复杂的TCP Client通信协议封装进了LabVIEW FPGA下的Socket CLIP,用户只需要根据四线握手协议来调用对应的CLIP端口就可以了。这部分我们在前面第10章已经介绍过了。

        本节FPGA TCP Client通信实验重点向大家讲解以下7个方面的内容:

1)      下位机(FPGA)TCP Client客户端通信程序开发。

2)      上位机(PC)服务器端通信应用程序开发。

3)      下位机FPGA内部多线程之间的数据交互与数据缓冲:FIFO。

4)      下位机FPGA内部不同速率之间的匹配机制:四线握手。

5)      下位机FPGA TCP Client通信IP核全双工通信的读写机制。

6)      TCP Client通信数据格式和类型转换(大小端与字节数组)(下行和上行都是大端)

7)      24位单通道ADC芯片(ADS127L01)的数据读取方法(参考本书前面的“实验53-高精度24位512K-DSA信号采集实验-ADS127L01”)

        关于TCP Client下位机(FPGA)通信应用程序开发,指的是FPGA芯片中的代码编写。譬如,本节实验我们准备开发一个基于TCP网络传输的高精度动态信号采集卡(DSA),将24位ADC采集到的数据通过TCP Client实时发送到PC上,这段代码我们可以利用图形化的LabVIEW编程语言来开发,替代传统的VHDL/Verilog语言,这里我们称之为下位机LabVIEW FPGA编程。本节实验下位机FPGA程序里面的用户线程,我们会利用ADS127L01芯片(24位)采集外部真实的Sine正弦交流信号,然后发送到上位机进行显示或者流盘。

        关于上位机(PC)服务器端的应用程序开发,指的是运行在windows或者linux系统中的LabVIEW上位机程序,可以通过调用LabVIEW软件自身就有的TCP函数选板里面的VI函数与下位机FPGA进行TCP网络数据交互。我们把上位机收发线程分成两个独立的while循环来处理,这样调试起来简单一些。当然,如果有些用户不会LabVIEW,也可以使用C\C++\C#\Python来调用网卡DLL动态库进行上位机程序开发。

        关于FIFO的概念和操作,可以参考前面的“实验4-串口通信”,里面有详细的介绍和演示过程。

        关于四线握手制的工作过程和原理,也可以参考前面的“实验4-串口通信”,这里不再赘述。

        关于TCP Client通信IP核全双工通信机制,我们会通过两个独立的收发线程来演示。发送和接收可以同时并行执行,而且是上行和下行同时全双工工作。

        最后一个需要注意的问题是,下位机FPGA 跟上位机之间的TCP通信数据格式和数据类型,需要匹配上才能正确解析,好在我们封装的下位机TCP Client协议栈和上位机LabVIEW里面默认是大端格式的U8字节数组;另外,模拟或者采集的ADC波形,对应的数据类型跟TCP内部的字节数组之间需要通过“强制类型转换”函数转换一下才能看到准确的波形曲线。

        下面带着大家一起,利用LabVIEW编写符合标准四线握手制的TCP Client下位机FPGA客户端程序,来实现一个基于FPGA的TCP千兆以太网 24位单通道数据采集卡(最大采样率512KS/s,ADS127L01芯片本身的采集电压范围±2.5V(取决于参考电压),但是模块上有缩小和增益电路,后面会讲解),采集外部真实的Sine正弦信号,通过TCP网络发送给上位机PC服务器,同时还能接收上位机服务器端下发的指令和参数对FPGA板卡进行采样率和使能采集等控制。

 

        2、硬件资源

        2.1、先回顾一下FPGA千兆以太网接口方面的硬件知识

        打开本书配套的光盘/云盘里面1号文件夹里面的AX7103底板原理图,然后找到PHY网络接口这部分原理图,如图119-2所示。这些引脚其实可以分成4类:PHY芯片复位引脚、PHY芯片寄存器参数配置的IIC引脚(mdc和mdio)、PHY芯片收发125MHz时钟引脚;PHY芯片收发数据引脚(GMII:8bit;RGMII:4bit)。

        这4类引脚在前面第10章里面的图10-37定义过了,如果用户自己画的板子或者网上买的其他家的板子上的网口PHY芯片引脚定义不一样,那么照葫芦画瓢对应修改一下这个FPGA终端下的xdc约束文件里面的PHY芯片引脚就可以了。

图119-2:打开AX7103底板原理图,找到PHY网络芯片相关的4大类引脚

        然后,打开AX7103开发板上插着的核心板AC7100原理图,如图119-3所示,可以看到黑金AX7103开发板上第1路和第2路KSZ9031 PHY芯片都挂在了FPGA BANK16上面。


图119-3:在AC7100核心板上找到PHY网络芯片与FPGA相连的引脚名称

 

        2.2、再回顾一下24位单通道高精度ADC芯片ADS127L01相关的硬件内容

        本节实验需要用到的ADC采集模块是ADS127L01高精度24位高速AD模块,这款模块上面集成了一片ADS127L01芯片,并且预留了1个BNC焊接口,因为这个模块不是黑金开发的,所以不能直接接插到AX7103开发板右上角的扩展口上面,但是我们可以通过杜邦线接到J11扩展口。如图119-4所示。

图119-4:DSA模块上的ADS127L01电路实物图

        DSA IEPE模块的等效示意图,如图119-5所示。可以看出,该模块集成了ADS127L01和DAC7512E两个主要芯片;其中,ADS127L01就是24位高精度高速ADC芯片,负责采集小信号;DAC7512E是一颗DAC电压输出芯片,配合XTR111芯片来完成输出电流可编程的恒流源,再通过BNC接口输出给到IEPE这类需要激励源的传感器。当外部加速度、声音、振动等传感器输出微弱电压信号时,先经过AMP电路进一步衰减,然后再通过可编程PGA增益放大电路进行放大,最后再经过ADC Driver电路将单端信号变成差分信号传递给ADS127L01芯片进行采集。其中,Voltage REF选择的是2.5V基准电压芯片。

图119-5:ADS127L01 DSA模块等效电路示意图

 

图119-14:ADS127L01模块通过杜邦线接到FPGA底板扩展口J11

        通过查看ADS127L01模块与AX7103扩展口之间的线序关系,然后在AX7103底板原理图上找到这些引脚序号,如图119-15所示。本节实验,我们准备使用J11扩展口里面的2P、2N……9P、9N,对应FPGA的16个IO引脚。

图119-15:FPGA开发板上的扩展口引脚序号图


        3、FPGA TCP Client下位机ADC DSA动态信号采集程序开发(ADS127L01)

        下面,我们带着用户一起利用LabVIEW开发一个FPGA TCP Client下位机FPGA数据采集应用程序,这个程序可以下载到FPGA芯片里面运行,为了更加全面形象的展示TCP网络通信的魅力,我们模拟一个TCP Gige高精度动态信号采集卡(DSA),将24位ADS127L01芯片采集到的Sine正弦信号,拆分成3个字节后,通过8位位宽的TCP Client上行通道发送到上位机进行显示,上位机通过8位位宽的下行通道下发不同的指令参数来控制FPGA开始采集、停止采集和调整采集频率。以此向大家展示FPGA(客户端)与上位机PC(服务器)之间通过TCP网络进行双向高速通信的过程。

        提醒: ADS127L01芯片的最大采样率可以到512KS/s,FXP<±24,24>换算成字节为单位,也就是512K/s×24/8B=1.5MB/s;远小于我们封装的纯FPGA TCP传输带宽(95MB/s),同时拆分后的位宽也可以直接匹配TCP数据位宽,不需要像前面实验那样进行复杂的拼凑了,因此,可以直接参考本书实验15(AD9226/AD9238+千兆以太网通信)的框架进行替换就可以了,这样可以极大简化我们的FPGA编程;我们只需要一个并转串线程将拆分后的3个U8字节FIFO里面的数据直接转移到LabVIEW TCP CLIP的上行发送FIFO里面就可以了,不浪费一个bit,非常简单。

 

    3.1、LabVIEW FPGA项目创建

        1)启动LabVIEW 2019 SP1软件,用户可以点击左上角的“文件>>新建”或者直接点击“新建”下方的“项目”选项。这里我们也可以直接打开前面实验里面已经创建好的“My_FPGA_Starter_Board_Artix7_AX7103_TCP_Client.lvproj”这个项目,如图119-16所示。

图119-16:打开前面创建过的LabVIEW项目

        由于本章我们引入了TCP网络通信,之前创建的FPGA终端里面没有添加TCP Client Socket CLIP,所以,我们需要先右击“我的电脑”选择新建“终端和设备”,如图119-17所示;然后再在弹出来的FPGA终端选择列表里面,选择一个带TCP Client后缀的ARTIX7-100T FPGA终端设备,如图119-18所示;点击“确定”按钮后,创建好的ARTIX7 TCP Client FPGA终端设备,如图119-19所示。

        提醒:新建含有FPGA TCP Client Socket CLIP的过程,在前面实验111里面已经创建过了,所以这里可以忽略,如果是用户自己新建的项目,只需要参考上面的步骤走一遍就可以了。

图119-17:右击我的电脑选择新建“终端和设备”
图119-18:选择一个TCP Client后缀的ARTIX7-100T FPGA终端
图119-19:创建成功后的ARTIX7 FPGA TCP Client终端设备

         2)右击FPGA终端,选择“新建>>虚拟文件夹”,如图119-20所示。将添加到FPGA终端里面的虚拟文件夹,重命名为“实验119-TCP客户端+24位AD数据采集实验(模拟动态信号采集卡)-下位机”,如图119-21所示。

图119-20:右击FPGA终端,新建一个虚拟文件夹
图119-21:将虚拟文件夹重命名为“实验119-TCP客户端+24位AD数据采集实验(模拟动态信号采集卡)-下位机”


    3.2、LabVIEW FPGA EIO节点与FIFO创建

1)      新建按键KEYLED灯的EIO节点

        1)由于本节所有的TCP通信实验里面都会用到LED指示灯和按键KEY等EIO资源,所以,我们可以在FPGA终端上面右击,选择“新建>>FPGA I/O”,如图119-22所示。然后在弹出来的I/O资源选择对话框里面,找到AX7103 FPGA开发板上的LED和KEY对应的管脚资源,如图119-23所示。单击对话框中间的“向右箭头”按钮,将这些引脚对应的EIO节点添加到右侧的FPGA资源列表里面,如图119-24所示。

        提醒:实际上LED灯和按键KEY的EIO节点在前面实验111里面已经创建过了,所以这里可以忽略,如果是用户自己新建的项目,那么参考上面的步骤做一遍就可以了。

图119-22:新建FPGA I/O EIO节点
图119-23:找到AX7103开发板上LED指示灯和KEY按键对应的EIO节点
图119-24:将LED和KEY EIO节点全部添加到右侧的可用列表中

        点击“确定”按钮后,这些EIO节点会被添加到FPGA终端项目里面,如图119-25所示。

图119-25:LED灯和按键KEY的EIO节点被添加到FPGA终端项目里面
(在前面做实验111的时候已经添加过了)


2)      新建ADS127L01DAC7512E芯片对应的EIO节点

        1)右击“FPGA终端”,选择“新建>>FPGA I/O”,如图119-26所示。然后在弹出来的I/O资源选择对话框里面,找到DSA模块上的ADS127L01和DAC7512E两个芯片对应到AX7103 FPGA开发板J11扩展口关联的管脚资源,如图119-27所示。单击对话框中间的“向右箭头”按钮,将这些引脚资源添加到右侧的FPGA资源列表里面,如图119-28所示。因为,Vivado编译器不支持同一个物理IO在xdc约束文件里面有多处定义,所以这里我们直接使用原始的扩展口IO名称。

图119-26:新建FPGA I/O EIO节点
图119-27:找到ADS127L01和DAC7512E对应FPGA(XC7A100T)芯片上的引脚EIO节点
图119-28:将ADS127L01芯片的EIO节点添加到右侧的可用列表中

        点击“确定”按钮后,这些EIO节点被添加到FPGA终端项目里面,如图119-29所示。

图119-29:ADS127L01和DAC7512E芯片EIO节点被添加到FPGA终端项目里面  

        注意:细心的用户会发现,这些EIO节点实际上已经在前面2个实验里面添加过了,所以本节实验里面的图119-27实际上里面并没有这些EIO节点。如果是用户自己新建的一个FPGA终端项目,那么可以完整的添加。

3)      新建FIFO

        我们可以将TCP通信IP核看成一个独立的功能模块,类似MCU里面的子函数或者子VI,FPGA程序只需要关心如何将不同类型的数据(U64、U32、U16、U8)通过TCP协议发送出去以及收到的数据怎么反馈给FPGA用户程序,这个中间的桥梁,可以采用FIFO缓冲区来实现。FIFO非常适合在不同的线程之间传递数据,而且设计合理的话,数据不会丢失或者被覆盖。

        注意:FPGA用户线程相当于生产者,TCP收发线程相当于消费者,所以,二者之间有个速率匹配的问题,生产者发送数据的速度不能快于消费者(其中,基于纯FPGA实现的TCP传输吞吐率实测最高在95MB/s左右),否则会造成数据丢失。比如,本节实验里面,我们使用的是24位单通道的ADS127L01芯片,每通道最大采样率是512KS/s,因此,需要的通道带宽至少大于3×512KS=1.5MB/s的上行通道才能把下位机FPGA采集的数据无损的传输给上位机PC,否则会造成数据丢失,显然我们封装的纯FPGA TCP千兆以太网带宽完全足够,后面我们会根据具体程序进一步分析二者之间的速度匹配问题。

 

        1)右击FPGA终端项目,选择新建一个“虚拟文件夹”,如图119-30所示。然后重命名为“FIFO_ADC”,这个虚拟文件夹专门用来存放接下来我们创建的各种ADC芯片的FIFO缓冲区资源,如图119-31所示。

图119-30:新建一个虚拟文件夹
图119-31:将虚拟文件夹重命名为“FIFO_ADC”
(这个虚拟文件夹在前面实验116里面创建过了)

        2)右击虚拟文件夹“FIFO_ADC”,选择“新建>>FIFO”,如图119-32所示。

        提醒:考虑到后续我们需要将原始24位经过拆分之后得到的连续3个8位字节数据(U8)通过并转串依次转移到TCP发送通道往上位机传输,所以这里需要创建3个U8类型的ADS127L01临时缓冲区FIFO,分别命名为:FIFO_ADS127L01 _U8_ 1、FIFO_ADS127L01 _U8_ 2、FIFO_ADS127L01 _U8_ 3;为了保持程序结构统一性,我们可以将中间过渡的ADS127L01 U8 FIFO单独新建出来,命名为FIFO_ADS127L01 _U8,这样一共会创建4个U8类型的FIFO。

图119-32:新建ADC FIFO资源

        3)接着会自动弹出FIFO属性设置对话框,如图119-33所示。下面我们逐项解释一下每个选项的含义。

        首先是“名称”,这里可以随便输入一个能够体现这个FIFO功能的名称,比如我们要把FPGA从ADS127L01芯片里面采集到的有符号24位数据(FXP<±24,24>)拆分成3个字节之后,存放到这个FIFO,那么可以重命名为“FIFO_ADS127L01 _U8_ 1”。

        其次是“类型”,这个下拉列表里面默认只有一个选项“终端范围”,意思就是我们创建的这个FIFO只能在这个FPGA芯片内部使用,不能用于其他终端,如果用户使用的是NI的RT+FPGA终端设备,那么这个地方会有更多的选择,这里不再赘述。     

        接着是“请求元素数量”,默认是1023,这个数值就是FIFO的深度,最大可以缓冲的数据长度,数值越大,编译消耗的FPGA资源就越多。很多客户以为这个数值设置越大越好,这样就不容易溢出了,实则不然,如果多线程之间的FIFO读写速度差别很大的话,再大的FIFO对于FPGA这种高速运行的器件来说,也是瞬间就会溢出或者覆盖丢点的。所以问题的关键不在于FIFO深度,而是要设计一个合理的读写匹配机制。这里我们可以将FIFO深度设置为128.

        新增重大更新:对于FPGA跟上位机(Windows/Linux)之间存在握手机制的通信协议来说,比如常见的TCP和PCIe协议,FPGA什么时候可以往上行FIFO里面送数据,是可以根据ready信号来判断的,UDP协议不存在握手,所以下位机FPGA不需要大容量缓冲FIFO;通常这些存在握手协议的上行FIFO一般都是异步的,比如ADC采集循环(线程)与TCP或者PCIe传输循序(线程)往往是两个独立的线程,并且时钟域也不一样,因此,这个上行FIFO的深度就显得非常重要,而不是随便设置的。因为我们的上位机特别是Windows系统,抖动非常大,通常都是ms量级的,举个例子,假设下位机FPGA模拟或者实际的ADC采样率是10MS/s,ADC位数是16位,如果上位机系统稍微卡顿或者阻塞的时间是1ms,那么下位机FPGA需要缓冲的FIFO深度至少是10M×0.001=10K,也就是最少需要1万个点的空间或者2万个字节空间;因此,我们建议在FPGA资源足够的情况下,尽量将这类承担高速传输的上行FIFO(FIFO_TCP_Send_U8)深度设置的足够大,比如这里我们可以设置为120K个点,这样后续上位机只要抖动不是很剧烈的话(比如ms量级),是可以保证下位机FPGA数据不溢出丢点的;但是,如果下位机ADC采样率非常高的话,比如100MS/s甚至上GS/s的话,那么光靠下位机FPGA芯片自身的Memory空间显然不足,因为宝贵的LUT资源一般不要轻易作为FIFO用,那么此时,FPGA外围的DDR3或者DDR4就起到了真正的作用;在我们整本书里面虽然有DDR的实验例程和讲解,但是并没有真正说清楚这些DDR颗粒在什么情况下使用,实际上存在高速采集和握手协议的传输或者通信程序中,DDR可以起到大容量数据缓冲的作用,这样上位机即使卡顿或者抖动时间达到几百ms都不用担心了,当然,如果上位机的抖动这么大的话,用户还是需要对上位机程序进行优化的。在我们单独移植开发的纯FPGA TCP Socket CLIP里面也会着重强调上行FIFO空间深度设置的大小合理性。

图119-33:FIFO属性对话框:名称、类型与深度

        然后是“实现”方式,里面有3个选项“触发器”、“查找表”和“存储器块”,如图119-34所示。前两个就是FPGA最为宝贵的逻辑门资源了,一般不轻易使用,除非是用户已经将FPGA内部的存储器全部用完了,否则优先使用内部存储器块,这个存储器不占用FPGA内部的逻辑资源,不用也是浪费。


图119-34:FIFO属性对话框:实现方式

        最后是“控制逻辑”,这个特别需要注意,默认选择的是“终端优化”,如图119-35所示。最下方有个提示框,里面有段文字“根据FIFO使用的时钟域和终端类型,应用程序将会通过逻辑片架构或内置控制逻辑实现FIFO,因此当使用“终端优化”控制逻辑时,元素的实际数量可能有所不同。”也就是说LabVIEW在生成VHDL代码的时候,真实生成的FIFO深度并没有达到我们前面实际设置的“请求元素长度”。如果用户忽略这个,可能会导致程序在运行的时候,出现一些跟预期目标不一致的情况。


图119-35:FIFO属性对话框:控制逻辑:终端优化

        所以建议用户选择“逻辑片架构”,如图119-36所示。这时下面会提醒用户“元素数量已强制转换为FPGA可高效实现的值。”也就是说LabVIEW生成的FIFO深度会强制为我们申请的长度。

图119-36:FIFO属性对话框:控制逻辑:逻辑片架构

        4)接下来需要设置FIFO缓冲区单元的数据类型,在左侧的“类别”列表里面选择“数据类型”,然后在右侧的下拉列表里面选择8位无符号整形数据,如图119-37所示。因为我们从ADS127L01芯片里面采集回来的数据位宽是8位。


图119-37:FIFO属性对话框:数据类型:U8

        5)最后点击左侧的“接口”,切换到仲裁选项,如图119-38所示。将读取和写入的仲裁全部设置为“从不仲裁”,这样编译出来的代码执行速度也就是时钟约束可以提高不少,同时代码的健壮性和确定性也比仲裁来的稳。


图119-38:FIFO属性对话框:接口:从不仲裁

        6)全部设置完成后,点击“确定”按钮,即可创建出一个用来存放ADS127L01数据的缓冲区“FIFO_ADS127L01 _U8_ 1”,然后再以同样的方式再创建3个接收缓冲区“FIFO_ADS127L01 _U8_ 2”、“FIFO_ADS127L01 _U8_ 3”和“FIFO_ADS127L01 _U8”,如图119-39所示。

图119-39:创建4个ADS127L01临时FIFO缓冲区

        7)因为我们给用户封装的LabVIEW FPGA TCP Client Socket CLIP里面,正好上下行通道位宽也是8位,与并转串后的ADS127L01 FIFO位宽正好匹配上。为了将ADS127L01的数据通过TCP Client上行通道传输到上位机PC服务器端,我们还需要创建一个8位位宽的TCP Client FIFO缓冲区作为不同线程里面的过渡。用户可以参考前面FIFO的创建步骤单独新建一个,也可以直接利用我们前面创建好的“FIFO_TCP_Send_U8”这个FIFO,位于虚拟文件夹“FIFO_TCP”里面,如图119-40所示。


图119-40:创建1个U8类型的TCP上行通道FIFO缓冲区(实验111里面已经新建过了)

        8)最后,我们还需要新建一个可以接收上位机PC(服务器端)下发指令和参数的接收FIFO缓冲区。需要注意的是:因为上位机下发的指令和参数一般速度不会太快,另外,上位机发送的数据一般会经过“强制类型转换”VI变成字符串或者字节数组,这两种类型的数据表示法默认都是U8,所以,这里我们创建的FPGA接收PC下发的读取FIFO的数据类型也要设置为U8,因此,“FIFO_TCP_Receive_U8”的数据类型要设置为U8,如图119-41所示。其实,这个FIFO我们在前面实验111里面也已经创建过了。如果用户没有新建,那么参考前面的FIFO创建步骤自己创建一个就可以了。


图119-41:创建U8类型的TCP下行接收通道FIFO缓冲区(实验111里面已经新建过了)

        9)开始编写程序之前,我们先通过创建虚拟文件夹的方式,将接下来新建的主VI等文件分类进行管理,便于维护和调试。这里用到的方法建议用户在开发自己的项目时,优先分类管理。首先右击虚拟文件夹“实验119-TCP客户端+24位AD数据采集实验(模拟动态信号采集卡)-下位机”,新建1个子虚拟文件夹(Main),如图119-42所示。这个虚拟文件夹用来存放主VI文件。


图119-42:创建1个虚拟文件夹分别用来存放1类文件-便于管理

    3.3、下位机FPGA TCP DSA主VI编写过程(基于TCP Client CLIP + ADS127L01+DAC7512E)

        1)右击“实验119-TCP客户端+24位AD数据采集实验(模拟动态信号采集卡)-下位机”里面的子虚拟文件夹“Main”,选择“新建>>VI”,如图119-43所示。然后,新建一个VI,另存为“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”,如图119-44所示。

图119-43:右击虚拟文件夹Main新建一个主VI
图119-44:新建一个下位机FPGA TCP 24位动态信号采集卡程序VI

        2)再创建一个名为NGC的虚拟文件夹,然后右击该虚拟文件夹NGC,选择“添加”,将实验53里面的ADS127L01和DAC7512E两个芯片的FPGA驱动网表文件添加到项目浏览器里面来,如图119-45所示。

图119-45:将ADS127L01和DAC7512E网表文件添加进来


        3.3.1、编写24位高速ADC数据采集程序(ADS127L01采集线程)

        1)虽然ADS127L01芯片的最大采样率只有512KSps,但是底层的NGC网表文件需要运行的时钟域比较高,需要200MHz,另外,DAC7512E对应的时钟域是100MHz,所以我们需要提前创建1个100MHz的衍生时钟,因为板载时基就是默认的200MHz时钟,所以这个200MHz可以不用再创建了。

        2)右击项目浏览器里面的板载时钟“200 MHz Onboard Clock”,如图119-46所示。在弹出的衍生时钟属性配置页面里面,将所需衍生频率设置为100MHz,如图119-47所示。点击“确定”按钮后,展开板载时钟“200 MHz Onboard Clock”可以看到这个新建的时钟源,如图119-48所示。实际上,这个100M的衍生时钟我们在前面的实验里面创建过了。

图119-46:新建FPGA衍生时钟
图119-47:新建100MHz衍生时钟
图119-48:本节实验需要的100MHz衍生时钟

        3)打开主VI“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”,切换到程序框图,放置一个定时循环结构,然后双击打开这个定时循环的时钟源配置页面,选择“200 MHz Onboard Clock”作为ADS127L01采集线程的时钟源,如图119-49所示。

图119-49:为定时循环配置时钟源

        4)接下来,我们直接把本书前面第53个实验里面的这个FPGA VI“实验53-高精度24位512KS-DSA动态信号采集-IEPE.vi”里面的ADS127L01数据采集线程定时循环拷贝到本节程序里面,如图119-50所示。然后将里面的3个FIFO换成本节实验我们创建的3个ADS127L01临时FIFO缓冲区;添加一个布尔型的开关按钮来控制ADS127L01采集使能,将按钮名称改成“开始/停止”,更加形象一些,这个按钮可以由上位机PC通过TCP下发指令控制ADS127L01是否采集数据。

        注意:拷贝过来的IP节点,需要重新配置一遍,用户可以直接双击IP Node节点,然后做一遍配置流程即可。

图119-50:拷贝ADS127L01数据采集线程(替换FIFO、增加使能开关)

        5)由于ADS127L01芯片本身可以实现4个档位的采样率控制,因此,我们不需要像前面实验那样,人为加计数分频代码,比如,我们直接控制“sample_rate”就可以实现不同的采样率;当然了,如果用户觉得ADS127L01芯片自身的几个固定档位的采样率不方便自己使用,用户可以自己在FPGA下位机里面加入计数分频或者在上位机进行抽点分频都行,这里,不再赘述了。

        6)为了能够调节ADS127L01的采样率,我们在下位机FPGA程序前面板上放置了一个“sample_rate”,如图119-51所示,本质上是一个3bit的数值控件。假设,sample_rate设置为0,那么实际的采样率就是64KS/s,等效于的吞吐率是3×64KS=0.192MSps,如图119-51所示;如果设置为1,那么采样率就是128KS/s,一共4个档位;以此类推,用户可以提前在前面板上设置好sample_rate,但是需要保存为默认值之后再编译,或者由上位机PC通过TCP下发参数来控制这个sample_rate参数,然后观察上位机PC端的波形图控件里面的信号周期点数是否发生符合预期的变化。

        注意1这种方式相对来说比较简单,不会影响其他时序,特别是有些芯片需要严格时序逻辑时,不得不采用定时循环,但是同时又希望自己能够掌控实际采样率,那么可以采用这种设计模式,两全其美。

图119-51:FPGA下的24位高精度ADS127L01动态信号采集程序前面板

       注意2直接复制过来的ADS127L01采集线程提示有错误,LabVIEW运行箭头是断开的,这是因为里面有IP Block调用网表的节点存在,拷贝意味着挪动,所以我们需要双击这个IP节点,重新走一遍配置过程就可以了,如图119-52所示。

图119-52:将拷贝到本节实验里面的ADS127L01 IP Block节点重新配置一遍

        7)如果用户希望通过TCP网络控制DSA模块上的恒流源输出指定大小的电流来激励外部的IEPE这些无源传感器,那么还需要将本书前面实验53里面的“DAC7512E恒流源控制线程”拷贝到本节下位机FPGA里面来,如图119-53所示。然后双击IP Node节点重新配置一遍,需要注意的是:这个恒流源输出线程的定时循环时钟要选择前面我们创建好的100MHz,其次,如果用户想屏蔽恒流源输出,可以拉高Source_ENA这个按钮,而不能通过对DAC芯片赋值为0,因为会存在漏电流,所以最保险的方式就是控制Source_ENA来决定是否开启XTR111使能输出;关于12位的DAC7512E的赋值跟实际输出的电流之间的关系,我们在前面的模块原理图部分已经给用户做过详细的讲解了。

图119-53:拷贝DAC7512E恒流源输出线程


        3.3.2、编写并转串程序(3个U8依次转移到1个U8缓冲里面)

        接着我们需要将这3个并行的U8字节FIFO里面的数据依次存放到TCP发送FIFO里面,不能错位,不然上位机就无法正确解析出来了。ADS127L01最大采样时钟频率是512KHz,那么为了能够快速实现3个FIFO的数据转移,并转串线程的时钟只要≥512KHz×3=1.5MHz,就不会发生数据溢出或者覆盖,这里我们选择常见的10MHz或者50MHz时钟作为并转串线程的时钟域都行。

 

        下面,我们单独开辟一个并转串线程,将ADS127L01临时3个U8类型的FIFO数据直接转移到我们创建的临时8位FIFO里面去。并转串线程的几个case条件程序框图,如图119-54~119-56所示。当右侧的临时U8类型的FIFO没有溢出的情况下,“输入就绪”会拉高,将这个信号按照四线握手接到ADS127L01拆分出来的3个原始数据FIFO的“输出就绪”端口上,然后再根据“输出有效”高低来决定是否跳转到下一个case条件分支,这样就实现了将3个ADS127L01 FIFO里面的按照顺序转移到这个临时FIFO里面去了,上位机只需要把原始的U8字节数组拼接成有符号24位定点数据后,再利用公式节点转成实际的电压值就可以了。

图119-54:并转串(第1帧)
图119-55:并转串(第2帧)
图119-56:并转串(第3帧)

        提醒:并转串这个架构在前面的多个实验都讲到了,不熟悉的用户需要加深一下理解,多动手自己练习一下就会了。

        注意:由于我们需要将3个字节依次上传到上位机进行拼接解析,如果中间错了一个字节或者丢失一个字节,那么会导致上位机解析的所有数据都会出错。因为负责把FPGA采集的数据发送到上位机的是8位位宽的TCP通道,如果传输的时候出现非3个字节,顺序计数不对的话,就完蛋了,因为上位机下发给FPGA的停止条件是随机的,虽然在后续的TCP发送线程里面已经无条件将上行通道里面的字节进行读取清空了,但是ADS127L01拆分出来的3个U8字节的FIFO并没有清空,所以,为了保险起见,万无一失,我们可以将图119-54~119-56里面的逻辑代码框起来,然后在条件为“假”的分支里面对3个临时FIFO进行读取清空,同时对状态机的计数器进行清零操作,如下图119-57所示。这样就能搞定因通道排序错点等问题造成的上位机解析问题。这个思想跟前面实验63里面的8通道AD7606是完全一样的。

图119-57:将状态机逻辑代码框起来并进行读取清空操作

        最后,为了判断ADS127L01采集过程中是否丢点,我们在这个并转串线程里面加上FIFO溢出计数判断,另外把LED4指示灯与溢出信号相连,也能通过板子上LED灯闪烁来直观的判断是否因为TCP带宽原因而造成的ADS127L01丢点,如图119-58所示。注意:“输入就绪”取反之后跟“超时”是一个效果。

图119-58:增加溢出计数判断程序


        3.3.3、编写ADC FIFO转移至TCP FIFO(数据转移线程)

        为了保持FPGA程序框架的统一性,我们将前面ADC采集线程里面的FIFO数据利用四线握手转移到TCP发送FIFO里面去,如图119-59所示。需要注意的是,这个线程的时钟频率要≥ADC采样率,比如本节实验里面的ADS127L01数据吞吐率换算成字节最大是512KS/s×24/8Byte=1.5MB/s,远远小于千兆以太网的极限传输带宽,为了相同的时钟域,这里我们将125MHz的TCP时钟频率作为定时循环时钟源。

图119-59:将ADC FIFO数据转移至TCP发送FIFO中


      3.3.4、编写下位机FPGA TCP Client Send程序框图(FPGA-->PC):上行

        1)为了降低FPGA TCP程序开发的难度,我们提前将ComBlock公司提供的VHDL版本的TCP Client IP核,利用NI公司的Socket CLIP技术,将其封装到FPGA终端下面,只把需要进行握手的FIFO端口预留出来,如图119-60所示。这样做的好处在于,用户即使完全不懂TCP协议栈,也能在FPGA里面调用CLIP进行TCP网络通信。关于这部分内容,前面10.4节已经做过了详细的讲解,不记得的用户一定要把前面10.4节温习一遍。

图119-60:利用NI Socket CLIP技术把ComBlock TCP Client IP核封装到LabVIEW里面

        2)打开主VI“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”,切换到程序框图,放置一个定时循环结构,然后双击打开这个定时循环的时钟源配置页面,选择125MHz的TCP Client CLIP时钟作为时钟源,如图119-61所示。这个125MHz同步时钟驱动的定时循环,是专门用来处理用户创建的FIFO跟TCP IP核内部的FIFO之间进行数据交互的,支持标准四线握手串联。

图119-61:为定时循环配置TCP Client 125MHz同步时钟源

        3)接下来,我们可以将FPGA终端下“TCP_Client Data”里面的前8个节点(TCP Client IP核复位和TCP网络配置参数)和“lv_tcp_client_connect_status”拖拽到刚刚创建的定时循环里面,然后创建相应的复位按钮和连接指示灯控件以及相应的IP参数,如图119-62所示。

图119-62:编写TCP Client IP核复位和参数设置程序框图

        其中,“TCP_Client Data\lv_tcp_client_reset”拉高(True),复位TCP Client IP核;如果TCP连接成功,“TCP_Client Data\lv_tcp_client_connect_status”指示灯会点亮;中间的7个TCP参数含义分别是:

l  下位机FPGA 客户端MAC地址:01-02-03-04-05-06

l  下位机FPGA客户端IP地址:192.168.1.16

l  下位机FPGA客户端端口:1028

l  下位机FPGA客户端网关:192.168.1.1

l  下位机FPGA客户端子网掩码:255.255.255.0

l  下位机FPGA需要连接的远程服务器IP地址:192.168.1.10

l  下位机FPGA需要连接的远程服务器端口:1024

        4)接下来,我们需要编写一下FPGA(客户端)传递数据给TCP IP核然后发送到上位机PC(服务器)的代码。首先,我们把FPGA终端下的TCP_Client Data里面的3个发送信号端口“lv_tcp_client_tx_data_in”、“lv_tcp_client_tx_data_in_vld”、“lv_tcp_client_tx_data_req_en”,拖拽到程序框图里面来,如图119-63所示。这3个信号端口其实符合标准的四线握手。

图119-63:将FPGA终端下的TCP Client CLIP上行通道3个信号端口拖拽到定时循环里面

        5)然后把我们前面创建好的8位位宽的用户FIFO(FIFO_TCP_Send_U8)也拖到程序框图里面,然后根据四线握手的方式,将TCP Client CLIP上行通道的3个握手信号接到FIFO上面去,完整的TCP Client数据上行发送程序框图,如图119-64所示。

图119-64:将FPGA终端下的TCP CLIP上行通道的3个握手信号连接到用户FIFO上

(FPGA-->PC上行数据发送程序框图)

        下面我们来讲解一下上面红色框框里面的程序框图含义:当TCP Client IP核内部的FIFO没有满时,这个“lv_tcp_client_tx_data_req_en”信号会拉高,也就是通知FPGA,可以将采集的数据发送给TCP IP核内部的FIFO;我们可以将这个信号接到FPGA里面用户创建的FIFO(FIFO_TCP_Send_U8)的“输出就绪”端口,然后把“元素”和“输出有效”两个端口分别接到TCP Client IP核的“lv_tcp_client_tx_data_in”和“lv_tcp_client_tx_data_in_vld”两个信号端口上;当用户FIFO里面有数据输出时,就会直接通过TCP传输到上位机PC端了。

        提醒:为了让上位机PC(服务器)能够自由动态的控制下位机FPGA(客户端)使能采集,我们加了一个布尔型控件“开始/停止”按钮,这个控件可以由上位机下发指令和参数进行控制,通过取反之后跟准备就绪“lv_tcp_client_tx_data_req_en”信号“相或”之后接到用户FIFO上面,同时还直接接到case结构上面。这样设计的目的是:是为了让下位机FPGA能够自动把用户FIFO(FIFO_TCP_Send_U8)残留剩余的数据读走等效于清空掉,比如上位机此时下发了一个停止采集指令,然后将布尔控件“开始/停止”设置为“假”,取反之后为“真”,接到了用户FIFO上面,如果此时用户FIFO里面依然残留了一些数据,直接就读出来,通过后面的case结构“假”分支过滤掉了;如果此时上位机PC再下发一个开始采集指令,那么用户FIFO里面一定是最新的数据,通过TCP发送到上位机的数据也就是最新的了。利用这种巧妙的方式可以模拟一个真实的DAQ数据采集设备。

        当然,我们还需要在ADS127L01采集线程里面加上这个“开始/停止”按钮来控制ADS127L01原始FIFO数据是否写入,如图119-65所示。只有当这个按钮为“真”时,才会启动采集。

图119-65:将“开始/停止”按钮添加到ADS127L01采集线程里面


        3.3.5、编写下位机FPGA TCP Client Receive程序框图(PC-->FPGA):下行

        1)接下来,我们还需要编写一个下行(PC-->FPGA)数据接收的程序框图。由于发送的下行数据一般都是经过“强制类型转换”函数转成了字节数组或者字符串形式,本质上数据类型属于U8,所以这里,我们可以使用FPGA终端下TCP_Client Data这个CLIP里面的8位下行通道来接收PC下发的字节数组。比如,本节实验我们使用下行通道来接收PC下发的指令和参数。

        2)首先,用户可以将FPGA终端下行通道的2个握手信号(lv_tcp_client_rx_data_out、lv_tcp_client_rx_data_out_vld)拖拽到FPGA程序框图里面,如图119-66所示。

图119-66:将FPGA终端下的TCP Client CLIP下行通道的2个信号端口拖拽到定时循环里

        3)然后根据四线握手的方式,将TCP Client CLIP下行通道的2个握手信号接到用户创建的Receive FIFO(FIFO_TCP_Receive_U8)上面去,完整的FPGA TCP数据下行接收程序框图,如图119-67所示。

图119-67:将FPGA终端下的TCP Client CLIP下行通道的2个握手信号连接到Receive FIFO

(PC --> FPGA下行数据接收程序框图)

        至此,关于下位机FPGA TCP Client四线握手的通信线程代码就编写完成了,这个线程也是最为核心的一个程序,今后,用户可以直接拷贝这个线程到自己的程序里面,而无需从头编写。

        3.3.6、编写下位机FPGA数据解析程序框图:下行数据解析线程

        1)为了能够真实的模拟上位机PC(服务器)和下位机FPGA(客户端)之间的交互运行,我们还需要编写一个FPGA数据解析线程,将PC下发的指令和参数正确的解析出来,然后赋值给FPGA里面相应的控件。关于这个数据解析线程的框架,其实我们在本书前面的串口通信和千兆以太网通信实验里面都有提到,不熟悉的用户可以回顾一下前面的相关内容。

        2)数据解析线程的整体框架,其实很简单:就是一个普通while循环,首先通过FIFO“获取待读取元素数量”方法节点,轮询TCP Receive FIFO里面是否接收到指定长度的数据(比如,做定长解析),如果达到了指定长度的数据,则利用for循环一次性将这些字节数组读取出来,然后进行拼接合并转换,变成实际意义的参数或者指令。

        3)比如本节实验里面,上位机PC每次下发的指令和参数一共是12个字节数据,那么我们在下位机FPGA程序里面,就可以将case结构的条件设置为12..,也就是说,只要下位机FPGA接到了至少有12个字节的数据,就会进入case里面,然后将for循环的长度也设置为12,这样就能一次性把这12个字节数据全部读取出来变成一个字节数组,然后再对这个一维数组进行索引拼接合并,甚至于进行加减乘除计算,完整的数据解析线程框图,如图119-68所示。通过程序框图可以看出:第1个字节跟0进行比较,如果大于0就启动采集,小于等于0则停止采集;第2个字节跟0进行比较,如果大于0就将ADS127L01工作模式设置为高性能高分辨率,小于等于0则设置为低功耗模式;第3个字节跟0进行比较,如果大于0就对ADS127L01芯片进行硬件复位,小于等于0则取消复位,可以看出,这些开关量都是通过给布尔控件进行赋值实现的;第4个字节赋给ADS127L01的增益控件“gain”,因为ADS127L01模块的增益只有3档(2.02、6.6、13.2),所以IP Node调用的ngc网表里面的“gain”端口只用了2bit来表示,我们用U8来表达布尔和小于8位宽度的数值是为了简化编程;第5个字节赋给ADS127L01的采样率控件“sample_rate”,用来改变ADS127L01芯片的采样率,因为ADS127L01芯片的采样率只有4档(64KS/s、128KS/s、256KS/s、512KS/s),所以IP Node调用的ngc网表里面的“sample_rate”端口只用了3bit来表示;第6个字节跟0进行比较,如果大于0就将就把XTR111芯片的OUT-EN引脚拉高,也就是关断了恒流源输出,如果小于0,则开启恒流源输出功能;将第7和第8个字节进行拼接之后赋值给DAC7512E作为恒流源的电压输出值,因为DAC7512E的位宽是12bit,所以我们直接用两个U8拼接变成U16可以完全覆盖12bit的数值范围(0~4095); 最后4个字节是预留的,用户可以根据实际情况下发更多的参数或者指令给FPGA,只要改下对应的数据长度就行了,这里我们就不再赘述了。

图119-68:完整的下位机FPGA里面的数据解析线程

        注意:如果用户想节约FPGA上的资源,也可以将布尔开关命令和数值指令按照bit进行组合拼接,然后下位机进行拆分赋值,这样会增加下位机FPGA的编程复杂度;同时需要提醒用户的是,在前面我们封装的Xillybus IP里面专门给用户讲解过PCIe Memory的用法,其实关于这个mem的读写,完全可以用我们这里介绍的FIFO数据解析线程来等效实现,感兴趣的用户可以自己尝试一下。在贯穿本书的通信协议里面,除了PCIe外,还有串口、USB、网口等等,如果想实现类似的mem效果,其实用我们介绍的FIFO数据接口拼接解析线程是最好不过的,因为这个框架更加统一方便,不受限于具体的总线通信,大小通吃,只要用户能够理解其中的含义即可,关于这点,我们早在UDP千兆以太网通信实验里面的最后一个衍生内容里面给大家讲解过了。

         4)将前面的ADS127L01数据采集线程、DAC7512E恒流源输出线程、并转串线程、FPGA TCP通信线程(上行+下行)、下发的数据解析线程等6个线程(循环)放在一起,就形成了一个完整的基于LabVIEW TCP Client Socket CLIP实现的FPGA TCP下位机动态信号采集DSA程序,如图119-69所示。

图119-69:完整的TCP动态信号采集卡FPGA下位机程序框图


       4、LabVIEW FPGA VI仿真

        本节实验涉及的是FPGA TCP网络通信,无法在计算机上进行虚拟,所以这里的功能性仿真可以跳过,直接将LabVIEW FPGA TCP主VI程序编译下载到FPGA芯片里面运行,然后再利用上位机通过下发指令和参数来测试通过网线连到上位机PC端(服务器)的黑金AX7103开发板(客户端)上的TCP网口能否正常发送和接收数据包,并在上位机前面板上把采集到的波形数据显示出来。

       5、LabVIEW FPGA VI编译下载

        1)直接点击FPGA主VI“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”上方工具栏里面的“运行”箭头按钮,保存VI之后,弹出Xilinx 编译服务器选择对话框,如图119-70所示。选择本地编译器,然后单击“取消”按钮,此时,在FPGA项目下的程序生成规范里面就会多出来一个与TCP通信VI同名的程序生成规范(实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA),如图119-71所示。双击打开这个程序生成规范属性配置页面,勾选“加载至FPGA时运行”复选框,最后点击“生成”或者“确定”按钮,如图119-72所示。如果点击的是“确定”按钮,那么需要重新运行一下VI即可再次启动Xilinx Vivado 2017.2编译器,进入编译状态窗口,如图119-73所示。

图119-70:选择本地编译器进行编译
图119-71:自动生成的FPGA VI程序生成规范
图119-72:勾选加载至FPGA时运行
图119-73: Xilinx Vivado 2017.2编译器正在编译

        2)提醒:编译很顺利,因为我们已经突破了7系列FPGA的编译、下载和在线前面板交互式运行和调试功能。等待FPGA VI程序编译完成后,就可以看到最终消耗的FPGA硬件资源,如图119-74所示。由于我们默认将TCP网络通信IP核也封装到这个FPGA终端下面,所以编译消耗的资源显的非常多,实际上,纯TCP协议栈消耗的FPGA资源很少,不到10%。

图119-74:“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI编译完成后的FPGA资源消耗情况

        3)当上面编译完成后,会弹出一个“正在准备交互式执行”对话框,如图119-75所示,这个想必用过NI或者看过我们Pro1开发宝典的用户很熟悉,正是LabVIEW FPGA启动在线前面板交互式运行和调试功能的提示框;如果大家还没有将Xilinx JTAG下载器和FPGA开发板接到这台电脑或者接的不是Xilinx JTAG下载器而是Digilent HS系列下载器,等一会会弹出一个超时错误对话框,提醒用户找不到下载通信线缆,也就是说主机找不到Xilinx JTAG下载器,如图119-76所示。

图119-75:编译完成后会启动LabVIEW FPGA在线前面板交互式运行
图119-76:提醒用户找不到Xilinx JTAG下载器

        重大更新:很多用户关心的是Vivado编译器编译出来的原始bit文件,而不是NI的lvbitx文件,因为原始FPGA bit文件更灵活更方便,将这个原始的bit文件发给任何人都可以通过任何手段下载到FPGA里面运行;虽然上面我们没有连接下载器和FPGA板子到电脑上导致下载超时,但是LabVIEW项目浏览器所在路径下的“FPGA Bitfiles”文件夹里面,依然会自动生成一个同名的原始bit文件,如图119-77所示。

图119-77:FPGA VI编译完成后会自动生成一个lvbitx文件和一个同名的原始bit文件

        注意1:这个自动生成原始FPGA bit文件的功能是我们在后台帮大家实现的,也就是说,用户再也不需要像前面第5章5.3节那样总是开着获取bit文件的程序才能得到原始bit文件。很明显经过我们重大更新后的宝典和LabVIEW My FPGA工具包更方便、更易用,体验效果跟NI完全一样。

        注意2:lvbitx不是FPGA原始的bit位文件,而是NI在bit基础上又封装了一层,因此,不能通过其他软件进行下载。但是,lvbitx里面包含了FPGA VI前面板上的控件类型和FPGA寄存器地址等信息,所以在后续FPGA VI在线前面板交互式运行里面会用得到lvbitx,这个也是LabVIEW后台自动完成下载和解析的,用户了解一下即可。

 

       6、TCP通信上位机(PC服务器端)程序编写

        下面我们需要编写一个TCP上位机(服务器端)应用程序来测试下位机FPGA(客户端)程序是否满足设计需求,相当于开发一个TCP千兆以太网采集卡上位机程序。这里用户可以直接调用LabVIEW软件自身就有的TCP函数选板里面的VI,如图119-78所示,不熟悉的用户可以自行研究一下,这里不再赘述。当然了,喜欢用C、C#、Python、QT等文本编程语言开发上位机TCP服务器测试程序的话,可以上网搜索一下或者问问ChatGPT。

图119-78:LabVIEW软件自带的超强版TCP函数选板(运行效率高,功能超级多)

        下面我们简单介绍一下上位机TCP服务器程序的编写过程。

        1)右击项目浏览器里面的“我的电脑”,选择新建一个“虚拟文件夹”,如图119-79所示。


图119-79:在“我的电脑”下面新建一个上位机虚拟文件夹

        2)然后对新建出来的虚拟文件夹重命名为“实验119-TCP服务器端+24位AD数据采集实验-上位机”,如图119-80所示。


图119-80:将新建的虚拟文件夹进行重命名

        3)然后右击上面的虚拟文件夹,选择新建一个VI,将这个VI保存为“实验119-TCP服务器端+24位数据采集卡(ADS127L01)-PC.vi”,如图119-81所示。


图119-81:新建一个TCP上位机服务器端通信程序

        4)为了加快讲解速度,这里我们直接给出TCP上位机服务器通信程序框图,如图119-82所示。程序框图由两个相互独立的线程组成,也就是两个while循环,分别是TCP写线程(PC服务器下发数据给客户端FPGA)和TCP读线程(PC服务器读取FPGA客户端上传的数据)。对应的前面板控件布局,我们也先贴出来,如图119-83所示。

图119-82:TCP上位机服务器端通信程序框图
图119-83:TCP上位机服务器端通信程序前面板

        下面我们来分别介绍一下这两个线程对应的程序框图编写过程及其注意事项。

        5)首先,程序启动的时候,一般都会有一个初始化过程,这里也不例外。由于前面板上有一些按键和指示灯等控件,为了让程序每次运行的时候,都能恢复到一个默认状态,这里利用顺序结构,对需要设置的控件进行赋值操作,如图119-84所示。


图119-84:TCP通信上位机前面板控件初始化代码

        6)接下来,我们看看上位机TCP写线程代码是怎么实现的。由于下位机FPGA跑的是TCP Client客户端程序,那么上位机的角色就是服务器;所以,我们需要从TCP函数选板里面选择侦听函数“TCP listen.vi”,侦听来自下位机FPGA的TCP连接请求;这个“TCP Listen.vi”要侦听的下位机FPGA客户端IP地址是192.168.1.10,端口是1024,如图119-85所示,这两个参数就是前面下位机FPGA VI程序里面设置的PC IP和port;同时为了防止上位机阻塞死机,将TCP侦听超时设置为30s。


图119-85:上位机服务器端利用“TCP Listen.vi”侦听来自下位机FPGA客户端发起的连接

        7)一旦上位机TCP侦听成功,说明上位机PC跟下位机FPGA成功建立起TCP网络连接,同时,这个“TCP Listen.vi”会返回一个非零的TCP引用句柄出来,用户可以通过这个引用实现TCP网络数据的下发和读取。为了人为控制下发的指令和参数,可以利用case条件结构将下行数据的发送代码框起来,如图119-86所示。


图119-86:TCP下行数据的发送代码

        为了让上位机PC能够控制下位机FPGA里面的采样率和信号采集的启动和停止,我们将上位机前面板上的数值类型的“gain”、“sample_rate”和“DAC7512_Value”输入控件通过“强制类型转换”函数变成字节数组;再把前面板上的布尔型“开始/停止采集”、“work_mode”、“RST_P_ADS127L01”和“Source_ENA”按钮控件转成U8类型的0或者1;然后再把预留的一个参数“size_read_U32”控件通过“强制类型转换”变成字节数组;最后将这几类转换后的数据进行数组拼接(实际上就是字节数组),赋给“写入TCP数据.vi”,如图119-87所示。这样就可以将上位机服务器端的数据通过TCP下发给FPGA客户端。


图119-87:将上位机的指令和参数转换成字节数组后下发给FPGA

        8)下面,我们再来看看上位机PC服务器端是如何把FPGA采集上传的数据通过TCP函数读取出来的。为了提高TCP读取效率或者为了方便定长数据的解析,我们可以给“TCP读取数据.vi”函数设置一个长度阈值,只有当上位机PC端的TCP缓冲区里面接收到指定长度的字节数之后,再把这些字节数组一次性读取出来。因为TCP传输的数据都是以字节为单位,所以如果用户希望读取的数据位宽是字节的倍数,比如本节实验,下位机FPGA上传的ADS127L01采集的数据是FXP<±24,24>类型的信号,正好就是3个字节,所以在判断之前,我们可以将指定读取的点数×3,再做比较判断,这样读出来的数据正好能被8整除,通过“抽取一维数组”的方式将8个通道的波形还原出来。

        LabVIEW里面自带的“TCP读取数据.vi”这个函数非常强大,它提供了4种内在读取模式,分别是Standard、Buffered、CRLF、Immediate这4种模式:

表1:LabVIEW TCP读取函数4种读取方法

        这里很多用户经常搞不清楚这些模式的含义以及用法,这个属于基本功问题了。下面我们简单讲解一下这4种模式。

1Standard标准模式,也是默认模式,因为这个“TCP读取数据.vi”拖拽到LabVIEW程序框图里面之后,这个模式参数默认是不显示的,如果用户不去手动创建的话,那么默认就是第一个“标准模式”。这种模式下,如果TCP缓冲区里面接收到的字节数量少于指定读取的长度,那么该VI就是有多少读取多少,并且产生超时错误,虽然产生了超时错误,但是读出来的数据都是有效的,并不妨碍数据本身,只是我们可以通过是否超时来判断读取的数据长度是否达到我们指定的长度。这种模式内部存在阻塞机制,直到发生超时退出为止。

2Buffered缓冲模式,这种模式相比于标准模式,它的优势更明显,那就是当缓冲区里面的字节数据没有达到指定读取的长度,那么这个VI读出来的数据是无效的,TCP数据依然很好的保留在TCP缓冲区里面,通过超时错误告知用户,当前返回的数据可以直接忽略。

3CRLF回车换行模式,这个模式带有一定的协议分段功能在里面,特别适合不定长数据的读取和解析,比如下位机每次发送的TCP数据有效内容长度不固定,那么可以在TCP发送每包有效数据的尾巴加上CR(回车)LF(换行)结束符,这样,TCP对等端只需要将读取长度设置为一个超级大的数,该函数内部自己轮询TCP缓冲区收到的字节数据,一旦发现有CRLF结束符,立刻输出当前有效内容,可以看出,这个模式非常适合不定长数据和自定义协议解析等应用

4Immediate立即模式,这个模式是所有模式里面读取效率最高的,如果用户将超时设置为0的话,那么实际效果就是,每次执行这个TCP读取VI的话,缓冲区有多少字节数据,就会立刻读取出来,不管有没有超时产生,读出来的数据都是有效的,这个模式配上LabVIEW里面自带的队列函数,可以快速构建出来一个“生产者-消费者”模式,将TCP报文通过队列存放到计算机内存中。

        总结:如果想要实现上面指定长度字节数据的读取、解析和信号波形恢复,应该选择Buffered缓冲模式最佳,这样如果下位机FPGA采集的是一个周期性信号,那么只要上位机读取的点数能够整除波形周期点数,那么波形图里面就不会存在左右滑动跳动的不稳定效果了,因为我们需要观察一个相对稳定的周期信号,类似示波器周期信号触发功能一样。当然了,如果想要测试TCP传输的极限吞吐率,应该选择Immediate立即模式,同时还要关闭所有影响CPU效率的代码,比如波形图显示。

        基于以上分析,编写的上位机服务器端TCP读取程序框图,如图119-88所示。


图119-88:利用Buffered缓冲模式读取下位机FPGA发送的TCP报文数据(指定读取长度)

        9)一般情况下,如果下位机FPGA发送的TCP数据吞吐率很高,那么上位机读取的频率和每次读取的字节长度(size_read_U32)要满足一定的范围才能保证所有的数据不会丢失,如果每次读取的字节长度很短,那么需要读取的速度就要很快,这样不仅会极大的消耗CPU的资源,还有可能会造成数据溢出丢失;关于这个数值取多少合适,用户可以根据实际情况做实验决定。

        10)“TCP读取数据.vi”函数读取返回的数据类型是字节数组,如果从FPGA里面接收到的数据物理意义并不是字节类型,那我们还需要借助“强制类型转换”函数将原始的字节数组转换真实的数据。本节实验下位机FPGA采集的ADS127L01数据类型比较特殊,需要把接收到的字符串先利用“强制类型转换”函数转换为无符号U8字节数组,再利用“抽取一维数组”函数把ADS127L01相邻的3个U8提取出来,然后利用for循环将相邻3个点变成布尔数组,再进行拼接变成24位布尔数组,接着利用“布尔数组至数值转换”函数将这个24位的布尔数组变成有符号定点数FXP<±24,24>,最后根据利用公式节点把采集的原始数据转换成单精度浮点数,单位就是电压V。其中,公式里面的2.5是基准电压,3是AMP衰减电路的比例系数。如图119-89所示。

图119-89:利用“强制类型转换”VI转成U8数组再利用“抽取一维数组”和公式节点将原始AD数据转换成浮点数

        提醒:在对24位ADS127L01进行转换的时候,切记,ADS127L01转换出来的24位数据是带符号的,也就是I24(-8388608~8388607),假设ADS127L01芯片电压输入量程设置的是±10V,那么-8388608代表-10V,0代表0V,8388607代表+10V。

        11)当ADS127L01采集到信号之后,我们可以在前面板上放置1个波形图显示控件,将FPGA客户端发送上来的数据以波形的方式呈现出来,但是考虑到实际应用中,如果波形图控件里面每次显示的点数过大的话,会导致电脑CPU、内存和显卡压力过大,CPU运行速度会降低,这样不利于TCP快速读取数据,因此,我们在TCP-读线程里面加了两个控制按钮,可以人为控制读取出来的波形是否进行拼接以及是否开启波形显示功能,如图119-90所示。关于这几个功能的演示,我们在后续的实验演示环节里面再给用户做详细的介绍。


图119-90:是否开启波形显示和波形首尾拼接功能

        12)当用户需要将这个程序停止运行的时候,可以通过TCP发送停止指令给下位机FPGA,让FPGA内部的TCP Client发送线程进入case为假的分支,也就是停止给上位机服务器发送数据了,同时下位机FPGA里面的“FIFO_TCP_Send_U8”也会自动清空,这样下次再运行这个上位机程序的时候,采集的又是当前最新的数据了;最后关闭上位机TCP引用句柄,防止出现内存泄漏,如图119-91所示。


图119-91:上位机程序停止之前给FPGA下发停止指令再关闭TCP网络引用句柄

        注意:细心的用户发现了我们的“TCP-读线程”while循环里面有一个禁用结构,里面是ms倍数延时,如图119-92。这个延时的作用是什么呢?这个ms倍数延时函数主要是用来控制我们的while循环读取频率,可以释放CPU资源。假设,当FPGA采样率很低的时候,也就意味着上位机PC端接收到的数据吞吐率低,那么我们就没有必要让“TCP-读线程”跑的太快,这样会极大消耗CPU资源,如果主程序里面还有其他的事情要处理,那么CPU会显得吃力;如果下位机FPGA采样率很高的时候,为了避免TCP缓冲区溢出,我们需要以最快的速度将里面的数据全部读取出来,这时我们可以给ms倍数延时函数赋值0或者直接将这延时函数禁用掉,这样“TCP-读线程”这个while循环就会全速运行。


图119-92:控制TCP读取速度的ms倍数延时函数

        13)最后,再来介绍一下这个上位机PC TCP服务器端通信程序前面板上的控件有哪些功能和注意事项,完整的上位机程序前面板,如图119-93所示。


图119-93:上位机PC TCP服务器端通信程序前面板

        上位机程序运行之后,一旦侦听到下位机FPGA客户端发来的连接请求后,成功建立连接之后,前面板上的“Running_W”和“Running_R”两个显示控制里面的数值就会快速递增;然后用户可以通过“sample_rate”控件里面的数值参数控制下位机FPGA里面的采样率,比如当我们设置为3,实际传递下去控制的是FPGA前面板上的采样率控件里面的512KS/s,将24位的ADS127L01数据换算成字节为单位的采样率的话,也就是1.5MByte/s,这个采样率其实并不高;所以我们可以将前面板上的“开始/停止采集”和“显示波形?”两个按钮全部点亮,前者是用来通知FPGA启动采集发送数据,后者是把上位机接收到的波形数据在波形图控件中显示出来;然后可以在“size_read_U32”控件里面输入一个点数,比如512000,也就是512K个FXP<±24,24>点;最后,当我们点击一下“Send”按钮之后,上位机PC就会把指令和参数通过TCP下发给FPGA,然后就能看到波形图里面出现一个长度为512K个点的信号。整个过程可以很好地反应下位机FPGA客户端采集数据发送到PC服务器端的整个动态展示,更多现象我们在后续的实验演示环节再给用户讲解。

        需要注意的是:虽然本节实验中用到的ADS127L01产生的数据量,对于我们封装的ComBlock TCP IP核来说,完全小case;不过对于性能很差的电脑,建议用户最好把前面板上的“显示波形?”熄灭关掉,这样可以节省CPU资源,加快LabVIEW应用程序读取速度,减少上位机的TCP缓冲区溢出造成的数据丢失。

       7、实验操作

    7.1、准备工作

        1)接好硬件设备。

        将AN706模块(AD7606)插到黑金AX7103开发板上的J11拓展口上面;然后利用一根CAT5+或者CAT6类网线,一头接到黑金AX7103开发板第2路网口里面(ETH2),另外一头接到电脑的网口里面;要想实现FPGA VI在线下载和在线前面板交互式运行,必须使用Xilinx JTAG下载器(不能使用任何第三方Digilent HS系列下载器,比如黑金的红色下载器本质上就是高仿的Digilent HS1下载器),将JTAG线缆一头插到黑金AX7103开发板上的JTAG下载口,USB一头接到电脑上(注意:如果用户使用的是不带RJ45网口的超薄笔记本电脑的话,可以在网上买一个雷电转千兆网口扩展坞,相当于给笔记本扩展了一个RJ45千兆网口,这样上位机PC(服务器)和下位机FPGA(客户端)之间的TCP网络通信实际AX7103与ADS127L01模块实验就可以在一台笔记本上完成了,更方便);此时,笔记本的设备管理器里面识别出来一个Xilinx JTAG下载器设备,如图117-94所示。关于Xilinx下载器驱动安装方法在前面,我们已经给用户介绍过了,这里不再赘述。实际AX7103与ADS127L01模块、信号发生器、JTAG下载器和笔记本之间的接线实物图,可参考图119-95所示。

图119-94:识别出来的Xilinx JTAG下载器(DCL9或者DCL10)
图119-95:AX7103、ADS127L01模块、信号发生器、JTAG下载器和笔记本接线实物图

        提醒:黑金并没有开发ADS127L01这个模块,市面上能买到的模块没有做成黑金那种标准40pin的接口,所以这里需要利用杜邦线将ADS127L01模块接到黑金AX7103开发板的J11扩展口里面。

    7.2、手动下载bit文件(传统手动下载方式,效率低,不推荐,跳过,直接看7.3节)

 

    7.3、自动下载bit文件(支持在线前面板交互式运行和调试,效率高,更方便,推荐)

        接下来,就是见证奇迹的时刻了,大家屏住呼吸哈

        硬件接好之后,给FPGA开发板上电,然后再点击一下编译过的“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI前面板左上角的运行箭头,此时,LabVIEW会在后台自动将编译好的bit文件下载到FPGA芯片里面,几秒之后,奇迹发生了,可以看到就像我们开发的LabVIEW STM32工具包那样,LabVIEW前面板成功地进入了FPGA在线交互式运行模式,如图119-115所示。

图119-115:“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”
FPGA VI前面板自动进入了在线交互式运行

        几秒之后,可以看到上位机“控制面板\网络和Internet\网络连接”里面的网卡由断开状态变成了连接状态,如图119-116所示。说明,上位机识别到了下位机FPGA网络。

图119-116:上位机网卡由断开状态变成了连接状态


    7.4、准备外部信号函数发生器(产生标准电压信号给ADS127L01模块)

        将外部函数信号发生器的波形设置为Sine正弦,频率设置为:1KHz,峰峰值设置为±2.5V,如图119-117所示。

图119-117:将函数信号发生器输出信号设置为正弦(频率=1KHz;峰峰值=±2.5V)

        那么增益这个参数该怎么设置最合适呢?下面我们给用户分析一下这个DSA模块上面的电压变换过程:由于分压电路的原因,输入的信号先除以3,再乘以增益gain才会输入到ADS127L01芯片差分引脚上面,其中,ADS127L01芯片的参考电压Vref是2.5V基准电压,也就是说ADS127L01能实际能采集的输入信号范围是±2.5V;所以为了提高采集精度,在已知输入信号最大峰峰值Vpp范围的前提下,增益gain可以按照下面的公式进行推算:

Vin/3×gain≤Vref

gain≤3×Vref/Vin≤7.5/Vin

        其中,Vref=2.5V,Vin是输入信号峰峰值Vpp的一半。这款IEPE模块上的gain有3档可以选择:2.02、6.6和13.2。所以当输入的信号Vpp是±2.5V时,根据上面公式计算出来的增益gain理论值是3,所以用户只能选择2.02;如果外部信号Vpp是±1V,那么增益可以选择6.6。理论上,增益越大,ADS127L01采集的效果越好。

    7.5、观察现象(运行上位机TCP服务器端通信测试程序)

        1)首先,需要根据下位机FPGA Client VI里面设置的远程服务器端IP地址和端口,把对等端上位机的网络地址也做相应的设置,如图119-118所示。这里,上位机服务器端IP是192.168.1.10,端口是1024.

图119-118(a):根据下位机FPGA Client程序的参数来对上位机网络做相应的设置
图119-118(b):根据下位机FPGA Client程序的参数来对上位机网络做相应的设置

        2)为了提高TCP的极限传输吞吐率,建议将上位机网卡里面的“传输缓冲区”和“接收缓冲区”深度改到最大值2048,如图119-119所示。

图119-119:将上位机网卡属性里面的传输和接收缓冲区深度改到最大值2048

        3)为了测试下位机FPGA Client客户端与上位机服务器端是否建立起网络通信,最简单的办法就是利用Windows系统自带的cmd命令窗口,利用ping指令来测试下位机FPGA,比如这里,我们可以输入ping 192.168.1.16,如图119-120所示。可以看出,下位机FPGA对于上位机的ping指令立马做出了回应。提醒:如果用户ping指令没有反应,也可以点击一下下位机FPGA VI前面板上的“reset”按钮对TCP IP核复位一下即可。

图119-120:利用ping指令测试下位机FPGA网络ARP协议是否运行正常

        4)为了验证下位机FPGA DAQ Client客户端程序的功能是否符合前面的预期设计,需要一个对等端,比如本节实验需要一个上位机作为服务器端来与下位机FPGA进行网络测试。这里测试用到的上位机TCP服务器端程序也是利用LabVIEW编写的,无论是执行效率还是灵活性还是可阅读性都是最强的。

        5)打开运行上位机TCP服务器端通信测试程序,位于项目浏览器“我的电脑”下面的“实验119-TCP服务器端+24位数据采集卡(ADS127L01)-PC.vi”,如图119-121所示。

图119-121:运行上位机TCP网络通信测试程序

        6)运行上位机程序之后,可以看到下位机FPGA Client VI前面板上的两个指示灯控件点亮了,说明上位机PC服务器端侦听到了下位机FPGA发起的连接,并成功建立起了TCP网络通信,如图119-122所示;同时,上位机VI前面板上的“Running_W”和“Running_R”显示控件里面的数字快速增加,说明上位机TCP读线程和写线程运行起来了。

图119-122:运行上位机TCP服务器端程序之后,下位机FPGA VI指示灯点亮(建立连接)

        7)运行上位机程序之后,按下“work_mode”按钮点亮,将ADS127L01设置为高分辨率工作模式;在输入控件“gain”里面输入0,相当于将ADS127L01模块的增益电路放大系数设置为2.02倍;在输入控件“sample_rate”里面输入0,相当于等效的采样率是64KS/s<=>192KB/s(ADS127L01位宽是24位);因为本节实验我们直接通过信号发生器输出的正弦信号,所以不需要恒流源激励,如果用户外接的是IEPE无源传感器,那么可以输出几个mA的电流出去,这里不需要恒流源功能,因此,可以按下“Source_ENA”按钮点亮;参数设置完成后,可以按下“波形显示?”按钮,这样后面就能在波形图里面看到每次读取的Sine信号了;再在输入控件“size_read_U32”里面输入每次从PC端的TCP FIFO缓冲区里面需要读取的数据长度,由于前面我们设置的采样率不高,所以这里输入的读取长度相对自由一些,比如我们设置512000,也就是每个通道都准备读取512K个点,就是每次读取1.5M个Byte;最后再按下点亮“开始/停止采集”这个按钮。

        当一切设置就绪后,点击一下前面板上的“Send”发送按钮(这是一个触发型的控件),每点击一次,上位机(服务器端)都会把前面板上设置的这些参数转换成字节数组通过TCP下行通道发送给下位机FPGA(客户端),当FPGA接收完成并解析出来指令和参数后,会立刻把采集到的Sine信号通过TCP上行通道源源不断的发送给上位机PC。

        此时前面板上出现了10个周期的波形,每个周期的点数是512个点,但是我们明明设置的采样率是64KS/s,为什么采样率变成了512KS/s,这是因为采样率和增益这两个参数的更新,需要发送复位指令才可以生效,于是,我们点亮前面板上的“RST_P_ADS127L01”这个按钮,然后再点击一下“Send”按钮,此时,Buffer内存池“Buffer_Valid_Length_U8[]”里面没有数据增长了,因为下位机ADS127L01处于复位状态,不会采集数据,如图119-123所示。

图119-123:每次更改ADS127L01采样率或者增益时,需要下发RST复位指令才能生效

        然后我们再熄灭“RST_P_ADS127L01”这个按钮,再次点击一下“Send”按钮,此时,大约8s之后出现的新波形数据,如图119-124所示。并且波形周期数变成了80个,恰好证明了下位机ADS127L01的采样率变成了64KS/s。并且,传输过程非常稳定,说明下位机FPGA通过ADS127L01采集到的所有数据没有发生溢出或者丢失,上位机全部接收到了。

图119-124:开启波形显示功能,禁用波形首尾拼接(采样率:64KS/s<=>192KB/s)

       实际观察到的情况是:每隔8s,TCP缓冲区清空一次,同时,波形图里面的曲线会刷新一次,这是因为下位机FPGA的采样率是192KB/s(64KS×3),上位机LabVIEW程序每次批量读取1.536MB数据,所以刷新周期就是8s。

        我们将波形图里面的曲线进行放大,比如,将横坐标设置为512个点进行显示,可以看到,正好有8个周期的正弦曲线在里面,因为外部Sine信号频率是1KHzADS127L01采样率设置的是64KS/s,所以每个周期的采集量化点数就是64个,因此,512个点就是8个周期信号。再来看看幅度对不对,外部信号峰峰值是±2.5V,而ADS127L01模块的采集范围是正负2.5V,采集到上位机的FXP<±24,24>经过公式转换之后变成了±2.48V,这个分析结果正好与上面图119-124完全匹配上了,说明我们编写的下位机FPGA程序和上位机程序都是完全正确的。

 

        实际上,当下位机FPGA接收到上位机通过TCP下发的指令和参数后,也可以在下位机FPGA Client VI前面板上看到这些控件参数自动发生更新了,并且下位机FPGA VI前面板上的“溢出点数”始终为0,说明原始的ADC FIFO没有数据溢出,也就不存在丢点,非常好,如图119-125所示;同时,Windows任务管理器里面显示的网络使用率是0.16%,如图119-126所示,换算一下就是:1Gbps×0.16/100=1.6Mbps=200KB/s,符合预期。算上TCP包头、MAC、IP地址和CRC等信息,大于有效数据的192KB/s完全合理。

图119-125:进入在线交互式运行模式下的FPGA VI前面板上的控件值自动实时更新,并且下位机FPGA Client VI前面板上没有数据溢出(说明192KB/s传输速度下,TCP没有丢包)
图119-126:上位机Windows任务管理器显示的网络使用率(0.16%:200KB/s)

        注意:如果用户按下上位机VI前面板上的“拼接”按钮,可以将TCP读取的所有波形进行收尾拼接相连,但是如果让这个LabVIEW上位机程序一直运行着,过一会会弹出一个错误提示:系统内存不足,请释放内存空间。这是因为我们在程序框图里面开启了波形首尾拼接功能,随着时间的延长,程序框图里面的数组长度和波形里面的数据量越来越大,一旦超越了LabVIEW软件本身的承受能力,就会导致LabVIEW报警甚至卡死崩溃。所以,一般情况下,我们都是人为控制一下程序框图里面的数组长度以及波形控件里的数据点数,不能太大,否则不仅会造成计算机卡顿甚至造成软件崩溃;或者利用“生产者-消费者”模式将从网络缓冲区里面读取到的TCP数据转移到队列里面,本质上相当于从网卡转移到计算机内存里面,因为计算机内存一般都很大,而计算机网络缓冲区则很小,因此这种方式可以实现数据流盘和无损回放。

 

        8)下面我们来提高一下FPGA采样率,看看会有什么情况发生:首先,将输入控件“sample_rate”里面的0改成1,相当于等效的采样率提高了2倍:128KS/s<=>384MB/s(ADS127L01位宽是8位);按下“波形显示?”按钮,这样后面就能在波形图里面看到每次读取的Sine信号了,熄灭“拼接?”按钮;其他参数保存不变,比如,输入控件“size_read_U32”里面还是输入512000,也就是每个通道都准备读取512K个点,换算成字节的话,就是每次读取1.536M个Byte(点数×3);“开始/停止采集”这个按钮要一直点亮。

        当一切设置就绪后,点击一下前面板上的“Send”发送按钮(这是一个触发型的控件),每点击一次,上位机(服务器端)都会把前面板上设置的这些参数转换成字节数组通过TCP下行通道发送给下位机FPGA(客户端),当FPGA接收完成并解析出来指令和参数后,会立刻把采集到的Sine信号通过TCP上行通道源源不断的发送给上位机PC。

        此时,下位机FPGA Client VI前面板上的“sample_rate”采样率变成了128KS/s,如图119-127所示,说明上位机下发的TCP参数和指令成功了,并且“溢出点数”始终为0,说明下位机FPGA TCP上行通道即使384KB/s传输速度下,依然稳健,没有发生数据丢失。

图119-127:下位机FPGA Client VI接收上位机下发的参数更新之后(采样率128KS/s)

        同时,上位机依然能够全部接收FPGA上传的全部波形数据,即使下位机FPGA里面的采样率提高到了128KS/s,下位机FPGA实际采集到的所有Sine正弦信号依然没有发生溢出或者丢失,上位机全部接收到了,如图119-128所示。

图119-128:开启波形显示功能,禁用波形首尾拼接(采样率:128KS/s<=>384KB/s)

        注意:修改后的采样率并没有生效,用户需要像前面那样,先发送一次ADS127L01复位指令然后再进行采集就对了,切记!!!

        上位机前面板上的波形图经过4s刷新一次,这是因为下位机FPGA的采样率是128KB/s,上位机LabVIEW程序每次批量读取1.536MB数据,所以刷新周期就是4s,相当于0.25Hz的刷新率;波形图里面的Sine信号基本上处于不变状态,这是因为ADS127L01采样率跟外部信号的频率整除关系,用户可以尝试改变一下外部Sine信号的频率或者幅度就能看到上位机Sine曲线明显变化了。

        我们将波形图里面的曲线进行放大,比如,将横坐标设置为1024个点进行显示,可以看到,正好有8个周期的正弦曲线在里面,因为外部Sine信号频率是1KHzADS127L01采样率设置的是128KS/s,所以每个周期的采集量化点数就是128个,因此,1024个点就是8个周期信号。

        此时,可以看到当前时刻Windows任务管理器的以太网传输速度,网络吞吐率变成了0.32%,如图119-129所示,换算一下就是:1Gbps×0.32/100=3.2Mbps=400KB/s。算上TCP包头、MAC、IP地址和CRC等信息,大于有效数据的384KB/s完全合理。

图119-129:上位机Windows任务管理器显示的网络使用率(0.32%:400KB/s)

        9)下面我们进一步提高FPGA采样率,看看会有什么情况发生:先将输入控件“sample_rate”里面的1改成3,相当于等效的采样率提高了4倍:512KS/s<=>1.5MB/s(ADS127L01位宽是24位FXP<±24,24>);其他保持不变,比如,“波形显示?”按钮处于点亮状态,这样后面就能在波形图里面看到每次读取的正弦信号了;“拼接?”按钮依然设置为熄灭状态,防止内存溢出;输入控件“size_read_U32”里面的512000,也就是1.536M个点保持不变,换算成字节的话,就是每次读取1.536M个Byte(点数×3);“开始/停止采集”这个按钮要一直点亮。注意:修改后的采样率并没有生效,用户需要像前面那样,先发送一次ADS127L01复位指令然后再进行采集就对了,切记!!!

        设置完成后,再点击一下前面板上的“Send”发送按钮(这是一个触发型的控件),每点击一次,上位机(服务器端)都会把前面板上设置的这些参数转换成字节数组通过TCP下行通道发送给下位机FPGA(客户端),当FPGA接收完成并解析出来指令和参数后,会立刻把采集到的Sine信号通过TCP上行通道源源不断的发送给上位机PC。

        此时,下位机FPGA Client VI前面板上的“sample_rate”分频系数变成了1,如图119-130所示,说明上位机下发的TCP参数和指令成功了,并且“溢出点数”保持为0,说明下位机FPGA TCP上行通道即使1.536MB/s传输速度下,依然稳健,没有发生数据丢失。

图119-130:下位机FPGA Client VI接收上位机下发的参数更新之后(采样率512KS/s)

        通过观察“溢出点数”控件数值一直保持为0,说明即使下位机FPGA里面的ADS127L01采样率提高到了512KS/s,FPGA采集的信号数据没有溢出和丢失;上位机读到的Sine信号依然是连续的,如图119-131所示。这是因为我们封装的TCP Client传输带宽吞吐率最大是95MB/s,加上上位机没有什么复杂的解析和算法,能及时读走TCP FIFO缓冲区里面的数据,所以就没有产生数据溢出或者丢失。

图119-131:开启波形显示功能,禁用波形首尾拼接(采样率:512KS/s<=>1.536MB/s)

        我们将波形图里面的曲线进行放大,比如,将横坐标设置为5120个点进行显示,可以看到,正好有10个周期的正弦曲线在里面,因为外部Sine信号频率是1KHzADS127L01采样率设置的是512KS/s,所以每个周期的采集量化点数就是512个,因此,5120个点就是10个周期信号。幅度没有变化,峰峰值依然是±2.5V

        此时,网络吞吐率变成了1.3%,如图119-132所示,换算一下就是:1Gbps×1.3/100=13Mbps=1.625MB/s。算上TCP包头、MAC、IP地址和CRC等信息,大于有效数据的1.536MB/s完全合理。

图119-132:上位机Windows任务管理器显示的网络使用率(1.3%:1.625MB/s)

        10)当然,感兴趣的用户,还可以将外部信号源输出的Sine信号峰峰值变小,然后尝试加大增益系数,看看采集到的波形是否存在失真。

    7.6、实验分析(至关重要)

        1)本节实验因为下位机FPGA的采样率不高,远远小于我们封装的纯FPGA TCP协议栈的极限带宽,加上上位机没有什么复杂的算法,所以即使把采样率提到最大,依然不会溢出或者丢点。

        2)如果某些用户的电脑性能一般,可以将上位机PC程序前面板上的“波形显示”功能关闭掉,这样可以进一步提高上位机的TCP读取效率,以保证下位机FPGA Client ADC采集的数据不会溢出丢失。

        3)重要结论:只要上位机TCP读线程足够快,就不会发生下位机FPGA FIFO溢出,所有采集的数据都可以通过TCP网络传输到计算机内存里面来;本节实验我们测试的24位ADS127L01芯片最大采样率512KS/s,换算成小bit,也就是24/8×512K×8bps =12.288Mbps,远小于我们封装的FPGA TCP IP核底层协议支持的800Mbps吞吐率。

        4)有些细心的用户发现了,如果上位机每次读取长度不是采样率与实际信号的整数倍时,上位机波形图里面的锯齿波就会出现左右滑动,而不是一个稳定状态,这个跟示波器原理类似,上位机要想稳定的显示出来,每次从TCP网络缓冲区里面读取的点数就需要满足整除。

        5)一定要把上位机影响CPU和网络性能的软件全部关闭,特别是todesk、teamview、向日葵等。

       8、手动固化FPGA VI程序(传统手动固化方式,效率低,不推荐,跳过,直接看第9节)


       9、自动固化FPGA VI程序(右击VI直接自动下载固化,效率高,更方便,推荐)

        当我们借助LabVIEW FPGA强大的在线交互式运行前面板调试完FPGA VI程序后,就可以将这个FPGA VI进行批量部署了,也就是把编译出来的FPGA原始bit文件转成mcs或者bin文件固化到FPGA开发板上的Flash芯片里面。

        前面第8节我们向大家介绍了可以通过Vivado手动将FPGA bit文件固化到Flash芯片里面,但是那个方法过于复杂,操作起来非常不方便!感兴趣的用户可以自行了解一下即可,无须深入学习第8节,除非是一种特殊的情况,那就是你设计的FPGA产品卖给了你的用户,当你的FPGA bit文件升级了,你把最新的bit文件发给远在其他城市的客户,需要将这个bit文件重新固化到你的FPGA板子里面去,但是你的客户又不懂LabVIEW,此时,你可以教他如何利用Vivado进行手动下载和固化。

 

        为了让我们的LabVIEW My FPGA工具包,跟NI FPGA硬件开发有着相同的用户体验,我们将整个FPGA bit文件到mcs/bin文件格式的转换、下载器速度的设置以及各种Flash芯片的选择,全部在后台自动完成,极大的方便了用户的使用!  

       需要注意的是:有些厂家做的FPGA板子为了降低硬件成本,实际焊接的Flash芯片跟其提供的说明书有时候对不上,导致固化总是不成功,此时,保险起见,最好用眼睛实际观察一下FPGA板子上Flash芯片的具体型号和厂家,这种情况时有发生!经验之谈、少走弯路!

        下面进入实战操作:将“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI固化到黑金FPGA开发板的Flash芯片里面。

        1)首先根据黑金提供的FPGA开发板原理图找到上面的Flash芯片具体型号,比如黑金AX7103开发板上的Flash芯片都是N25Q128,如图119-143所示。可以看出,这款Flash容量是128Mbit,换成大B就是16MByte。

图119-143:黑金AX7103 FPGA开发板上的Flash芯片型号

        2)然后找到黑金FPGA开发板AX7103对应的终端模板文件所在的路径,如图119-144所示。到这个文件夹里面找到xdc约束文件,打开xdc文件,发现里面定义了这句话:set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design],如图119-145所示,那就意味着FPGA VI编译生成的bit文件内部将读写位宽设置的是x4模式。也就是当FPGA上电从Flash里面可以通过SPI x4模式并行读取,提高了bit文件加载和启动速度。

        通常情况下,只要FPGA板子上的Flash芯片引脚支持x4的话,建议大家在xdc约束文件加上set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]这句话,这样后续FPGA程序加载启动速度更快,体验更好!

        3)知道了上面的信息,我们就可以在LabVIEW FPGA VI固化页面的下拉列表里面选择对应的类型即可。右击该终端下编译过的“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI名称,选择菜单里面的“Download Bit to Flash”,如图119-146所示;然后在弹出来的页面里面,Flash芯片型号选择N25Q128;容量设置为16MByte;SPI数据读写位宽选择x4模式,如图119-147所示。

图119-146:右击编译过的“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI名称选择Download固化菜单项
图119-147:根据黑金AX7103 FPGA开发板上的Flash型号和xdc约束文件选择SPI x4 mode

        4)最后,点击页面“Download”下载按钮,出现一个bit文件下载进度条,如图119-148所示;大约等待几十秒,会弹出Flash烧写成功提示框,如图119-149所示。然后将黑金FPGA开发板重新上电,就能看到先前我们编写的“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI程序成功的被加载和运行了。

图119-148:正在将“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI程序固化到Flash芯片里面
图119-149:“实验119-TCP客户端+24位动态信号采集卡(ADS127L01)-FPGA.vi”FPGA VI程序成功固化到黑金FPGA板子上的Flash芯片里


       10、总结

        本节实验内容写的非常细致,难度不大,因为涉及到很多下位机FPGA TCP Client客户端和上位机PC服务器端通信的知识点和内容,用户需要细心学习研究。在学习研究本节实验之前,有些用户是跳着看的,建议大家最好先把本章前面的TCP基础内容看一遍,否则有些概念都不清楚的话,是很难真正掌握LabVIEW FPGA下的TCP网络设备开发的。

        本节实验重点需要理解和掌握纯FPGA TCP总线通信过程、原理;学会我们封装的下位机FPGA TCP Client Socket CLIP里面的读写通道的调用及其注意事项;复习前面我们学过的24位ADC芯片ADS127L01采集线程的编写以及DAC7512E+XTR111恒流源的基本原理;掌握控制ADS127L01采样率的编程方法;学会接收并解析上位机下发的指令和参数;熟练使用FIFO四线握手制编程方式;最后就是学习和掌握LabVIEW上位机软件自带的TCP函数选板里面的所有函数(VI)的功能和注意事项,做到熟练使用。

 

实验119:下位机FPGA TCP Client客户端 +24位ADC(模拟DSA动态信号采集卡)的评论 (共 条)

分享到微博请遵守国家法律