FPGA-DDS信号发生器

FPGA-DDS信号发生器

DDS基本原理

​ FPGA实现的DDS(直接数字频率合成)波形生成器是一种高效、灵活的数字信号生成技术,广泛应用于通信、雷达和测试设备中。其核心原理是通过数字计算生成特定频率的波形。

​ DDS通过相位累加、查找表(LUT)和数模转换(DAC) 三个步骤生成波形:

  • 相位累加器: 以固定时钟频率 F c l k F_{clk} Fclk运行,每个时钟周期将当前相位值增加一个频率控制字M。相位值决定了波形的瞬时相位;
  • 查找表(LUT): 存储预先计算的波形样本(如正弦波的离散幅度值)。相位累加器的输出作为地址索引,从LUT中读取对应幅值;
  • 数模转换(DAC): 将数字幅值转换为模拟信号(需外部DAC)。若仅需数字输出(如仿真或数字处理),可省略DAC;
  • 其输出频率公式为: F o u t = M 2 N F c l k F_{out}=\frac{M}{2^N}F_{clk} Fout=2NMFclk,其中N为累加器的位数。

ACM9767 DAC模块

​ ACM9767是一个高速双通道DAC模块,每个通道数据分辨率为14位 ,输出电压为±5V,且转换速率高达125MHz,非常适合信号发生器、数字调制通信等应用。

​ 其引脚如下图所示,每个通道有14个数据引脚,1个时钟输入(CLK),一个写入使能(WRT),其中写入使能与CLK保持一致即可(根据芯片手册描述,CLK信号的上升沿必须提前或恰好和 WRT 信号的上升沿一起出现)。

总体设计

​ 每个通道分别通过三个按键控制其生成信号的波形,频率和相位。其中频率的可选范围在1Hz-10MHz,每次按动按钮频率提高十倍。波形分为正弦波、三角波和方波。

​ DDS相关设计分三层。最底层为基本原理层,用三个ROM保存不同波形的信息,根据输入的频率字和相位字,输出一定频率的14位的Data。中间层模块中预设好能够选择的频率和相位,根据输入的频率选择字和相位选择字,得到对应的频率字和相位字,再调用最底层模块得到相应的Data输出。顶层模块例化两个中间层模块作为通道A和B,并例化6个按键,对两个通道的波形、频率和相位进行控制。

ACM9767模块

ACM9767模块为最底层模块,实现DDS信号发生器最底层的原理。主要实现的功能如图所示。其中D/A转换器的功能由外接硬件模块实现。

波形数据表ROM

​ 首先生成对应波形的LUT,LUT的深度为4096,也就是由4096个数据构成完整的波形,数据的位宽为14位(跟ACM9767的14位分辨率对应),波形用厂商提供的软件生成。如下图所示,生成正弦波形的数据。

​ 然后创建ROM IP核,将LUT存储到ROM中。

​ 具体步骤为,打开IP Catalog,然后搜索rom,双击Block Memory ...

​ 然后选择存储器类型为单口ROM,并将IP核名字改成rom_sin

​ 配置数据位宽为14,深度为4096,使能配置为一直使能即可

​ 最后载入波形数据即可

按照以上方法生成方波和三角波的波形和ROM

ACM9767.v

​ 需要注意这里相位累加器(Freq_ACC )的位数设为32位,相位控制器的位数为12(因为数据的深度为 4096 = 2 12 4096=2^{12} 4096=212),则输出波形的频率为:
F o u t = M 2 32 ∗ F c l k F_{out}=\frac{M}{2^{32}}*F_{clk} Fout=232M∗Fclk

  • Note: 实际中使用时, F c l k F_{clk} Fclk通过锁相环产生125MHz频率的时钟信号,但仿真文件中始终信号波形为50MHz
