2ASK调制基带信号 vivado实现

前几天一直在配置个博客引导页,所以在 vivado 上的 2ASK 调制拖得比较久,虽然 2ASK 是比较简单地实现键控信号不过利用Verilogvivado上面实现,还是需要不少功夫的(从无到有的慢慢调的时候就知道了)。主要思路就是结合前置的基带信号、DDS发出载波信号、乘法器、滤波器(前面在 Matlab 上面用的成形 filter 这边就没有再搞了,毕竟现在频带资源丰富👻)。思路的话还是比较简单的,可以看看下面的RTL工程图很好理解

ASK的基本原理在前面Matlab实现的时候提过了,这边就不赘述了,下面主要介绍如何在Vivado上面实现这一调制技术,摸索了很多网上写的开发记录,不过还是感觉不太合意吧,所以我也会讲讲如何进行Debug

DDS、MULTIPLIER IP核设定

  • DDS主要参数

  • System Clock - 50MHz
  • 可以调调SFDR - 无杂散动态范围
  • Parameters 中需要在Hardware里调下output Width 这边可以康康官方的DDS IP核解释 因为包含sin cos 的生成所以这边只需要8的宽度,然后看下IP Symbol中的m_axis_data_tdata是否为 [15:0] ,这是为了后面输入乘法器的输入端配对宽度
  • 千万记得在OUTPUT那边选定通道设定输出载波频率
  • 如果忘了的话,一般需要可以通过逐步检查RTL工程图上的输入端是哪里没有工作,可以先仿真然后康从哪里没有信号,再回来找,最离谱的是有时候你设定了,它可能会给你覆盖掉,所以最后仿真如果死了,可以先来康康


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文件的时候不能直接复制,需要进行一定的语法修改,这个按照报错来改就行
  • reg、wire的经典问题我觉得就遇到报错改吧
  • 记得修改定义引脚 - 比如时钟

Bug 群

经过上面的步骤基本可以进行仿真了,不过一般来说是不会这么顺利的,主要的Debug其实就是围绕如何将每一级信号有效输出

  • 基本方法 - 观察dout是否有输出你要的键控信号,然后结合RTL分析图和文件代码分级调试知道有效输出

  • 我遇到的就比如忘记给DDS加时钟激励,这时候如果没有做RTL工程的分析,就无法直接从图中看出DDS没有输出信号是因为IP核模块没有输入激励时钟信号,所以出现信号无效时可以回过头康康RTL工程图的相关路径什么的是否有出错也是个不错的方法
  • 再比如tb文件没有加乘法器的激励时钟😓😓😓
  • 最后如果仿真图出现“ xxx ”这时候就是未知波形图的意思,一般的原因是因为有部分关键的信号名没有设置位宽,导致赋值执行的时候,其不确定性的存在
  • 就像这边我的输入信号数组没有定义宽度 - din


最后就可以欣赏下调制技术啦🥳

项目代码已开源至我的 Github 上

https://github.com/HY-Kevin/share_exploring

过几天应该会做下4ASK的调制技术以及ASK解调的实现,然后如果有空的话我也会提供下引导页的简易制作方案😁