基于FPGA的数字信号处理系统开发笔记(一)
本笔记参考B站大佬up:的教学视频,特此说明,笔记仅供学习参考无教学意义视频地址因为Xilinx被AMD收购了,现在B站能查到的教学视频,CSDN能查到的参考文章,都是较为旧版的软件,使用上大差不差,但是有些细节和以前不太一样,对于初学者来说可能有时候一个小的不一样就会导致半天找不到问题,所以我想分享我学习过程中遇到的问题,以供大家参考。我所使用的软件及其版本:Vivado 2024.2;MATL
本笔记参考B站大佬up: Rong晔 的教学视频,特此说明,笔记仅供学习参考无教学意义
因为Xilinx被AMD收购了,现在B站能查到的教学视频,CSDN能查到的参考文章,都是较为旧版的软件,使用上大差不差,但是有些细节和以前不太一样,对于初学者来说可能有时候一个小的不一样就会导致半天找不到问题,所以我想分享我学习过程中遇到的问题,以供大家参考。
一,提前下载好Vivado和MATLAB(这个具体去查找下载的教程)
我所使用的软件及其版本:Vivado 2024.2;MATLAB R2024a(实测此版本的两个软件支持联合使用)
基本开发流程

注意要通过这个软件打开matlab,这个软件应该对应的就是B站大佬up: Rong晔视频中说的System Generator。 我是先下载的Vivado后下载的MATLAB,开始下载的是2024B版本的MATLAB,Vivado显示不支持,随后下载的2017a也显示不支持,最后根据提示选择了2024a,结果可以。
二,通过Vitis Model Composer 2024.2打开matlab
(1)matlab文件编写
进入后新建一个脚本,命名为demo
输入以下代码;
clc;clear all;close all;
%% System parameters
N = 1024; %一共采集多少个点
Fs = 10000;%KHz
Ts = 1/Fs;
%% Input signal parameters
A = 1;
t = (0:1024-1)*Ts;
f = 50;
n = Fs/f; %一个周期采了多少点
x = A * sin(2*pi*f*t);
figure(1)
plot(t,x);
hold on;
%% Multiply,add,delay
C = 2;
D = n/2;
y_0 = zeros(1,N);
y_1 = zeros(1,N);
y = zeros(1,N);
for i = 1:N
y_0(i) = C * x(i);
if(i>D)
y_1(i)=y_0(i-D);
end
y(i) = y_0(i) + y_1(i);
end
figure(1)
plot(t,y);
legend('Input','Output');
x_in(:,1) = 1:N;
x_in(:,2) = x;
F5运行,运行结果如下

(2)使用Simulink进行仿真


创建空白模型
打开库

第一步,在库中搜索Vitis Model Composer Hub

应该都一样,随便选一个。添加到页面上,双击打开后如下界面,点击红框处开始选择硬件

我用的是野火的开发板,A7,XC7A-35T mini。 我的配置如下

主要用的部件在如下两个选项里(找不到的话就输入名称搜索)

搭建仿真电路如下



更正一下,是16位数,里面有14位用来作为小数
更正一下,是16位数,里面有14位用来作为小数
更正一下,是16位数,里面有14位用来作为小数

这样设置以后就可以看到各个数据的类型,如下

给示波器添加一路输入,将原始输入信号也接入示波器
并且调整运行时间为1024


仿真运行,运行结果如下

与matlab结果一致,证明仿真成功。
三,转为HDL语言
(1)添加输入数据
将输入换成一个计数器和一个ROM,这样可以把matlab中的数据存到ROM中方便下载到FPGA开发板中进行仿真验证。

计数器和ROM参数配置如下



将所选区域封装成一个子系统


在matlab命令行中输入以下代码(路径为自己软件安装的路径)
hdlsetuptoolpath('ToolName','Xilinx Vivado','ToolPath','D:\FPGA\Vivado\2024.2\bin')

(2)使用HDL Coder中的HDL Code Advisor进行转换前的验证。
不是用HDL Coder进行代码的转换,是用它底下的HDL Code Advisor模块进行一个检查


选中所有选项,点击“运行所选检查”,正常情况下会报一个“所选模块不支持的错误”