matlab 复制代码
module ACM9767(  
            Clk, 
            Reset_n,
            Model_Sel[1:0],  // 选择时钟
            Fword[31:0],      // 频率控制字
            Pword[11:0],     // 相位控制字
            Data[13:0]        // 输出数据
    );
    input Clk;
    input Reset_n;
    input [1:0] Model_Sel;
    input [31:0] Fword;
    input [11:0] Pword;
    output reg [13:0] Data;
    
    // 频率控制字同步寄存器
    reg [31:0] Fword_r;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Fword_r <= 0;
    else
            Fword_r <= Fword;
    
    // 相位控制字同步寄存器
    reg [11: 0] Pword_r;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Pword_r <= 0;
     else
            Pword_r <= Pword;
    
    // 相位累加器
    reg [31:0] Freq_ACC;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Freq_ACC <= 0;
    else
            Freq_ACC <= Fword_r + Freq_ACC;
    
    // 波形数据表地址
    wire [11:0] Rom_Addr;
    assign Rom_Addr = Freq_ACC[31:20] + Pword_r;
    
    // 三角波
    wire [13: 0] Data_Tri;
    rom_triangular rom_triangular_ins(
              .clka(Clk),
              .addra(Rom_Addr),
              .douta(Data_Tri)
    );
    
    // 正弦波
    wire [13: 0] Data_Sin;
    rom_sin rom_sin_ins(
              .clka(Clk),
              .addra(Rom_Addr),
              .douta(Data_Sin)
    );
    
    // 方波
    wire [13:0] Data_Squ;
        rom_square rom_square_ins(
              .clka(Clk),
              .addra(Rom_Addr),
              .douta(Data_Squ)
    );
    
    // 输出波形选择
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Data <= 0;
    else begin
            case(Model_Sel)
                    0: Data <= Data_Tri;
                    1: Data <= Data_Sin;
                    2: Data <= Data_Squ;
                    3: Data <= 0;
            endcase
     end
endmodule
ACM9767_tb.v
matlab 复制代码
`timescale 1ns / 1ns

module ACM9767_tb();
        reg Clk;
        reg Reset_n;
        reg [1:0] Model_Sel;
        reg [31:0] Fword;
        reg [11:0] Pword;
        wire [13:0] Data;
        ACM9767 ACM9767_ins(
                .Clk(Clk), 
                .Reset_n(Reset_n),
                .Model_Sel(Model_Sel),  // 选择时钟
                .Fword(Fword),      // 频率控制字
                .Pword(Pword),     // 相位控制字
                .Data(Data)        // 输出数据
        );
        initial Clk = 1;
        always #10 Clk = !Clk;
        
        initial begin
                Reset_n = 0;
                #201;
                Reset_n = 1;
                Model_Sel = 0;
                Fword = 85899;   // 1khz  1ms
                Pword  = 0;
                #20000000;
                $stop;
        end
endmodule

DDS_ACM9767模块

​ DDS_ACM9767为中间模块,主要功能为根据计算出的频率字和相位字,预设频率和相位,并能通过频率选择字、相位选择字进行选择。

  • Note: 该模块仿真中设定的 F c l k F_{clk} Fclk为125MHz
DDS_ACM9767.v
matlab 复制代码
// 时钟为125MHz
module DDS_ACM9767(
            Clk,
            Reset_n,
            Model_Sel[1:0],
            Fword_Sel[2:0],
            Pword_Sel[2:0],
            Data[13:0]
    );
    input Clk;
    input Reset_n;
    input [1:0] Model_Sel;
    input [2:0] Fword_Sel;
    input [2:0] Pword_Sel;
    output wire [13:0] Data;
    
    // Fword
    reg [31:0] Fword;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Fword <= 0;
    else begin
            case(Fword_Sel)
                    0: Fword <= 34;    // 1Hz  1/(125MHz)/2^{32}
                    1: Fword <= 344;  // 10Hz
                    2: Fword <= 3436;  // 100Hz
                    3: Fword <= 34360;  // 1KHz
                    4: Fword <= 343597;  // 10KHz
                    5: Fword <= 3435974; // 100KHZ
                    6: Fword <= 34359738;  // 1MHz
                    7: Fword <= 343597384;  // 10MHz
                    default: Fword <= 0;
           endcase
    end
    
    // Pword
    reg [11:0] Pword;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Pword <= 0;
    else begin
            case(Pword_Sel)
                    0: Pword <= 0;   // 0
                    1: Pword <= 341;  // 30      4096 / 12
                    2: Pword <= 683; // 60
                    3: Pword <= 1024;  // 90
                    4: Pword <= 1707;  // 150
                    5: Pword <= 2048;  // 180
                    6: Pword <= 3072;  // 270
                    7: Pword <= 3641;  // 320
                    default: Pword <= 0;
           endcase
    end
    ACM9767 ACM9767_Ins(
                .Clk(Clk), 
                .Reset_n(Reset_n),
                .Model_Sel(Model_Sel),  // 波形选择
                .Fword(Fword),      // 频率控制字
                .Pword(Pword),     // 相位控制字
                .Data(Data)        // 输出数据
    );
endmodule
DDS_ACM9767_tb.v
matlab 复制代码
`timescale 1ns / 1ns

