版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_46621272/article/details/125292610
XILINX FIR IP 详解、Verilog 源码、Vivado 工程
文章目录
- 前言
- 一、FIR IP 详解(Vivado 2017.4 环境 FIR Compiler 7.2)
- 二、实验内容
- 三、 实验相关 vivado 工程、IP 设置等详细文档连接,采用 Xilinx vivado 2017.4 版本
- [XILINX FIR IP 详解、Verilog 源码、Vivado 工程](https://blog.csdn.net/qq_46621272/article/details/125292610)
- 实验一、[FIR 基础应用 - AM 调幅波调制解调(FIR 低通滤波)详细介绍](https://blog.csdn.net/qq_46621272/article/details/125334644)
- 实验二、[FIR 基础应用 - FM 调频波调制解调(FIR 低通滤波) 详细介绍](https://blog.csdn.net/qq_46621272/article/details/125337119)
- 实验三、[FIR 中级应用 - AM 调幅波调制解调(FIR + FIFO)详细介绍](https://blog.csdn.net/qq_46621272/article/details/125384724)
- 实验四、[FIR 高级应用 - AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO ) 详细介绍](https://blog.csdn.net/qq_46621272/article/details/125385375)
- 实验五、[FIR 高级应用 - 多通道实验 (四个通道用一个 FIR IP,每通道用不同的系数) 详细介绍](https://blog.csdn.net/qq_46621272/article/details/125346332)
- 实验六、[FIR 高级应用 FIR Reload的使用) 详细介绍](https://blog.csdn.net/qq_46621272/article/details/125348908)
- 实验一、 [AM 调幅波调制解调(FIR 低通滤波) vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85674733)
- 实验二、 [FM 调频波调制解调(FIR 低通滤波) Vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85722410)
- 实验三、 [AM 调幅波调制解调(FIR + FIFO) Vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85722449)
- 实验四、 [AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO ) Vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85722484)
- 实验五、 [FIR 高级应用 - 多通道实验 Vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85722518)
- 实验六、 [FIR 高级应用 FIR Reload 的使用 vivado 工程文件下载](https://download.csdn.net/download/qq_46621272/85722534)
前言
FIR 是个比较复杂的 IP ,不同的设置需要不同的代码去配合。这篇文章详细介绍了这 FIR IP 设置需要注意的地方。
本文中介绍了五个实验,最基础的应用实验,FIR +FIFO实验,多通道多套系数配置实验,Reload Config 实验等,全面介绍了 FIR 的各种应用。所有实验提供 Vivado工程,Verilog代码下载,还有较为详细的文字图片介绍。
一、FIR IP 详解(Vivado 2017.4 环境 FIR Compiler 7.2)
XILINX 官方 FIR 手册: https://docs.xilinx.com/v/u/en-US/pg149-fir-compiler
本文只介绍一些常用到的功能设置,和需要注意的地方。一些没介绍到的功能和细节请仔细阅读手册。
-
01:这部分很多人容易忽略,需要时刻关注这部分,在做一些 Reload/Config/多通道/等应用设置后,要及时查看这部分的变化。
-
02: FIR 系数,本文的所有例子都是采用 COE File 方式导入 FIR 系数文件,本文的“COE”文件是由 Matlab 下的
Filter Designer 生成,相关方法和使用请看本文的附件二。 -
03:多套系数的导入,这个数需要我们填写,还需要根据这个数去合理的人工合并编辑 COE 文件或 Vector 内容。这里需要注意的是我们在合并 COE 文件时,最好选用相同系数的数量及相同的系数对称方式去合并。
- A:最好选用相同系数的对称方式的COE数据去合并
系数的对称方式简介:
奇对称:系数数量是奇数,且左右对称,比如:1,-2,3,-2,1
偶对称:系数数量是偶数,且左右对称,比如:-1,2,2,-1
负对称:系数数量是偶数,且左右负对称,比如:1,-2,3,-3,2,-1
不对称:比如:1,-2,3,4 - B:最好选用相同系数数量的 COE 系数去合并,在数量不一致且对称方式一样的情况下,可以手工补 0 的方式将 COE 的系数数量调整到一致。
比如:
B1:对称系数:0, 1,-2, 3,-2, 1, 0 (前后补 0 ,可以补多个 0)
B2:不对称系数: 1,-2,3,4,0,0 (后补 0 ,可以补多个 0) - C:在系数数量不同,而且系数对称方式不一致时,也能合并。需要将所有的系数都按不对称处理。这种模式下会占用较多的 DSP 资源。
C1:需要在 FIR Coefficient Options的设置中将 Coefficient Structure 选成 Non-symmetric (不对称方式)
C2:按不对称系数的后补 0 方式将所有数据的数量调整成一样再合并
可以参考下本文后面的实验,有具体的例子和代码: - FIR 高级应用 - 多通道共用一个 FIR (四个通道共用同一个 FIR I+P 每个通道采用不同的 FIR 系数算法)。
- FIR 高级应用 FIR Reload、Config 的使用。
- D:在编辑 COE 文件补 0 时要补全比如 16 位系数,要敲 “0000” 四个零,要敲全。
- D1:奇对称 5 个系数和奇对称 7 个系数合并
- 奇对称 5 个系数文件
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
0003,
0002,
0001;
- 奇对称 7 个系数文件
Radix = 16;
Coefficient_Width = 16;
CoefData = 0005,
0004,
0003,
0002,
0003,
0004,
0005;
- 奇对称 5 个系数和奇对称 7 个系数合并后
Radix = 16;
Coefficient_Width = 16;
CoefData = 0000,
0001,
0002,
0003,
0002,
0001,
0000,
0005,
0004,
0003,
0002,
0003,
0004,
0005;
- D2: 偶对称 6 个系数,奇对称 5 个系数合并,这只能按不对称补 0 合并
- 偶对称 6 个系数文件
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
0003,
0003,
0002,
0001;
- 奇对称 5 个系数文件
Radix = 16;
Coefficient_Width = 16;
CoefData = 0003,
0004,
0005,
0004,
0003;
- 奇对称 5 个系数和 5.coe 偶对称 6 个系数合并后文件,按不对称后补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
0003,
0003,
0002,
0001,
0003,
0004,
0005,
0004,
0003,
0000;
- A:最好选用相同系数的对称方式的COE数据去合并
-
04:Reload 重新加载系数
- A:重新加载的系数与原系数的数量必须一致,如果不一致可以参考 03 将系数补 0 的方式调整成一样。
- B:重新加载的系数的对称方式必须一致,如果不一致可以参考 03 将系数的对称方式全部按不对称处理。
- C:重新加载的系数必须用 Config 去激活才能生效。
- D:可以参考下本文后面的实验:FIR 高级应用 FIR Reload、Config 的使用。
- E:人工编辑、补 0 Reload 数据,对称数据需要折半后前补 0
- E1:Reload 奇对称数据编辑,按 9 个长度补 0 折半后就是 5 个系数数据。
- 奇对称 5 个系数,按对称数据折半后前补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
000a,
0002,
0001; - 编辑后
0000
0000
0001
0002
000a
- 奇对称 7 个系数,按对称数据折半后前补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0005,
000b,
0003,
0002,
0003,
000b,
0005; - 编辑后
0000
0005
000b
0003
0002
- D2:Reload 偶对称数据编辑,按 10 个长度补 0 折半后就是 5 个系数数据。
- 偶对称 6 个系数,按对称数据折半后前补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
0003,
0003,
0002,
0001; - 编辑后
0000
0000
0001
0002
0003
- 偶对称 4 个系数,按对称数据折半后前补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 000a,
000b,
000b,
000a; - 编辑后
0000
0000
0000
000a
000b
- E3:Reload 奇偶对称混合数据编辑,按 10 个长度补 0 ,按不对称数据处理。
- 奇对称 5 个系数,按不对称数据后补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
000a,
0002,
0001; - 编辑后
0001
0002
000a
0002
0001
0000
0000
0000
0000
0000
- 偶对称 6 个系数,按不对称数据后补 0
Radix = 16;
Coefficient_Width = 16;
CoefData = 0001,
0002,
0003,
0003,
0002,
0001; - 编辑后
0001
0002
0003
0003
0002
0001
0000
0000
0000
0000
-
05: Filter Specification 滤波器类型,可以支持以下五种类型
FIR IP 持 5 种滤波类型
Single-rate (缺省)
Interpolating
Decimating (实验 FIR 高级应用 - AM 调幅波调制解调通过这个选择改变 FIR 输出的采样频率)
Hilbert transform
Interpolated
我们可以选用合适的类型完成我们的设计。其中的 Interpolating 插值,Decimating 抽值能改变 FIR 输出的采样频率。可以参考下实验的代码。在实验里我们就用 Decimating 类型将采样频率降低为原来的 1/16,将采样频率从 1MHz 降低到 62.5KHz。
- 06:Channel Sequence 通道序列选择,在我们的实验中均选用 Basic。在 Number of Channels 通道数量为 1 时也只能选用 Basic。
Basic 的多通道模式,各通道的采样频率必须同步、一致。
在 Advanced 选项里,各通道的采样频率允许有限制的不一样,但必须是同步的同一时钟源的。这 Advanced 选项的细节请阅读手册吧。 - 07:Number of Channels 通道数量,这里的多通道是串行的,比如双通道 C0,C1 这俩通道 C0、C1 交错输入交错输出分时使用。
- 08:Parallel Channel Specification 并行的通道设置,并行通道数量。各通道的采样频率必须同步、一致。
- 09:输入的采样时钟频率,这是个虚值,并没用这个采样时钟的管脚。这个值的设置要根据整个 FIR 的应用来决定。
- 10:FIR 实际工作的时钟频率
- 11:FIR 时钟设置,09,10 这俩时钟的设置需要是相互关联的。这俩值根据不同的应用会有不同的变化。
- 应用1: 输入的采样时钟频率和 FIR 实际工作的时钟频率设成一样。
优点:这种 FIR 的应用,FIR 外围设计非常简单。
缺点:占用 DSP 资源较大。
使用范围:适用于高速的采样速率的方案,适用于对 DSP 资源消耗不高的应用。- 应用2: 输入的采样时钟频率小于 FIR 实际工作的时钟频率。
由于输入的采样时钟和 FIR 的工作时钟不同,输入的数据流一般要用一个 FIFO 做跨越时钟域的转换。
优点:这种 FIR 的应用,能极大的降低 DSP 资源的使用。在一些低速应用中能选用高阶滤波算法。比如一万个系数的 FIR 运算。
缺点:这种 FIR 的应用,FIR 外围设计设计较复杂,一般需要用 FIFO。
使用范围:适用于低速的采样速率的方案,适用于对 DSP 资源消耗很高的应用。- 应用3: 输入的采样时钟频率大于 FIR 实际工作的时钟频率。
这种应用能实现超高速的 FIR 应用。这种应用消耗资源成倍的增加。和应用2一样这种应用也需要 FIFO ,应用比较复杂。
优点:实现超高速的 FIR 运算,比如 7 系列 XILINX FPGA 实现。FIR 的工作时钟能到 300MHz,用这种方法能实现 300MHz * N 的高速计算。
缺点:这种 FIR 的应用占用 DSP 的资源成 N 倍的增长。FIR 外围设计设计较复杂,一般需要用 FIFO。
使用范围:适用于超高速的采样速率的方案。
-
12:FIR 系数的设置需要和 COE 文件保持一致,在我们的实验中这个设置均为 Signed,16 位宽度。
-
13:Coefficient Structure 系数结构,自动,对称,非对称,负对称系数的选择。在多组系数 Config 应用和 Reload 应用中,需要设置该值。请参考 03,04章节的介绍,请参考实验。
-
14:输入输出数据设置,按实际应用去设置位宽和精度。
-
15:请阅读手册。在我们的实验中这部分都是按缺省值设置。
-
16:数据通道选择。按实际应用去选择。
-
17:USER 输入输出设置,在多通道的实验中 USER Output 设置 Chan ID Field
-
18:在串行多通道中,该选项能支持每个通道选用不同的 FIR 系数设置。在实验中,选用 By Channel
-
19:Reload Slots ,在 Reload 应用中需要关注此值,这个值在我们使用 Reload 时,会影响 Reload 时的数据堵塞。这东西文字说不清楚,最好看看实验的代码和波形。
举例:
Reload Slots = 1,在 Reload 时只能下载一组系数后就堵塞了,下载数据通过 Config 须激活后才能继续下载数据。
Reload Slots = 3,在 Reload 时能下载三组系数后就才堵塞,激活后才能继续下载数据。 -
20:按实际应用去选择。在我们的所有实验中 ARESETn 均为使能。
二、实验内容
实验一、FIR 基础应用 - AM 调幅波调制解调(FIR 低通滤波)。
1. AM 调幅波调制模块
2. am_modulation_dds.v verilog 代码
//am_modulation_dds.v
module am_modulation_dds
(
output m_axis_data_tvalid,
input m_axis_data_tready,
output [15:0] m_axis_data_tdata,
input rst_n,
input clk
);
wire signed [7:0] dds_100khz_tdata_i; // 100KHz 正弦波 AM 载波
wire dds_100khz_tvalid_i;
wire dds_100khz_tready_i;
wire signed [7:0] dds_4khz_tdata_i; // 4khz 正弦波 AM 调制信号
wire dds_4khz_tvalid_i;
wire dds_4khz_tready_i;
reg signed [15:0] am_tdata_r;
reg am_tvalid_r;
wire am_tready_i;
assign am_tready_i = m_axis_data_tready;
assign dds_100khz_tready_i = am_tready_i;
assign dds_4khz_tready_i = am_tready_i;
assign m_axis_data_tvalid = am_tvalid_r;
assign m_axis_data_tdata = am_tdata_r;
always @(posedge clk) //AM 调制算法实现
begin
if(rst_n == 0 )
begin
am_tdata_r <= 0;
am_tvalid_r <= 0;
end
else if(am_tready_i == 1)
begin
am_tdata_r <= dds_100khz_tdata_i * (dds_4khz_tdata_i/2 + 128); // 128 是直流分量,式中的除2是为了不使数据超过16位溢出
// 这个代码中,载波频率很低,就直接用乘法去写代码了。
// 如果载波频率比较高就需要用DSP单元或乘法 IP 去实现。
am_tvalid_r <= dds_4khz_tvalid_i & dds_100khz_tvalid_i;
end
end
dds_compiler_1m_100k dds1 // XILINX VIVADO DDS IP,1MHz 时钟输入,100KHz正弦波 8 位输出
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (dds_100khz_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (dds_100khz_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (dds_100khz_tdata_i) // output wire [7 : 0] m_axis_data_tdata
);
dds_compiler_1m_4k dds2 // XILINX VIVADO DDS IP,1MHz 时钟输入,4khz正弦波 8 位输出
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (dds_4khz_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (dds_4khz_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (dds_4khz_tdata_i) // output wire [7 : 0] m_axis_data_tdata
);
endmodule
3. AM 调幅波解调模块
4. am_demodulation_fir.v verilog 代码
//am_demodulation_fir.v
module am_demodulation_fir
(
input rst_n,
input clk,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
reg [15:0] abs_data_r = 0;
reg abs_valid_r = 0;
wire abs_tready_i;
always @(posedge clk)
begin
if(rst_n == 0 )
abs_valid_r <= 0;
else if(abs_tready_i == 1)
abs_valid_r <= s_axis_data_tvalid;
end
always @(posedge clk) //取绝对值
begin
if(rst_n == 0 )
abs_data_r <= 0;
else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
begin
if(s_axis_data_tdata >= 0)
abs_data_r <= s_axis_data_tdata;
else
abs_data_r <= -s_axis_data_tdata;
end
end
wire signed [39:0] fir_fm_tdata_i;
wire fir_fm_tvalid_i;
wire fir_fm_tready_i;
assign fir_fm_tready_i = m_axis_data_tready;
assign m_axis_data_tdata = fir_fm_tdata_i >>>19;
assign m_axis_data_tvalid = fir_fm_tvalid_i;
assign s_axis_data_tready = abs_tready_i;
fir_compiler_lowpass_10k_30k_1m am_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (clk), // input wire aclk
.s_axis_data_tvalid (abs_valid_r), // input wire s_axis_data_tvalid
.s_axis_data_tready (abs_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (abs_data_r), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_fm_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_fm_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_fm_tdata_i) // output wire [39 : 0] m_axis_data_tdata
);
endmodule
5. am_modem_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//am_modem_fir_testbench.v
module am_modem_fir_testbench;
reg rst_n;
reg clk;
parameter CLK_PERIOD = 1000; //1MHz
initial begin
rst_n = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(3000 * CLK_PERIOD)
$stop;
end
initial
clk = 0;
always
begin
clk = #(CLK_PERIOD/2.0) ~clk;
end
wire signed [15:0] am_mod_tdata; //调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
wire am_mod_tvalid;
wire am_mod_tready;
wire signed [15:0] am_demod_tdata; //经过解调还原的 4KHz 正弦波
wire am_demod_tvalid;
wire am_demod_tready=1;
am_modulation_dds am_u1 //调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.m_axis_data_tdata (am_mod_tdata), //调幅波数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_mod_tvalid),
.m_axis_data_tready (am_mod_tready)
);
am_demodulation_fir am_u2 //调幅波解调模块,将调幅波解调还原调制信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.s_axis_data_tdata (am_mod_tdata), //调幅信号输入 intput wire [16 : 0]
.s_axis_data_tvalid (am_mod_tvalid),
.s_axis_data_tready (am_mod_tready),
.m_axis_data_tdata (am_demod_tdata), //调幅波解调数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_demod_tvalid),
.m_axis_data_tready (am_demod_tready)
);
endmodule
实验二、FIR 基础应用 - FM 调频波调制解调(FIR 低通滤波)。
1. FM 调频波调制模块
2. fm_modulation_dds.v verilog 代码
//fm_modulation_dds.v
module fm_modulation_dds
(
output m_axis_data_tvalid,
input m_axis_data_tready,
output [15:0] m_axis_data_tdata,
input rst_n,
input clk
);
parameter PHASE_COEF = 6554;//100KHz
reg signed [15:0] phase_cnt_r;
wire signed [15:0] s_axis_phase_tdata_i;
reg s_axis_phase_tvalid_r;
wire s_axis_phase_tready_i;
wire signed [15:0] phase_step_i;
wire signed [7:0] dds_4khz_tdata_i; // 4khz 正弦波 FM 调制信号
wire dds_4khz_tvalid_i;
wire dds_4khz_tready_i;
wire signed [15:0] fm_tdata_i; // FM 调频波
wire fm_tvalid_i;
wire fm_tready_i;
assign phase_step_i = dds_4khz_tdata_i*16;
assign dds_4khz_tready_i = s_axis_phase_tready_i;
assign s_axis_phase_tdata_i = phase_cnt_r;
always @(posedge clk)
begin
if(rst_n == 0 )
s_axis_phase_tvalid_r <= 0;
else if(s_axis_phase_tready_i == 1)
s_axis_phase_tvalid_r <= dds_4khz_tvalid_i;
end
always @(posedge clk)
begin
if(rst_n == 0 )
begin
phase_cnt_r <= 0;
end
else if(s_axis_phase_tready_i == 1 && dds_4khz_tvalid_i == 1)
begin
phase_cnt_r <= phase_cnt_r + phase_step_i + PHASE_COEF;
end
end
dds_compiler_1m_4k dds1 // XILINX VIVADO DDS IP,100MHz 时钟输入,4khz正弦波 8 位输出
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (dds_4khz_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (dds_4khz_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (dds_4khz_tdata_i) // output wire [7 : 0] m_axis_data_tdata
);
dds_compiler_phase dds2
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.s_axis_phase_tvalid(s_axis_phase_tvalid_r), // input wire s_axis_phase_tvalid
.s_axis_phase_tready(s_axis_phase_tready_i), // output wire s_axis_phase_tready
.s_axis_phase_tdata (s_axis_phase_tdata_i), // input wire [15 : 0] s_axis_phase_tdata
.m_axis_data_tvalid (fm_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fm_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fm_tdata_i) // output wire [15 : 0] m_axis_data_tdata
);
assign fm_tready_i = m_axis_data_tready;
assign m_axis_data_tvalid = fm_tvalid_i;
assign m_axis_data_tdata = fm_tdata_i;
endmodule
3. FM 调频波解调模块
4. fm_demodulation_fir.v verilog 代码
//fm_demodulation_fir.v
module fm_demodulation_fir
(
input rst_n,
input clk,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
reg signed [15:0] uf_data_r = 0;
reg signed [15:0] sv_data_r = 0;
reg uf_valid_r = 0;
wire uf_tready_i;
reg [15:0] abs_data_r = 0;
reg abs_valid_r = 0;
wire abs_tready_i;
////////////////////////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
if(rst_n == 0 )
uf_valid_r <= 0;
else if(uf_tready_i == 1)
uf_valid_r <= s_axis_data_tvalid;
end
always @(posedge clk) //微分 dx/dt ,dt =一个时钟周期,dx=当前数据减去上个时钟的数据的差
begin
if(rst_n == 0 )
begin
uf_data_r <= 0;
sv_data_r <= 0;
end
else if(uf_tready_i == 1 && s_axis_data_tvalid == 1)
begin
sv_data_r <= s_axis_data_tdata; //将当前数据存起来
uf_data_r <= s_axis_data_tdata - sv_data_r; //当前数据 - 上个时钟保存的数据
end
end
////////////////////////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
if(rst_n == 0 )
abs_valid_r <= 0;
else if(abs_tready_i == 1)
abs_valid_r <= uf_valid_r;
end
always @(posedge clk) //绝对值
begin
if(rst_n == 0 )
abs_data_r <= 0;
else if(abs_tready_i == 1 && uf_valid_r == 1)
begin
if(uf_data_r >= 0)
abs_data_r <= uf_data_r;
else
abs_data_r <= -uf_data_r;
end
end
////////////////////////////////////////////////////////////////////////////////////
wire signed [39:0] fir_fm_tdata_i;
wire fir_fm_tvalid_i;
wire fir_fm_tready_i;
assign fir_fm_tready_i = m_axis_data_tready;
assign m_axis_data_tdata = fir_fm_tdata_i >>>19;
assign m_axis_data_tvalid = fir_fm_tvalid_i;
assign s_axis_data_tready = abs_tready_i;
assign uf_tready_i = abs_tready_i;
fir_compiler_lowpass_10k_30k_1m fm_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (clk), // input wire aclk
.s_axis_data_tvalid (abs_valid_r), // input wire s_axis_data_tvalid
.s_axis_data_tready (abs_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (abs_data_r), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_fm_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_fm_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_fm_tdata_i) // output wire [31 : 0] m_axis_data_tdata
);
endmodule
5. fm_modem_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//fm_modem_fir_testbench.v
module fm_modem_fir_testbench;
reg rst_n;
reg clk;
parameter CLK_PERIOD = 1000; //1MHz
initial begin
rst_n = 0;
#(10 * CLK_PERIOD)
rst_n = 1;
#(3000 * CLK_PERIOD)
$stop;
end
initial
clk = 0;
always
begin
clk = #(CLK_PERIOD/2.0) ~clk;
end
wire signed [15:0] fm_mod_tdata; //调频波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
wire fm_mod_tvalid;
wire fm_mod_tready;
wire signed [15:0] fm_demod_tdata; //经过解调还原的 4KHz 正弦波
wire fm_demod_tvalid;
wire fm_demod_tready=1;
fm_modulation_dds fm_u1 //调频波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调频信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.m_axis_data_tdata (fm_mod_tdata), //调频波数据输出, output wire [16 : 0]
.m_axis_data_tvalid (fm_mod_tvalid),
.m_axis_data_tready (fm_mod_tready)
);
fm_demodulation_fir fm_u2 //调频波解调模块,将调频波解调还原调制信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.s_axis_data_tdata (fm_mod_tdata), //调频信号输入 intput wire [16 : 0]
.s_axis_data_tvalid (fm_mod_tvalid),
.s_axis_data_tready (fm_mod_tready),
.m_axis_data_tdata (fm_demod_tdata), //调频波解调数据输出, output wire [16 : 0]
.m_axis_data_tvalid (fm_demod_tvalid),
.m_axis_data_tready (fm_demod_tready)
);
endmodule
实验三、FIR 中级应用 - AM 调幅波调制解调(FIR + FIFO)
1. AM 调幅波调制模块,请参考实验一
2. AM 调幅波解调模块(FIR 中级应用)
3. am_fifo_demodulation_fir.v verilog 代码
//am_fifo_demodulation_fir.v
module am_fifo_demodulation_fir
(
input rst_n,
input clk,
input clk_100mhz,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
reg [15:0] abs_data_r = 0;
reg abs_valid_r = 0;
wire abs_tready_i;
always @(posedge clk)
begin
if(rst_n == 0 )
abs_valid_r <= 0;
else if(abs_tready_i == 1)
abs_valid_r <= s_axis_data_tvalid;
end
always @(posedge clk)
begin
if(rst_n == 0 )
abs_data_r <= 0;
else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
begin
if(s_axis_data_tdata >= 0)
abs_data_r <= s_axis_data_tdata;
else
abs_data_r <= -s_axis_data_tdata;
end
end
assign s_axis_data_tready = abs_tready_i;
wire signed [15:0] fifo_as_tdata_i;
wire fifo_as_tvalid_i;
wire fifo_as_tready_i;
wire fifo_as_clk_i;
wire signed [15:0] fifo_am_tdata_i;
wire fifo_am_tvalid_i;
wire fifo_am_tready_i;
wire fifo_am_clk_i;
wire signed [15:0] fifo_bs_tdata_i;
wire fifo_bs_tvalid_i;
wire fifo_bs_tready_i;
wire fifo_bs_clk_i;
wire signed [15:0] fifo_bm_tdata_i;
wire fifo_bm_tvalid_i;
wire fifo_bm_tready_i;
wire fifo_bm_clk_i;
assign fifo_as_clk_i = clk;
assign fifo_am_clk_i = clk_100mhz;
assign fifo_bs_clk_i = clk_100mhz;
assign fifo_bm_clk_i = clk;
assign fifo_as_tdata_i = abs_data_r;
assign fifo_as_tvalid_i = abs_valid_r;
assign abs_tready_i = fifo_as_tready_i;
axi_fifo_a16 fifo_ua
(
.wr_rst_busy (), // output wire wr_rst_busy
.rd_rst_busy (), // output wire rd_rst_busy
.m_aclk (fifo_am_clk_i), // input wire m_aclk
.s_aclk (fifo_as_clk_i), // input wire s_aclk
.s_aresetn (rst_n), // input wire s_aresetn
.s_axis_tvalid (fifo_as_tvalid_i), // input wire s_axis_tvalid
.s_axis_tready (fifo_as_tready_i), // output wire s_axis_tready
.s_axis_tdata (fifo_as_tdata_i), // input wire [15 : 0] s_axis_tdata
.m_axis_tvalid (fifo_am_tvalid_i), // output wire m_axis_tvalid
.m_axis_tready (fifo_am_tready_i), // input wire m_axis_tready
.m_axis_tdata (fifo_am_tdata_i) // output wire [15 : 0] m_axis_tdata
);
wire fir_a_clk_i;
wire signed [15:0] fir_as_tdata_i;
wire fir_as_tvalid_i;
wire fir_as_tready_i;
wire signed [39:0] fir_am_tdata_i;
wire fir_am_tvalid_i;
wire fir_am_tready_i;
assign fir_a_clk_i = fifo_am_clk_i;
assign fir_as_tvalid_i = fifo_am_tvalid_i;
assign fir_as_tdata_i = fifo_am_tdata_i;
assign fifo_am_tready_i = fir_as_tready_i;
fir_compiler_lowpass_10k_30k_100m am_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (fir_a_clk_i), // input wire aclk
.s_axis_data_tvalid (fir_as_tvalid_i), // input wire s_axis_data_tvalid
.s_axis_data_tready (fir_as_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (fir_as_tdata_i), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_am_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_am_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_am_tdata_i) // output wire [39 : 0] m_axis_data_tdata
);
assign fifo_bs_tvalid_i = fir_am_tvalid_i;
assign fifo_bs_tdata_i = fir_am_tdata_i >>>19;
assign fir_am_tready_i = fifo_bs_tready_i;
axi_fifo_a16 fifo_ub
(
.wr_rst_busy (), // output wire wr_rst_busy
.rd_rst_busy (), // output wire rd_rst_busy
.m_aclk (fifo_bm_clk_i), // input wire m_aclk
.s_aclk (fifo_bs_clk_i), // input wire s_aclk
.s_aresetn (rst_n), // input wire s_aresetn
.s_axis_tvalid (fifo_bs_tvalid_i), // input wire s_axis_tvalid
.s_axis_tready (fifo_bs_tready_i), // output wire s_axis_tready
.s_axis_tdata (fifo_bs_tdata_i), // input wire [15 : 0] s_axis_tdata
.m_axis_tvalid (fifo_bm_tvalid_i), // output wire m_axis_tvalid
.m_axis_tready (fifo_bm_tready_i), // input wire m_axis_tready
.m_axis_tdata (fifo_bm_tdata_i) // output wire [15 : 0] m_axis_tdata
);
assign fifo_bm_tready_i = m_axis_data_tready;
assign m_axis_data_tdata = fifo_bm_tdata_i;
assign m_axis_data_tvalid = fifo_bm_tvalid_i;
endmodule
4. am_fifo_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//am_fifo_fir_testbench.v
module am_fifo_fir_testbench;
reg rst_n;
reg clk;
reg clk_100mhz;
parameter CLK_PERIOD = 1000; //1MHz
parameter CLK_PERIOD_100MHz = 10; //100MHz
initial begin
rst_n = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(1000 * CLK_PERIOD)
$stop;
end
initial
clk = 0;
always
begin
clk = #(CLK_PERIOD/2.0) ~clk;
end
initial
clk_100mhz = 0;
always
begin
clk_100mhz = #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
end
wire signed [15:0] am_mod_tdata; //调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
wire am_mod_tvalid;
wire am_mod_tready;
wire signed [15:0] am_demod_tdata; //经过解调还原的 4KHz 正弦波
wire am_demod_tvalid;
wire am_demod_tready=1;
am_modulation_dds am_u1 //调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.m_axis_data_tdata (am_mod_tdata), //调幅波数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_mod_tvalid),
.m_axis_data_tready (am_mod_tready)
);
am_fifo_demodulation_fir am_u2 //调幅波解调模块,将调幅波解调还原调制信号
(
.clk (clk), //1MHz
.clk_100mhz (clk_100mhz), //100MHz
.rst_n (rst_n), //复位
.s_axis_data_tdata (am_mod_tdata), //调幅信号输入 intput wire [16 : 0]
.s_axis_data_tvalid (am_mod_tvalid),
.s_axis_data_tready (am_mod_tready),
.m_axis_data_tdata (am_demod_tdata), //调幅波解调数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_demod_tvalid),
.m_axis_data_tready (am_demod_tready)
);
endmodule
实验四、FIR 高级应用 - AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO )
1. AM 调幅波调制模块,请参考实验一
2. AM 调幅波解调模块(FIR 高级应用)
3. am_fifo_dc_demodulation_fir.v verilog 代码
//am_fifo_dc_demodulation_fir.v
module am_fifo_dc_demodulation_fir
(
input rst_n,
input clk,
input clk_100mhz,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
wire clk_62_5khz;
reg [3:0] clk_cnt = 0;
reg [15:0] abs_data_r = 0;
reg abs_valid_r = 0;
wire abs_tready_i;
assign clk_62_5khz = clk_cnt[3];
always @(posedge clk)
begin
clk_cnt <= clk_cnt + 1;
end
always @(posedge clk)
begin
if(rst_n == 0 )
abs_valid_r <= 0;
else if(abs_tready_i == 1)
abs_valid_r <= s_axis_data_tvalid;
end
always @(posedge clk)
begin
if(rst_n == 0 )
abs_data_r <= 0;
else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
begin
if(s_axis_data_tdata >= 0)
abs_data_r <= s_axis_data_tdata;
else
abs_data_r <= -s_axis_data_tdata;
end
end
assign s_axis_data_tready = abs_tready_i;
wire signed [15:0] fifo_as_tdata_i;
wire fifo_as_tvalid_i;
wire fifo_as_tready_i;
wire fifo_as_clk_i;
wire signed [15:0] fifo_am_tdata_i;
wire fifo_am_tvalid_i;
wire fifo_am_tready_i;
wire fifo_am_clk_i;
wire signed [15:0] fifo_bs_tdata_i;
wire fifo_bs_tvalid_i;
wire fifo_bs_tready_i;
wire fifo_bs_clk_i;
wire signed [15:0] fifo_bm_tdata_i;
wire fifo_bm_tvalid_i;
wire fifo_bm_tready_i;
wire fifo_bm_clk_i;
assign fifo_as_clk_i = clk;
assign fifo_am_clk_i = clk_100mhz;
assign fifo_bs_clk_i = clk_100mhz;
assign fifo_bm_clk_i = clk_62_5khz;
assign fifo_as_tdata_i = abs_data_r;
assign fifo_as_tvalid_i = abs_valid_r;
assign abs_tready_i = fifo_as_tready_i;
axi_fifo_a16 fifo_ua
(
.wr_rst_busy (), // output wire wr_rst_busy
.rd_rst_busy (), // output wire rd_rst_busy
.m_aclk (fifo_am_clk_i), // input wire m_aclk
.s_aclk (fifo_as_clk_i), // input wire s_aclk
.s_aresetn (rst_n), // input wire s_aresetn
.s_axis_tvalid (fifo_as_tvalid_i), // input wire s_axis_tvalid
.s_axis_tready (fifo_as_tready_i), // output wire s_axis_tready
.s_axis_tdata (fifo_as_tdata_i), // input wire [15 : 0] s_axis_tdata
.m_axis_tvalid (fifo_am_tvalid_i), // output wire m_axis_tvalid
.m_axis_tready (fifo_am_tready_i), // input wire m_axis_tready
.m_axis_tdata (fifo_am_tdata_i) // output wire [15 : 0] m_axis_tdata
);
wire fir_a_clk_i;
wire fir_b_clk_i;
wire signed [15:0] fir_as_tdata_i;
wire fir_as_tvalid_i;
wire fir_as_tready_i;
wire signed [39:0] fir_am_tdata_i;
wire fir_am_tvalid_i;
wire fir_am_tready_i;
wire signed [15:0] fir_bs_tdata_i;
wire fir_bs_tvalid_i;
wire fir_bs_tready_i;
wire signed [39:0] fir_bm_tdata_i;
wire fir_bm_tvalid_i;
wire fir_bm_tready_i;
assign fir_a_clk_i = fifo_am_clk_i;
assign fir_b_clk_i = fifo_am_clk_i;
assign fir_as_tvalid_i = fifo_am_tvalid_i;
assign fir_as_tdata_i = fifo_am_tdata_i; // >>>17;
assign fifo_am_tready_i = fir_as_tready_i;
fir_compiler_lowpass_10k_30k_1m_dec am_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (fir_a_clk_i), // input wire aclk
.s_axis_data_tvalid (fir_as_tvalid_i), // input wire s_axis_data_tvalid
.s_axis_data_tready (fir_as_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (fir_as_tdata_i), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_am_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_am_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_am_tdata_i) // output wire [39 : 0] m_axis_data_tdata
);
assign fir_bs_tvalid_i = fir_am_tvalid_i;
assign fir_bs_tdata_i = fir_am_tdata_i >>>19;
assign fir_am_tready_i = fir_bs_tready_i;
fir_compiler_highpass_30_50_62k am_fir_u2
(
.aresetn (rst_n), // input wire aresetn
.aclk (fir_b_clk_i), // input wire aclk
.s_axis_data_tvalid (fir_bs_tvalid_i), // input wire s_axis_data_tvalid
.s_axis_data_tready (fir_bs_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (fir_bs_tdata_i), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_bm_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_bm_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_bm_tdata_i) // output wire [39 : 0] m_axis_data_tdata
);
// assign fir_bm_tvalid_i = fir_bs_tvalid_i;
// assign fir_bm_tdata_i = fir_bs_tdata_i << 18;
// assign fir_bs_tready_i = fir_bm_tready_i;
assign fifo_bs_tvalid_i = fir_bm_tvalid_i;
assign fifo_bs_tdata_i = fir_bm_tdata_i >>>16;
assign fir_bm_tready_i = fifo_bs_tready_i;
axi_fifo_a16 fifo_ub
(
.wr_rst_busy (), // output wire wr_rst_busy
.rd_rst_busy (), // output wire rd_rst_busy
.m_aclk (fifo_bm_clk_i), // input wire m_aclk
.s_aclk (fifo_bs_clk_i), // input wire s_aclk
.s_aresetn (rst_n), // input wire s_aresetn
.s_axis_tvalid (fifo_bs_tvalid_i), // input wire s_axis_tvalid
.s_axis_tready (fifo_bs_tready_i), // output wire s_axis_tready
.s_axis_tdata (fifo_bs_tdata_i), // input wire [15 : 0] s_axis_tdata
.m_axis_tvalid (fifo_bm_tvalid_i), // output wire m_axis_tvalid
.m_axis_tready (fifo_bm_tready_i), // input wire m_axis_tready
.m_axis_tdata (fifo_bm_tdata_i) // output wire [15 : 0] m_axis_tdata
);
assign fifo_bm_tready_i = m_axis_data_tready;
assign m_axis_data_tdata = fifo_bm_tdata_i;
assign m_axis_data_tvalid = fifo_bm_tvalid_i;
endmodule
4. am_fifo_dc_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//am_fifo_dc_fir_testbench.v
module am_fifo_dc_fir_testbench;
reg rst_n;
reg clk;
reg clk_100mhz;
parameter CLK_PERIOD = 1000; //1MHz
parameter CLK_PERIOD_100MHz = 10; //100MHz
initial begin
rst_n = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(80000 * CLK_PERIOD)
$stop;
end
initial
clk = 0;
always
begin
clk = #(CLK_PERIOD/2.0) ~clk;
end
initial
clk_100mhz = 0;
always
begin
clk_100mhz = #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
end
wire signed [15:0] am_mod_tdata; //调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
wire am_mod_tvalid;
wire am_mod_tready;
wire signed [15:0] am_demod_tdata; //经过解调还原的 4KHz 正弦波
wire am_demod_tvalid;
wire am_demod_tready=1;
am_modulation_dds am_u1 //调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.m_axis_data_tdata (am_mod_tdata), //调幅波数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_mod_tvalid),
.m_axis_data_tready (am_mod_tready)
);
am_fifo_dc_demodulation_fir am_u2 //调幅波解调模块,将调幅波解调还原调制信号
(
.clk (clk), //1MHz
.clk_100mhz (clk_100mhz), //100MHz
.rst_n (rst_n), //复位
.s_axis_data_tdata (am_mod_tdata), //调幅信号输入 intput wire [16 : 0]
.s_axis_data_tvalid (am_mod_tvalid),
.s_axis_data_tready (am_mod_tready),
.m_axis_data_tdata (am_demod_tdata), //调幅波解调数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_demod_tvalid),
.m_axis_data_tready (am_demod_tready)
);
endmodule
实验五、FIR 高级应用 - 多通道实验 (四个通道用一个 FIR IP,每通道用不同的系数)。
1. FIR 多通道模块(FIR 高级应用)
2. multichannel_fir.v verilog 代码
//multichannel_fir.v
module multichannel_fir
(
input rst_n,
input clk,
input clk_100mhz,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[63:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[63:0] m_axis_data_tdata
);
wire [63:0] fifo_as_tdata_i;
wire fifo_as_tvalid_i;
wire fifo_as_full_i;
wire fifo_as_clk_i;
wire signed [15:0] fifo_am_tdata_i;
wire fifo_am_tvalid_i;
wire fifo_am_rden_i;
wire fifo_am_empty_i;
wire fifo_am_clk_i;
wire signed [15:0] fifo_bs_tdata_i;
wire fifo_bs_tvalid_i;
wire fifo_bs_full_i;
wire fifo_bs_clk_i;
wire signed [63:0] fifo_bm_tdata_i;
wire fifo_bm_tvalid_i;
wire fifo_bm_rden_i;
wire fifo_bm_empty_i;
wire fifo_bm_clk_i;
assign fifo_as_clk_i = clk;
assign fifo_am_clk_i = clk_100mhz;
assign fifo_bs_clk_i = clk_100mhz;
assign fifo_bm_clk_i = clk;
assign fifo_as_tdata_i = s_axis_data_tdata;
assign fifo_as_tvalid_i = s_axis_data_tvalid;
assign s_axis_data_tready = ~fifo_as_full_i;
assign fifo_am_tvalid_i = fifo_am_rden_i & ~fifo_am_empty_i;
fifo_w64_r16 fifo_ua
(
.rst (~rst_n), // input wire rst
.wr_clk (fifo_as_clk_i), // input wire wr_clk
.rd_clk (fifo_am_clk_i), // input wire rd_clk
.din (fifo_as_tdata_i), // input wire [63 : 0] din
.wr_en (fifo_as_tvalid_i), // input wire wr_en
.rd_en (fifo_am_rden_i), // input wire rd_en
.dout (fifo_am_tdata_i), // output wire [15 : 0] dout
.full (fifo_as_full_i), // output wire full
.empty (fifo_am_empty_i) // output wire empty
);
wire fir_a_clk_i;
wire signed [15:0] fir_as_tdata_i;
wire fir_as_tvalid_i;
wire fir_as_tready_i;
wire signed [39:0] fir_am_tdata_i;
wire fir_am_tvalid_i;
wire fir_am_tready_i;
wire [1:0] fir_am_tuser_i;
wire [7:0] fir_as_config_tdata_i;
wire fir_as_config_tvalid_i;
wire fir_as_config_tready_i;
wire fir_as_config_tlast_i;
wire event_s_config_tlast_missing_i;
wire event_s_config_tlast_unexpected_i;
reg [7:0] s_cfg_cnt = 0;
reg [7:0] s_config_tdata_r = 0;
assign fir_a_clk_i = fifo_am_clk_i;
assign fir_as_tvalid_i = fifo_am_tvalid_i;
assign fir_as_tdata_i = fifo_am_tdata_i;
assign fifo_am_rden_i = fir_as_tready_i;
reg [31:0] time_cnt = 0;
reg [7:0] channel_id_r = 0;
wire [31:0] load_cfg;
always @(posedge fir_a_clk_i)
begin
time_cnt <= time_cnt + 1;
end
assign load_cfg = ( time_cnt[14:0] == 15'h4000 && time_cnt > 'h8000 && time_cnt < 'h30000 ) ? 1:0;
always @(posedge fir_a_clk_i)
begin
if(rst_n == 0)
begin
channel_id_r <= 0;
end
else if(fir_as_config_tlast_i == 1 && fir_as_config_tvalid_i == 1 && fir_as_config_tready_i == 1 && channel_id_r < 4)
begin
channel_id_r <= channel_id_r +1;
end
end
always @(posedge fir_a_clk_i)
begin
if(load_cfg == 1)
begin
s_cfg_cnt <= 4;
if(channel_id_r <4)
s_config_tdata_r <= 3 - channel_id_r; //按 3/2/1/0 顺序
else
s_config_tdata_r <= 0;
end
else if(fir_as_config_tready_i == 1 && fir_as_config_tvalid_i == 1 && s_cfg_cnt != 0)
begin
s_cfg_cnt <= s_cfg_cnt -1;
if(channel_id_r ==4)
begin
s_config_tdata_r <= s_config_tdata_r + 1;
end
end
end
assign fir_as_config_tvalid_i = s_cfg_cnt == 0 ? 0:1;
assign fir_as_config_tdata_i = s_config_tdata_r;
assign fir_as_config_tlast_i = s_cfg_cnt == 1 ? 1:0;
fir_compiler_mc4_512 multichannel_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (fir_a_clk_i), // input wire aclk
.s_axis_data_tvalid (fir_as_tvalid_i), // input wire s_axis_data_tvalid
.s_axis_data_tready (fir_as_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (fir_as_tdata_i), // input wire [15 : 0] s_axis_data_tdata
.s_axis_config_tvalid (fir_as_config_tvalid_i), // input wire s_axis_config_tvalid
.s_axis_config_tready (fir_as_config_tready_i), // output wire s_axis_config_tready
.s_axis_config_tlast (fir_as_config_tlast_i), // input wire s_axis_config_tlast
.s_axis_config_tdata (fir_as_config_tdata_i), // input wire [7 : 0] s_axis_config_tdata
.m_axis_data_tvalid (fir_am_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_am_tready_i), // input wire m_axis_data_tready
.m_axis_data_tuser (fir_am_tuser_i), // output wire [1 : 0] m_axis_data_tuser
.m_axis_data_tdata (fir_am_tdata_i), // output wire [39 : 0] m_axis_data_tdata
.event_s_config_tlast_missing (event_s_config_tlast_missing_i), // output wire event_s_config_tlast_missing
.event_s_config_tlast_unexpected(event_s_config_tlast_unexpected_i) // output wire event_s_config_tlast_unexpected
);
assign fifo_bs_tvalid_i = fir_am_tvalid_i;
assign fifo_bs_tdata_i = fir_am_tdata_i >>>24;
assign fir_am_tready_i = ~fifo_bs_full_i;
fifo_w16_r64 fifo_ub
(
.rst (~rst_n), // input wire rst
.wr_clk (fifo_bs_clk_i), // input wire wr_clk
.rd_clk (fifo_bm_clk_i), // input wire rd_clk
.din (fifo_bs_tdata_i), // input wire [16 : 0] din
.wr_en (fifo_bs_tvalid_i), // input wire wr_en
.rd_en (fifo_bm_rden_i), // input wire rd_en
.dout (fifo_bm_tdata_i), // output wire [63 : 0] dout
.full (fifo_bs_full_i), // output wire full
.empty (fifo_bm_empty_i) // output wire empty
);
assign fifo_bm_rden_i = m_axis_data_tready;
assign fifo_bm_tvalid_i = fifo_bm_rden_i & ~fifo_bm_empty_i;
assign m_axis_data_tdata = fifo_bm_tdata_i;
assign m_axis_data_tvalid = fifo_bm_tvalid_i;
endmodule
3. multichannel_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//multichannel_fir_testbench.v
module multichannel_fir_testbench;
reg rst_n;
reg ts;
reg clk;
reg clk_100mhz;
reg clk_10khz;
reg clk_30khz;
reg clk_50khz;
reg clk_70khz;
parameter CLK_PERIOD = 476.1904762; //2.1MHz
parameter CLK_PERIOD_100MHz = 10; //100MHz
parameter CLK_10K = CLK_PERIOD * 210;
parameter CLK_30K = CLK_PERIOD * 70;
parameter CLK_50K = CLK_PERIOD * 42;
parameter CLK_70K = CLK_PERIOD * 30;
initial begin
rst_n = 0;
ts = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(4500 * CLK_PERIOD)
ts = 1;
#(1000 * CLK_PERIOD)
$stop;
end
initial
begin
clk = 0;
clk_100mhz = 0;
clk_10khz = 0;
clk_30khz = 0;
clk_50khz = 0;
clk_70khz = 0;
end
always clk = #(CLK_PERIOD/2.0) ~clk;
always clk_100mhz = #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
always clk_10khz = #(CLK_10K/2.0) ~clk_10khz;
always clk_30khz = #(CLK_30K/2.0) ~clk_30khz;
always clk_50khz = #(CLK_50K/2.0) ~clk_50khz;
always clk_70khz = #(CLK_70K/2.0) ~clk_70khz;
wire signed[15:0] s_tdata[3:0];
wire s_tvalid;
wire s_tready;
wire signed[15:0] m_tdata[3:0];
wire m_tvalid;
wire m_tready = 1;
assign s_tdata[0] = clk_10khz == 0 ? -10000:10000;
assign s_tdata[1] = ts == 0 ? {clk_30khz == 0 ? -10000:10000}:s_tdata[0];
assign s_tdata[2] = ts == 0 ? {clk_50khz == 0 ? -10000:10000}:s_tdata[0];
assign s_tdata[3] = ts == 0 ? {clk_70khz == 0 ? -10000:10000}:s_tdata[0];
assign s_tvalid = s_tready;
multichannel_fir u1
(
.clk (clk), //1MHz
.clk_100mhz (clk_100mhz),
.rst_n (rst_n),
.s_axis_data_tdata ({s_tdata[0],s_tdata[1],s_tdata[2],s_tdata[3]}),
.s_axis_data_tvalid (s_tvalid),
.s_axis_data_tready (s_tready),
.m_axis_data_tdata ({m_tdata[0],m_tdata[1],m_tdata[2],m_tdata[3]}),
.m_axis_data_tvalid (m_tvalid),
.m_axis_data_tready (m_tready)
);
endmodule
4. fir_compiler_mc4_512 FIR IP 设置需要关注的地方
5. FIR 多通道实验时序图
6. FIR 多通道实验时序图CONFIG 时序细节放大
实验六、FIR 高级应用 FIR Reload的使用。
- Reload 模块很简单只有一个 FIR IP 这里就不介绍框图了。把代码、时序时序贴出来看看。
1. reload_fir.v verilog 代码
//reload_fir.v
module reload_fir
(
input rst_n,
input clk,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
wire fir_tlast_missing;
wire fir_tlast_unexpected;
wire [39:0] m_axis_data_tdata_i;
wire[15:0] fir_reload_dat[3:0][127:0];
reg [15:0] fir_dat0[127:0];
reg [15:0] fir_dat1[127:0];
reg [15:0] fir_dat2[127:0];
reg [15:0] fir_dat3[127:0];
wire [07:0] fir_s_cfg_tdata;
wire fir_s_cfg_tvalid;
wire fir_s_cfg_tready;
reg [15:0] fir_s_reload_tdata;
reg fir_s_reload_tvalid;
wire fir_s_reload_tready;
reg fir_s_reload_tlast;
genvar m;
for(m=0;m<128;m=m+1)
begin:for_mx
assign fir_reload_dat[0][m] = fir_dat0[m];
assign fir_reload_dat[1][m] = fir_dat1[m];
assign fir_reload_dat[2][m] = fir_dat2[m];
assign fir_reload_dat[3][m] = fir_dat3[m];
end
initial
begin
$readmemh("../../../../../reload_bandpass_10k_30k_30k_50k_1m.txt", fir_dat0);
$readmemh("../../../../../reload_bandpass_30k_50k_50k_70k_1m.txt", fir_dat1);
$readmemh("../../../../../reload_bandpass_50k_70k_70k_90k_1m.txt", fir_dat2);
$readmemh("../../../../../reload_bandpass_70k_90k_90k_110k_1m.txt", fir_dat3);
end
parameter NUMBER_COE_SIZE = 128; //64;
parameter NUMBER_COE_SETS = 2; //
reg [15:0] reload_cnt=16'hffff;
reg [15:0] cfg_cnt=0;
wire reload_en;
reg [1:0] reload_sn=0;
reg[15:0] fir_cntx=0;
reg[15:0] psel=0;
reg[15:0] w_psel=1;
assign fir_s_cfg_tdata = psel;
assign fir_s_cfg_tvalid = cfg_cnt == 0 ? 1:0;
assign reload_en = fir_cntx[9:0] == 0 && fir_cntx != 0 ? 1:0;
always @(posedge clk)
begin
if(rst_n == 0 )
begin
fir_s_reload_tdata <= 0;
fir_s_reload_tvalid <= 0;
fir_s_reload_tlast <= 0;
end
else if(fir_s_reload_tready == 1)
begin
if(NUMBER_COE_SETS == 1)
begin
if(reload_cnt == NUMBER_COE_SIZE-1)
fir_s_reload_tlast <= 1;
else
fir_s_reload_tlast <= 0;
if(reload_cnt < NUMBER_COE_SIZE)
begin
fir_s_reload_tdata <= fir_reload_dat[reload_sn][reload_cnt];
fir_s_reload_tvalid <= 1;
end
else
begin
fir_s_reload_tdata <= 0;
fir_s_reload_tvalid <= 0;
end
end
else
begin
if(reload_cnt == NUMBER_COE_SIZE)
fir_s_reload_tlast <= 1;
else
fir_s_reload_tlast <= 0;
if(reload_cnt<NUMBER_COE_SIZE+1)
begin
fir_s_reload_tvalid <= 1;
if(reload_cnt == 0)
fir_s_reload_tdata <= w_psel;
else
fir_s_reload_tdata <= fir_reload_dat[reload_sn][reload_cnt-1];
end
else
begin
fir_s_reload_tdata <= 0;
fir_s_reload_tvalid <= 0;
end
end
end
end
always @(posedge clk)
begin
if(rst_n == 0 )
begin
fir_cntx <= 0;
end
else if(fir_s_reload_tready == 1 && fir_s_cfg_tready == 1)
begin
fir_cntx <= fir_cntx + 1;
end
end
always @(posedge clk)
begin
if(rst_n == 0 )
begin
reload_sn <= 0;
psel <= 0;
end
else if(fir_s_reload_tlast == 1 && fir_s_reload_tready == 1)
begin
reload_sn <= reload_sn + 1;
psel <= 1;
end
end
always @(posedge clk)
begin
if(rst_n == 0 )
begin
reload_cnt <= 16'hffff;
end
else if(reload_en == 1)
begin
reload_cnt <= 0;
end
else if(fir_s_reload_tready == 1)
begin
if(reload_cnt != 16'hffff)
reload_cnt <= reload_cnt + 1;
end
end
always @(posedge clk)
begin
if(rst_n == 0 ||(fir_s_reload_tlast == 1 && fir_s_reload_tready == 1))
begin
cfg_cnt <= 0;
end
else if(fir_s_cfg_tready == 1)
begin
if(fir_s_cfg_tvalid == 1 || cfg_cnt != 16'hffff)
cfg_cnt <= cfg_cnt + 1;
end
end
assign m_axis_data_tdata = m_axis_data_tdata_i >> 18;
reload_fir_256x2 am_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (clk), // input wire aclk
.s_axis_config_tvalid (fir_s_cfg_tvalid), // input wire s_axis_config_tvalid
.s_axis_config_tready (fir_s_cfg_tready), // output wire s_axis_config_tready
.s_axis_config_tdata (fir_s_cfg_tdata), // input wire [7 : 0] s_axis_config_tdata
.s_axis_reload_tvalid (fir_s_reload_tvalid), // input wire s_axis_reload_tvalid
.s_axis_reload_tready (fir_s_reload_tready), // output wire s_axis_reload_tready
.s_axis_reload_tlast (fir_s_reload_tlast), // input wire s_axis_reload_tlast
.s_axis_reload_tdata (fir_s_reload_tdata), // input wire [15 : 0] s_axis_reload_tdata
.s_axis_data_tvalid (s_axis_data_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready (s_axis_data_tready), // output wire s_axis_data_tready
.s_axis_data_tdata (s_axis_data_tdata), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready (m_axis_data_tready), // input wire m_axis_data_tready
.m_axis_data_tdata (m_axis_data_tdata_i), // output wire [39 : 0] m_axis_data_tdata
.event_s_reload_tlast_missing (fir_tlast_missing), // output wire event_s_reload_tlast_missing
.event_s_reload_tlast_unexpected(fir_tlast_unexpected) // output wire event_s_reload_tlast_unexpected
);
endmodule
2. reload_fir_testbench.v verilog 代码
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//reload_fir_testbench.v
module reload_fir_testbench;
reg rst_n;
reg clk;
reg clk_10khz;
parameter CLK_PERIOD = 1000; //1MHz 采样频率
parameter CLK_10K = CLK_PERIOD * 100;
initial begin
rst_n = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(6000 * CLK_PERIOD)
$stop;
end
initial
begin
clk = 0;
clk_10khz = 0;
end
always clk = #(CLK_PERIOD/2.0) ~clk;
always clk_10khz = #(CLK_10K/2.0) ~clk_10khz;
wire signed[15:0] s_tdata;
wire s_tvalid;
wire s_tready;
wire signed[15:0] m_tdata;
wire m_tvalid;
wire m_tready;
assign s_tdata = clk_10khz == 0 ? -10000:10000;
assign s_tvalid = s_tready;
assign m_tready = 1;
reload_fir am_fir_u1
(
.rst_n (rst_n), // input wire aresetn
.clk (clk), // input wire aclk
.s_axis_data_tvalid (s_tvalid), // input wire s_axis_data_tvalid
.s_axis_data_tready (s_tready), // output wire s_axis_data_tready
.s_axis_data_tdata (s_tdata), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (m_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready (m_tready), // input wire m_axis_data_tready
.m_axis_data_tdata (m_tdata) // output wire [15 : 0] m_axis_data_tdata
);
endmodule
3. FIR 高级应用 FIR Reload时序图
4. FIR 高级应用 FIR Reload细节时序图放大1
5. FIR 高级应用 FIR Reload细节时序图放大2
6. reload_fir FIR 高级应用 FIR IP 设置需要关注的地方1
7. reload_fir FIR 高级应用 FIR IP 设置需要关注的地方2
实验一、三综合布线后 FPGA 资源对比
实验一、三的AM解调部分单独综合布线后的FPGA资源占用报告
- 实验一和实验三的区别
- 实验一FIR IP 的工作时钟为 1MHz,AM 数据的采样频率为 1MHz 。
- 实验三FIR IP 的工作时钟为 100MHz,AM 数据的采样频率为 1MHz 。在 FIR 前后加了两个 FIFO。
- 从资源占用图可以看出 这两个 FIFO 只占用了 1 个 BRAM块(一个FIFO占用0.5个)。
- 从资源占用图可以看出 实验三的资源占用远少于实验一,特别是 DSP 这种珍贵资源的的占用只有 1个。实验三只多了 1 个BRAM块。这样的交换是非常划算的。
- 实验三仿真运行相比实验一非常慢
三、 实验相关 vivado 工程、IP 设置等详细文档连接,采用 Xilinx vivado 2017.4 版本
-
XILINX FIR IP 详解、Verilog 源码、Vivado 工程
-
实验一、FIR 基础应用 - AM 调幅波调制解调(FIR 低通滤波)详细介绍
-
实验二、FIR 基础应用 - FM 调频波调制解调(FIR 低通滤波) 详细介绍
-
实验三、FIR 中级应用 - AM 调幅波调制解调(FIR + FIFO)详细介绍
-
实验四、FIR 高级应用 - AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO ) 详细介绍
-
实验五、FIR 高级应用 - 多通道实验 (四个通道用一个 FIR IP,每通道用不同的系数) 详细介绍
-
实验六、FIR 高级应用 FIR Reload的使用) 详细介绍
-
实验一、 AM 调幅波调制解调(FIR 低通滤波) vivado 工程文件下载
-
实验二、 FM 调频波调制解调(FIR 低通滤波) Vivado 工程文件下载
-
实验三、 AM 调幅波调制解调(FIR + FIFO) Vivado 工程文件下载
-
实验四、 AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO ) Vivado 工程文件下载
-
实验五、 FIR 高级应用 - 多通道实验 Vivado 工程文件下载
-
实验六、 FIR 高级应用 FIR Reload 的使用 vivado 工程文件下载