因为我们使用的是“AMD Toolbox”的库,不是“HDL Coder”的库所以这个报错是正常的,别的只要没有报错应该就没有什么问题。
(3)使用Vitis Model Composer Hub进行HDL代码的转换输出
双击Vitis Model Composer Hub
硬件配置如下,根据自己的开发板进行选择

代码生成配置如下


没问题后点击Export。
四,用Vivado打开Simulink生成的工程进行仿真验证
(1)添加IP核心:集成逻辑分析仪(ILA)


ILA配置如下


添加完ILA后,打开如下文件,先要将ILA实例化

将该文件中框选的代码复制到顶层文件中


对顶层文件进行修改,首先将input,output变量改为wire [32-1:0] input_x0;wire [32-1:0] output_x0;(wire类型),其次将input,output传入实例化的ILA中,完整的.v文件如下;
`ifndef xlConvPkgIncluded
`include "conv_pkg.v"
`endif
`timescale 1 ns / 10 ps
// Generated from Simulink block test_1/Test_0_struct
module test_0_struct (
input clk_1,
input ce_1,
output [32-1:0] input_x0,
output [32-1:0] output_x0
);
wire [49-1:0] addsub_s_net;
wire [32-1:0] convert_dout_net;
wire [48-1:0] cmult_p_net;
wire clk_net;
wire ce_net;
wire [32-1:0] rom_data_net;
wire [10-1:0] counter_op_net;
wire [48-1:0] delay_q_net;
assign input_x0 = rom_data_net;
assign output_x0 = convert_dout_net;
assign clk_net = clk_1;
assign ce_net = ce_1;
test_0_xladdsub #(
.a_arith(`xlSigned),
.a_bin_pt(30),
.a_width(48),
.b_arith(`xlSigned),
.b_bin_pt(30),
.b_width(48),
.c_has_c_out(0),
.c_latency(0),
.c_output_width(49),
.core_name0("test_0_c_addsub_v12_0_i0"),
.extra_registers(0),
.full_s_arith(2),
.full_s_width(49),
.latency(0),
.overflow(1),
.quantization(1),
.s_arith(`xlSigned),
.s_bin_pt(30),
.s_width(49)
)
addsub (
.clr(1'b0),
.en(1'b1),
.a(cmult_p_net),
.b(delay_q_net),
.clk(clk_net),
.ce(ce_net),
.s(addsub_s_net)
);
test_0_xlcmult #(
.a_arith(`xlSigned),
.a_bin_pt(16),
.a_width(32),
.b_bin_pt(14),
.c_a_type(0),
.c_a_width(32),
.c_b_type(1),
.c_b_width(16),
.c_output_width(48),
.core_name0("test_0_mult_gen_v12_0_i0"),
.extra_registers(0),
.multsign(2),
.overflow(1),
.p_arith(`xlSigned),
.p_bin_pt(30),
.p_width(48),
.quantization(1),
.zero_const(0)
)
cmult (
.clr(1'b0),
.core_clr(1'b1),
.en(1'b1),
.rst(1'b0),
.a(rom_data_net),
.clk(clk_net),
.ce(ce_net),
.core_clk(clk_net),
.core_ce(ce_net),
.p(cmult_p_net)
);
test_0_xlconvert #(
.bool_conversion(0),
.din_arith(2),
.din_bin_pt(30),
.din_width(49),
.dout_arith(2),
.dout_bin_pt(16),
.dout_width(32),
.latency(0),
.overflow(`xlSaturate),
.quantization(`xlRound)
)
convert (
.clr(1'b0),
.en(1'b1),
.din(addsub_s_net),
.clk(clk_net),
.ce(ce_net),
.dout(convert_dout_net)
);
test_0_xlcounter_limit #(
.cnt_15_0(1023),
.cnt_31_16(0),
.cnt_47_32(0),
.cnt_63_48(0),
.core_name0("test_0_c_counter_binary_v12_0_i0"),
.count_limited(0),
.op_arith(`xlUnsigned),
.op_width(10)
)
counter (
.en(1'b1),
.rst(1'b0),
.clr(1'b0),
.clk(clk_net),
.ce(ce_net),
.op(counter_op_net)
);
test_0_xldelay #(
.latency(100),
.reg_retiming(0),
.reset(0),
.width(48)
)
delay (
.en(1'b1),
.rst(1'b0),
.d(cmult_p_net),
.clk(clk_net),
.ce(ce_net),
.q(delay_q_net)
);
test_0_xlsprom #(
.c_address_width(10),
.c_width(32),
.latency(1),
.mem_init_file("xpm_221ba9_vivado.mem"),
.mem_size(32768),
.mem_type("block"),
.read_reset_val("0")
)
rom (
.en(1'b1),
.rst(1'b0),
.addr(counter_op_net),
.clk(clk_net),
.ce(ce_net),
.data(rom_data_net)
);
endmodule
`timescale 1 ns / 10 ps
// Generated from Simulink block
module test_0_default_clock_driver (
input test_0_sysclk,
input test_0_sysce,
input test_0_sysclr,
output test_0_clk1,
output test_0_ce1
);
xlclockdriver #(
.period(1),
.log_2_period(1)
)
clockdriver (
.sysclk(test_0_sysclk),
.sysce(test_0_sysce),
.sysclr(test_0_sysclr),
.clk(test_0_clk1),
.ce(test_0_ce1)
);
endmodule
`timescale 1 ns / 10 ps
// Generated from Simulink block
(* core_generation_info = "test_0,sysgen_core_2024_2,{,compilation=HDL Netlist,block_icon_display=Default,family=artix7,part=xc7a35t,speed=-2,package=fgg484,synthesis_language=verilog,hdl_library=xil_defaultlib,synthesis_strategy=Vivado Synthesis Defaults,implementation_strategy=Vivado Implementation Defaults,testbench=1,interface_doc=0,ce_clr=0,clock_period=20,system_simulink_period=1,waveform_viewer=0,axilite_interface=0,ip_catalog_plugin=0,hwcosim_burst_mode=0,simulation_time=1024,addsub=1,cmult=1,convert=1,counter=1,delay=1,sprom=1,}" *)
module test_0 (
input clk
);
wire [32-1:0] input_x0;
wire [32-1:0] output_x0;
wire clk_1_net;
wire ce_1_net;
test_0_default_clock_driver test_0_default_clock_driver (
.test_0_sysclk(clk),
.test_0_sysce(1'b1),
.test_0_sysclr(1'b0),
.test_0_clk1(clk_1_net),
.test_0_ce1(ce_1_net)
);
test_0_struct test_0_struct (
.clk_1(clk_1_net),
.ce_1(ce_1_net),
.input_x0(input_x0),
.output_x0(output_x0)
);
ila_0 ila_inst (
.clk(clk), // input wire clk
.probe0(input_x0), // input wire [31:0] probe0
.probe1(output_x0) // input wire [31:0] probe1
);
endmodule
(2)进行RTL分析

RTL分析结果如下;可以与Simulink模块图进行对比



(3)配置管脚约束文件


根据自己的开发板原理图进行配置,我的开发板CLK引脚为W19,3.3V
配置完成后Ctrl+S进行保存。
五,用Vivado进行仿真验证
(1)生成比特流文件

生成较慢请
耐心等待 耐心等待 耐心等待
生成好后点击OK
选择Open target中的自动连接

链接成功后,点击下载到设备

下载成功后出现如下界面:

点击运行

(2)修改输出数据类型
此时输出数据为16进制,数字信号,观察起来很不直观。
并且Vivado2017.3后的版本,Radix 的real setting被删除了!!!
所以想要查看模拟信号的波形图有如下方法:


选择模拟信号,数据类型选择有符号小数


(3)导出ILA数据文件
随后进行ILA数据的导出,导出格式选择CSV。
随后打开CSV文件,将input和output两列进行制图,如下,则可得到波形图

至于为什么会出现途中红框框选的突变呢?详细原因可以看B站大佬up: Rong晔 的教学视频,大概原因就是因为输入的信号是固定的一个周期1024个点,每个周期的第一个点都是0,第1024个点都是一个正值,第一个周期第1024个点一结束,立刻就接着第二个周期的第一个点,所以会产生跳变。
返回Simulink,将运行时间从1024改为2048结果如下:

此结果也佐证了上述观点,至此一整套完整的从matlab设计到Simulink设计,再到Vivado仿真验证,到下载到FPGA开发板上的一整套流程就完毕了。
再次感谢B站大佬up: Rong晔 的教学视频,受益良多。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)