module DDS_ACM9767_tb();
        reg Clk;
        reg Reset_n;
        reg [1:0] Model_Sel_A;
        reg [2:0] Fword_Sel_A;
        reg [2:0] Pword_Sel_A;
        wire [13: 0] DataA;
        
        reg [1:0] Model_Sel_B;
        reg [2:0] Fword_Sel_B;
        reg [2:0] Pword_Sel_B;
        wire [13: 0] DataB;
        DDS_ACM9767 DDS_ACM9767_Ins_A(
                .Clk(Clk),
                .Reset_n(Reset_n),
                 .Model_Sel(Model_Sel_A),
                 .Fword_Sel(Fword_Sel_A),
                 .Pword_Sel(Pword_Sel_A),
                 .Data(DataA)
        );
        
        DDS_ACM9767 DDS_ACM9767_Ins_B(
                .Clk(Clk),
                .Reset_n(Reset_n),
                 .Model_Sel(Model_Sel_B),
                 .Fword_Sel(Fword_Sel_B),
                 .Pword_Sel(Pword_Sel_B),
                 .Data(DataB)
        );
        initial Clk = 1;
        always #4 Clk = !Clk;   //125MHz
        initial begin
                Reset_n = 0;
                #201;
                Reset_n = 1;
                Model_Sel_A = 0;
                Fword_Sel_A = 6;  // 1MHz
                Pword_Sel_A = 0;
                Model_Sel_B = 0;
                Fword_Sel_B = 6;  // 1MHz
                Pword_Sel_B = 3;  // 90
                #2000000;
                Reset_n = 0;
                #201;
                Reset_n = 1;
                Model_Sel_A = 1;
                Fword_Sel_A = 5;  // 1MHz
                Pword_Sel_A = 0;
                #2000000;
                $stop;
        end
endmodule

DDS_Module模块

​ 该模块为顶层模块,例化两个DDS_ACM9767模块,并例化六个按键用于控制波形、频率和相位。由于晶振为50MHz有源晶振,要想使用125MHz的时钟信号来驱动ACM9767运行,需要通过锁相环(PLL)对基频信号 进行倍频分频 ,锁相环的配置可通过时钟管理单元IP核进行。

  • Note: 用按键触发信号,作为DDS_ACM9767模块的复位信号,当按下按键改变设置时,相应参数也重新复原。
时钟管理单元IP核

​ 由于开发板上晶振为50MHz,需要使用时钟管理单元,生成125MHz信号。

​ 在IP Catlalog中找到Clocking Wizard

​ 输入信号频率设为50MHz

​ 输出信号频率设为125MHz

​ 复位类型选择低电平触发(根据开发板硬件设计)

