目前发行的主要版本包括RHEL、Debian及其派生版本,这里选用Ubuntu22 LTS(长期支持版本)有以下几个原因:
当然Ubuntu也有其劣势,如性能利用率较低、内核稳定性较差等,但相比于其优势,这些可能存在的缺点对于日常开发工作的影响可以忽略不计。
Ubuntu官方网站的账号注册、ISO镜像下载和VMWare安装Ubuntu系统在此不过多赘述,网上已有许多文档提供解答,例如以下博客即可供参考(已包括VMWare Tools安装):
VMware&Ubuntu安装
切记!!!关注Xilinx官方对Vivado对Linux版本的要求,血的教训!!!
详细步骤可参考以下博客:
共享文件夹配置
主要推荐使用NAT模式,桥接模式基于我本机的Wifi网卡还没成功过。
具体操作可参考如下博客:
https://blog.csdn.net/xuqingda/article/details/124033331
参考此官方文档:
Vivado安装说明
原理是利用一个包含数字波形信息的存储块(可以是RAM/ROM),利用一定的逻辑读取该存储块的数据并输出,经过DA转换后得到模拟波形。
优点:
精度高:DDS合成器能够产生非常准确的输出信号,其频率和相位精度很高,适用于需要精确控制的应用,如通信、测量和精密仪器。
频率可编程:DDS可以轻松实现频率的可编程,只需改变相应的寄存器值即可。这使得DDS非常适合需要频率切换的应用,如无线电通信、雷达和频谱分析仪器。
稳定性好:DDS合成器通常具有稳定的频率和相位,不受温度和环境变化的影响。这对需要长时间运行的应用非常有利。
低相位噪声:DDS合成器通常具有较低的相位噪声,适用于需要低噪声的应用,如通信和雷达系统。
缺点:
相位跳变:DDS在频率切换时可能会出现相位跳变,这可能会引入干扰,因此在某些应用中需要特殊的处理来减小相位跳变的影响。
硬件成本:较高精度和更高频率的DDS合成器通常需要复杂的硬件和高速时钟源,这可能会增加成本和功耗。
动态范围:DDS的动态范围可能受到限制,尤其是在高频率下。对于需要大动态范围的应用,可能需要额外的信号处理步骤。
频率字 = (输出频率 / 参考时钟频率) * 2N,其中N为存储深度的位数,即N位对应2N个采样点数。
详情请见数字信号处理课本或以下知乎链接:
FIR滤波器初步
为方便开发者观察工程输出的信号以及工程内部的信号细节,Xilinx的Vivado套件中提供了ILA的IP核,相当于一个硬件逻辑分析仪,是基于物理电路和实时系统的,省去了额外购买逻辑分析仪或者混合信号示波器的麻烦,代价是增加了逻辑和存储资源的开销。
具体文档请见Xilinx官方:
Xilinx ILA说明
用于时钟管理的PLL由鉴相器、环路滤波器、压控振荡器和两个分频器组成,通过分频器使得输出频率与参考频率的按比例锁定,达到倍频/分频的目的,再Vivado中没有独立的PLL IP核心,而是集成在Clocking Wizard里的PLL方式选项。
在工具栏的APP选项卡中打开Filter Builder(滤波器设计工具)
注意!!以上的每一部分都需要跟后面Vivado中FIR IP核的设置完全对应!!
代码如下:可生成包含任意数值序列的COE文件,注释都已经较为详细
N=2^8; % 数据位数
s_p=0:255;
Mem_depth = 256; % 存储深度
Mem_width = 8;
sin_data=sin(2*pi*s_p/N);
for i=1:length(sin_data)
if(sin_data(i)>0)
sin_data(i)=1;
else
sin_data(i)=0;
end
end
% plot(sin_data);
% hold on;
% plot(sin_data);
% Signed Dec to Bin
fix_p_sin_data=fix(sin_data*((N / 2) -1));
for i=1:N
if fix_p_sin_data(i)<0
fix_p_sin_data(i)=N+fix_p_sin_data(i);
else
fix_p_sin_data(i)=fix_p_sin_data(i);
end
end
fid=fopen('sp_ram_256x8.mif','w+');
fprintf(fid,'WIDTH=%d;\n', Mem_width);
fprintf(fid,'DEPTH=%d;\n',Mem_depth);
fprintf(fid,'ADDRESS_RADIX=UNS;\n');
fprintf(fid,'DATA_RADIX=UNS;\n');
fprintf(fid,'CONTENT BEGIN \n');
for i=1:N
fprintf(fid,'%d:%d; \n',i-1,fix_p_sin_data(i));
end
fprintf(fid,'END; \n');
fclose(fid);
fid=fopen('sp_ram_256x8_sqare.coe','w+');
fprintf(fid,'memory_initialization_radix=10;\n');
fprintf(fid,'memory_initialization_vector= \n');
for i=1:N
if i == N
fprintf(fid,'%d; ',fix_p_sin_data(i));
else
fprintf(fid,'%d, ',fix_p_sin_data(i));
end
end
最后将会得到一个sp_ram_256x8_sqare.coe文件,同样将其拷贝至Vivado工程目录下以备调用。
以下操作都是基于Vivado平台,需要读者自行建立和配置Vivado工程。本例程是基于Xilinx ZYNQ XC7Z020-CLG400芯片以及Alinx 7020板卡搭建的工程,读者请自行按手册和自己的产品文档建立对应兼容的工程。
建立工程完毕后打开并新建一个Block Design文件,并点击图纸上方的加号在设计中添加IP核(不要用IP Catalog,那个方式是IP核综合后再进行主程序HDL设计)
主要的参数有:实现方式、参考时钟输入频率、输出频率。
实验引入PLL的目的是为了更好地贴近实际应用情况,掌握时钟树的管理和配置,同时适当加强例程的深度和复杂性。
配置按如下步骤:
实现方式采用PLL,即锁相环(该FPGA内置4个高性能锁相环)。输入参考时钟为板载50M晶振。
输出时钟选择1路100MHz,并点击确定。
主要的参数有:输入输出位深、参考时钟频率、系数矩阵数据。
在此将滤波器系数源选择COE File,并导入Filter Builder生成的COE文件。
设置同步时钟的参数,这里使用Clocking Wizard输出的100MHz时钟源。
设置系数以及输入、输出数据的类型(模式)和位深,输入需与Distributed Memory Generator的输出严格对映。
主要的参数有:实现方式、位数、单位时钟周期增量、计数方向。
分别设置上述三个参数即可,实现原理可以选择用逻辑单元或者DSP单元,性能差别不大,主要看资源占用率。计数位数需要跟DMG的地址位数一致,由于本次操作为遍历存储块,即每周期读取1次,故增量设置为1,方向为自增。
生成的波形频率计算为:256/100M=2.56MHz
在这里需要补充说明的一点是有关DMG和BMG(Block Memory Generator):
块存储器生成器(BRAM):
BRAM是Xilinx FPGA中的一种内存类型,它被组织成固定大小的块。BMG允许创建根据设计要求定制的BRAM结构。可以配置BRAM生成器以创建单口、双口或真双口内存,具有不同的数据宽度和深度,通常用于需要高速随机访问内存的任务。
分布式存储器生成器(DRAM):
DRAM是一种分布在FPGA结构中而不是组织成固定大小块的内存类型。DMG允许创建基于FPGA结构中的查找表(LUT)的自定义分布式内存结构。与BRAM相比,分布式内存结构在内存大小和组织方面更加灵活,通常用于查找表和小型缓冲内存等功能。
由此可见本实验选用DRAM或者BRAM均可,由于性能开销不大,配置DMG相对较为简单,因此本例程以DMG为例。
主要的参数有:存储单元类型、数据位深和长度、数据源、寄存器加载。
本例中实现的是256个8位数据的ROM,采用COE文件导入,输入输出均寄存(优化时序性能)。
参数需要与MATLAB查找表生成脚本一致
主要的参数有:通道数、存储深度、各通道位深。
各参数与被测信号对应即可,存储深度选4096足够。
最终连接完成的模块设计如下图所示:
为了便于入门的理解且考虑到该项目的规模较小,本次设计采用Block Design的模式,以后的更新会在文末附上Verilog HDL的代码。由于不包含用户逻辑,所以这次敲Verilog主要是练习例化和路由。
对Block Design进行综合(Synthesis),点击Run Synthesis
在已综合工程中打开(Open Synthesized Design)约束向导和I/O Ports(管脚约束)
在I/O Ports中按下图设计:
复位端口按手册配置至PL KEY1(高有效),查看板卡手册得知端口是上拉3.5V,因此是按下取消复位,使能程序;反之松开是停止程序。
最后将会生成.xdc约束文件用作实现时的约束,在Source的Constraints的文件夹下打开即可查看和修改。
所有内容添加完成后即可开始Implementation(实现)。
依次点击左侧流程栏中的Run Implementation, Generate Bitstream, Open Hardware Manager, 进入下一步。此时系统的管脚、时钟分配已经完成,并且已经准备好用于写入硬件的比特流。
首先确认硬件板卡已连接至虚拟机(在VMWare顶栏的虚拟机 -> 可移动设备中查看板卡的连接状态(连接主机/连接虚拟机))
选择Open target -> Auto Connect
同样在项目顶部的绿色栏或左侧流程栏中选择Program device,若是已经本地经过综合实现的工程,默认已经选好比特流文件和Debug文件,直接点击Program即可。
点击Waveform - hw_ila_1菜单栏的加号(Add Probe),全选所有信号。
部分信号需参考如下设定:
按下PL KEY1并点击运行图标(Run trigger for this ILA core),即可得到如下结果,大功告成。
由上至下分别为数据有效标志位、DDS生成信号、计数信号(DDS地址/相位信号)、FIR滤波后信号。
这是例程构建早期的一次仿真,观察BMG的输出,ROM中加载的同样是方波,但在此看到三角波的原因是ILA模拟显示设置不正确,应在Analog Settings中调整为hold(保持)模式,这样在时钟前进时收到同样的信号会被解释成保持同样电平而不是离散点之间的连接。
这是例程构建中期的一次仿真,由滤波后的图像可大致反推FIR接收到的应该是一系列脉冲信号,但BMG输出的是一个很明确的方波信号(当然有些竞争冒险的现象)。
当时真是百思不得其解,之后发现可能是BMG的问题,遂换成DMG则试验成功,但具体原理仍不太清楚。这个问题大概花了我半天的时间调试BMG的各种参数,但仍然不起作用。最后干脆换了个更简单的实现方式,即DMG,直接用查找表和逻辑实现,结构更简单,一般而言错误的概率更低。
当然学到最后仍应该思考这个问题,但在实验的过程中应该首先以功能和结果为目标,花过多时间在自己认知意外的问题上很容易陷入困境导致实验难以继续进展。
本次实验中完成了DDS和FIR的FPGA实现,较为简单的原理在实现的过程中遇到了些问题,这也提醒了我们实践的重要性,有些在理论上并不关心的东西反而是工程中最终要的环节(比如浮点转定点、位数和深度匹配等等)。也许我们知道DSP和计算机原理的理论,但单纯记忆课本并不会理解并真正注意到它;实验同时也开拓了我的思路,并且告诉我解决问题的方法都不是一成不变的。
当然结尾也遗留下来了一些问题,我相信每个疑问和解答都是下一次开始实验的动力和目标。
希望本文能帮助到初学FPGA或者初次接触Xilinx套件的同学们,上手难度适中又能有所收获。希望各位看官老爷们点赞收藏关注一键三连,你们的支持是我创作和更新博客的最大动力!