前几天一直在配置个博客引导页,所以在 vivado 上的 2ASK 调制拖得比较久,虽然 2ASK 是比较简单地实现键控信号不过利用Verilog
在vivado
上面实现,还是需要不少功夫的(从无到有的慢慢调的时候就知道了)。主要思路就是结合前置的基带信号、DDS发出载波信号、乘法器、滤波器(前面在 Matlab 上面用的成形 filter 这边就没有再搞了,毕竟现在频带资源丰富👻)。思路的话还是比较简单的,可以看看下面的RTL工程图很好理解
ASK的基本原理在前面Matlab
实现的时候提过了,这边就不赘述了,下面主要介绍如何在Vivado
上面实现这一调制技术,摸索了很多网上写的开发记录,不过还是感觉不太合意吧,所以我也会讲讲如何进行Debug
DDS、MULTIPLIER IP核设定
COMPILER主要参数
A - unsigned 2 Width
B - signed 14 Width
代码例化 - 引出必要接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| `timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Create Date: 2023/01/13 15:23:21 // Design Name: ASK // Module Name: ASK_modulation // author: Kevin //////////////////////////////////////////////////////////////////////////////////
module ASK_modulation( input rst_n, input sys_clk, input [1:0] din, output signed [13:0] dout ); wire out_valid; wire [15:0] dds_data; wire [13:0] sin_data = dds_data[13:0];
dds_compiler_0 U0 ( .aclk(sys_clk), // input wire aclk .m_axis_data_tvalid(out_valid), // output wire m_axis_data_tvalid .m_axis_data_tdata(dds_data) // output wire [31 : 0] m_axis_data_tdata );
wire signed [15:0] ask_data;
mult_gen_0 U1 ( .CLK(sys_clk), .A(din), // input wire [1 : 0] A .B(sin_data), // input wire [13 : 0] B .P(ask_data) // output wire [15 : 0] P );
endmodule
|
- 设计的顶层文件主要就是定义下引出的接口然后从VEO文件中将例化代码转移过来
重点:tb文件的设计
tb仿真文件的设计最先的难点就是如何引入基带信号,我还是通过Matlab生成基带信号然后导入到vivado
。不过需要设计的是,因为我们是需要一个信号一个信号的读取,即如何实现利用输入信号din
来键控载波信号
想法:利用大容量数组先将信号存在足够大的DATA中,然后再逐一赋值给小容量的din
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| initial begin sys_clk = 0; forever begin #10 sys_clk = ~sys_clk; end end
initial begin data_clk = 0; forever begin #5000 data_clk = ~data_clk; end end
reg [3:0] data [0:4096]; //输入Matlab基带信号 initial begin $readmemh("signal_in.txt", data); end initial begin rst_n = 0; #5000 rst_n = 1; end
always@(posedge data_clk)begin
din <=data[data_cnt][3-data_cnt[1:0]]; data_cnt = data_cnt + 1; end
|
这就实现了基带信号的输入与读取,然后接下来是引入乘法器与DDS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| //重置的时候注意检查IP核是否有输出频率被暗修改 dds_compiler_0 U0 ( .aclk(sys_clk), // input wire aclk .m_axis_data_tvalid(out_valid), // output wire m_axis_data_tvalid .m_axis_data_tdata(dds_data) // output wire [31 : 0] m_axis_data_tdata ); mult_gen_0 U1 ( .CLK(sys_clk), .A(din), // input wire [1 : 0] A .B(sin_data), // input wire [13 : 0] B .P(ask_data) // output wire [15 : 0] P ); //做截尾输出 assign dout = ask_data[15:2];
|
- 参考VEO文件的时候不能直接复制,需要进行一定的语法修改,这个按照报错来改就行
Bug 群
经过上面的步骤基本可以进行仿真了,不过一般来说是不会这么顺利的,主要的Debug其实就是围绕如何将每一级信号有效输出
基本方法 - 观察dout是否有输出你要的键控信号,然后结合RTL分析图和文件代码分级调试知道有效输出
我遇到的就比如忘记给DDS加时钟激励,这时候如果没有做RTL工程的分析,就无法直接从图中看出DDS没有输出信号是因为IP核模块没有输入激励时钟信号,所以出现信号无效时可以回过头康康RTL工程图的相关路径什么的是否有出错也是个不错的方法
最后如果仿真图出现“ xxx ”这时候就是未知波形图的意思,一般的原因是因为有部分关键的信号名没有设置位宽,导致赋值执行的时候,其不确定性的存在
就像这边我的输入信号数组没有定义宽度 - din
最后就可以欣赏下调制技术啦🥳
项目代码已开源至我的 Github 上
https://github.com/HY-Kevin/share_exploring
过几天应该会做下4ASK的调制技术以及ASK解调的实现,然后如果有空的话我也会提供下引导页的简易制作方案😁