DDS_Module.v
matlab 复制代码
module DSS_Module(
            Clk,
            Reset_n,
            ClkA,
            SkeyA,
            FkeyA,
            PkeyA,
            WrtA,
            ClkB,
            SkeyB,
            FkeyB,
            PkeyB,
            WrtB,
            DataA[13:0],
            DataB[13:0]
    );
    input Clk;
    input Reset_n;
    input SkeyA;
    input FkeyA;
    input PkeyA;
    input SkeyB;
    input FkeyB;
    input PkeyB;
    output wire ClkA;
    output wire ClkB;
    output wire WrtA;
    output wire WrtB;
    output wire [13:0] DataA;
    output wire [13:0] DataB;
    // clock
    wire Clk125MHz;
    wire locked;
    // DDS_ACM9767
    reg [1:0] Model_Sel_A;
    reg [2:0] Fword_Sel_A;
    reg [2:0] Pword_Sel_A;
    reg [1:0] Model_Sel_B;
    reg [2:0] Fword_Sel_B;
    reg [2:0] Pword_Sel_B;
    // key
    wire Press_Flag_SkeyA;
    wire Release_Flag_SkeyA;
    wire filter_state_SkeyA;
    wire Press_Flag_FkeyA;
    wire Release_Flag_FkeyA;
    wire filter_state_FkeyA;
    wire Press_Flag_PkeyA;
    wire Release_Flag_PkeyA;
    wire filter_state_PkeyA;
    
    wire Press_Flag_SkeyB;
    wire Release_Flag_SkeyB;
    wire [1:0] filter_state_SkeyB;
    wire Press_Flag_FkeyB;
    wire Release_Flag_FkeyB;
    wire [1:0] filter_state_FkeyB;
    wire Press_Flag_PkeyB;
    wire Release_Flag_PkeyB;
    wire [1:0] filter_state_PkeyB;
    wire Reset_A;
    wire Reset_B;
    
    assign Reset_A = Release_Flag_SkeyA | Release_Flag_FkeyA | Release_Flag_PkeyA;
    assign Reset_B = Release_Flag_SkeyB | Release_Flag_FkeyB | Release_Flag_PkeyB;
    assign ClkA = Clk125MHz;
    assign ClkB = Clk125MHz;
    
    assign WrtA = ClkA;
    assign WrtB = ClkB;
    // 时钟管理单元生成125MHz时钟
    clk_wiz_0 clk_125_ins(
                .Clk125MHz(Clk125MHz),     // output Clk125MHz
                .resetn(Reset_n), // input rese    
                .locked(locked),       // output locked
               // Clock in ports
                .clk_in1(Clk)
    );      

    // 例化DDS_ACM9767
    DDS_ACM9767 DDS_ACM9767_Ins_A(
            .Clk(Clk125MHz),
            .Reset_n(!Reset_A),
//            .Reset_n(Reset_n),
            .Model_Sel(Model_Sel_A),
            .Fword_Sel(Fword_Sel_A),
            .Pword_Sel(Pword_Sel_A),
            .Data(DataA)
    );
    
    DDS_ACM9767 DDS_ACM9767_Ins_B(
            .Clk(Clk125MHz),
            .Reset_n(!Reset_B),
//            .Reset_n(Reset_n),
            .Model_Sel(Model_Sel_B),
            .Fword_Sel(Fword_Sel_B),
            .Pword_Sel(Pword_Sel_B),
            .Data(DataB)
    );
    // 例化Key_Filter
    key_filter key_filter_SkeyA(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(SkeyA),
            .Press_Flag(Press_Flag_SkeyA),
            .Release_Flag(Release_Flag_SkeyA),
            .filter_state(filter_state_SkeyA),
            .result()
    );
    
    key_filter key_filter_FkeyA(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(FkeyA),
            .Press_Flag(Press_Flag_FkeyA),
            .Release_Flag(Release_Flag_FkeyA),
            .filter_state(filter_state_FkeyA),
            .result()
    );
    
    key_filter key_filter_PkeyA(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(PkeyA),
            .Press_Flag(Press_Flag_PkeyA),
            .Release_Flag(Release_Flag_PkeyA),
            .filter_state(filter_state_PkeyA),
            .result()
    );
    
    key_filter key_filter_SkeyB(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(SkeyB),
            .Press_Flag(Press_Flag_SkeyB),
            .Release_Flag(Release_Flag_SkeyB),
            .filter_state(filter_state_SkeyB),
            .result()
    );
    
    key_filter key_filter_FkeyB(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(FkeyB),
            .Press_Flag(Press_Flag_FkeyB),
            .Release_Flag(Release_Flag_FkeyB),
            .filter_state(filter_state_FkeyB),
            .result()
    );
    
    key_filter key_filter_PkeyB(
            .Clk(Clk125MHz),
            .Reset_n(Reset_n),
            .signal(PkeyB),
            .Press_Flag(Press_Flag_PkeyB),
            .Release_Flag(Release_Flag_PkeyB),
            .filter_state(filter_state_PkeyB),
            .result()
    );
    
    // Model_Sel_A
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Model_Sel_A <= 0;
    else if(Release_Flag_SkeyA && (filter_state_SkeyA == 0))
        Model_Sel_A <= Model_Sel_A + 1;
    
    // Fword_Sel_A
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Fword_Sel_A <= 3;  // 1khz
    else if(Release_Flag_FkeyA && (filter_state_FkeyA == 0))
        Fword_Sel_A <= Fword_Sel_A + 1;
    
    // Pword_Sel_A
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Pword_Sel_A<= 0;
    else if(Release_Flag_PkeyA && (filter_state_PkeyA == 0))
        Pword_Sel_A <=Pword_Sel_A + 1;
    
    // Model_Sel_B
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Model_Sel_B <= 1;
    else if(Release_Flag_SkeyB && (filter_state_SkeyB == 0))
        Model_Sel_B <= Model_Sel_B + 1;
    
    // Fword_Sel_B
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Fword_Sel_B <= 3;
    else if(Release_Flag_FkeyB && (filter_state_FkeyB == 0))
        Fword_Sel_B <= Fword_Sel_B + 1;
    
    // Pword_Sel_B
    always@(posedge Clk125MHz or negedge Reset_n)
    if(!Reset_n)
        Pword_Sel_B<= 0;
    else if(Release_Flag_PkeyB && (filter_state_PkeyB == 0))
        Pword_Sel_B <= Pword_Sel_B + 1;
