当前位置:   article > 正文

基于vivado+Verilog FPGA开发 — 基于AD9767高速DAC的DDS信号发生器

ad9767

代码规范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)芯片协同工作而设计。

  1. /*
  2. Tips:
  3. 1、可分别于A、B通道同时输出两路波形
  4. 2、每次按下 f_switch_button_a_i , 通道A输出频率在预设的四种情况切换;通道B同理。
  5. 3、每次按下 p_switch_button_a_i , 通道A输出相位在预设的两种情况切换;通道B同理。
  6. */
  7. module dds_ad9767(
  8. reset_n_i,
  9. clk_i,
  10. mode_switch_button_a_i,
  11. f_switch_button_a_i,
  12. p_switch_button_a_i,
  13. mode_switch_button_b_i,
  14. f_switch_button_b_i,
  15. p_switch_button_b_i,
  16. data_a_o,
  17. data_b_o
  18. );
  19. input reset_n_i,clk_i;
  20. input [1:0]mode_switch_button_a_i,mode_switch_button_b_i;
  21. input f_switch_button_a_i,p_switch_button_a_i,f_switch_button_b_i,p_switch_button_b_i;
  22. output [13:0] data_a_o;
  23. output [13:0] data_b_o;
  24. // A通道dds例化
  25. reg [31:0] u_f_word_a;
  26. reg [11:0] u_p_word_a;
  27. dds U_dds_a(
  28. .reset_n_i(reset_n_i),
  29. .clk_i(clk_i),
  30. .f_word_i(u_f_word_a),
  31. .p_word_i(u_p_word_a),
  32. .mode_i(mode_switch_button_a_i),
  33. .data_o(data_a_o)
  34. );
  35. // A通道频率切换
  36. wire f_switch_button_a_press_key_flag;
  37. key_filter U_f_switch_button_a_i(
  38. .clk_i(clk_i),
  39. .reset_n_i(reset_n_i),
  40. .key_i(f_switch_button_a_i),
  41. .press_key_flag_o(f_switch_button_a_press_key_flag)
  42. );
  43. reg [1:0] f_switch_cnt_a;
  44. always@(posedge clk_i or negedge reset_n_i)
  45. if(!reset_n_i)
  46. f_switch_cnt_a <= 0;
  47. else if(f_switch_button_a_press_key_flag == 1)
  48. f_switch_cnt_a <= f_switch_cnt_a + 1;
  49. always@(*)
  50. case(f_switch_cnt_a)
  51. 0 : u_f_word_a <= 65536;
  52. 1 : u_f_word_a <= 65536*2;
  53. 2 : u_f_word_a <= 65536*3;
  54. 3 : u_f_word_a <= 65536*4;
  55. endcase
  56. // A通道相位切换
  57. wire p_switch_button_a_press_key_flag;
  58. key_filter U_p_switch_button_a_i(
  59. .clk_i(clk_i),
  60. .reset_n_i(reset_n_i),
  61. .key_i(p_switch_button_a_i),
  62. .press_key_flag_o(p_switch_button_a_press_key_flag)
  63. );
  64. reg p_switch_cnt_a;
  65. always@(posedge clk_i or negedge reset_n_i)
  66. if(!reset_n_i)
  67. p_switch_cnt_a <= 0;
  68. else if(p_switch_button_a_press_key_flag == 1)
  69. p_switch_cnt_a <= p_switch_cnt_a + 1;
  70. always@(*)
  71. case(p_switch_cnt_a)
  72. 0 : u_p_word_a <= 0;
  73. 1 : u_p_word_a <= 1024;
  74. endcase
  75. // B通道dds例化
  76. reg [31:0] u_f_word_b;
  77. reg [11:0] u_p_word_b;
  78. dds U_dds_b(
  79. .reset_n_i(reset_n_i),
  80. .clk_i(clk_i),
  81. .f_word_i(u_f_word_b),
  82. .p_word_i(u_p_word_b),
  83. .mode_i(mode_switch_button_b_i),
  84. .data_o(data_b_o)
  85. );
  86. // B通道频率切换
  87. wire f_switch_button_b_press_key_flag;
  88. key_filter U_f_switch_button_b_i(
  89. .clk_i(clk_i),
  90. .reset_n_i(reset_n_i),
  91. .key_i(f_switch_button_b_i),
  92. .press_key_flag_o(f_switch_button_b_press_key_flag)
  93. );
  94. reg [1:0] f_switch_cnt_b;
  95. always@(posedge clk_i or negedge reset_n_i)
  96. if(!reset_n_i)
  97. f_switch_cnt_b <= 0;
  98. else if(f_switch_button_b_press_key_flag == 1)
  99. f_switch_cnt_b <= f_switch_cnt_b + 1;
  100. always@(*)
  101. case(f_switch_cnt_b)
  102. 0 : u_f_word_b <= 65536;
  103. 1 : u_f_word_b <= 65536*2;
  104. 2 : u_f_word_b <= 65536*3;
  105. 3 : u_f_word_b <= 65536*4;
  106. endcase
  107. // B通道相位切换
  108. wire p_switch_button_b_press_key_flag;
  109. key_filter U_p_switch_button_b_i(
  110. .clk_i(clk_i),
  111. .reset_n_i(reset_n_i),
  112. .key_i(p_switch_button_b_i),
  113. .press_key_flag_o(p_switch_button_b_press_key_flag)
  114. );
  115. reg p_switch_cnt_b;
  116. always@(posedge clk_i or negedge reset_n_i)
  117. if(!reset_n_i)
  118. p_switch_cnt_b <= 0;
  119. else if(p_switch_button_b_press_key_flag == 1)
  120. p_switch_cnt_b <= p_switch_cnt_b + 1;
  121. always@(*)
  122. case(p_switch_cnt_b)
  123. 0 : u_p_word_b <= 0;
  124. 1 : u_p_word_b <= 1024;
  125. endcase
  126. endmodule

 2、DDS模块

