目录
一、功能定义
二、设计输入
1、主模块
2、DDS模块
3、 按键消抖模块
三、功能仿真
四、综合优化
五、布局布线
六、时序仿真
七、板级调试
代码规范:Verilog 代码规范_verilog代码编写规范-CSDN博客
开发流程:FPGA基础知识----第二章 FPGA 开发流程_fpga 一个项目的整个流程-CSDN博客
源码下载:GitHub - Redamancy785/FPGA-Learning-Record: 项目博客:https://blog.csdn.net/weixin_51460407
一、功能定义
二、设计输入
1、主模块
这段代码是一个Verilog模块,名为
dds_ad9767
,它实现了一个双通道的直接数字频率合成器(DDS)系统。DDS是一种用于生成模拟波形(如正弦波、方波等)的电子技术,广泛应用于信号发生器、通信系统等领域。这个模块特别为与AD9767这类数字信号处理器(DSP)芯片协同工作而设计。
/*
Tips:
1、可分别于A、B通道同时输出两路波形
2、每次按下 f_switch_button_a_i , 通道A输出频率在预设的四种情况切换;通道B同理。
3、每次按下 p_switch_button_a_i , 通道A输出相位在预设的两种情况切换;通道B同理。
*/
module dds_ad9767(
reset_n_i,
clk_i,
mode_switch_button_a_i,
f_switch_button_a_i,
p_switch_button_a_i,
mode_switch_button_b_i,
f_switch_button_b_i,
p_switch_button_b_i,
data_a_o,
data_b_o
);
input reset_n_i,clk_i;
input [1:0]mode_switch_button_a_i,mode_switch_button_b_i;
input f_switch_button_a_i,p_switch_button_a_i,f_switch_button_b_i,p_switch_button_b_i;
output [13:0] data_a_o;
output [13:0] data_b_o;
// A通道dds例化
reg [31:0] u_f_word_a;
reg [11:0] u_p_word_a;
dds U_dds_a(
.reset_n_i(reset_n_i),
.clk_i(clk_i),
.f_word_i(u_f_word_a),
.p_word_i(u_p_word_a),
.mode_i(mode_switch_button_a_i),
.data_o(data_a_o)
);
// A通道频率切换
wire f_switch_button_a_press_key_flag;
key_filter U_f_switch_button_a_i(
.clk_i(clk_i),
.reset_n_i(reset_n_i),
.key_i(f_switch_button_a_i),
.press_key_flag_o(f_switch_button_a_press_key_flag)
);
reg [1:0] f_switch_cnt_a;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
f_switch_cnt_a <= 0;
else if(f_switch_button_a_press_key_flag == 1)
f_switch_cnt_a <= f_switch_cnt_a + 1;
always@(*)
case(f_switch_cnt_a)
0 : u_f_word_a <= 65536;
1 : u_f_word_a <= 65536*2;
2 : u_f_word_a <= 65536*3;
3 : u_f_word_a <= 65536*4;
endcase
// A通道相位切换
wire p_switch_button_a_press_key_flag;
key_filter U_p_switch_button_a_i(
.clk_i(clk_i),
.reset_n_i(reset_n_i),
.key_i(p_switch_button_a_i),
.press_key_flag_o(p_switch_button_a_press_key_flag)
);
reg p_switch_cnt_a;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
p_switch_cnt_a <= 0;
else if(p_switch_button_a_press_key_flag == 1)
p_switch_cnt_a <= p_switch_cnt_a + 1;
always@(*)
case(p_switch_cnt_a)
0 : u_p_word_a <= 0;
1 : u_p_word_a <= 1024;
endcase
// B通道dds例化
reg [31:0] u_f_word_b;
reg [11:0] u_p_word_b;
dds U_dds_b(
.reset_n_i(reset_n_i),
.clk_i(clk_i),
.f_word_i(u_f_word_b),
.p_word_i(u_p_word_b),
.mode_i(mode_switch_button_b_i),
.data_o(data_b_o)
);
// B通道频率切换
wire f_switch_button_b_press_key_flag;
key_filter U_f_switch_button_b_i(
.clk_i(clk_i),
.reset_n_i(reset_n_i),
.key_i(f_switch_button_b_i),
.press_key_flag_o(f_switch_button_b_press_key_flag)
);
reg [1:0] f_switch_cnt_b;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
f_switch_cnt_b <= 0;
else if(f_switch_button_b_press_key_flag == 1)
f_switch_cnt_b <= f_switch_cnt_b + 1;
always@(*)
case(f_switch_cnt_b)
0 : u_f_word_b <= 65536;
1 : u_f_word_b <= 65536*2;
2 : u_f_word_b <= 65536*3;
3 : u_f_word_b <= 65536*4;
endcase
// B通道相位切换
wire p_switch_button_b_press_key_flag;
key_filter U_p_switch_button_b_i(
.clk_i(clk_i),
.reset_n_i(reset_n_i),
.key_i(p_switch_button_b_i),
.press_key_flag_o(p_switch_button_b_press_key_flag)
);
reg p_switch_cnt_b;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
p_switch_cnt_b <= 0;
else if(p_switch_button_b_press_key_flag == 1)
p_switch_cnt_b <= p_switch_cnt_b + 1;
always@(*)
case(p_switch_cnt_b)
0 : u_p_word_b <= 0;
1 : u_p_word_b <= 1024;
endcase
endmodule
2、DDS模块
1、IP设置
2、初始文件生成设置
3、代码部分
这段代码是一个Verilog模块,名为
dds
,它实现了一个直接数字频率合成器(DDS)的功能。DDS是一种电子系统,能够通过数字技术生成模拟波形,如正弦波、方波和三角波等。这个模块通过接收频率字(f_word_i
)和相位字(p_word_i
)输入,以及模式选择信号(mode_i
),来输出相应的波形数据。
/*
Tips:
1、修改 mode_i 可以切换三种不同的输出波形
2、f_word_i 频率字输入,当等于典型值2^16=65536时,dds输出的波形频率在738Hz左右
3、p_word_i 相位字输入,当等于典型值1024时,dds输出的波形起始相位为90°
*/
module dds(
reset_n_i,
clk_i,
f_word_i,
p_word_i,
mode_i,
data_o
);
input [1:0] mode_i;
input reset_n_i,clk_i;
input [31:0]f_word_i;
input [11:0]p_word_i;
output reg [13:0] data_o;
// 频率字输入寄存器 r_f_word_i
reg [31:0] r_f_word_i;
always@(posedge clk_i)
r_f_word_i <= f_word_i;
// 相位字输入寄存器 r_f_word_i
reg [11:0] r_p_word_i;
always@(posedge clk_i)
r_p_word_i <= p_word_i;
// 相位累加器 phase_accumulator
reg [31:0] phase_accumulator;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
phase_accumulator <= 0;
else
phase_accumulator <= phase_accumulator + r_f_word_i;
// 波形数据表地址 rom_addr
reg [11:0] rom_addr;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
rom_addr <= 0;
else
rom_addr <= r_p_word_i + phase_accumulator[31:20];
// sine波形
wire [13:0] sine_data_o;
sine_rom U_sine_rom (
.clka(clk_i), // input wire clka
.addra(rom_addr), // input wire [11 : 0] addra
.douta(sine_data_o) // output wire [13 : 0] douta
);
// square波形
wire [13:0] square_data_o;
square_rom U_square_rom (
.clka(clk_i), // input wire clka
.addra(rom_addr), // input wire [11 : 0] addra
.douta(square_data_o) // output wire [13 : 0] douta
);
// triangular波形
wire [13:0] triangular_data_o;
triangular_rom U_triangular_rom (
.clka(clk_i), // input wire clka
.addra(rom_addr), // input wire [11 : 0] addra
.douta(triangular_data_o) // output wire [13 : 0] douta
);
// 模式选择
always@(*)
case(mode_i)
0 : data_o = sine_data_o;
1 : data_o = square_data_o;
2 : data_o = triangular_data_o;
3 : data_o = 8192;
endcase
endmodule
3、 按键消抖模块
这段代码是一个Verilog模块,名为
key_filter
,它实现了一个按键滤波器的功能。该模块用于检测按键的按下和释放,并确保按键动作至少持续20毫秒。模块提供了按键按下和释放的输出标志,以及当前按键的状态。
/*
Tips:
1、检测到按键按下,会产生一个周期的 press_key_flag_o 提示信号
2、按键按下时间需要持续20ms
*/
module key_filter(
clk_i,
reset_n_i,
key_i,
press_key_flag_o,
release_key_flag_o,
key_state_o
);
input clk_i,reset_n_i,key_i;
output press_key_flag_o,release_key_flag_o,key_state_o;
reg press_key_flag_o,release_key_flag_o;
reg [1:0] state;
wire time_20ms_reached;
reg key_state_o;
localparam IDLE = 0;
localparam PRESS_FILTER = 1;
localparam WAIT = 2;
localparam RELEASE_FILTER = 3;
// 输入 key_i 同步处理 消除亚稳态
reg r_key_i,sync_d_0_key_i,sync_d_1_key_i;
wire nedge_key,pedge_key;
always@(posedge clk_i)
sync_d_0_key_i <= key_i;
always@(posedge clk_i)
sync_d_1_key_i <= sync_d_0_key_i;
always@(posedge clk_i)
r_key_i <= sync_d_1_key_i;
assign nedge_key = r_key_i & (~sync_d_1_key_i);
assign pedge_key = ~r_key_i & sync_d_1_key_i;
// 状态机
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i) begin
release_key_flag_o <= 0;
press_key_flag_o <= 0;
state <= IDLE;
key_state_o <= 1;
end
else begin
case(state)
IDLE :
begin
release_key_flag_o <= 0;
if(nedge_key)
state <= PRESS_FILTER;
else
state <= IDLE;
end
PRESS_FILTER :
if(time_20ms_reached) begin
state <= WAIT;
press_key_flag_o <= 1;
key_state_o <= 0;
end
else if(pedge_key)
state <= IDLE;
else
state <= PRESS_FILTER;
WAIT :
begin
press_key_flag_o <= 0;
if(pedge_key)
state <= RELEASE_FILTER;
else
state <= WAIT;
end
RELEASE_FILTER :
if(time_20ms_reached) begin
state <= IDLE;
release_key_flag_o <= 1;
key_state_o <= 1;
end
else if(nedge_key)
state <= WAIT;
else
state <= RELEASE_FILTER;
endcase
end
// time_20ms_reached
parameter MCNT = 1000_000;
reg [29:0] counter;
always@(posedge clk_i or negedge reset_n_i)
if(!reset_n_i)
counter <= 0;
else if(state == RELEASE_FILTER || state == PRESS_FILTER)
counter <= counter + 1;
else
counter <= 0;
assign time_20ms_reached = ( counter >= (MCNT - 1) );
endmodule
三、功能仿真
这段代码是一个Verilog测试平台(testbench),名为
dds_ad9767_tb
,用于模拟和测试dds_ad9767
模块的行为。测试平台没有物理硬件,它通过模拟输入信号来验证dds_ad9767
模块的功能是否符合预期。
文章来源:https://www.toymoban.com/news/detail-841122.html
`timescale 1ns / 1ps
module dds_ad9767_tb();
reg u_reset_n_i,u_clk_i;
reg [1:0] u_mode_switch_button_a_i,u_mode_switch_button_b_i;
reg u_f_switch_button_a_i,u_p_switch_button_a_i,u_f_switch_button_b_i,u_p_switch_button_b_i;
wire [13:0] u_data_a_o;
wire [13:0] u_data_b_o;
dds_ad9767 U_dds_ad9767(
.reset_n_i(u_reset_n_i),
.clk_i(u_clk_i),
.mode_switch_button_a_i(u_mode_switch_button_a_i),
.f_switch_button_a_i(u_f_switch_button_a_i),
.p_switch_button_a_i(u_p_switch_button_a_i),
.mode_switch_button_b_i(u_mode_switch_button_b_i),
.f_switch_button_b_i(u_f_switch_button_b_i),
.p_switch_button_b_i(u_p_switch_button_b_i),
.data_a_o(u_data_a_o),
.data_b_o(u_data_b_o)
);
initial u_clk_i = 1;
always #10 u_clk_i = ~u_clk_i; // 50MHz
initial begin
u_reset_n_i = 0;
u_f_switch_button_a_i = 1;
u_f_switch_button_b_i = 1;
u_p_switch_button_a_i = 1;
u_p_switch_button_b_i = 1;
// 通道 波形类型 频率倍数 相位
// a sine x1 0 \ b square x1 0
u_mode_switch_button_a_i = 0;
u_mode_switch_button_b_i = 1;
#201;
u_reset_n_i = 1;
#10_000_000;
// a square x1 0 \ b square x1 0
u_mode_switch_button_a_i = 1;
// a square x2 0 \ b square x1 0
u_f_switch_button_a_i = 0;
#20_000_000;
u_f_switch_button_a_i = 1;
#10_000_000;
// a square x2 90 \ b square x1 0
u_p_switch_button_a_i = 0;
#20_000_000;
u_p_switch_button_a_i = 1;
#10_000_000;
// a square x2 90 \ b square x1 90
u_p_switch_button_b_i = 0;
#20_000_000;
u_p_switch_button_b_i = 1;
#10_000_000;
// a square x2 90 \ b triangular x1 90
u_mode_switch_button_b_i = 2;
// a square x2 90 \ b triangular x2 90
u_f_switch_button_a_i = 0;
#20_000_000;
u_f_switch_button_a_i = 1;
#10_000_000;
$stop;
end
endmodule
文章来源地址https://www.toymoban.com/news/detail-841122.html
四、综合优化
五、布局布线
六、时序仿真
七、板级调试
到了这里,关于基于vivado+Verilog FPGA开发 — 基于AD9767高速DAC的DDS信号发生器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!