endmodule
DDS_Module_tb.v
  • Note: 由于信号较多,软件仿真的速度很慢,不利于调试,仅供参考,推荐使用ILA硬件调试。(ILA硬件调试方法会在后面小节具体介绍)
matlab 复制代码
`timescale 1ns / 1ns
// Not in use
module DDS_Module_tb();
        reg Clk;
        reg Reset_n;
        reg SkeyA;
        reg FkeyA;
        reg PkeyA;
        reg SkeyB;
        reg FkeyB;
        reg PkeyB;
        wire ClkA;
        wire ClkB;
        wire [13:0] DataA;
        wire [13:0] DataB;
        DSS_Module DSS_Module_ins(
                .Clk(Clk),
                .Reset_n(Reset_n),
                .ClkA(ClkA),
                .SkeyA(SkeyA),
                .FkeyA(FkeyA),
                .PkeyA(PkeyA),
                .WrtA(),
                .ClkB(ClkB),
                .SkeyB(SkeyB),
                .FkeyB(FkeyB),
                .PkeyB(PkeyB),
                .WrtB(),
                .DataA(DataA),
                .DataB(DataB)
    );
    initial Clk = 1;
    always #10 Clk = !Clk;
    reg [31: 0] rand;
    initial begin
            Reset_n = 0;
            #201;
            Reset_n = 1;
            press_skeyA(0);
            press_pkeyA(0);
            press_fkeyA(0);
            $stop;
    end
    
    task press_skeyA;
            input [3:0] seed;
            begin
                   SkeyA = 1;
                   #20000000;
                   repeat(5)begin
                         rand = {$random} % 10000000;   // 10ms以内的抖动
                        #rand SkeyA = ~SkeyA;
                   end
                   SkeyA = 0;
                   #20000000;
                   repeat(5)begin
                          rand = {$random} % 10000000;   // 10ms以内的抖动
                         #rand SkeyA = ~SkeyA;
                   end
                   SkeyA = 1;
                   #20000000;
                   #20000000;
            end
    endtask
    
     task press_fkeyA;
            input [3:0] seed;
            begin
                   FkeyA = 1;
                   #20000000;
                   repeat(5)begin
                         rand = {$random} % 10000000;   // 10ms以内的抖动
                        #rand FkeyA = ~FkeyA;
                   end
                   FkeyA = 0;
                   #20000000;
                   repeat(5)begin
                          rand = {$random} % 10000000;   // 10ms以内的抖动
                         #rand FkeyA = ~FkeyA;
                   end
                   FkeyA = 1;
                   #20000000;
                   #20000000;
            end
    endtask
    
      task press_pkeyA;
            input [3:0] seed;
            begin
                   PkeyA = 1;
                   #20000000;
                   repeat(5)begin
                         rand = {$random} % 10000000;   // 10ms以内的抖动
                        #rand PkeyA = ~PkeyA;
                   end
                   PkeyA = 0;
                   #20000000;
                   repeat(5)begin
                          rand = {$random} % 10000000;   // 10ms以内的抖动
                         #rand PkeyA = ~PkeyA;
                   end
                   PkeyA = 1;
                   #20000000;
                   #20000000;
            end
    endtask
endmodule

key_filter模块

​ 按键模块,进行20ms的消抖处理,若时钟频率改变,则需要修改对于计数器的最大计数值,这里支持的是125MHz的频率。

key_filter.v
matlab 复制代码
// 按键消抖  等待按键按下(下降沿) --->消抖, 若20ms没出现上升沿 ---> 按键已按下---?等待释放 ---> 20ms? --->已释放
module key_filter(
            Clk,
            Reset_n,
            signal,
            Press_Flag,
            Release_Flag,
            filter_state,
            result
    );
    input Clk;
    input Reset_n;
    input signal;
    output reg Press_Flag;
    output reg Release_Flag;
    output reg [1:0] filter_state;
    output reg result;
    // 多级寄存器缓解亚稳态现象
    reg [1: 0] sync_reg;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            sync_reg <= 0;
    else
           sync_reg <= {sync_reg[0], signal};
    // 边缘检测器
    reg [1:0] edge_reg;    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            edge_reg <= 0;
    else
           edge_reg <= {edge_reg[0], sync_reg[1]};
    wire pos_edge;
    assign pos_edge = (edge_reg == 2'b01);
    wire neg_edge;
    assign neg_edge = (edge_reg == 2'b10);
    reg [23:0] cnt;
    // filter_state
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            filter_state <= 0;
    else if(filter_state == 0)begin
            if(neg_edge)
                    filter_state <= 1;
    end
    else if(filter_state == 1)begin
            if(pos_edge)
                    filter_state <= 0;  // 回到等待状态
            else if(cnt == 2500000 - 1)// 20ms
                    filter_state <= 2;
    end
    else if(filter_state == 2)begin
            if(pos_edge)    // 出现上升沿
                    filter_state <= 3;  // 进入释放消抖
    end
    else if(filter_state == 3)begin
            if(neg_edge)
                    filter_state <= 2;
            else if(cnt == 2500000 - 1)
                    filter_state <= 0;
    end
    
    // Press_Flag
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Press_Flag <= 0;
    else if(filter_state == 1 && (cnt == 2500000 - 1))
            Press_Flag <= 1;
    else if(filter_state == 2)
            Press_Flag <= 0;
            
    // Release_Flag
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            Release_Flag <= 0;
    else if(filter_state == 0)
            Release_Flag <= 0;
    else if(filter_state == 3 && (cnt == 2500000 - 1)) 
            Release_Flag <= 1;
    
    // result
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            result <= 1;
    else if(filter_state == 1 && (cnt == 2500000 - 1))
            result <= 0;
    else if(filter_state == 3 && (cnt == 2500000 - 1))
            result <= 1;

    
    // cnt
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
            cnt <= 0;
    else if(filter_state == 1)begin
            cnt <= cnt + 1;
            if(pos_edge)
                    cnt <= 0;
            else if(cnt == 2500000 - 1)
                    cnt <= 0;
    end
    else if(filter_state == 3)begin
            cnt <= cnt + 1;
            if(neg_edge)
                    cnt <= 0;       
            else if(cnt == 2500000 - 1)
                    cnt <= 0;
     end
endmodule
key_filter_tb.v
matlab 复制代码
`timescale 1ns / 1ns
module key_filter_tb();
        reg Clk;
        reg Reset_n;
        reg signal;
        wire Press_Flag;
        wire Release_Flag;
        wire [1:0] filter_state;
        wire result;
        key_filter key_filter_ins(
                .Clk(Clk),
                .Reset_n(Reset_n),
                .signal(signal),
                .Press_Flag(Press_Flag),
                .Release_Flag(Release_Flag),
                .filter_state(filter_state),
                .result(result)
        );
        initial Clk = 1;
        always #4 Clk = !Clk;
       reg [31: 0] rand;
        initial begin
            Reset_n = 0;
            #201;
            Reset_n = 1;
            #20;
            press_key(0);
            $stop;
        end
        
        task press_key;
                input [3:0] seed;
                begin
                       signal = 1;
                       #20000000;
                       repeat(5)begin
                             rand = {$random} % 10000000;   // 10ms以内的抖动
                            #rand signal = ~signal;
                       end
                       signal = 0;
                       #20000000;
                       repeat(5)begin
                              rand = {$random} % 10000000;   // 10ms以内的抖动
                             #rand signal = ~signal;
                       end
                       signal = 1;
                       #20000000;
                       #20000000;
                end
        endtask