1、IP设置

 

 

 2、初始文件生成设置

3、代码部分

这段代码是一个Verilog模块,名为dds,它实现了一个直接数字频率合成器(DDS)的功能。DDS是一种电子系统,能够通过数字技术生成模拟波形,如正弦波、方波和三角波等。这个模块通过接收频率字(f_word_i)和相位字(p_word_i)输入,以及模式选择信号(mode_i),来输出相应的波形数据。

  1. /*
  2. Tips:
  3. 1、修改 mode_i 可以切换三种不同的输出波形
  4. 2、f_word_i 频率字输入,当等于典型值2^16=65536时,dds输出的波形频率在738Hz左右
  5. 3、p_word_i 相位字输入,当等于典型值1024时,dds输出的波形起始相位为90°
  6. */
  7. module dds(
  8. reset_n_i,
  9. clk_i,
  10. f_word_i,
  11. p_word_i,
  12. mode_i,
  13. data_o
  14. );
  15. input [1:0] mode_i;
  16. input reset_n_i,clk_i;
  17. input [31:0]f_word_i;
  18. input [11:0]p_word_i;
  19. output reg [13:0] data_o;
  20. // 频率字输入寄存器 r_f_word_i
  21. reg [31:0] r_f_word_i;
  22. always@(posedge clk_i)
  23. r_f_word_i <= f_word_i;
  24. // 相位字输入寄存器 r_f_word_i
  25. reg [11:0] r_p_word_i;
  26. always@(posedge clk_i)
  27. r_p_word_i <= p_word_i;
  28. // 相位累加器 phase_accumulator
  29. reg [31:0] phase_accumulator;
  30. always@(posedge clk_i or negedge reset_n_i)
  31. if(!reset_n_i)
  32. phase_accumulator <= 0;
  33. else
  34. phase_accumulator <= phase_accumulator + r_f_word_i;
  35. // 波形数据表地址 rom_addr
  36. reg [11:0] rom_addr;
  37. always@(posedge clk_i or negedge reset_n_i)
  38. if(!reset_n_i)
  39. rom_addr <= 0;
  40. else
  41. rom_addr <= r_p_word_i + phase_accumulator[31:20];
  42. // sine波形
  43. wire [13:0] sine_data_o;
  44. sine_rom U_sine_rom (
  45. .clka(clk_i), // input wire clka
  46. .addra(rom_addr), // input wire [11 : 0] addra
  47. .douta(sine_data_o) // output wire [13 : 0] douta
  48. );
  49. // square波形
  50. wire [13:0] square_data_o;
  51. square_rom U_square_rom (
  52. .clka(clk_i), // input wire clka
  53. .addra(rom_addr), // input wire [11 : 0] addra
  54. .douta(square_data_o) // output wire [13 : 0] douta
  55. );
  56. // triangular波形
  57. wire [13:0] triangular_data_o;
  58. triangular_rom U_triangular_rom (
  59. .clka(clk_i), // input wire clka
  60. .addra(rom_addr), // input wire [11 : 0] addra
  61. .douta(triangular_data_o) // output wire [13 : 0] douta
  62. );
  63. // 模式选择
  64. always@(*)
  65. case(mode_i)
  66. 0 : data_o = sine_data_o;
  67. 1 : data_o = square_data_o;
  68. 2 : data_o = triangular_data_o;
  69. 3 : data_o = 8192;
  70. endcase
  71. endmodule

