1、实验内容
上一节实验里面介绍的FIFO通道比较适合在PS端和PL端之间传递速度要求不高的连续数据流等数据,如果要传递高吞吐率的数据就不合适了。
本节实验我们向大家讲解如何借助DMA通道在PS(ARM)端Linux RT和PL端FPGA之间快速传递连续的ADC采集点或者AWG任意波形数据。比如最常见的应用之一就是实现高速DAQ数据采集卡或者AWG任意波形发生器。
我们可以将PS端Linux RT里面的任意波形或者记事本里面的不定长数据通过PS2PL下行DMA通道快速传递给PL端FPGA,然后通过DAC生成模拟电压波形输出去。
又或者PL端FPGA将ADC采集到的连续数据流通过PL2PS上行DMA通道快速发送给PS端Linux RT做处理,因为很多算法在FPGA里面做起来很麻烦,但是在PS端直接拖拽一下LabVIEW里面现成的算法VI就搞定了,比如多项式拟合、高斯拟合、不限点数的FFT变化、互相关、波形寻峰寻谷算法等。
为了方便用户使用,我们提前将无符号32位类型的PS2PL下行和PL2PS上行DMA通道封装到ZYNQ PS端和PL端,大家只需要有一点LabVIEW基础,简单拖拽和连线就能实现ZYNQ芯片内部ARM端跟FPGA端之间的DMA交互了。
**提醒:**对于有符号整形或者FXP定点数传输也很简单,那就是先把FXP定点数先通过"数值至布尔数组"函数去除符号特性,然后再利用"布尔数组至数值"函数转换成U32或者字节数组再发送出去。
2、实验目标
本节实验需要利用LabVIEW同时开发ZYNQ PS端Linux RT程序和PL端FPGA程序。 先编写一个PL端FPGA VI,将FPGA函数选板里面所有数据类型的DMA通道VI函数拖拽到FPGA VI里面,再在前面板上创建一维输入和显示数组控件,借助LabVIEW FPGA在线前面板交互式运行功能,动态修改数组元素并观察PS端的数组元素是否一致。
然后编写一个PS端Linux RT程序,调用PS端DMA函数选板里面的读写VI,读取PL端FPGA发送过来的各种类型的数组元素并显示在前面板上,同时将Linux RT程序里面的数据实时发送给PL端FPGA VI,从而实现双向通信和交互。
最后把写好的PL端FPGA程序框图编译成bit文件,再将Linux RT程序编译部署下载到ZYNQ芯片的PS端ARM里面去运行,利用LabVIEW Linux RT动态加载前面编译好的PL端FPGA bit文件,然后接上Xilinx JTAG下载器和千兆网线或者WiFi模块,就可以同时在线观察到PL端FPGA VI前面板和Linux RT前面板上的控件运行效果了。对于初学者着重复习并熟练掌握ZYNQ芯片PS(ARM)端LabVIEW Linux RT程序开发和PL端FPGA程序开发的过程和原理。
为了方便讲解,我们设计了4个DMA通道读写交互实验程序,分别是:
- PS端Linux RT发送数据给PL端FPGA(PS2PL下行)
- PL端FPGA发送数据给PS端Linux RT(PL2PS上行)
- PS端发送数据给PL端同时读取回来(PS2PL回环)
- PS端与PL端FIFO通道吞吐率测试(PL2PS测速)
3、硬件介绍
本节实验没有用到其他外设,只需要正点原子领航者ZYNQ开发板,Xilinx JTAG下载器和一根千兆网线即可。
其中,Xilinx JTAG下载器可以用来在线观察ZYNQ芯片PL端的FPGA VI前面板实际运行效果也可以动态修改前面板上的控件数值,减少因频繁编译而浪费的时间。
网线是用来将上位机编写好的ZYNQ PS(ARM)端Linux RT程序通过网络方式部署下载到ZYNQ PS端ARM里面去运行。**提醒:**这里的Xilinx JTAG下载器不需要下载PL端FPGA bit文件,因为PS端可以动态加载编译好的FPGA bit文件,所以如果大家不准备观察FPGA VI前面板上的控件状态,实际上这个Xilinx JTAG下载器也可以不用接。
图9-1显示的是正点原子领航者ZYNQ开发板实物图。
图9-1:正点原子领航者ZYNQ开发板上实物图
4、原理图介绍
由于本节实验没有用到ZYNQ开发板上的任何外设,只需要在ZYNQ芯片内部的PS端ARM和PL端FPGA之间进行内部通信和交互,所以,理论上只要ZYNQ芯片没坏,Linux RT系统能正常启动运行就可以了,故此,本节实验不需要原理图。
5、驱动VI函数讲解
5.1:PL端FPGA FIFO通道
对于ZYNQ PL端FPGA来说,要想把不定长度的数据快速发给PS端ARM或者从PS端快速读取传递过来的连续点,那么可以借助DMA通道。为了方便客户调用DMA通道,我们将PL侧的DMA通道直接以Socket CLIP的方式封装到FPGA终端下面,如图9-2所示。按照传输方向分为mm2s和s2mm,其中,mm2s指的是PS端Linux RT通过DMA下行通道发送数据给PL端FPGA,那么FPGA VI直接读取这个通道即可,相当于下行;s2mm则是PL端FPGA将数据通过DMA上行通道发送到PS端ARM里面,相当于上行。
图9-2:ZYNQ FPGA终端下的DMA端口信号(最原始的)
上面这些DMA队列CLIP端口是最原始的,操作起来不直观,为了方便用户调用,我们将32位的DMA读写操作直接封装成VI,放在了"PL-DMA"函数选板里面了,如图9-3所示。
图9-3:ZYNQ PL端FPGA终端里面的DMA通道读写VI函数
其中,PL往PS端发送数据的DMA通道按照单次传输最大长度默认划分成了5种,分别是512、2048、4096、8192、16384,单位是U32,也就是4个字节,有点类似UDP传输的报文帧长度。以最右侧的16384这个DMA上行VI函数为例,每次传输的报文长度就是16384*4=65536个字节,极限传输速度约在74MB/s,传输速度最快。
当然了,其实这些FPGA环境下的PL2PS DMA上行子VI程序框图都能打开的,里面有一个用来控制DMA帧长度的参数,这个数值用户可以自行修改,比如某些场合希望传输500个U32,而不是512,那么可以直接在这个PL2PS DMA程序框图里面将512改成500即可。
5.2:PS(ARM)端Linux RT驱动函数选板
正式开始采用LabVIEW编写ZYNQ PS端Linux RT 访问和更新PL端FPGA里面的DMA通道数据之前,我们先来了解一下本节实验需要用到的PS端Linux RT环境下的DMA驱动VI函数功能。
为了方便用户调用,我们提前将底层负责PS端与PL端沟通的DMA通道函数封装到LabVIEW Linux RT环境下的"PowerGod-RIO-RT"选板里面,变成一个个小图标,一目了然。
要完成本节实验,我们需要用到4个函数选板,分别是"PS_Load_FPGA_bit"、"PS_Load_KO"和"PS_AXI_DMA"和"PS_Reg_Address",如图9-4所示。
图9-4:本节实验要用到的神电测控"PowerGod-RIO-RT"里面的4个函数选板
下面,我们分别介绍一下这4个选板里面的VI功能和应用场合。
1)由于本节实验展示ZYNQ PL端FPGA跟PS端相互通信,所以需要编写FPGA VI编译生成bit文件,然后由PS端Linux RT程序动态加载到ZYNQ芯片里面运行,所以Linux RT程序运行时的第一个VI就是"PS_Load_FPGA_bit.vi"这个函数。凡是需要调用ZYNQ芯片里面PL端FPGA参与的程序,都需要调用这个FPGA bit文件动态加载函数,切记!
2)为了提高ZYNQ芯片PS端的内存使用率,我们将很多外设KO驱动做成了动态加载和卸载。比如本节实验,我们需要读取PL端FPGA里面的DMA数据或者将PS端发送过来的数据写入PL端FIFO,所以在Linux RT程序初始化之前,我们需要利用下面图9-5里面的DMA动态加载"Load_DMA_KO"函数(PSLoadDMAKO(SubVI).vi)加载DMA驱动,等到Linux RT程序停止退出之前,再调用"Unload_DMA_KO"卸载函数(PSUnloadDMAKO(SubVI).vi)卸载DMA驱动以便释放DMA类占用的内存和资源。注意:实际上在后续编程的时候,DMA函数选板里面有两个VI函数的句柄来自于GPIO的,也就是下图9-5里面的"Load_FPIO_KO"和"Unload_GPIO_KO"也是需要调用的。
图9-5:DMA类外设驱动动态加载和卸载函数
3)本节实验的重点就是要学会使用PS端和PL端之间的DMA通道,因此,PS端少不了要对DMA通道初始化打开,等到Linux RT程序退出的时候,再关闭DMA通道,这两个VI函数就位于下图9-6所示的"PS2PL _DMA"函数选板里面。
图9-6:ZYNQ芯片PS端DMA通道打开和关闭函数
**注意:**只要是对PS端DMA进行操作的场合,都需要调用上面"PS_DMA"函数选板里面的第1个和第2个VI,也就是"PS_DMA_Open"和"PS_DMA_Close",相当于对DMA通道的初始化和程序退出前的DMA关闭。
4)为了让ZYNQ PS(ARM)端Linux RT能够访问和操作PL端FPGA里面的DMA通道,我们特地在PS端Linux RT下封装了4类函数,位于"PS2PL_AXI_DMA"函数选板里面,如图9-7所示。
图9-7:负责PS端与PL端二者之间通信的FIFO通道读写VI函数
这4类函数分别是:
1 第2列PL2PS上行DMA缓冲区字节长度函数: "AXI_DMA_FIFO_Bytes_Check.vi",这个VI很重要,类似大家所熟知的NI-VISA里面的"串口缓冲区Buffer字节数"这个属性。其实,不管是串口、USB总线、CAN总线、PCIe,本质上都是FIFO队列机制,因为上位机不可能实时读取下位机发送过来的数据,当上位机或者ZYNQ PS端忙于其他任务时,那么就需要一段FIFO队列缓冲区用来缓冲ZYNQ PL端FPGA发送过来的数据,当PS端需要读取DMA缓冲区里面的数据时,需要提前知道这个FIFO通道里面有多少字节数据,这样可以平衡主机端的读取速度和读取块大小,以优化ZYNQ PS端ARM处理器性能。
2第4列第1行PL2PS DMA读取函数:"AXI_DMA_Read_PL2PS.vi",PS端可以通过这个VI读取PL端FPGA通过DMA通道发送过来的数据。读取之前可以先调用上面第2列里面的Bytes_Check获取一下当前DMA接收缓冲区里面的字节数量(除以4等于U32数据个数),然后再执行读取,这样可以有效减少不必要的读取浪费。
3第4列第2行PS2PL DMA写入函数:"AXI_DMA_Send_PS2PL.vi",也就是Linux RT程序可以通过这个VI将PS端的数据通过DMA下行通道快速写入PL端FPGA的FIFO里面去;需要注意的是,这个子VI数据输入端是有符号8位字节数组,因此,对于其他类型的数据,需要提前借助强制类型转换将其转换成I8字节数组再连到这个VI上。
4第5列PL2PS DMA清除缓冲区函数:"AXI_DMA_FIFO_Clear_DLW30.vi",这个类似NI-VISA里面的清除FIFO队列缓冲区VI,当采集中断后,需要重新开始采集PL端FPGA通过DMA上行通道发送过来的数据,可以先把PS端Linux RT里面的DMA缓冲区清空一下,这样接收到的数据就是最新的,并且解析的时候不会出错。
提醒 1 **:**上面介绍的第2列(AXI_DMA_FIFO_Bytes_Check_DLW30.vi)获取DMA缓冲区字节长度和第5列(AXI_DMA_FIFO_Clear_DLW30.vi)清除DMA缓冲区数据这两个VI函数,需要的引用句柄是前面多次介绍过的"PS_Reg_Address"函数选板里面的通用型Reg寄存器函数,如图9-8(a)所示。这个在后续编程环节可以看到,而其余的DMA函数引用句柄都是AXI_DMA初始化成功后的句柄。
图9-8(a):DMA通道缓冲区字节长度与清除VI需要接到PS_Reg初始化后输出的引用
提醒 2 **:**为了更好的区分ZYNQ芯片里面PS端和PL端的VI函数,我们特地在每个子VI图标里面加入了PS或者PL字样,如图9-8(b)所示。如果这个子VI有PS字样,那么这个VI就可以被Linux RT主机端也就是PS端调用,反之如果是PL端字样,那就是被FPGA VI调用。比如,下图中上方就是PS端Linux RT程序可以调用的DMA通道函数,下方则是PL端FPGA里面可以调用的DMA操作函数。
图9-8(b):子VI图标上有PS和PL字样(用于区分该VI是运行在PS端Linux RT里面还是在PL端FPGA里面)
6、ZYNQ程序开发讲解(PL(FPGA)+PS(ARM))
6.1:ZYNQ PL端FPGA程序开发过程
6.1.1:新建或者打开已有的LabVIEW ZYNQ PL FPGA终端
1)前面第五章里面我们已经新建过了一个LabVIEW ZYNQ FPGA终端了,这里不再重复创建了,不记得的用户可以回顾一下前面第五章5.3.1节里面的相关内容。
2)打开之前新建的项目浏览器"My_FPGA_Stater_Board_ZYNQ7020_PS+PL.lvproj",如图9-9所示,可以看到该项目里面有两个终端分别是ZYNQ PL端FPGA部分和PS端Linux RT部分。
图9-9:打开前面新建好的LabVIEW项目浏览器(My_FPGA_Stater_Board_ZYNQ7020_PS+PL.lvproj)
6.1.2:LabVIEW ZYNQ PL端FPGA应用程序编写(FPGA VI)
1)右击"FPGA Target(My_FPGA, ZYNQ_XC7Z020_2CLG400_Navigator_MyRIO_V3_All)",选择"New/新建>>Virtual Folder/虚拟文件夹",创建一个虚拟文件夹,如图9-10所示;然后重命名为"实验9-PS与PL通过DMA通道交互(ZYNQ PL端)",如图9-11所示。
图9-10:右击FPGA终端新建一个虚拟文件夹
图9-11:虚拟文件夹重命名为"实验9-PS与PL通过DMA通道交互(ZYNQ PL端)"
6.1.2.1:新建FPGA FIFO
为了对FPGA终端下的不同对象进行分类管理,我们将DMA通道所需的FIFO缓冲区单独存放到1个子虚拟文件夹里面,具体步骤如下:
1)右击虚拟文件夹"实验9-PS与PL通过DMA通道交互(ZYNQ PL端)",选择"New/新建>>Virtual Folder/虚拟文件夹",如图9-12所示,重命名为"PL-DMA",如图9-13所示,PL指的就是FPGA。
图9-12:右击ZYNQ PL端FPGA新建1个子虚拟文件夹
图9-13:将子虚拟文件夹重命名为"PL-DMA"
然后,再以相同的方式创建两个虚拟文件夹分别用来管理PS2PL下行DMA FIFO和PL2PS上行DMA FIFO,如图9-14所示。
图9-14:新建两个虚拟文件夹分别用来管理上行和下行DMA FIFO通道
2)右击"PS2PL-DMA-FIFO"虚拟文件夹,选择"New/新建>>FIFO",如图9-15所示;在弹出来的FIFO属性配置页面里面将"Name/名称"改成"FIFO_DMA_U32_PS2PL";"Requested number of elements/请求元素数量"默认是10240,这里仅仅是演示功能,为了加快FPGA VI编译速度,可以将元素数量改小,具体改成多少,用户可以根据自己的实际项目或者产品需求来定;"Control Logic"选择成Slice Fabric/逻辑片架构。配置结果如图9-16所示。
图9-15:右击"PS2PL-DMA-FIFO"虚拟文件夹新建一个FIFO
图9-16:在FIFO属性配置页面里面设置名称和元素数量以及控制逻辑
3)切换到"Data Type/数据类型"页面里面,选择无符号32位也就是U32类型,如图9-17所示。创建成功后的FIFO所在的FPGA终端效果,如图9-18所示。
图9-17:将FIFO数据类型选择位无符号U32类型
图9-18:创建一个10240个元素的无符号U32类型的PS2PL DMA FIFO
4)上面创建的DMA FIFO后缀是PS2PL,顾名思义,就是PS端用来读取PL端发送过来的DMA数据,为了好区分,我们可以将上面这个FIFO直接复制一下,然后将后缀名称改成PL2PS,如图9-20,这样后续编写FPGA程序的时候,可以将PL端的ADC数据存放在这些PL2PS DMA FIFO里面,然后PS端读取即可。
图9-19:以相同的方式创建一个无符号32位类型的PL2PS上行DMA FIFO
5)后续,我们要测试PL2PS上行DMA的极限传输速度,所以这里,我们需要提前开辟一个缓冲区足够大的FIFO,才能体现出DMA的速度优势,创建方法与前面类似,只是将这个DMA FIFO深度改成最大的131077,并在名称里面加上65536以示区分,如图9-19所示。**注意:**这个65536表达的意思是后续我们借助16384那个PL2PS DMA上行函数来进行吞吐率极限传输测试。其中,16384单位是U32,相当于4个字节,也就是65536个字节。
图9-20:创建一个深度更大的PL2PS 上行DMA FIFO用于后续DMA极限速度测试
6.1.2.2:新建FPGA VI应用程序
6.1.2.2.1:创建PS2PL下行方向的DMA通道读取FPGA VI程序
1)为了方便FPGA下不同对象的管理,我们将所有FPGA主VI放在"Main"虚拟文件夹里面,如果存在子VI的话,一般会放在"SubVI"虚拟文件夹里面,如果是ngc或者edf网表的话,一般放在"NGC/EDF"网表文件夹里面。
右击虚拟文件夹"实验9-PS与PL通过DMA通道交互(ZYNQ PL端)",选择"New/新建>>Virtual Folder/虚拟文件夹",如图9-21所示,重命名为"Main",如图9-22所示。
图9-21:右击ZYNQ PL端FPGA新建1个子虚拟文件夹
图9-22:将子虚拟文件夹重命名为"Main"
2)右击子虚拟文件夹"Main",选择"New/新建>>VI",如图9-23所示;然后保存该VI,命名为"实验9.1-PL端读取PS端的DMA数据(ZYNQ PL端).vi",如图9-24所示。
图9-23:右击虚拟文件夹"Main"新建一个FPGA主VI程序
图9-24:将VI另存为"实验9.1-PL端读取PS端的DMA数据(ZYNQ PL端).vi"
3)打开上面新建的FPGA VI,切换到程序框图,然后放置一个普通循环,将while循环的停止条件设置为F,如图9-25所示,即永不停止。
图9-25:放置一个永不停歇的普通while循环
4)然后将LabVIEW FPGA环境下"PowerGod_ZYNQ_FPGA_PL"函数选板里面的"PL-DMA"选板里面的"PS2PL_DMA_32bit(SubVI).vi"拖到FPGA VI程序框图,创建一个FIFO常量,选择前面创建好的PS2PL端DMA FIFO,最后在普通while循环里面利用for循环将FPGA端DMA FIFO里面的前10个元素读出来放在前面板上进行观察,如图9-26所示。借助我们强大的LabVIEW FPGA在线前面板交互式运行功能,可以动态观察前面板上的数组显示控件里面的元素,看看是不是ZYNQ PS端Linux RT通过DMA通道发送过来的数据。同时还能观察到PL端FPGA FIFO已经接收到的U32元素数量,当点击读取按钮后,元素数量会减少10个。
图9-26:ZYNQ PL端FPGA接收PS端发送的DMA数据并以数组方式显示在前面板上
**提醒:**上面程序框图里面的DMA FIFO常量或者控件,需要配置数据类型,这样才能跟FPGA里面的子VI端口对应上,并且可以对FPGA终端下创建好的FIFO进行过滤,具体方法如下,右击FIFO常量,选择"Configure FIFO Type/配置FIFO数据类型",如图9-27所示;然后在弹出来的"FIFO数据类型"页面里面选择跟使用的PS2PL DMA子VI相同的数据类型,比如这里面的无符号32位(U32),如图9-28所示。
图9-27:右击FIFO常量或者控件,选择"Configure FIFO Type/配置FIFO类型"
图9-28:根据使用的PS2PL端DMA上行子VI函数选择对应的数据类型
6)最终,编写完成的ZYNQ PL端FPGA读取PS端Linux RT通过DMA通道发送过来的不定长数据的FPGA VI程序前面板,如图9-29所示。
图9-29:ZYNQ PL端FPGA读取PS端通过DMA通道下发数据的FPGA VI前面板
6.1.2.2.2:创建PL2PS上行方向的DMA通道发送FPGA VI程序
上面我们编写的是PS2PL下行,也就是PS端将数据通过DMA通道发给PL端FPGA,为了展示DMA通道的双向通信能力,这里,我们再编写一个PL2PS上行方向,也就是PL端FPGA将自己的FIFO数据通过DMA通道发送给PS端,具体过程与前面6.1.2.2.1节相似,唯一不同的地方就是将FPGA VI程序框图里面的 "PS2PL_DMA_32bit(SubVI).vi"子VI换成"PL2PS_DMA_32bit_512(SubVI).vi"以及DMA FIFO通道枚举控件里面的PS2PL也换成PL2PS的FIFO即可。编写过程,这里就不展示了,直接给出PL2PS DMA上行通信的数据发送FPGA框图和前面板,分别如图9-30和9-31所示。详细过程可以参考后续录制的视频教程,这里不再赘述了。
图9-30:PL2PS上行DMA数据发送给PS端的FPGA VI程序框图
图9-31:ZYNQ PL端FPGA将数据通过DMA通道发送给PS端的FPGA VI前面板
**注意:**这里我们演示的DMA发送报文帧长度是512个U32,也就是2048个字节数据,大家也可以试试其他帧长度的PL2PS DMA VI函数,或者自行在子VI内部将帧长度数值改成自己项目合适的,但是需要注意的是,后续PS端程序里面读取的时候要跟下位机PL端保持一致最佳。
6.1.2.2.3:创建PS端与PL端DMA回环通信FPGA VI程序
前面两个FPGA VI分别展示的是FPGA接收和发送DMA数据的能力,按照以往惯例,为了同时展现双向通信,我们可以将前面PS2PL和PL2PS两个程序结合起来,形成一个回环程序,那么ZYNQ PS端Linux RT可以自发自收,也就是PS端通过DMA通道发送给PL端的数据又原封不动的回来了,以此来验证一下PS端与PL端之间的DMA双向数据交互功能。
具体编写过程可以参考后续录制的视频教程,程序本身比较简单,利用四线握手方式将PS2PL下行FPGA端读到的DMA数据逐点转移到PL2PS上行FIFO里面去即可实现回环,对应的ZYNQ PL端DMA通道数据回环交互FPGA程序框图和前面板,分别如图9-32和9-33所示。
图9-32:PS端发送给ZYNQ PL端的DMA通道数据回环通信FPGA程序框图
图9-33:PS端发送给ZYNQ PL端的DMA通道数据回环通信FPGA前面板
6.1.2.2.4:创建PS端与PL端DMA吞吐率测试FPGA程序
本节实验介绍的DMA 要比前面介绍的普通FIFO传输速度快,那么具体的DMA极限吞吐率大概是多少呢?这里我们需要编写一个FPGA VI程序来验证一下DMA通道的数据传输速度。
理论上单次传输的报文数据量越大,等效的传输效率和吞吐就率越大,所以我们可以选择"PL-DMA"函数选板里面的单次可以传输16384个U32无符号数据类型的"PL2PS_DMA_32bit_16384(SubVI).vi",然后利用计数器控制进入DMA FIFO数据的速度,相当于动态调节生成DMA FIFO数据的采样率,最后再根据FIFO的"Ready for input/输入是否就绪"信号来判断当前FIFO是否产生溢出了,并对溢出点数进行统计,这样就可以直观的判断PL端FPGA在多少吞吐率下会发生溢出,据此可以得出PL端与PS端之间的DMA传输带宽。
具体ZYNQ PL端FPGA DMA测速程序框图和前面板,分别如图9-34和图9-35所示。
图9-34:模拟不同采样率的ZYNQ PL端DMA传输速度FPGA程序框图
图9-35:模拟不同采样率的ZYNQ PL端DMA传输速度FPGA前面板
最终编写完成的本节4个ZYNQ PL端DMA通道实验FPGA程序所在的ZYNQ FPGA终端,如图9-36所示。
图9-36:4个ZYNQ PL端DMA数据通信FPGA VI程序
6.1.3:LabVIEW ZYNQ PL端FPGA仿真、编译、下载、运行和调试
一般情况下,为了减少FPGA VI的编译次数和提高调试效率缩短开发周期,用户可以参考下面的5个步骤进行:仿真、编译、下载、在线前面板交互式运行和调试。
6.1.3.1:LabVIEW ZYNQ PL端FPGA VI离线仿真
1)前面我们编写好的ZYNQ PL端FPGA VI程序虽然比较简单,只有1个while循环,但是在编译下载前,我们可以借助上位机LabVIEW对其进行功能性仿真,做到心中有数。如果FPGA程序里面有复杂的算法(比如FFT)或者时序(FIFO溢出)或者第三方网表(NGC/EDF),更需要如此。如果用户对LabVIEW非常熟练精通的话,也可以跳过这个步骤,直接进入编译下载环节。
右击FPGA终端,选择"Select Execution Mode/执行VI>>Simulation(Simulated I/O)/带仿真I/O的计算机",如图9-37所示。一旦切换到这个模式,表明位于该ZYNQ FPGA终端项目下的所有VI都会在PC机上进行在线模拟运行。
图9-37:将VI执行模式切换到计算机仿真模式
2)然后打开"实验9.1-PL端读取PS端的DMA数据(ZYNQ PL端).vi",点击左上角的"运行"箭头按钮,如图9-38所示。此时发现这个VI运行起来了,可以看到前面板上的"Running_FPGA"显示控件里面的数值以非常快的速度在增加,说明FPGA VI程序框图里面的while循环开始执行了,但是运行速度达不到50MHz,这是因为上位机模拟仿真只是对整个程序框图的功能性仿真,而涉及到FPGA芯片驱动时钟的速度仿真,LabVIEW无法精确模拟时钟频率,但是不影响相对时钟之间的关系和时序结果。当然,用户还可以在程序框图里面用探针去观察每条线上的数据流变化。其他两个FPGA VI也是一样的操作。
图9-38:FPGA VI程序快速运行起来了(功能性仿真和时序仿真)
提醒 1 **:**离线仿真模式下,前面板上的数组显示控件里面的数据都是随机的,仿真出来的,并非PS端真正传递过来的,因为我们还没有将FPGA VI编译成bit文件下载到ZYNQ芯片里面运行呢!这里的仿真主要是功能性仿真。
提醒 2 **:**如果用LabVIEW FPGA环境下的IP Block节点调用ngc或者edf网表的话,这里的离线仿真模式也是支持的,也能完全仿真出来网表里面的行为特性。
6.1.3.2:LabVIEW ZYNQ PL端FPGA VI程序编译
1)在计算机仿真模式下,用户无法仿真FPGA真实的I/O电平,因为仿真计算机上没有对应的物理I/O引脚。所以,我们需要将VI执行模式切换回FPGA终端运行模式。右击FPGA终端,选择"Select Execution Mode/执行VI>>FPGA Target/FPGA终端",如图9-39所示。
图9-39:将FPGA VI执行模式切换回FPGA终端模式
用过NI LabVIEW FPGA的用户知道,LabVIEW FPGA默认编译出来的是NI加密过的lvbitx文件,而不是原始的FPGA bit位文件,因此,我们需要想办法将FPGA编译完成后最原始的bit文件弄出来,为此,我们专门给大家提供了一个名为"License-ID-Bitfile-ZYNQ.vi"程序,只要在FPGA VI编译过程中一直打开运行这个VI就可以得到最原始的FPGA bit位文件了。为了防止用户忘记打开运行这个VI,我们可以将这个VI提前添加到LabVIEW项目下的"我的电脑"下面,然后打开点击运行箭头即可,直如图9-40所示。
图9-40:将获取原始ZYNQ FPGA bit文件的VI(License-ID-Bitfile-ZYNQ.vi)拖拽到项目里面的"我的电脑"下面,而不是拖到FPGA终端(切记)
然后,在LabVIEW FPGA Bit文件导出路径里面选择开发电脑存在的路径,至于导出来的FPGA bit文件名称,可以自己随意取,比如,我们将实验9编译出来的ZYNQ FPGA bit文件存放到这个目录下(E:\ZYNQ FPGA Bit Files),分别取名为"9.1-PS2PL-DMA.bit"、"9.2-PL2PS-DMA.bit"、"9.3-Loopback-DMA.bit"和"9.4-Speed-DMA.bit",如图9-41所示。**唯一需要注意的是:**导出来的FPGA bit文件存放路径最好不放在C盘根目录下,因为很多系统的C盘根目录没有复制权限会导致保存失败,选择其他的盘符更保险。
图9-41(a):选择合适的路径将实验9.1编译成功后的原始的ZYNQ FPGA bit文件保存下来
(这个VI一直开着运行即可)
图9-41(b):选择合适的路径将实验9.2编译成功的原始的ZYNQ FPGA bit文件保存下来
(这个VI一直开着运行即可)
图9-41(c):选择合适的路径将实验9.3编译成功的原始的ZYNQ FPGA bit文件保存下来
(这个VI一直开着运行即可)
图9-41(d):选择合适的路径将实验9.4编译成功的原始的ZYNQ FPGA bit文件保存下来
(这个VI一直开着运行即可)
**需要注意的是:**设置的FPGA bit文件路径不能太深,而且bit文件名称里面不能有中文字符,切记,否则后续下载会失败!
3)然后点击FPGA VI前面板上的"运行"箭头按钮,LabVIEW会启动编译服务器提示对话框,如图9-42所示。里面有3行,分别是:
- 本地编译服务器:顾名思义,就是调用安装在本地计算机上的Xilinx ISE或者Vivado编译器来编译这个VI。这个最为常用。
- 连接至网络编译服务器:这个相当于将这个VI生成的VHDL代码传送给远程服务器上的ISE或者Vivado编译器进行编译,需要用户提前配置好一台安装有Xilinx编译环境的服务器。目的是可以借助服务器强大的性能来加速编译过程,缩短编译时间。需要联网,因此,这个用的很少。
- 连接至LabVIEW FPGA编译云服务:这个是NI官方提供的远程服务器,需要付费才能使用,而且编译速度也没有想象中快多少,所以这个功能基本上也就是NI内部使用的多。如果用户报名参考NI FPGA认证考试或者提供购买过NI硬件产品序列号的话,NI会提供一个试用期为30天的LabVIEW FPGA编译云服务,编译速度跟本地基本一样,没有多大优势。因此,用的也很少。
图9-42:FPGA编译服务器选择提示框
此时,先不着急点击上图里面的"OK/确定"按钮,让我看看自动产生的FPGA程序生成规范里面是不是还有什么特殊的地方需要设置。因此,这里,我们选择"Cancel/取消"按钮,如图9-43所示。
图9-43:先取消编译(因为我们要检查一下FPGA程序生成规范)
4)展开FPGA终端里面的"Build Specifications/程序生成规范",如图9-44所示;然后双击打开这个程序生成规范(实验9.1-PL端读取PS端的DMA数据(ZYNQ PL端)),将里面的一个重要选项"Run when loaded to FPGA/加载至FPGA时运行"勾选上,如图9-45,否则后续编译出来的ZYNQ FPGA bit文件下载到FPGA芯片里面是运行不了的,所以这里一定要检查一下是否打勾了。最后点击"OK/确定"关闭程序生成规范对话框。
图9-44:展开FPGA终端里面的程序生成规范,然后直接双击打开即可
图9-45:将"加载至FPGA时运行"勾选上(一定要勾上,切记!!!)
5)接下来,再次点击FPGA VI左上角的运行箭头,触发重新编译对话框,这次就可以放心点击里面的"OK/确定"按钮了,如图9-46所示;然后就会自动进入"正在生成中间文件"对话框,如图9-47和9-48所示。里面一共有5个阶段,主要就是将LabVIEW编写的FPGA VI程序框图转换为VHDL代码,然后进行压缩传递给Xilinx编译器进行编译。
图9-46:再次点击FPGA VI左上角运行箭头触发重新编译对话框(这次点击OK)
图9-47:LabVIEW FPGA VI程序框图正在生成中间VHDL文件
图9-48:正在压缩打包生成好的中间VHDL文件
6)等待中间文件生成完毕后,LabVIEW会启动"Compilation Status/编译状态"窗口,如图9-49所示。里面一共经历5个步骤:配置、综合、布局、时钟约束、时钟布线。如果是6代FPGA,例如,Spartan6,需要经过每一步的编译,每个步骤都不能报错,否则会无法生成bit文件。但是对于7系列FPGA来说,例如ZYNQ、A7、K7、V7,如果FPGA VI里面用的是普通while循环,或者用的定时循环时钟源是默认的,那么后面两项"估计定时"和"最终定时"是不起作用的,LabVIEW会跳过检查,直接生成可以运行的原始FPGA bit文件;如果定时循环用到了创建的衍生时钟,那么最后两项定时约束还是会进行的。
图9-49:Xilinx编译器正在执行综合
7)在"Reports/报表"的下拉列表里面选择"Configuration/配置",可以看到配置页面里面的信息汇总,如图9-50所示。可以发现LabVIEW FPGA调用的是64位的Xilinx Vivado 2019.1这个版本的编译器,7系列FPGA只支持Vivado编译器。
图9-50:Xilinx编译器"配置"页面里面的信息汇总
8)等待综合完成后,切换到"Estimated device utilization(synthesis)/估计设备使用(综合)",如图9-51所示。可以看到这个VI编译后的资源预估计占用情况。
图9-51:Xilinx编译器"Synthesis/综合"页面里面的资源预估计
9)等待转换和映射完成之后,就能在"Final device utilization(placement)/最终设备使用(布局)"页面里面,看到Xilinx编译器反馈的FPGA芯片实际资源使用情况,如图9-52所示。可以看出实际编译的结果与前面的资源预估计相差无几,这样,用户可以根据在资源预估计阶段里面的资源占用情况,来判断是否直接结束编译过程,避免浪费不必要的编译时间。例如,如果预估计的资源使用率严重超过100%的话,那么建议用户直接终止编译,返回去优化程序后再编译。
图9-52:Xilinx编译器"placement/映射"页面里面的最终资源占用结果
10)当用户在"Status/状态"提示框里面看到"Generating programming file/正在生成编程文件",说明LabVIEW FPGA正在生成可执行bit文件,如图9-53所示。相同的代码要比之前Spartan6里面的ISE编译器快了一倍多。这也是Vivado编译器改变编译策略后的一大优势。
图9-53:Xilinx Vivado编译器正在生成可编程bit文件
11)编译完成,会自动启动弹出"Preparing for interactive execution/准备交互式运行"提示框,但是不会像第五章那样弹出一个路径选择对话框,这是因为,前面我们将配置Xilinx JTAG下载器下载还是仿真的ini.txt文件里面的1改成0了,所以就LabVIEW就会跳过选择FPGA bit文件和下载这个过程了。接着我们到这个"License-ID-Bitfile-ZYNQ.vi"里面指定的路径下,发现了刚刚编译出来的FPGA bit文件,如图9-54所示。再以同样的方式将实验9.2、9.3和9.4的FPGA VI编译一下。
图9-54:到先前设置的路径里面找到刚刚编译出来的ZYNQ FPGA bit文件
12)如果用户的Xilinx JTAG下载器驱动没有提前安装好,或者没有接入实际的下载器跟ZYNQ开发板的话,那么过一会会弹出一个错误代码位-310601的错误提示框,如图9-55所示。错误代码的意思就是LabVIEW无法识别到Xilinx JTAG下载器通信线缆,如果大家接了Xilinx下载器和板子上电之后还出现这种错误提示,可以参考前面第三章里面的Xilinx下载器驱动安装方法,重新安装一遍驱动即可。我们这里报错是因为我们还没有将Xilinx JTAG下载器跟板子接到电脑上,故意触发这个错误提醒用户的。另外,前面我们将ini.txt里面的1改成0,所以在PS端没有动态加载这里的FPGA bit之前,在线前面板也是无法运行的,切记!!!
图9-55:弹出-310601错误(提示LabVIEW没有识别到Xilinx JTAG下载器通信线缆)
至此,关于LabVIEW ZYNQ FPGA VI程序的编译过程就结束了,并且我们成功得到了原始的ZYNQ FPGA bit文件,这为用户产品的批量部署奠定了基础。
6.1.3.3:将Xilinx下载器跟ZYNQ开发板连到电脑上
为了验证一下上面编译出来的ZYNQ PL端FPGA bit文件功能是否正常,我们可以将其下载到真实的ZYNQ芯片里面跑一下看看实验现象,比如本书配套的是正点原子的领航者ZYNQ开发板。由于现在验证的是PL端FPGA VI程序,所以只需要JTAG下载器跟ZYNQ板子就可以了,至于千兆网线现在接不接都行,网线在后续的PS(ARM)端Linux RT实验里面才会用到,这里暂时不需要,而且学会后续PS端Linux RT程序开发和部署之后,其实连Xilinx JTAG下载器不接都行,因为PS端可以动态加载FPGA bit文件。
下面将Xilinx JTAG下载器跟原子领航者ZYNQ开发板连接之后接到电脑上,实物接线如图9-56所示。
图9-56:将Xilinx下载器接到ZYNQ开发板上(板子未上电)
此时,设备管理器会自动识别加载Xilinx USB Cable驱动,如图9-57所示,如果电脑上没有出现这个设备名称,那么应该前面第三章里面的下载器驱动安装一节看漏了,回过去重新参考里面的驱动安装方法安装一遍Xilinx JTAG下载器驱动就可以了。
图9-57:设备管理器里面识别出来的Xilinx JTAG下载器名称
然后给ZYNQ开发板上电,此时Xilinx JTAG下载器上的指示灯由黄色变成了绿色,说明我们的硬件接线和驱动基本正常了,如图9-58所示。
图9-58:FPGA板子上电之后,Xilinx JTAG下载器指示灯变成绿色才是正常的
6.1.3.5:LabVIEW自动下载ZYNQ PL端FPGA VI程序(强烈推荐)
可以看出,上面传统的手动Vivado下载FPGA bit文件非常的不智能,每一步都需要自己手动去操作Vivado实现,对于很多不熟悉Vivado工具的用户来说,还要花时间摸索一下,那么有没有一种简便的方式来完成下载和运行调试呢?答案是肯定的!
为了让用户能够享受到跟使用NI FPGA板卡一样的自动下载和交互式运行效果。我们将底层FPGA bit文件的自动下载和交互式运行全部集成到LabVIEW里面了。用户只需要点击编译好的FPGA VI左上角的运行箭头即可自动弹出选择FPGA bit文件对话框,如图9-74所示,然后在对话框里面找到这个FPGA VI对应编译出来的bit文件,然后点击"OK/确定"按钮即可进入自动下载页面,等待一会就可以看到ZYNQ PL端FPGA VI前面板活了。说明我们的自动下载和自动运行完全OK,爽!
图9-74:运行FPGA VI会弹出FPGA bit文件选择对话框
**提醒:**要想让上位机LabVIEW FPGA VI通过Xilinx JTAG下载器自动下载bit文件,需要将ini.txt配置文件里面0改成1,如图9-75所示;如果想通过后续的PS端Linux RT系统动态加载FPGA bit文件的话,这里的下载步骤可以忽略,同时ini.txt文件里面的1要改成0
图9-75:要想通过Xilinx JTAG下载器自动下载FPGA bit文件,ini文件改成1
6.1.3.6:LabVIEW ZYNQ PL端FPGA程序运行与在线调试(在线前面板交互式运行,直观方便)
1)当FPGA VI编译出来的FPGA bit文件自动下载到ZYNQ芯片里面运行之后,此时,可以看到位于开发电脑上的这个ZYNQ PL端FPGA VI(实验9.1-PL端读取PS端的DMA数据(ZYNQ PL端).vi)前面板自动活了,也就是自动进入在线前面板交互式运行模式了,可以观察到FPGA VI前面板上的定时循环的迭代值"Running_FPGA"显示控件里面的数值则是按照50MHz的速度递增,所以一瞬间就到了最大值,如图9-76所示。前面板上的数组显示控件都是0,这是因为我们的PS端Linux RT程序还没写呢,并没有通过DMA通道给PL端的FIFO发送数据呢,因此,默认值都是0。
图9-76(a):实验9.1对应的PS2PL DMA读取FPGA VI程序通过JTAG下载器单独下载到ZYNQ PL里面运行
图9-76(b):实验9.2对应的PL2PS DMA发送FPGA VI程序通过JTAG下载器单独下载到ZYNQ PL里面运行
图9-76(c):实验9.3对应的Loopback DMA回环通信FPGA VI程序通过JTAG下载器单独下载到ZYNQ PL里面运行
图9-76(d):实验9.4对应的DMA测速FPGA VI程序通过JTAG下载器单独下载到ZYNQ PL里面运行
**结论:**说明我们设计的FPGA VI功能没有问题,同时也能看出,在不需要编写LabVIEW上位机的情况下,我们就能借助FPGA VI的在线前面板交互式运行方式快速的观察和控制我们的FPGA VI程序,不需要反复去编译这个FPGA VI,从而可以大幅减少FPGA程序开发调试的时间,降低开发调试成本,提高了调试效率,真正做到了降本增效。
**提醒:**接下来我们会在PS(ARM)端Linux RT里面编写4个LabVIEW程序来跟PL端FPGA的DMA通道进行数据写入与更新操作。
6.2:ZYNQ PS(ARM)端Linux RT程序开发过程
6.2.0:编程思路(PS端Linux RT)
要想ZYNQ芯片PS端Linux RT跟PL端FPGA通过DMA通道进行通信和交互,必须按照下面的流程至少调用11个VI函数,其中,最常用的9个VI函数调用次序如下,后面Linux RT程序编写就是参考这个流程来的:PS_Load_FPGA_bitàLoad_DMA_KOàPS_DMA_OpenàPS2PL_DMA_Write/ PS2PL_DMA_Read/DMA_Length_Check/DMA_ClearàPS_DMA_CloseàUnload_DMA_KO
里面的PS端DMA缓冲区长度查询"DMA_Length_Check"函数和DMA缓冲区清空"DMA_Clear"函数则需要连接通用寄存器打开后的句柄(PS_Reg_Open),程序退出之前再把通用GPIO句柄关闭释放掉(PS_Reg_Close),因此,一共就有11个VI函数参与本次实验。
了解完ZYNQ芯片PS端GPIO通用寄存器类和DMA类的驱动VI和操作流程后,接下来,我们就可以利用LabVIEW编写4个Linux RT程序访问和刷新PL端FPGA的DMA数据了,然后下载到ZYNQ PS端ARM里面去运行。
6.2.1:新建或者打开已有的LabVIEW ZYNQ Linux RT项目
打开前面第五章我们新建好的LabVIEW ZYNQ项目(My_FPGA_Stater_Board_ZYNQ7020_PS+PL.lvproj),这个项目前面我们在编写ZYNQ PL端FPGA程序时已经打开过了,如图9-77所示。
图9-77:打开前面我们创建好的同时包含ZYNQ PS(ARM)端和PL(FPGA)端的LabVIEW ZYNQ项目
由于前面FPGA VI已经编写完成了,并且生成了可用的FPGA bit文件,这里为了截图不至于过大,我们暂且先将FPGA Target终端收起来,如图9-78所示。
图9-78:将My FPGA终端暂时收起来(因为前面FPGA VI已经编写好了)
6.2.2:编写LabVIEW Linux RT应用程序(访问和刷新PL端FPGA DMA通道)
6.2.2.1:编写PS2PL DMA下行方向的PS端Linux RT应用程序(PS通过DMA通道发送数据给PL)
1)右击Linux RT终端(ZYNQ7020_PS_Linux_RT)选择"New/新建"一个"Virtual Folder/虚拟文件夹",如图9-79所示。将其重命名为"实验9-PS与PL通过DMA通道交互(ZYNQ PS端)",如图9-80所示;再右击刚刚创建的虚拟文件夹,新建1个子虚拟文件夹,命名为"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端)",如图9-81所示,以示分类管理好区分。
图9-79:右击Linux RT终端选择新建一个虚拟文件夹
图9-80:将刚刚新建出来的虚拟文件夹重命名为"实验9-PS与PL通过DMA通道交互(ZYNQ PS端)"
图9-81:将子虚拟文件夹重命名为"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端)"
2)接着,右击刚刚创建的虚拟文件夹"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端)"选择"New/新建"一个VI程序,如图9-82所示,然后将这个VI另存为"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端).vi",如图9-83所示。
图9-82:右击虚拟文件夹新建一个VI
图9-83:将新建出来的VI保存并重命名为"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端).vi"
3)打开这个新建的VI,将前面第5.2节"PowerGod-RIO-RT"函数选板里面的11个子VI函数拖拽到程序框图里面,然后按照6.2.0节里面的步骤进行排序串联,最后在前面板上创建相应的控件,即可完成PS端通过DMA通道发送数据给PL端FPGA,最终形成完整的Linux RT程序框图,如图9-84所示。提醒:看不清的用户可以缩放一下pdf,因为这里贴的程序框图是直接复制的LabVIEW原始矢量图,不是截图。
图9-84:完整的ZYNQ PS(ARM)端通过DMA通道发送数据给PL端FPGA的
Linux RT程序框图
4)ZYNQ PS端通过DMA通道发送数据给PL端的Linux RT应用程序前面板,如图9-85所示。
图9-85:ZYNQ PS端通过DMA通道发送数据给PL端的Linux RT程序前面板
**提醒:**ZYNQ PS端Linux RT程序前面板上有一个FPGA bit文件加载路径,这个路径"/home/lvuser/natinst/bin/data/"是LabVIEW在Linux RT系统下的默认路径,如果用户自己编译出来的FPGA bit文件名称跟我们的不一样,只需要将路径里面最后的bit文件名称替换一下即可,前面的默认路径最好不要动。
6.2.2.2:编写PL2PS DMA上行方向的PS端Linux RT应用程序(PS端读取PL端DMA通道数据)
接下来,我们还需要针对前面PL端实验9.2上行的FPGA VI编写一个对应的PS端读取DMA通道数据的Linux RT应用程序。过程与上面的6.2.2.1类似,用户可以直接复制上面的FPGA VI框图,然后将前面板上的动态加载的FPGA bit文件换成实验9.2编译出来的bit文件,然后将框图里面的"AXI_DMA_Write.vi"全部换成"AXI_DMA_Read.vi",然后加上获取DMA缓冲区里面已有的数据量函数,最后加上一个手动清除DMA缓冲区按钮和case条件结构,如图9-86所示,这样可以全方面的展示PS端DMA操作过程;与之相应的Linux RT程序前面板如图9-87所示。
图9-86:完整的ZYNQ PS(ARM)端读取PL端FPGA里面DMA通道数据的Linux RT程序框图(矢量图)
图9-87:ZYNQ PS端Linux RT读取PL端FPGA里面DMA通道数据的前面板
6.2.2.3:编写Loopback DMA回环的PS端Linux RT应用程序(PS端通过DMA通道先发送给PL端再回读回来)
为了展示PS端与PL端之间的DMA通道双向通信,我们可以将前两个Linux RT程序里面的FIFO读写合在一起,然后与实验9.3里面的FPGA VI对应起来,就能实现一个DMA数据发送和回读的回环程序,具体编写过程可以参考后续录制的视频教程,这里直接给出PS端DMA回环实验Linux RT程序框图和前面板,如图9-88和9-89所示。
图9-88:ZYNQ PS端通过DMA通道发送数据给PL端FPGA再回读回来的Linux RT程序框图(矢量图)
图9-89:ZYNQ PS端通过DMA通道发送数据给PL端FPGA再回读回来的Linux RT前面板
6.2.2.4:编写PS端DMA通道吞吐率极限传输测试Linux RT程序
为了测试一下PS端DMA通道的吞吐率,我们需要编写一个可以用来测试DMA平均读取速度的Linux RT程序。具体原理就是Linux RT程序以最快的速度循环读取PL端DMA发送过来的数据,然后计算每次读取耗费的时间,相除就能得到瞬时读取速度,为了观察读取块大小跟读取速度之间的关系以便找出最优关系,我们在Linux RT前面板上放置了几个输入控件,以便动态调节观察。这里直接给出PS端DMA测速的Linux RT程序框图和前面板,分别如图9-90和9-91所示。注意:每次读取的快越大,等效的吞吐率越高,因此,在前面PL端实验9.4里面我们选择的是16384个U32的DMA发送VI函数,因此,本节PS端读取的字节数量就是16384*4=65536个字节。
图9-90:ZYNQ PS端DMA读取吞吐率带宽测速的Linux RT程序框图
图9-91:ZYNQ PS端DMA读取吞吐率带宽测速的Linux RT前面板
最终完成的4个PS端DMA通道访问和操作的Linux RT程序,分别位于ZYNQ PS终端下的效果,如图9-92所示。
图9-92:与前面PL端FPGA里面相对应的4个PS端DMA交互Linux RT程序
7、硬件接线实物图
**提醒:**由于本节实验用到了ZYNQ PL端FPGA部分,前面也编写好了FPGA VI程序,如果用户想在线观察ZYNQ PL端FPGA VI前面板实际运行情况,可以将Xilinx JTAG下载器接到ZYNQ开发板上;反之,如果不想观察FPGA VI的在线前面板交互式运行,这里也可以不用接下载器,因为PL端的FPGA bit文件可以通过PS端来动态加载,不需要通过下载器下载都行。
对于ZYNQ PS端Linux RT程序的部署和下载,则需要一根CAT5+或者CAT6类千兆网线或者通过WiFi无线部署(参考第6章实验2),然后将ZYNQ开发板跟上位机开发电脑互联起来即可,上位机开发电脑通过网线和Xilinx JTAG下载器与正点原子ZYNQ开发板之间的硬件接线实物图,如图9-93所示。
图9-93:完整的硬件接线实物图(千兆网线接到PS端网口里面)
8、程序编译下载
8.1:准备工作(将前面编译好的PL端FPGA bit文件添加到PS端)
由于本节实验用到了ZYNQ芯片PL端FPGA部分,为了让PS端Linux RT程序可以动态加载PL端的FPGA bit文件,我们需要将前面编译好的FPGA bit文件添加到ZYNQ PS端Linux RT终端里面来,步骤如下。
右击ZYNQ PS端Linux RT终端下的"ZYNQ PL FPGA bit files",选择"Add/添加>>File/文件",如图9-94所示;然后在弹出来的文件选择对话框里面找到前面编译出来的PL端FPGA bit文件,如图9-95所示;添加成功后的效果如图9-96所示。
图9-94:右击Linux RT终端选择添加FPGA bit文件
图9-95:选择前面编译出来的4个PL端FPGA bit文件
图9-96:FPGA bit文件添加成功后的效果
8.2:ZYNQ PS端Linux RT应用程序编译、部署、下载
1)由于ZYNQ开发板与上位机电脑之间是通过网线直连的,中间没有经过路由器,所以,上位机要利用ZYNQ PS端Linux RT默认的静态IP地址:192.168.2.99来部署下载上位机写好的Linux RT程序,因此,上位机网卡IP地址也要设置成同一个网段,比如192.168.2.10,如图9-97所示。
图9-97:将上位机开发电脑网卡IP地址设置成跟下位机ZYNQ里面的eth0:1虚拟网卡静态IP地址在同一个网段内
2)然后检查一下LabVIEW ZYNQ PS端Linux RT终端里面的IP地址是否为下位机ZYNQ里面的固定IP地址(192.168.2.99),如果不是,则右击终端选择"Properties/属性",如图9-98所示;再在属性设置页面里面修改一下即可,如图9-99所示。
图9-98:如果IP地址不一样的话,可以右击LabVIEW Linux RT终端选择属性
图9-99:在Linux RT属性配置里面将IP地址改成ZYNQ直连方式下的固定静态IP地址
3)右击ZYNQ PS端Linux RT终端(ZYNQ7020_PS_Linux_RT)选择"Connect/连接",如图9-100所示;不出意外的话,会弹出来一个"Deployment Progress"部署成功的提示框,如图9-101所示;最后点击一下"Close/关闭"该对话框即可,此时,可以看到LabVIEW Linux RT终端左下角的指示灯点亮了,如图9-102所示,表明上位机Linux RT终端与下位机ZYNQ板子通过网线建立起了连接。
图9-100:右击LabVIEW Linux RT终端(ZYNQ7020_PS_Linux_RT)选择"Connect/连接"
图9-101:弹出一个部署进度与部署成功的提示框(Close即可)
图9-102:连接成功后Linux RT终端logo图标指示灯会点亮
4)右击Linux RT终端(ZYNQ7020_PS_Linux_RT)里面的程序生成规范,选择"New/新建"一个"Real-Time Application/实时应用程序",如图9-103所示;然后在弹出来的RT应用程序属性配置页面里面,将程序生成规范重命名为"实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端)",如图9-104所示;再选择左侧目录里面的"Source Files/源文件"里面的本节实验9编写的VI程序(实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端).vi)添加到右侧的"Startup Vis/启动VIs"列表里面,如图9-105所示;最后将中间文件夹"ZYNQ PL FPGA bit files"里面的FPGA bit文件(9.1-PS2PL-DMA.bit)作为附件添加到右下方的"Always Included/总是包含"里面,如图9-106所示。
图9-103:右击Linux RT终端下的程序生成规范新建一个RT应用程序规范
图9-104:将新建出来的Linux RT应用程序生成规范重命名以示区分
图9-105:将源文件里面本节实验9编写的Linux RT VI添加到右侧启动VIs列表里面
图9-106:将前面编译好的PL端FPGA bit文件添加到右侧"Always Included/总是包含"
**提醒:**所有非LabVIEW静态调用的文件都可以放到这个"Always Included/总是包含"里面,这样后续部署下载的时候,上位机LabVIEW会把这些文件自动通过网络下载到下位机ZYNQ Linux RT系统里面去,免去了手动拷贝,简单实用可靠。
5)接下来,右击刚刚创建的实验9对应的RT应用程序生成规范,选择"Build/编译",如图9-107所示;大概几秒钟就能编译完成,并且会有一个编译成功的提示框,如图9-108所示;点击"Done/完成"按钮退出这个提示框,再右击实验9程序生成规范,选择"Deploy/部署"将刚刚编译出来的Startup.rtexe以及FPGA bit文件全部部署下载到ZYNQ板子里面去,如图9-109所示;一切顺利的话,会有一个部署进度条和部署成功的提示框出现,如图9-110所示。
图9-107:右击实验8 Linux RT应用程序生成规范进行"Build/编译"
图9-108:编译完成后会有一个编译进度条和编译成功提示框
图9-109:右击Linux RT实验9程序生成规范选择"Deploy/部署"下载
图9-110:ZYNQ PS端Linux RT程序及其组件附件会一起部署下发到ZYNQ里面去
9、实验现象
1)直接点击本节实验9.1对应的Linux RT程序(实验9.1-PS端通过DMA通道发送数据给PL端(ZYNQ PS端).vi)左上角的运行箭头,可以看到上位机LabVIEW会把这个VI程序及其组件、驱动和FPGA bit文件一起部署下载到ZYNQ芯片里面运行,如图9-111所示;同时PS端里面的Linux RT应用前面板活了,自动进入在线前面板交互式运行模式,此时,前面板上的"Running_PS"显示控件里面的数值开始递增,说明PS端的Linux RT程序里面的while循环开始运行起来了,如图9-112所示。
图9-111:上位机实验9.1对应的Linux RT程序和FPGA bit文件成功部署到了下位机ZYNQ芯片里面运行
图9-112:Running_PS显示控件数值递增,表明Linux RT程序里的while循环开始运行了
2)为了同步观察ZYNQ PL端FPGA VI程序运行情况,我们可以借助Xilinx JTAG下载器和LabVIEW FPGA在线前面板交互式运行功能,由于PS端已经将PL端的FPGA bit加载到ZYNQ芯片里面运行了,所以这里不需要Xilinx下载器去下载FPGA bit文件了,因此,我们需要先将ini.txt文件里面的1改成0,如图9-113所示,让PL端FPGA VI直接进入在线前面板交互式运行,直接运行项目下的ZYNQ PL端My FPGA终端下的实验9.1这个FPGA VI,等待几秒可以看到,FPGA VI前面板活了,同时前面板上的"Running_FPGA"显示控件里面的数值变成了最大值,如图9-114,这是因为这个while 循环迭代值运行速度是50MHz,非常快。
图9-113:将Xilinx JTAG下载器配置文件ini改成0(跳过下载直接进入在线前面板)
图9-114:直接运行ZYNQ PL端My FPGA终端里面的FPGA VI(前面板活了)
3)接下来,测试一下PS端通过DMA通道发送数据给PL端,看看PL端FPGA能不能收到。用户可以点击PS端Linux VI前面板上"Write"按钮,如图9-115所示;此时可以看到PL端FPGA VI前面板上的"待读取元素数量"显示控件里面的数值由0变成了512,如图9-116所示,说明PL端收到了PS端发送的512个32位数据;然后点击一下PL端FPGA VI前面板上的"读取"按钮,此时,"待读取元素数量"清空变成了502,这是因此每点击一次"读取"都会从FIFO里面读走10个元素,并且"数组"显示控件里面出现了PS端下发的斜坡递增数据,如图9-117所示。
图9-115:点击PS端Linux RT程序前面板上的"Write"按钮,发送DMA数据
图9-116:ZYNQ PL端FPGA VI前面板上的"待读取元素数量"立刻更新变成了512
图9-117:每点击一次"读取"按钮,即可从DMA FIFO缓冲区里面取走10个元素
4)下面,测试一下PL端是否能够通过DMA通道将FPGA前面板上的数据发送给PS端。实验9.2对应的Linux RT编译和部署方法,跟前面类似,这里不再演示了,直接创建一个Linux RT应用程序生成规范,然后添加实验9.2 Linux RT程序(实验9.2-PS端读取PL端的DMA通道数据(ZYNQ PS端).vi)和对应的FPGA bit文件(9.2-PL2PS-DMA.bit),然后编译和部署,最后直接点击实验9.2 Linux RT程序左上角的运行箭头开始运行。可以看到前面板上的"Running_PS"显示控件里面的数值开始递增了,如图9-118所示,说明Linux RT程序里面的while循环运行起来了。
图9-118:ZYNQ PS端实验9.2对应的Linux RT程序运行起来了
接下来,运行一下PL端实验9.2 FPGA VI程序,修改一下FPGA VI前面板上的"元素"输入控件里面的数值,比如,这里输入十进制"12345678",接着点击一下前面板上的"发送"按钮,即可将PL端的FPGA数据通过DMA通道发给PS端,如图9-119所示;此时,PS端实验9.2 Linux RT前面板上的"FIFO_Valid_Length[Bytes]"显示控件由0变成了2048,说明PS端DMA缓冲区里面已经接收到了512个点的U32数据(2048/4=512),如图9-120所示;然后点击一下"Read"按钮即可读取DMA缓冲区里面的数据,并且"FIFO_Valid_Length[Bytes]"重新清空恢复成0了,可以看出PS端Linux RT接收到的"read_data"数据与PL端FPGA通过DMA通道发送过来的数据完全一致。如果用户想舍弃这些数据,还可以点击PS端Linux RT前面板上的"Clear"清空按钮。
图9-119:修改PL端实验9.2 FPGA VI前面板上的元素再点击"发送"按钮
图9-120:ZYNQ PS端实验9.2 Linux RT程序接收到的数组元素跟PL端发送的完全一致
5)下面,我们测试一下PS端与PL端之间的FIFO数据能否正常回环。同样需要先创建一个Linux RT应用程序生成规范,将PS端实验9.3 Linux RT程序(实验9.3-PS端发送数据给PL端再回读回来-DMA-Loopback(ZYNQ PS端).vi)和对应的FPGA bit文件(9.3-Loopback-DMA.bit)添加进去,然后编译部署一下,再运行Linux RT程序,可以看到Linux RT程序前面板上的"Running_PS"显示控件里面的数值递增了,说明程序框图里面的while循环开始运行了,如图9-121所示。
图9-121:ZYNQ PS端实验9.3 Linux RT程序开始运行了
我们可以在实验9.3 Linux RT程序前面板"Amplitude"输入控件里面输入1000,然后依次点击一下"Write"按钮和"Read"按钮,观察一下右侧从PL端FPGA返回来的波形图与左侧生成的波形是否完全一样,如图9-122所示。可以发现,左侧Sine信号幅度发生变化的时候,右侧返回的波形幅度也会跟着实时变化,说明我们的PL端FPGA DMA回环程序起作用了,动态变化过程可以参考后续录制的视频教程。
图9-122:ZYNQ PS端实验9.3 Linux RT程序前面板发送的波形与PL端返回的波形一致
6)最后,我们来测试一下PS端Linux RT程序读取DMA通道的速度能到多快。先按照前面的步骤新建Linux RT程序生成规范进行编译和部署下载,再运行实验9.4对应的Linux RT程序,等到前面板上的"Running_PS"显示控件里面的数值递增之后,再运行前面PL端FPGA里面的实验9.4程序。等到PL端FPGA VI运行之后,将FPGA VI前面板上的"分频系数"设置成10,再按下"PL发送"按钮,如图9-123所示。并且FPGA VI前面板上的"溢出点数"始终为0,说明在50M/10*4Byte/s=20MB/s传输速度下,PS端完全能够快速取走DMA里面的数据,没有发生溢出。
图9-123:运行PL端实验9.4对应的FPGA VI程序(分频系数设置为10)
此时,可以看到PS端实验9.4前面板上的仪表盘指针开始变化了,并且旁边的波形图表里面也出现了波动的曲线,前面板上的"批量读取点数"设置为65536,单位是U8字节,当前PS端实际读取速度在22MB/s左右,如图9-124所示,实验结果符合预期。
图9-124:ZYNQ PS端Linux RT DMA读取速度(22MB/s左右)
7如果将PL端FPGA VI前面板上的"分频系数"改成5的话,等效的FPGA FIFO数据发送速度就是50M/5*4Byte/s=40MB/s,如图9-125所示。此时,前面板上的"溢出点数"还是0,说明当前这个速度下,PS端还是能够胜任的。
图9-125:将PL端实验9.4对应的FPGA VI前面板上的"分频系数"设置为5
PL端FPGA VI分频系数改小之后,PS端Linux RT前面板上的仪表盘速度增大了,显示在44MB/s,如图9-126所示。说明只要PS端DMA读取速度足够快,FPGA端就不会发生溢出丢点。
图9-126:ZYNQ PS端Linux RT DMA读取速度(44MB/s左右)
8)经过反复修改PL端FPGA VI前面板上的"分频系数"和PS端Linux RT程序前面板上的"批量读取点数",最终确认的PS端FIFO最佳读取点数是65536,最快平均速度是70MB/s左右,如图9-127所示;而PL端FPGA VI前面板上的"分频系数"是3,等效的DMA吞吐率就是50M/3*4Byte/s=66MB/s,如图9-128所示。
图9-127:ZYNQ PS端Linux RT FIFO读取速度(70MB/s左右)
图9-128:将PL端实验9.4对应的FPGA VI前面板上的"分频系数"设置为3(66MB/s)
**提醒:**如果用户在测试的时候,发现速度跟不上,可以将PS端Linux RT程序框图所有影响读取的代码禁用掉,比如获取DMA缓冲区长度和强制类型转换以及波形显示等代码全部禁用掉,只保留读取和速度计算这部分,这样可以进一步提高DMA吞吐率。
11、实验总结
我们总结一下本节实验学到的内容和需要注意的事项。
本节实验我们通过DMA通道实现了ZYNQ芯片内部PL端FPGA部分与PS(ARM)端Linux RT程序之间的高速通信和交互,与前面第五章开发过程类似,程序本身不复杂。但是由于涉及到利用LabVIEW同时开发ZYNQ里面的PL端与PS端部分,对于初学者来说,里面的每个步骤和操作过程都要熟练掌握,虽然都是一些基础知识,但是熟能生巧,后续实验会越来越复杂,功能越来越多,希望大家都能轻松学会掌握。
本节内容主要是全方位讲解PS端与PL端进行双向通信的32位数据类型的DMA通道,熟悉了DMA FIFO通道,大家就能打通PS端与PL端之间的ADC、DAC连续点、不定长的数组、向量、图像、簇等数据的高速交互了;下一节实验我们会重点讲解PS端如何直接控制PL端生成想要的PWM波形。