endmodule

ILA硬件调试方法

​ ILA的使用方式有很多,这里就讲一种我比较喜欢的方式。

​ 首先,运行综合,后打开综合设计器。

​ 然后在netlist里面,可以选择感兴趣的信号设置debug,被选中的信号左边会有个小爬虫

​ 右上角选择Debug界面

​ 在Debug界面为没有分配ILA IP核的信号,创建或分配一个探针

​ 进入到ILA IP核向导界面

​ 跟着向导走,直到来到以下界面,该界面可以配置需要debug信号探针的类型,DataTrigger Data&Trigger,触发类型信号,设置触发条件后,当达到触发条件时,ILA会对信号进行采样。这里我们只想看看按键按下后,对应的选择字位有没有变化,因此设置成Data类型的探针就好,当按下开发板按键后,手动触发信号采样。

  • PkeyA_IBUF: 是为了展示使用ILA过程。

    然后选择合适的深度,就是一次采样中,采样点的个数

设置完成后,正常流程生产比特流文件即可。然后当连接到硬件时,Vivado 会将比特流文件和调试文件一起烧录到开发板中。

​ 然后可以看到ILA的界面,点击触发按钮手动触发一次采样。

​ 可以看到采样到的值

​ 按下开发板上的按键,再重新手动触发采样,看看值是否有改变,若改变,则说明按键部分的功能实现无误。

​ ILA还能设置触发条件进行采样,在有些应用中只能通过该方法进行调试,具体方法自行了解。

实验现象

看看效果

FPGA-DDS

相关硬件

小梅哥FPGA ACX720

FPGA芯片型号: XC7A35TFGG484ABX2l

DMA: ACM9767

示波器: 正点原子

相关推荐
黄埔数据分析7 小时前
RecoNIC 入门:SmartNIC 上支持 RDMA 的计算卸载-FPGA-智能网卡-AMD-Xilinx
fpga开发
nanxl19 小时前
FPGA-数字时钟
fpga开发·verilog·vivado
尤老师FPGA1 天前
LVDS系列9:Xilinx 7系可编程输入延迟(二)
单片机·嵌入式硬件·fpga开发
内有小猪卖1 天前
时序约束 记录
fpga开发
Cao1234567893211 天前
FPGA时钟设计
fpga开发
JNTeresa1 天前
锁存器知识点详解
fpga开发
Cao1234567893211 天前
FPGA基础之基础语法
fpga开发
一大Cpp1 天前
通过Quartus II实现Nios II编程
fpga开发
7yewh2 天前
Verilog 语法 (二)
fpga开发