3、 按键消抖模块

这段代码是一个Verilog模块,名为key_filter,它实现了一个按键滤波器的功能。该模块用于检测按键的按下和释放,并确保按键动作至少持续20毫秒。模块提供了按键按下和释放的输出标志,以及当前按键的状态。

  1. /*
  2. Tips:
  3. 1、检测到按键按下,会产生一个周期的 press_key_flag_o 提示信号
  4. 2、按键按下时间需要持续20ms
  5. */
  6. module key_filter(
  7. clk_i,
  8. reset_n_i,
  9. key_i,
  10. press_key_flag_o,
  11. release_key_flag_o,
  12. key_state_o
  13. );
  14. input clk_i,reset_n_i,key_i;
  15. output press_key_flag_o,release_key_flag_o,key_state_o;
  16. reg press_key_flag_o,release_key_flag_o;
  17. reg [1:0] state;
  18. wire time_20ms_reached;
  19. reg key_state_o;
  20. localparam IDLE = 0;
  21. localparam PRESS_FILTER = 1;
  22. localparam WAIT = 2;
  23. localparam RELEASE_FILTER = 3;
  24. // 输入 key_i 同步处理 消除亚稳态
  25. reg r_key_i,sync_d_0_key_i,sync_d_1_key_i;
  26. wire nedge_key,pedge_key;
  27. always@(posedge clk_i)
  28. sync_d_0_key_i <= key_i;
  29. always@(posedge clk_i)
  30. sync_d_1_key_i <= sync_d_0_key_i;
  31. always@(posedge clk_i)
  32. r_key_i <= sync_d_1_key_i;
  33. assign nedge_key = r_key_i & (~sync_d_1_key_i);
  34. assign pedge_key = ~r_key_i & sync_d_1_key_i;
  35. // 状态机
  36. always@(posedge clk_i or negedge reset_n_i)
  37. if(!reset_n_i) begin
  38. release_key_flag_o <= 0;
  39. press_key_flag_o <= 0;
  40. state <= IDLE;
  41. key_state_o <= 1;
  42. end
  43. else begin
  44. case(state)
  45. IDLE :
  46. begin
  47. release_key_flag_o <= 0;
  48. if(nedge_key)
  49. state <= PRESS_FILTER;
  50. else
  51. state <= IDLE;
  52. end
  53. PRESS_FILTER :
  54. if(time_20ms_reached) begin
  55. state <= WAIT;
  56. press_key_flag_o <= 1;
  57. key_state_o <= 0;
  58. end
  59. else if(pedge_key)
  60. state <= IDLE;
  61. else
  62. state <= PRESS_FILTER;
  63. WAIT :
  64. begin
  65. press_key_flag_o <= 0;
  66. if(pedge_key)
  67. state <= RELEASE_FILTER;
  68. else
  69. state <= WAIT;
  70. end
  71. RELEASE_FILTER :
  72. if(time_20ms_reached) begin
  73. state <= IDLE;
  74. release_key_flag_o <= 1;
  75. key_state_o <= 1;
  76. end
  77. else if(nedge_key)
  78. state <= WAIT;
  79. else
  80. state <= RELEASE_FILTER;
  81. endcase
  82. end
  83. // time_20ms_reached
  84. parameter MCNT = 1000_000;
  85. reg [29:0] counter;
  86. always@(posedge clk_i or negedge reset_n_i)
  87. if(!reset_n_i)
  88. counter <= 0;
  89. else if(state == RELEASE_FILTER || state == PRESS_FILTER)
  90. counter <= counter + 1;
  91. else
  92. counter <= 0;
  93. assign time_20ms_reached = ( counter >= (MCNT - 1) );
  94. endmodule

三、功能仿真 

这段代码是一个Verilog测试平台(testbench),名为dds_ad9767_tb,用于模拟和测试dds_ad9767模块的行为。测试平台没有物理硬件,它通过模拟输入信号来验证dds_ad9767模块的功能是否符合预期。

  1. `timescale 1ns / 1ps
  2. module dds_ad9767_tb();
  3. reg u_reset_n_i,u_clk_i;
  4. reg [1:0] u_mode_switch_button_a_i,u_mode_switch_button_b_i;
  5. 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;
  6. wire [13:0] u_data_a_o;
  7. wire [13:0] u_data_b_o;
  8. dds_ad9767 U_dds_ad9767(
  9. .reset_n_i(u_reset_n_i),
  10. .clk_i(u_clk_i),
  11. .mode_switch_button_a_i(u_mode_switch_button_a_i),
  12. .f_switch_button_a_i(u_f_switch_button_a_i),
  13. .p_switch_button_a_i(u_p_switch_button_a_i),
  14. .mode_switch_button_b_i(u_mode_switch_button_b_i),
  15. .f_switch_button_b_i(u_f_switch_button_b_i),
  16. .p_switch_button_b_i(u_p_switch_button_b_i),
  17. .data_a_o(u_data_a_o),
  18. .data_b_o(u_data_b_o)
  19. );
  20. initial u_clk_i = 1;
  21. always #10 u_clk_i = ~u_clk_i; // 50MHz
  22. initial begin
  23. u_reset_n_i = 0;
  24. u_f_switch_button_a_i = 1;
  25. u_f_switch_button_b_i = 1;
  26. u_p_switch_button_a_i = 1;
  27. u_p_switch_button_b_i = 1;
  28. // 通道 波形类型 频率倍数 相位
  29. // a sine x1 0 \ b square x1 0
  30. u_mode_switch_button_a_i = 0;
  31. u_mode_switch_button_b_i = 1;
  32. #201;
  33. u_reset_n_i = 1;
  34. #10_000_000;
  35. // a square x1 0 \ b square x1 0
  36. u_mode_switch_button_a_i = 1;
  37. // a square x2 0 \ b square x1 0
  38. u_f_switch_button_a_i = 0;
  39. #20_000_000;
  40. u_f_switch_button_a_i = 1;
  41. #10_000_000;
  42. // a square x2 90 \ b square x1 0
  43. u_p_switch_button_a_i = 0;
  44. #20_000_000;
  45. u_p_switch_button_a_i = 1;
  46. #10_000_000;
  47. // a square x2 90 \ b square x1 90
  48. u_p_switch_button_b_i = 0;
  49. #20_000_000;
  50. u_p_switch_button_b_i = 1;
  51. #10_000_000;
  52. // a square x2 90 \ b triangular x1 90
  53. u_mode_switch_button_b_i = 2;
  54. // a square x2 90 \ b triangular x2 90
  55. u_f_switch_button_a_i = 0;
  56. #20_000_000;
  57. u_f_switch_button_a_i = 1;
  58. #10_000_000;
  59. $stop;
  60. end
  61. endmodule

四、综合优化

五、布局布线

六、时序仿真

七、板级调试 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/624806
推荐阅读
相关标签
  

闽ICP备14008679号